static void print_analysis_report(memcached_st *memc, memcached_analysis_st *report, memcached_server_st *server_list) { uint32_t server_count= memcached_server_count(memc); printf("Memcached Cluster Analysis Report\n\n"); printf("\tNumber of Servers Analyzed : %d\n", server_count); printf("\tAverage Item Size (incl/overhead) : %u bytes\n", report->average_item_size); if (server_count == 1) { printf("\nFor a detailed report, you must supply multiple servers.\n"); return; } printf("\n"); printf("\tNode with most memory consumption : %s:%u (%u bytes)\n", memcached_server_name(memc, server_list[report->most_consumed_server]), memcached_server_port(memc, server_list[report->most_consumed_server]), report->most_used_bytes); printf("\tNode with least free space : %s:%u (%u bytes remaining)\n", memcached_server_name(memc, server_list[report->least_free_server]), memcached_server_port(memc, server_list[report->least_free_server]), report->least_remaining_bytes); printf("\tNode with longest uptime : %s:%u (%us)\n", memcached_server_name(memc, server_list[report->oldest_server]), memcached_server_port(memc, server_list[report->oldest_server]), report->longest_uptime); printf("\tPool-wide Hit Ratio : %1.f%%\n", report->pool_hit_ratio); printf("\n"); }
static void print_server_listing(memcached_st *memc, memcached_stat_st *stat, memcached_server_st *server_list) { unsigned int x; memcached_return rc; printf("Listing %u Server\n\n", memcached_server_count(memc)); for (x= 0; x < memcached_server_count(memc); x++) { char **list; char **ptr; list= memcached_stat_get_keys(memc, &stat[x], &rc); printf("Server: %s (%u)\n", memcached_server_name(memc, server_list[x]), memcached_server_port(memc, server_list[x])); for (ptr= list; *ptr; ptr++) { memcached_return rc; char *value= memcached_stat_get_value(memc, &stat[x], *ptr, &rc); printf("\t %s: %s\n", *ptr, value); free(value); } free(list); printf("\n"); } }
/*doc Memcached stats Returns a Map with servers' statistics. Keys are server addresses, values are maps with actual stats. */ IoObject *IoMemcached_stats(IoMemcached *self, IoObject *locals, IoMessage *m) { IoMap *results_map = IoMap_new(IOSTATE); int errors = 0; uint32_t pos = 0; while(pos < memcached_server_count(DATA(self)->mc)) { memcached_server_instance_st server = memcached_server_instance_by_position(DATA(self)->mc, pos); if(server == NULL) continue; const char *hostname = memcached_server_name(server); const in_port_t port = memcached_server_port(server); memcached_stat_st stats; memcached_return_t rc = memcached_stat_servername(&stats, "", hostname, port); if(rc != MEMCACHED_SUCCESS) { errors++; continue; } char **ckeys = memcached_stat_get_keys(DATA(self)->mc, &stats, &rc); if(rc != MEMCACHED_SUCCESS) { errors++; continue; } IoMap *per_server_map = IoMap_new(IOSTATE); char *ckey = *ckeys; while(ckey != NULL) { char *cvalue = memcached_stat_get_value(DATA(self)->mc, &stats, ckey, &rc); if(rc != MEMCACHED_SUCCESS) { errors++; continue; } IoMap_rawAtPut(per_server_map, IOSYMBOL(ckey), IOSYMBOL(cvalue)); free(cvalue); ckey++; } free(ckeys); // "127.0.0.1:11211" char *server_key = (char *) malloc((strlen(hostname) + 1 + 5 + 1) * sizeof(char)); sprintf(server_key, "%s:%d", hostname, port); IoMap_rawAtPut(results_map, IOSYMBOL(server_key), per_server_map); free(server_key); pos++; } if(errors > 0) IoState_error_(IOSTATE, m, memcached_strerror(DATA(self)->mc, MEMCACHED_SOME_ERRORS)); return results_map; }
mcs_st *lmc_create(mcs_st *ptr, const char *config) { assert(ptr); memset(ptr, 0, sizeof(*ptr)); ptr->kind = MCS_KIND_LIBMEMCACHED; memcached_st *mst = memcached_create(NULL); if (mst != NULL) { memcached_behavior_set(mst, MEMCACHED_BEHAVIOR_NO_BLOCK, 1); memcached_behavior_set(mst, MEMCACHED_BEHAVIOR_KETAMA, 1); memcached_behavior_set(mst, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1); memcached_server_st *mservers; mservers = memcached_servers_parse(config); if (mservers != NULL) { memcached_server_push(mst, mservers); ptr->data = mst; ptr->nservers = (int) memcached_server_list_count(mservers); if (ptr->nservers > 0) { ptr->servers = calloc(sizeof(mcs_server_st), ptr->nservers); if (ptr->servers != NULL) { for (int i = 0; i < ptr->nservers; i++) { ptr->servers[i].fd = -1; } int j = 0; for (; j < ptr->nservers; j++) { strncpy(ptr->servers[j].hostname, memcached_server_name(mservers + j), sizeof(ptr->servers[j].hostname) - 1); ptr->servers[j].port = (int) memcached_server_port(mservers + j); if (ptr->servers[j].port <= 0) { moxi_log_write("lmc_create failed, could not parse port: %s\n", config); break; } } if (j >= ptr->nservers) { memcached_server_list_free(mservers); return ptr; } } } memcached_server_list_free(mservers); } } mcs_free(ptr); return NULL; }
int pr_memcache_kadd(pr_memcache_t *mcache, module *m, const char *key, size_t keysz, void *value, size_t valuesz, time_t expires, uint32_t flags) { memcached_return res; /* XXX Should we allow null values to be added, thus allowing use of keys * as sentinels? */ if (mcache == NULL || m == NULL || key == NULL || value == NULL) { errno = EINVAL; return -1; } mcache_set_module_namespace(mcache, m); res = memcached_add(mcache->mc, key, keysz, value, valuesz, expires, flags); mcache_set_module_namespace(mcache, NULL); switch (res) { case MEMCACHED_SUCCESS: return 0; case MEMCACHED_ERRNO: if (errno != EINPROGRESS) { int xerrno = errno; pr_trace_msg(trace_channel, 3, "error adding key (%lu bytes), value (%lu bytes): system error: %s", (unsigned long) keysz, (unsigned long) valuesz, strerror(xerrno)); errno = xerrno; } else { /* We know that we're not using nonblocking IO; this value usually * means that libmemcached could not connect to the configured * memcached servers. So set the value to something more * indicative, and fall through. */ res = MEMCACHED_CONNECTION_FAILURE; } break; case MEMCACHED_SERVER_MARKED_DEAD: case MEMCACHED_CONNECTION_FAILURE: { memcached_server_instance_st server; server = memcached_server_get_last_disconnect(mcache->mc); if (server != NULL) { pr_trace_msg(trace_channel, 3, "unable to connect to %s:%d", memcached_server_name(server), memcached_server_port(server)); } break; } default: pr_trace_msg(trace_channel, 2, "error adding key (%lu bytes), value (%lu bytes): %s", (unsigned long) keysz, (unsigned long) valuesz, memcached_strerror(mcache->mc, res)); errno = EPERM; break; } return -1; }
static int mcache_stat_servers(pr_memcache_t *mcache) { memcached_stat_st *mst; memcached_return res; mst = memcached_stat(mcache->mc, NULL, &res); if (mst != NULL) { if (res == MEMCACHED_SUCCESS) { register unsigned int i; const char *stat_keys[] = { "version", "uptime", "curr_connections", "curr_items", "bytes", "limit_maxbytes", NULL }; /* Log some of the stats about the memcached servers to which we just * connected. */ for (i = 0; stat_keys[i] != NULL; i++) { char *info; info = memcached_stat_get_value(mcache->mc, mst, stat_keys[i], &res); if (info != NULL) { pr_trace_msg(trace_channel, 9, "memcached server stats: %s = %s", stat_keys[i], info); free(info); } else { pr_trace_msg(trace_channel, 6, "unable to obtain '%s' stat: %s", stat_keys[i], memcached_strerror(mcache->mc, res)); } } } else { switch (res) { case MEMCACHED_ERRNO: if (errno != EINPROGRESS) { pr_trace_msg(trace_channel, 3, "error requesting memcached stats: system error: %s", strerror(errno)); } else { /* We know that we're not using nonblocking IO; this value usually * means that libmemcached could not connect to the configured * memcached servers. So set the value to something more * indicative, and fall through. */ res = MEMCACHED_CONNECTION_FAILURE; } break; case MEMCACHED_SOME_ERRORS: case MEMCACHED_SERVER_MARKED_DEAD: case MEMCACHED_CONNECTION_FAILURE: { memcached_server_instance_st server; server = memcached_server_get_last_disconnect(mcache->mc); if (server != NULL) { pr_trace_msg(trace_channel, 3, "unable to connect to %s:%d", memcached_server_name(server), memcached_server_port(server)); } break; } default: pr_trace_msg(trace_channel, 6, "error requesting memcached stats: %s", memcached_strerror(mcache->mc, res)); break; } } memcached_stat_free(mcache->mc, mst); } return 0; }
static int mcache_ping_servers(pr_memcache_t *mcache) { memcached_server_st *alive_server_list; memcached_return res; memcached_st *clone; uint32_t server_count; register unsigned int i; /* We always start with the configured list of servers. */ clone = memcached_clone(NULL, mcache->mc); if (clone == NULL) { errno = ENOMEM; return -1; } memcached_servers_reset(clone); /* Bug#4242: Don't use memcached_server_push() if we're using * libmemcached-1.0.18 or earlier. Doing so leads to a segfault, due to * this libmemcached bug: * * https://bugs.launchpad.net/libmemcached/+bug/1154159 */ #if LIBMEMCACHED_VERSION_HEX > 0x01000018 memcached_server_push(clone, configured_server_list); #endif server_count = memcached_server_count(clone); pr_trace_msg(trace_channel, 16, "pinging %lu memcached %s", (unsigned long) server_count, server_count != 1 ? "servers" : "server"); alive_server_list = NULL; for (i = 0; i < server_count; i++) { memcached_server_instance_st server; server = memcached_server_instance_by_position(clone, i); pr_trace_msg(trace_channel, 17, "pinging server %s:%d", memcached_server_name(server), memcached_server_port(server)); if (libmemcached_util_ping(memcached_server_name(server), memcached_server_port(server), &res) == FALSE) { pr_trace_msg(trace_channel, 4, "error pinging %s:%d: %s", memcached_server_name(server), memcached_server_port(server), memcached_strerror(clone, res)); } else { pr_trace_msg(trace_channel, 17, "server %s:%d is alive", memcached_server_name(server), memcached_server_port(server)); alive_server_list = memcached_server_list_append(alive_server_list, memcached_server_name(server), memcached_server_port(server), &res); if (alive_server_list == NULL) { pr_trace_msg(trace_channel, 1, "error appending server %s:%d to list: %s", memcached_server_name(server), memcached_server_port(server), memcached_strerror(clone, res)); memcached_free(clone); errno = EPERM; return -1; } } } if (alive_server_list != NULL) { memcached_servers_reset(mcache->mc); res = memcached_server_push(mcache->mc, alive_server_list); if (res != MEMCACHED_SUCCESS) { unsigned int count; count = memcached_server_list_count(alive_server_list); pr_trace_msg(trace_channel, 2, "error adding %u alive memcached %s to connection: %s", count, count != 1 ? "servers" : "server", memcached_strerror(mcache->mc, res)); memcached_free(clone); errno = EPERM; return -1; } else { unsigned int count; count = memcached_server_list_count(alive_server_list); pr_trace_msg(trace_channel, 9, "now using %d alive memcached %s", count, count != 1 ? "servers" : "server"); memcached_server_list_free(alive_server_list); } } memcached_free(clone); return 0; }
int pr_memcache_kincr(pr_memcache_t *mcache, module *m, const char *key, size_t keysz, uint32_t incr, uint64_t *value) { memcached_return res; if (mcache == NULL || m == NULL || key == NULL || incr == 0) { errno = EINVAL; return -1; } /* Note: libmemcached automatically handles the case where value might be * NULL. */ mcache_set_module_namespace(mcache, m); res = memcached_increment(mcache->mc, key, keysz, incr, value); mcache_set_module_namespace(mcache, NULL); if (res == MEMCACHED_NOTFOUND) { /* Automatically create a value for this key, with the given increment. */ pr_trace_msg(trace_channel, 18, "unable to increment nonexistent key (%lu bytes), automatically " "creating one", (unsigned long) keysz); return pr_memcache_kset(mcache, m, key, keysz, &incr, sizeof(uint32_t), 0, 0); } switch (res) { case MEMCACHED_SUCCESS: return 0; case MEMCACHED_ERRNO: if (errno != EINPROGRESS) { int xerrno = errno; pr_trace_msg(trace_channel, 3, "error incrementing key (%lu bytes) by %lu: system error: %s", (unsigned long) keysz, (unsigned long) incr, strerror(xerrno)); errno = xerrno; } else { /* We know that we're not using nonblocking IO; this value usually * means that libmemcached could not connect to the configured * memcached servers. So set the value to something more * indicative, and fall through. */ res = MEMCACHED_CONNECTION_FAILURE; } break; case MEMCACHED_SERVER_MARKED_DEAD: case MEMCACHED_CONNECTION_FAILURE: { memcached_server_instance_st server; server = memcached_server_get_last_disconnect(mcache->mc); if (server != NULL) { pr_trace_msg(trace_channel, 3, "unable to connect to %s:%d", memcached_server_name(server), memcached_server_port(server)); } break; } default: pr_trace_msg(trace_channel, 2, "error incrementing key (%lu bytes) by %lu: %s", (unsigned long) keysz, (unsigned long) incr, memcached_strerror(mcache->mc, res)); errno = EPERM; break; } return -1; }
char *pr_memcache_kget_str(pr_memcache_t *mcache, module *m, const char *key, size_t keysz, uint32_t *flags) { char *data = NULL, *ptr = NULL; size_t valuesz = 0; memcached_return res; int xerrno = 0; if (mcache == NULL || m == NULL || key == NULL || flags == NULL) { errno = EINVAL; return NULL; } mcache_set_module_namespace(mcache, m); data = memcached_get(mcache->mc, key, keysz, &valuesz, flags, &res); xerrno = errno; mcache_set_module_namespace(mcache, NULL); if (data == NULL) { switch (res) { case MEMCACHED_NOTFOUND: pr_trace_msg(trace_channel, 8, "no data found for key (%lu bytes)", (unsigned long) keysz); errno = ENOENT; break; case MEMCACHED_ERRNO: if (errno != EINPROGRESS) { pr_trace_msg(trace_channel, 3, "no data found for key (%lu bytes): system error: %s", (unsigned long) keysz, strerror(xerrno)); errno = xerrno; } else { /* We know that we're not using nonblocking IO; this value usually * means that libmemcached could not connect to the configured * memcached servers. So set the value to something more * indicative, and fall through. */ res = MEMCACHED_CONNECTION_FAILURE; } break; case MEMCACHED_SERVER_MARKED_DEAD: case MEMCACHED_CONNECTION_FAILURE: { memcached_server_instance_st server; server = memcached_server_get_last_disconnect(mcache->mc); if (server != NULL) { pr_trace_msg(trace_channel, 3, "unable to connect to %s:%d", memcached_server_name(server), memcached_server_port(server)); } break; } default: pr_trace_msg(trace_channel, 6, "error getting data for key (%lu bytes): [%d] %s", (unsigned long) keysz, res, memcached_strerror(mcache->mc, res)); errno = EPERM; break; } return NULL; } /* Create a duplicate of the returned data from the mcache's pool, so that * we can call free(3) on the data returned by libmemcached. */ ptr = pcalloc(mcache->pool, valuesz + 1); memcpy(ptr, data, valuesz); free(data); return ptr; }
void server_startup(server_startup_st *construct) { if ((construct->server_list= getenv("MEMCACHED_SERVERS"))) { printf("servers %s\n", construct->server_list); construct->servers= memcached_servers_parse(construct->server_list); construct->server_list= NULL; construct->count= 0; } else { { char server_string_buffer[8096]; char *end_ptr; end_ptr= server_string_buffer; for (uint32_t x= 0; x < construct->count; x++) { int count; int status; in_port_t port; { char *var; char variable_buffer[1024]; snprintf(variable_buffer, sizeof(variable_buffer), "LIBMEMCACHED_PORT_%u", x); if ((var= getenv(variable_buffer))) { port= (in_port_t)atoi(var); } else { port= (in_port_t)(x + TEST_PORT_BASE); } } char buffer[PATH_MAX]; snprintf(buffer, sizeof(buffer), PID_FILE_BASE, x); kill_file(buffer); if (x == 0) { snprintf(buffer, sizeof(buffer), "%s -d -u root -P "PID_FILE_BASE" -t 1 -p %u -U %u -m 128", MEMCACHED_BINARY, x, port, port); } else { snprintf(buffer, sizeof(buffer), "%s -d -u root -P "PID_FILE_BASE" -t 1 -p %u -U %u", MEMCACHED_BINARY, x, port, port); } if (libmemcached_util_ping("localhost", port, NULL)) { fprintf(stderr, "Server on port %u already exists\n", port); } else { status= system(buffer); fprintf(stderr, "STARTING SERVER: %s status:%d\n", buffer, status); } count= sprintf(end_ptr, "localhost:%u,", port); end_ptr+= count; } *end_ptr= 0; int *pids= calloc(construct->count, sizeof(int)); for (uint32_t x= 0; x < construct->count; x++) { char buffer[PATH_MAX]; /* Nothing special for number */ snprintf(buffer, sizeof(buffer), PID_FILE_BASE, x); uint32_t counter= 3000; // Absurd, just to catch run away process while (pids[x] <= 0 && --counter) { FILE *file= fopen(buffer, "r"); if (file) { char pid_buffer[1024]; char *found= fgets(pid_buffer, sizeof(pid_buffer), file); if (found) { pids[x]= atoi(pid_buffer); fclose(file); if (pids[x] > 0) break; } fclose(file); } global_sleep(); } bool was_started= false; if (pids[x] > 0) { counter= 30; while (--counter) { if (kill(pids[x], 0) == 0) { was_started= true; break; } global_sleep(); } } if (was_started == false) { fprintf(stderr, "Failed to open buffer %s(%d)\n", buffer, pids[x]); for (uint32_t y= 0; y < construct->count; y++) { if (pids[y] > 0) kill(pids[y], SIGTERM); } abort(); } } free(pids); construct->server_list= strdup(server_string_buffer); } printf("servers %s\n", construct->server_list); construct->servers= memcached_servers_parse(construct->server_list); } assert(construct->servers); srandom((unsigned int)time(NULL)); for (uint32_t x= 0; x < memcached_server_list_count(construct->servers); x++) { printf("\t%s : %d\n", memcached_server_name(&construct->servers[x]), memcached_server_port(&construct->servers[x])); assert(construct->servers[x].fd == -1); assert(construct->servers[x].cursor_active == 0); } printf("\n"); }
mcs_st *lmc_create(mcs_st *ptr, const char *config, const char *default_usr, const char *default_pwd, const char *opts) { assert(ptr); memset(ptr, 0, sizeof(*ptr)); ptr->kind = MCS_KIND_LIBMEMCACHED; memcached_st *mst = memcached_create(NULL); if (mst != NULL) { memcached_behavior_t b = MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED; uint64_t v = 1; if (opts != NULL) { if (strstr(opts, "distribution:ketama-weighted") != NULL) { b = MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED; v = 1; } else if (strstr(opts, "distribution:ketama") != NULL) { b = MEMCACHED_BEHAVIOR_KETAMA; v = 1; } else if (strstr(opts, "distribution:modula") != NULL) { b = MEMCACHED_BEHAVIOR_KETAMA; v = 0; } } memcached_behavior_set(mst, b, v); memcached_behavior_set(mst, MEMCACHED_BEHAVIOR_NO_BLOCK, 1); memcached_behavior_set(mst, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1); memcached_server_st *mservers; mservers = memcached_servers_parse(config); if (mservers != NULL) { memcached_server_push(mst, mservers); ptr->data = mst; ptr->nservers = (int) memcached_server_list_count(mservers); if (ptr->nservers > 0) { ptr->servers = calloc(sizeof(mcs_server_st), ptr->nservers); if (ptr->servers != NULL) { for (int i = 0; i < ptr->nservers; i++) { ptr->servers[i].fd = -1; } int j = 0; for (; j < ptr->nservers; j++) { strncpy(ptr->servers[j].hostname, memcached_server_name(mservers + j), sizeof(ptr->servers[j].hostname) - 1); ptr->servers[j].port = (int) memcached_server_port(mservers + j); if (ptr->servers[j].port <= 0) { moxi_log_write("lmc_create failed, could not parse port: %s\n", config); break; } if (default_usr != NULL) { ptr->servers[j].usr = strdup(default_usr); } if (default_pwd != NULL) { ptr->servers[j].pwd = strdup(default_pwd); } } if (j >= ptr->nservers) { memcached_server_list_free(mservers); return ptr; } } } memcached_server_list_free(mservers); } } mcs_free(ptr); return NULL; }