static void _regen_for_auto_eject(memcached_st *ptr) { if (_is_auto_eject_host(ptr) && ptr->next_distribution_rebuild) { struct timeval now; if (gettimeofday(&now, NULL) == 0 && now.tv_sec > ptr->next_distribution_rebuild) { run_distribution(ptr); } } }
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; }