/* create a memcached structure */ static memcached_st *memc_new() { char config_string[1024]; memcached_st *memc = NULL; memcached_server_st *servers = NULL; unsigned long long getter; memcached_return_t rc; pthread_mutex_lock (&printmutex); sprintf(config_string, "--SERVER=%s --BINARY-PROTOCOL", serverip); printf("config_string = %s\n", config_string); //memc = memcached(config_string, strlen(config_string)); memc = memcached_create(NULL); servers = memcached_server_list_append(servers, serverip, 11211, &rc); rc = memcached_server_push(memc, servers); if (rc == MEMCACHED_SUCCESS) fprintf(stderr, "Added server successfully\n"); else fprintf(stderr, "Couldnt add server: %s\n", serverip); getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK); printf("No block: %lld\n", getter); getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE); printf("Socket send size: %lld\n", getter); getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE); printf("Socket recv size: %lld\n", getter); memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); pthread_mutex_unlock (&printmutex); return memc; }
/** @note This should be testing to see if the server really supports the binary protocol. */ static test_return_t pre_binary(memcached_st *memc) { memcached_return_t rc= MEMCACHED_FAILURE; memcached_st *memc_clone; memcached_server_instance_st instance; memc_clone= memcached_clone(NULL, memc); test_true(memc_clone); // The memcached_version needs to be done on a clone, because the server // will not toggle protocol on an connection. memcached_version(memc_clone); instance= memcached_server_instance_by_position(memc_clone, 0); if (instance->major_version >= 1 && instance->minor_version > 2) { rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); test_true(rc == MEMCACHED_SUCCESS); test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1); } memcached_free(memc_clone); return rc == MEMCACHED_SUCCESS ? TEST_SUCCESS : TEST_SKIPPED; }
/* Set the value, then quit to make sure it is flushed. Come back in and test that add fails. */ static test_return_t add_test(memcached_st *memc) { memcached_return_t rc; const char *key= "foo"; const char *value= "when we sanitize"; unsigned long long setting_value; setting_value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK); rc= memcached_set(memc, key, strlen(key), value, strlen(value), (time_t)0, (uint32_t)0); test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); memcached_quit(memc); rc= memcached_add(memc, key, strlen(key), value, strlen(value), (time_t)0, (uint32_t)0); /* Too many broken OS'es have broken loopback in async, so we can't be sure of the result */ if (setting_value) { test_true(rc == MEMCACHED_NOTSTORED || rc == MEMCACHED_STORED); } else { test_true(rc == MEMCACHED_NOTSTORED); } return 0; }
static int php_memc_sess_lock(memcached_st *memc, const char *key) { char *lock_key = NULL; int lock_key_len = 0; unsigned long attempts; long write_retry_attempts = 0; long lock_maxwait = MEMC_G(sess_lock_max_wait); long lock_wait = MEMC_G(sess_lock_wait); long lock_expire = MEMC_G(sess_lock_expire); time_t expiration; memcached_return status; /* set max timeout for session_start = max_execution_time. (c) Andrei Darashenka, Richter & Poweleit GmbH */ if (lock_maxwait <= 0) { lock_maxwait = zend_ini_long(ZEND_STRS("max_execution_time"), 0); if (lock_maxwait <= 0) { lock_maxwait = MEMC_SESS_LOCK_EXPIRATION; } } if (lock_wait == 0) { lock_wait = MEMC_SESS_DEFAULT_LOCK_WAIT; } if (lock_expire <= 0) { lock_expire = lock_maxwait; } expiration = lock_expire + 1; attempts = (unsigned long)((1000000.0 / lock_wait) * lock_maxwait); /* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server */ if (MEMC_G(sess_remove_failed_enabled)) { write_retry_attempts = MEMC_G(sess_number_of_replicas) * ( memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT) + 1); } lock_key_len = spprintf(&lock_key, 0, "lock.%s", key); do { status = memcached_add(memc, lock_key, lock_key_len, "1", sizeof("1")-1, expiration, 0); if (status == MEMCACHED_SUCCESS) { MEMC_G(sess_locked) = 1; MEMC_G(sess_lock_key) = lock_key; MEMC_G(sess_lock_key_len) = lock_key_len; return 0; } else if (status != MEMCACHED_NOTSTORED && status != MEMCACHED_DATA_EXISTS) { if (write_retry_attempts > 0) { write_retry_attempts--; continue; } php_error_docref(NULL, E_WARNING, "Write of lock failed"); break; } if (lock_wait > 0) { usleep(lock_wait); } } while(--attempts > 0); efree(lock_key); return -1; }
/* create a memcached structure */ static memcached_st *memc_new() { char config_string[1024]; memcached_st *memc = NULL; unsigned long long getter; pthread_mutex_lock (&printmutex); sprintf(config_string, "--SERVER=%s --BINARY-PROTOCOL", serverip); printf("config_string = %s\n", config_string); memc = memcached(config_string, strlen(config_string)); getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK); printf("No block: %lld\n", getter); getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE); printf("Socket send size: %lld\n", getter); getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE); printf("Socket recv size: %lld\n", getter); pthread_mutex_unlock (&printmutex); return memc; }
memcached_return run_distribution(memcached_st *ptr) { switch (ptr->distribution) { case MEMCACHED_DISTRIBUTION_CONSISTENT: case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return update_continuum(ptr); case MEMCACHED_DISTRIBUTION_MODULA: if (ptr->flags & MEM_USE_SORT_HOSTS) sort_hosts(ptr); if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS)) update_live_host_indices(ptr); break; case MEMCACHED_DISTRIBUTION_RANDOM: if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS)) update_live_host_indices(ptr); break; default: WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */ } return MEMCACHED_SUCCESS; }
memcached_return update_continuum(memcached_st *ptr) { uint32_t host_index; uint32_t continuum_index= 0; uint32_t value; memcached_server_st *list; uint32_t pointer_index; uint32_t pointer_counter= 0; uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER; uint32_t pointer_per_hash= 1; uint64_t total_weight= 0; uint64_t is_ketama_weighted= 0; uint64_t is_auto_ejecting= 0; uint32_t points_per_server= 0; uint32_t live_servers= 0; struct timeval now; if (gettimeofday(&now, NULL) != 0) { ptr->cached_errno = errno; return MEMCACHED_ERRNO; } list = ptr->hosts; /* count live servers (those without a retry delay set) */ is_auto_ejecting= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS); if (is_auto_ejecting) { live_servers= 0; ptr->next_distribution_rebuild= 0; for (host_index= 0; host_index < ptr->number_of_hosts; ++host_index) { if (list[host_index].next_retry <= now.tv_sec) live_servers++; else { if (ptr->next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->next_distribution_rebuild) ptr->next_distribution_rebuild= list[host_index].next_retry; } } } else live_servers= ptr->number_of_hosts; is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED); points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER); if (live_servers == 0) return MEMCACHED_SUCCESS; if (live_servers > ptr->continuum_count) { memcached_continuum_item_st *new_ptr; new_ptr= ptr->call_realloc(ptr, ptr->continuum, sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server); if (new_ptr == 0) return MEMCACHED_MEMORY_ALLOCATION_FAILURE; ptr->continuum= new_ptr; ptr->continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION; } if (is_ketama_weighted) { for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index) { if (list[host_index].weight == 0) { list[host_index].weight = 1; } if (!is_auto_ejecting || list[host_index].next_retry <= now.tv_sec) total_weight += list[host_index].weight; } } for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index) { if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec) continue; if (is_ketama_weighted) { float pct = (float)list[host_index].weight / (float)total_weight; pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4); pointer_per_hash= 4; #ifdef DEBUG printf("ketama_weighted:%s|%d|%llu|%u\n", list[host_index].hostname, list[host_index].port, (unsigned long long)list[host_index].weight, pointer_per_server); #endif } for (pointer_index= 1; pointer_index <= pointer_per_server / pointer_per_hash; ++pointer_index) { char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= ""; size_t sort_host_length; if (list[host_index].port == MEMCACHED_DEFAULT_PORT) { sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, "%s-%d", list[host_index].hostname, pointer_index - 1); } else { sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, "%s:%d-%d", list[host_index].hostname, list[host_index].port, pointer_index - 1); } WATCHPOINT_ASSERT(sort_host_length); if (is_ketama_weighted) { unsigned int i; for (i = 0; i < pointer_per_hash; i++) { value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i); ptr->continuum[continuum_index].index= host_index; ptr->continuum[continuum_index++].value= value; } } else { value= memcached_generate_hash_value(sort_host, sort_host_length, ptr->hash_continuum); ptr->continuum[continuum_index].index= host_index; ptr->continuum[continuum_index++].value= value; } } pointer_counter+= pointer_per_server; } WATCHPOINT_ASSERT(ptr); WATCHPOINT_ASSERT(ptr->continuum); WATCHPOINT_ASSERT(ptr->number_of_hosts * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE); ptr->continuum_points_counter= pointer_counter; qsort(ptr->continuum, ptr->continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp); #ifdef DEBUG for (pointer_index= 0; ptr->number_of_hosts && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++) { WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value); } #endif return MEMCACHED_SUCCESS; }
static memcached_return_t update_continuum(memcached_st *ptr) { uint32_t host_index; uint32_t continuum_index= 0; uint32_t value; memcached_server_st *list; uint32_t pointer_index; uint32_t pointer_counter= 0; uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER; uint32_t pointer_per_hash= 1; uint64_t total_weight= 0; uint64_t is_ketama_weighted= 0; uint64_t is_auto_ejecting= 0; uint32_t points_per_server= 0; uint32_t live_servers= 0; struct timeval now; if (gettimeofday(&now, NULL) != 0) { ptr->cached_errno = errno; return MEMCACHED_ERRNO; } list = memcached_server_list(ptr); /* count live servers (those without a retry delay set) */ is_auto_ejecting= _is_auto_eject_host(ptr); if (is_auto_ejecting) { live_servers= 0; ptr->next_distribution_rebuild= 0; for (host_index= 0; host_index < memcached_server_count(ptr); ++host_index) { if (list[host_index].next_retry <= now.tv_sec) live_servers++; else { if (ptr->next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->next_distribution_rebuild) ptr->next_distribution_rebuild= list[host_index].next_retry; } } } else { live_servers= memcached_server_count(ptr); } is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED); points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER); if (live_servers == 0) return MEMCACHED_SUCCESS; if (live_servers > ptr->continuum_count) { memcached_continuum_item_st *new_ptr; new_ptr= libmemcached_realloc(ptr, ptr->continuum, sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server); if (new_ptr == 0) return MEMCACHED_MEMORY_ALLOCATION_FAILURE; ptr->continuum= new_ptr; ptr->continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION; } if (is_ketama_weighted) { for (host_index = 0; host_index < memcached_server_count(ptr); ++host_index) { if (list[host_index].weight == 0) { list[host_index].weight = 1; } if (! is_auto_ejecting || list[host_index].next_retry <= now.tv_sec) total_weight += list[host_index].weight; } } for (host_index= 0; host_index < memcached_server_count(ptr); ++host_index) { if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec) continue; if (is_ketama_weighted) { float pct = (float)list[host_index].weight / (float)total_weight; pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4); pointer_per_hash= 4; #ifdef DEBUG printf("ketama_weighted:%s|%d|%llu|%u\n", list[host_index].hostname, list[host_index].port, (unsigned long long)list[host_index].weight, pointer_per_server); #endif } if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY) { for (pointer_index= 0; pointer_index < pointer_per_server / pointer_per_hash; pointer_index++) { char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= ""; size_t sort_host_length; // Spymemcached ketema key format is: hostname/ip:port-index // If hostname is not available then: /ip:port-index sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, "/%s:%u-%u", list[host_index].hostname, (uint32_t)list[host_index].port, pointer_index); #ifdef DEBUG printf("update_continuum: key is %s\n", sort_host); #endif WATCHPOINT_ASSERT(sort_host_length); if (is_ketama_weighted) { for (uint32_t x= 0; x < pointer_per_hash; x++) { value= ketama_server_hash(sort_host, sort_host_length, x); ptr->continuum[continuum_index].index= host_index; ptr->continuum[continuum_index++].value= value; } } else { value= hashkit_digest(&ptr->distribution_hashkit, sort_host, sort_host_length); ptr->continuum[continuum_index].index= host_index; ptr->continuum[continuum_index++].value= value; } } } else { for (pointer_index= 1; pointer_index <= pointer_per_server / pointer_per_hash; pointer_index++) { char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= ""; size_t sort_host_length; if (list[host_index].port == MEMCACHED_DEFAULT_PORT) { sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, "%s-%u", list[host_index].hostname, pointer_index - 1); } else { sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, "%s:%u-%u", list[host_index].hostname, (uint32_t)list[host_index].port, pointer_index - 1); } WATCHPOINT_ASSERT(sort_host_length); if (is_ketama_weighted) { for (uint32_t x = 0; x < pointer_per_hash; x++) { value= ketama_server_hash(sort_host, sort_host_length, x); ptr->continuum[continuum_index].index= host_index; ptr->continuum[continuum_index++].value= value; } } else { value= hashkit_digest(&ptr->distribution_hashkit, sort_host, sort_host_length); ptr->continuum[continuum_index].index= host_index; ptr->continuum[continuum_index++].value= value; } } } pointer_counter+= pointer_per_server; } WATCHPOINT_ASSERT(ptr); WATCHPOINT_ASSERT(ptr->continuum); WATCHPOINT_ASSERT(memcached_server_count(ptr) * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE); ptr->continuum_points_counter= pointer_counter; qsort(ptr->continuum, ptr->continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp); #ifdef DEBUG for (pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++) { WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value); } #endif return MEMCACHED_SUCCESS; }
static int mcache_set_options(pr_memcache_t *mcache, unsigned long flags, uint64_t nreplicas) { memcached_return res; uint64_t val; val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_TCP_NODELAY); if (val != 1) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting TCP_NODELAY behavior on connection: %s", memcached_strerror(mcache->mc, res)); } } /* Enable caching of DNS lookups. */ val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_CACHE_LOOKUPS); if (val != 1) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_CACHE_LOOKUPS, 1); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting CACHE_LOOKUPS behavior on connection: %s", memcached_strerror(mcache->mc, res)); } } /* Verify that all keys are correct. */ val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_VERIFY_KEY); if (val != 1) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_VERIFY_KEY, 1); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting VERIFY_KEY behavior on connection: %s", memcached_strerror(mcache->mc, res)); } } /* We always want consistent hashing, to minimize cache churn when * servers are added/removed from the list. */ val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_DISTRIBUTION); if (val != MEMCACHED_DISTRIBUTION_CONSISTENT) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_DISTRIBUTION, MEMCACHED_DISTRIBUTION_CONSISTENT); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting DISTRIBUTION_CONSISTENT behavior on connection: %s", memcached_strerror(mcache->mc, res)); } } /* Use blocking IO */ val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_NO_BLOCK); if (val != 0) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting NO_BLOCK behavior on connection: %s", memcached_strerror(mcache->mc, res)); } } val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT); if (memcache_sess_conn_failures > 0) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, memcache_sess_conn_failures); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting SERVER_FAILURE_LIMIT behavior on connection: %s", memcached_strerror(mcache->mc, res)); } else { /* Automatically eject hosts which have reached this failure limit; * keeping them around in the memcached_st struct only causes * confusion. Note that this requires that an ejected timeout value * be configured. */ if (memcache_ejected_sec > 0) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, memcache_ejected_sec); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting RETRY_TIMEOUT behavior on connection to %lu ms: %s", memcache_ejected_sec, memcached_strerror(mcache->mc, res)); } res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS, 1); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting AUTO_EJECT_HOSTS behavior on connection: %s", memcached_strerror(mcache->mc, res)); } } } } /* Use the binary protocol by default, unless explicitly requested not to. */ val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL); pr_trace_msg(trace_channel, 16, "found BINARY_PROTOCOL=%s default behavior (val %lu) for connection", val != 1 ? "false" : "true", (unsigned long) val); if (val != 1) { if (!(flags & PR_MEMCACHE_FL_NO_BINARY_PROTOCOL)) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting BINARY_PROTOCOL=true behavior on connection: %s", memcached_strerror(mcache->mc, res)); } else { pr_trace_msg(trace_channel, 16, "%s", "set BINARY_PROTOCOL=true for connection"); } } } else { if (flags & PR_MEMCACHE_FL_NO_BINARY_PROTOCOL) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 0); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting BINARY_PROTOCOL=false behavior on connection: %s", memcached_strerror(mcache->mc, res)); } else { pr_trace_msg(trace_channel, 16, "%s", "set BINARY_PROTOCOL=false for connection"); } } } /* Configure the timeouts. */ res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, memcache_conn_millis); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting CONNECT_TIMEOUT behavior on connection to %lu ms: %s", memcache_conn_millis, memcached_strerror(mcache->mc, res)); } res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_RCV_TIMEOUT, memcache_rcv_millis); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting RCV_TIMEOUT behavior on connection to %lu ms: %s", memcache_rcv_millis, memcached_strerror(mcache->mc, res)); } res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_SND_TIMEOUT, memcache_snd_millis); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting SND_TIMEOUT behavior on connection to %lu ms: %s", memcache_snd_millis, memcached_strerror(mcache->mc, res)); } /* Make sure that the requested number of replicas does not exceed the * server count. */ if (nreplicas > memcached_server_count(mcache->mc)) { nreplicas = memcached_server_count(mcache->mc); } /* XXX Some caveats about libmemcached replication: * * 1. Replication is enabled only if the binary protocol is used. * 2. Replication occurs only for 'delete', 'get, 'set' operations, NOT * 'add', 'cas', 'incr', 'decr', etc. */ if (nreplicas > 0 && !(flags & PR_MEMCACHE_FL_NO_BINARY_PROTOCOL)) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, nreplicas); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting NUMBER_OF_REPLICAS behavior on connection: %s", memcached_strerror(mcache->mc, res)); } else { pr_trace_msg(trace_channel, 9, "storing %lu %s", (unsigned long) nreplicas, nreplicas != 1 ? "replicas" : "replica"); } } /* Use randomized reads from replicas by default, unless explicitly * requested not to. */ val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ); if (val != 1) { if (!(flags & PR_MEMCACHE_FL_NO_RANDOM_REPLICA_READ)) { res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ, 1); if (res != MEMCACHED_SUCCESS) { pr_trace_msg(trace_channel, 4, "error setting RANDOMIZE_REPLICA_READ behavior on connection: %s", memcached_strerror(mcache->mc, res)); } } } return 0; }
static bool use_binary(memcached_st* mc) { return memcached_behavior_get(mc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0; }
memcached_return update_continuum(memcached_st *ptr) { uint32_t index; uint32_t host_index; uint32_t continuum_index= 0; uint32_t value; memcached_server_st *list; uint32_t pointer_counter= 0; uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER; uint32_t pointer_per_hash= 1; uint64_t total_weight= 0; uint32_t is_ketama_weighted= 0; uint32_t points_per_server= 0; is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED); points_per_server= is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER; if (ptr->number_of_hosts > ptr->continuum_count) { memcached_continuum_item_st *new_ptr; if (ptr->call_realloc) new_ptr= (memcached_continuum_item_st *)ptr->call_realloc(ptr, ptr->continuum, sizeof(memcached_continuum_item_st) * (ptr->number_of_hosts + MEMCACHED_CONTINUUM_ADDITION) * points_per_server); else new_ptr= (memcached_continuum_item_st *)realloc(ptr->continuum, sizeof(memcached_continuum_item_st) * (ptr->number_of_hosts + MEMCACHED_CONTINUUM_ADDITION) * points_per_server); if (new_ptr == 0) return MEMCACHED_MEMORY_ALLOCATION_FAILURE; ptr->continuum= new_ptr; ptr->continuum_count= ptr->number_of_hosts + MEMCACHED_CONTINUUM_ADDITION; } list = ptr->hosts; if (is_ketama_weighted) { for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index) { if (list[host_index].weight == 0) { list[host_index].weight = 1; } total_weight += list[host_index].weight; } } for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index) { if (is_ketama_weighted) { float pct = (float)list[host_index].weight / (float)total_weight; pointer_per_server= floorf(pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)(ptr->number_of_hosts) + 0.0000000001) * 4; pointer_per_hash= 4; #ifdef HAVE_DEBUG printf("ketama_weighted:%s|%d|%llu|%u\n", list[host_index].hostname, list[host_index].port, (unsigned long long)list[host_index].weight, pointer_per_server); #endif } for (index= 1; index <= pointer_per_server / pointer_per_hash; ++index) { char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= ""; size_t sort_host_length; if (list[host_index].port == MEMCACHED_DEFAULT_PORT) { sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, "%s-%d", list[host_index].hostname, index - 1); } else { sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, "%s:%d-%d", list[host_index].hostname, list[host_index].port, index - 1); } WATCHPOINT_ASSERT(sort_host_length); if (is_ketama_weighted) { int i; for (i = 0; i < pointer_per_hash; i++) { value= ketama_server_hash(sort_host, sort_host_length, i); ptr->continuum[continuum_index].index= host_index; ptr->continuum[continuum_index++].value= value; } } else { value= generate_hash_value(sort_host, sort_host_length, ptr->hash_continuum); ptr->continuum[continuum_index].index= host_index; ptr->continuum[continuum_index++].value= value; } } pointer_counter+= pointer_per_server; } WATCHPOINT_ASSERT(ptr); WATCHPOINT_ASSERT(ptr->continuum); WATCHPOINT_ASSERT(ptr->number_of_hosts * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE); ptr->continuum_points_counter= pointer_counter; qsort(ptr->continuum, ptr->continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp); #ifdef HAVE_DEBUG for (index= 0; ptr->number_of_hosts && index < ((ptr->number_of_hosts * MEMCACHED_POINTS_PER_SERVER) - 1); index++) { WATCHPOINT_ASSERT(ptr->continuum[index].value <= ptr->continuum[index + 1].value); } #endif return MEMCACHED_SUCCESS; }