From: Trond Norbye Date: Tue, 3 Nov 2009 13:09:13 +0000 (+0100) Subject: Added MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE X-Git-Tag: 0.35~5^2 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=90a467967e3bc3a0508044e74ef9cf7b811ab095;p=m6w6%2Flibmemcached Added MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE --- diff --git a/docs/memcached_behavior.pod b/docs/memcached_behavior.pod index 00d76282..dd718454 100644 --- a/docs/memcached_behavior.pod +++ b/docs/memcached_behavior.pod @@ -32,7 +32,7 @@ that behavior is currently enabled in the client. memcached_behavior_set() changes the value of a particular option of the client. It takes both a flag (listed below) and a value. For simple on or -off options you just need to pass in a value of 1. Calls to +off options you just need to pass in a value of 1. Calls to memcached_behavior_set() will flush and reset all connections. =over 4 @@ -40,7 +40,7 @@ memcached_behavior_set() will flush and reset all connections. =item MEMCACHED_BEHAVIOR_USE_UDP Causes libmemcached(3) to use the UDP transport when communicating -with a memcached server. Not all I/O operations are supported +with a memcached server. Not all I/O operations are supported when this behavior is enababled. The following operations will return C when executed with the MEMCACHED_BEHAVIOR_USE_UDP enabled: memcached_version(), memcached_stat(), memcached_get(), @@ -50,7 +50,7 @@ memcached_fetch(), memcached_fetch_result(), memcached_value_fetch(). All other operations are supported but are executed in a 'fire-and-forget' mode, in which once the client has executed the operation, no attempt will be made to ensure the operation has been received and acted on by the -server. +server. libmemcached(3) does not allow TCP and UDP servers to be shared within the same libmemached(3) client 'instance'. An attempt to add a TCP server @@ -82,19 +82,19 @@ environments). =item MEMCACHED_BEHAVIOR_HASH Makes the default hashing algorithm for keys use MD5. The value can be set -to either MEMCACHED_HASH_DEFAULT, MEMCACHED_HASH_MD5, MEMCACHED_HASH_CRC, MEMCACHED_HASH_FNV1_64, MEMCACHED_HASH_FNV1A_64, MEMCACHED_HASH_FNV1_32, MEMCACHED_HASH_FNV1A_32, MEMCACHED_HASH_JENKINS, MEMCACHED_HASH_HSIEH, and MEMCACHED_HASH_MURMUR. +to either MEMCACHED_HASH_DEFAULT, MEMCACHED_HASH_MD5, MEMCACHED_HASH_CRC, MEMCACHED_HASH_FNV1_64, MEMCACHED_HASH_FNV1A_64, MEMCACHED_HASH_FNV1_32, MEMCACHED_HASH_FNV1A_32, MEMCACHED_HASH_JENKINS, MEMCACHED_HASH_HSIEH, and MEMCACHED_HASH_MURMUR. Each hash has it's advantages and it's weaknesses. If you dont know or dont care, just go with the default. -Support for MEMCACHED_HASH_HSIEH is a compile time option that is disabled by default. To enable support for this hashing algorithm, configure and build libmemcached with the --enable-hash_hsieh. +Support for MEMCACHED_HASH_HSIEH is a compile time option that is disabled by default. To enable support for this hashing algorithm, configure and build libmemcached with the --enable-hash_hsieh. =item MEMCACHED_BEHAVIOR_DISTRIBUTION Using this you can enable different means of distributing values to servers. The default method is MEMCACHED_DISTRIBUTION_MODULA. You can enable -consistent hashing by setting MEMCACHED_DISTRIBUTION_CONSISTENT. -Consistent hashing delivers better distribution and allows servers to be +consistent hashing by setting MEMCACHED_DISTRIBUTION_CONSISTENT. +Consistent hashing delivers better distribution and allows servers to be added to the cluster with minimal cache losses. Currently MEMCACHED_DISTRIBUTION_CONSISTENT is an alias for the value -MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA. +MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA. =item MEMCACHED_BEHAVIOR_CACHE_LOOKUPS @@ -117,7 +117,14 @@ and the hash to MEMCACHED_HASH_MD5. =item MEMCACHED_BEHAVIOR_KETAMA_HASH Sets the hashing algorithm for host mapping on continuum. The value can be set -to either MEMCACHED_HASH_DEFAULT, MEMCACHED_HASH_MD5, MEMCACHED_HASH_CRC, MEMCACHED_HASH_FNV1_64, MEMCACHED_HASH_FNV1A_64, MEMCACHED_HASH_FNV1_32, and MEMCACHED_HASH_FNV1A_32. +to either MEMCACHED_HASH_DEFAULT, MEMCACHED_HASH_MD5, MEMCACHED_HASH_CRC, MEMCACHED_HASH_FNV1_64, MEMCACHED_HASH_FNV1A_64, MEMCACHED_HASH_FNV1_32, and MEMCACHED_HASH_FNV1A_32. + +=item MEMCACHED_BEHAVIOR_KETAMA_COMPAT + +Sets the compatibility mode. The value can be set to either +MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED (this is the default) or +MEMCACHED_KETAMA_COMPAT_SPY to be compatible with the SPY Memcached client +for Java. =item MEMCACHED_BEHAVIOR_POLL_TIMEOUT @@ -136,16 +143,16 @@ of memcached_callback_set(3). This will be removed in 0.15. Enabling buffered IO causes commands to "buffer" instead of being sent. Any action that gets data causes this buffer to be be sent to the remote connection. Quiting the connection or closing down the connection will also -cause the buffered data to be pushed to the remote connection. +cause the buffered data to be pushed to the remote connection. =item MEMCACHED_BEHAVIOR_VERIFY_KEY -Enabling this will cause libmemcached(3) to test all keys to verify that they +Enabling this will cause libmemcached(3) to test all keys to verify that they are valid keys. =item MEMCACHED_BEHAVIOR_SORT_HOSTS -Enabling this will cause hosts that are added to be placed in the host list in +Enabling this will cause hosts that are added to be placed in the host list in sorted order. This will defeat consisten hashing. =item MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT @@ -165,7 +172,7 @@ times connection failure. =item MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK -Set this value to tune the number of messages that may be sent before +Set this value to tune the number of messages that may be sent before libmemcached should start to automatically drain the input queue. Setting this value to high, may cause libmemcached to deadlock (trying to send data, but the send will block because the input buffer in the kernel is full). @@ -175,7 +182,7 @@ but the send will block because the input buffer in the kernel is full). Set this value to tune the number of bytes that may be sent before libmemcached should start to automatically drain the input queue (need at least 10 IO requests sent without reading the input buffer). Setting -this value to high, may cause libmemcached to deadlock (trying to send +this value to high, may cause libmemcached to deadlock (trying to send data, but the send will block because the input buffer in the kernel is full). =item MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH @@ -192,7 +199,7 @@ sent to the server. =item MEMCACHED_BEHAVIOR_NOREPLY Set this value to specify that you really don't care about the result -from your storage commands (set, add, replace, append, prepend). +from your storage commands (set, add, replace, append, prepend). =item MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS @@ -213,7 +220,7 @@ returns failure or success. =head1 NOTES memcached_behavior_set() in version .17 was changed from taking a pointer -to data value, to taking a uin64_t. +to data value, to taking a uin64_t. =head1 HOME diff --git a/libmemcached/memcached_behavior.c b/libmemcached/memcached_behavior.c index dd988489..72b0d5cc 100644 --- a/libmemcached/memcached_behavior.c +++ b/libmemcached/memcached_behavior.c @@ -1,10 +1,10 @@ -#include "common.h" +#include "common.h" #include #include #include #include -/* +/* This function is used to modify the behavior of running client. We quit all connections so we can reset the sockets. @@ -18,8 +18,8 @@ static void set_behavior_flag(memcached_st *ptr, memcached_flags temp_flag, uint ptr->flags&= ~temp_flag; } -memcached_return memcached_behavior_set(memcached_st *ptr, - memcached_behavior flag, +memcached_return memcached_behavior_set(memcached_st *ptr, + memcached_behavior flag, uint64_t data) { switch (flag) @@ -38,18 +38,18 @@ memcached_return memcached_behavior_set(memcached_st *ptr, break; case MEMCACHED_BEHAVIOR_SND_TIMEOUT: ptr->snd_timeout= (int32_t)data; - break; + break; case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: ptr->rcv_timeout= (int32_t)data; - break; + break; case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: ptr->server_failure_limit= (uint32_t)data; - break; + break; case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: if (data) set_behavior_flag(ptr, MEM_VERIFY_KEY, 0); set_behavior_flag(ptr, MEM_BINARY_PROTOCOL, data); - break; + break; case MEMCACHED_BEHAVIOR_SUPPORT_CAS: set_behavior_flag(ptr, MEM_SUPPORT_CAS, data); break; @@ -105,6 +105,22 @@ memcached_return memcached_behavior_set(memcached_st *ptr, run_distribution(ptr); break; } + case MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE: + switch (data) + { + case MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED: + ptr->hash= MEMCACHED_HASH_MD5; + ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA; + break; + case MEMCACHED_KETAMA_COMPAT_SPY: + ptr->hash= MEMCACHED_HASH_MD5; + ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY; + break; + default: + return MEMCACHED_FAILURE; + } + run_distribution(ptr); + break; case MEMCACHED_BEHAVIOR_HASH: #ifndef HAVE_HSIEH_HASH if ((memcached_hash)(data) == MEMCACHED_HASH_HSIEH) @@ -169,7 +185,7 @@ memcached_return memcached_behavior_set(memcached_st *ptr, return MEMCACHED_SUCCESS; } -uint64_t memcached_behavior_get(memcached_st *ptr, +uint64_t memcached_behavior_get(memcached_st *ptr, memcached_behavior flag) { memcached_flags temp_flag= MEM_NO_BLOCK; @@ -186,7 +202,7 @@ uint64_t memcached_behavior_get(memcached_st *ptr, return ptr->io_key_prefetch; case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: temp_flag= MEM_BINARY_PROTOCOL; - break; + break; case MEMCACHED_BEHAVIOR_SUPPORT_CAS: temp_flag= MEM_SUPPORT_CAS; break; @@ -215,6 +231,17 @@ uint64_t memcached_behavior_get(memcached_st *ptr, return ptr->distribution; case MEMCACHED_BEHAVIOR_KETAMA: return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0; + case MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE: + switch (ptr->distribution) + { + case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: + return MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED; + case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: + return MEMCACHED_KETAMA_COMPAT_SPY; + default: + return (uint64_t)-1; + } + /* NOTREACHED */ case MEMCACHED_BEHAVIOR_HASH: return ptr->hash; case MEMCACHED_BEHAVIOR_KETAMA_HASH: @@ -244,7 +271,7 @@ uint64_t memcached_behavior_get(memcached_st *ptr, if ((memcached_connect(&ptr->hosts[0])) != MEMCACHED_SUCCESS) return 0; - if (getsockopt(ptr->hosts[0].fd, SOL_SOCKET, + if (getsockopt(ptr->hosts[0].fd, SOL_SOCKET, SO_SNDBUF, &sock_size, &sock_length)) return 0; /* Zero means error */ @@ -260,7 +287,7 @@ uint64_t memcached_behavior_get(memcached_st *ptr, if ((memcached_connect(&ptr->hosts[0])) != MEMCACHED_SUCCESS) return 0; - if (getsockopt(ptr->hosts[0].fd, SOL_SOCKET, + if (getsockopt(ptr->hosts[0].fd, SOL_SOCKET, SO_RCVBUF, &sock_size, &sock_length)) return 0; /* Zero means error */ diff --git a/libmemcached/memcached_constants.h b/libmemcached/memcached_constants.h index 1705bb6e..3a91ca01 100644 --- a/libmemcached/memcached_constants.h +++ b/libmemcached/memcached_constants.h @@ -17,7 +17,7 @@ #define MEMCACHED_MAX_HOST_SORT_LENGTH 86 /* Used for Ketama */ #define MEMCACHED_POINTS_PER_SERVER 100 #define MEMCACHED_POINTS_PER_SERVER_KETAMA 160 -#define MEMCACHED_CONTINUUM_SIZE MEMCACHED_POINTS_PER_SERVER*100 /* This would then set max hosts to 100 */ +#define MEMCACHED_CONTINUUM_SIZE MEMCACHED_POINTS_PER_SERVER*100 /* This would then set max hosts to 100 */ #define MEMCACHED_STRIDE 4 #define MEMCACHED_DEFAULT_TIMEOUT 1000 #define MEMCACHED_CONTINUUM_ADDITION 10 /* How many extra slots we should build for in the continuum */ @@ -70,7 +70,8 @@ typedef enum { MEMCACHED_DISTRIBUTION_MODULA, MEMCACHED_DISTRIBUTION_CONSISTENT, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA, - MEMCACHED_DISTRIBUTION_RANDOM + MEMCACHED_DISTRIBUTION_RANDOM, + MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY } memcached_server_distribution; typedef enum { @@ -103,9 +104,13 @@ typedef enum { MEMCACHED_BEHAVIOR_NOREPLY, MEMCACHED_BEHAVIOR_USE_UDP, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS, - MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS + MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, + MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE } memcached_behavior; +#define MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED 0 +#define MEMCACHED_KETAMA_COMPAT_SPY 1 + typedef enum { MEMCACHED_CALLBACK_PREFIX_KEY = 0, MEMCACHED_CALLBACK_USER_DATA = 1, diff --git a/libmemcached/memcached_hash.c b/libmemcached/memcached_hash.c index 129d7612..959fc296 100644 --- a/libmemcached/memcached_hash.c +++ b/libmemcached/memcached_hash.c @@ -31,13 +31,13 @@ uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memca hash= 1; break; /* FNV hash'es lifted from Dustin Sallings work */ - case MEMCACHED_HASH_FNV1_64: + case MEMCACHED_HASH_FNV1_64: { /* Thanks to pierre@demartines.com for the pointer */ uint64_t temp_hash; temp_hash= FNV_64_INIT; - for (x= 0; x < key_length; x++) + for (x= 0; x < key_length; x++) { temp_hash *= FNV_64_PRIME; temp_hash ^= (uint64_t)key[x]; @@ -45,10 +45,10 @@ uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memca hash= (uint32_t)temp_hash; } break; - case MEMCACHED_HASH_FNV1A_64: + case MEMCACHED_HASH_FNV1A_64: { hash= (uint32_t) FNV_64_INIT; - for (x= 0; x < key_length; x++) + for (x= 0; x < key_length; x++) { uint32_t val= (uint32_t)key[x]; hash ^= val; @@ -56,10 +56,10 @@ uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memca } } break; - case MEMCACHED_HASH_FNV1_32: + case MEMCACHED_HASH_FNV1_32: { hash= FNV_32_INIT; - for (x= 0; x < key_length; x++) + for (x= 0; x < key_length; x++) { uint32_t val= (uint32_t)key[x]; hash *= FNV_32_PRIME; @@ -67,10 +67,10 @@ uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memca } } break; - case MEMCACHED_HASH_FNV1A_32: + case MEMCACHED_HASH_FNV1A_32: { hash= FNV_32_INIT; - for (x= 0; x < key_length; x++) + for (x= 0; x < key_length; x++) { uint32_t val= (uint32_t)key[x]; hash ^= val; @@ -121,10 +121,11 @@ uint32_t generate_hash(memcached_st *ptr, const char *key, size_t key_length) static uint32_t dispatch_host(memcached_st *ptr, uint32_t hash) { - switch (ptr->distribution) + switch (ptr->distribution) { case MEMCACHED_DISTRIBUTION_CONSISTENT: case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: + case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: { uint32_t num= ptr->continuum_points_counter; WATCHPOINT_ASSERT(ptr->continuum); @@ -145,7 +146,7 @@ static uint32_t dispatch_host(memcached_st *ptr, uint32_t hash) if (right == end) right= begin; return right->index; - } + } case MEMCACHED_DISTRIBUTION_MODULA: return hash % ptr->number_of_hosts; case MEMCACHED_DISTRIBUTION_RANDOM: @@ -158,8 +159,8 @@ static uint32_t dispatch_host(memcached_st *ptr, uint32_t hash) /* NOTREACHED */ } -/* - One day make this public, and have it return the actual memcached_server_st +/* + One day make this public, and have it return the actual memcached_server_st to the calling application. */ uint32_t memcached_generate_hash(memcached_st *ptr, const char *key, size_t key_length) @@ -206,7 +207,7 @@ static uint32_t internal_generate_hash(const char *key, size_t key_length) const char *ptr= key; uint32_t value= 0; - while (key_length--) + while (key_length--) { uint32_t val= (uint32_t) *ptr++; value += val; @@ -215,7 +216,7 @@ static uint32_t internal_generate_hash(const char *key, size_t key_length) } value += (value << 3); value ^= (value >> 11); - value += (value << 15); + value += (value << 15); return value == 0 ? 1 : (uint32_t) value; } diff --git a/libmemcached/memcached_hosts.c b/libmemcached/memcached_hosts.c index f0af383a..d7f78dea 100644 --- a/libmemcached/memcached_hosts.c +++ b/libmemcached/memcached_hosts.c @@ -40,6 +40,7 @@ memcached_return run_distribution(memcached_st *ptr) { case MEMCACHED_DISTRIBUTION_CONSISTENT: case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: + case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return update_continuum(ptr); case MEMCACHED_DISTRIBUTION_MODULA: if (ptr->flags & MEM_USE_SORT_HOSTS) @@ -198,43 +199,93 @@ memcached_return update_continuum(memcached_st *ptr) pointer_per_server); #endif } - for (pointer_index= 0; - pointer_index < pointer_per_server / pointer_per_hash; - pointer_index++) + + + if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY) { - 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:%d-%d", - list[host_index].hostname, - list[host_index].port, - pointer_index); + 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:%d-%d", + list[host_index].hostname, + list[host_index].port, + pointer_index); #ifdef DEBUG - printf("update_continuum: key is %s\n", sort_host); + printf("update_continuum: key is %s\n", sort_host); #endif - WATCHPOINT_ASSERT(sort_host_length); + WATCHPOINT_ASSERT(sort_host_length); - if (is_ketama_weighted) - { - unsigned int i; - for (i = 0; i < pointer_per_hash; i++) + 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= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i); + 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; } } - else + } + else + { + for (pointer_index= 1; + pointer_index <= pointer_per_server / pointer_per_hash; + pointer_index++) { - 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; + 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; } diff --git a/tests/function.c b/tests/function.c index affa176f..0d7b2d1a 100644 --- a/tests/function.c +++ b/tests/function.c @@ -1463,7 +1463,7 @@ static test_return_t mget_execute(memcached_st *memc) memc->number_of_hosts= 1; int max_keys= binary ? 20480 : 1; - + char **keys= calloc((size_t)max_keys, sizeof(char*)); size_t *key_length=calloc((size_t)max_keys, sizeof(size_t)); @@ -2590,9 +2590,9 @@ static test_return_t user_supplied_bug18(memcached_st *trash) /* verify the standard ketama set. */ for (x= 0; x < 99; x++) { - uint32_t server_idx = memcached_generate_hash(memc, test_cases[x].key, strlen(test_cases[x].key)); + uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key)); char *hostname = memc->hosts[server_idx].hostname; - assert(strcmp(hostname, test_cases[x].server) == 0); + assert(strcmp(hostname, ketama_test_cases[x].server) == 0); } memcached_server_list_free(server_pool); @@ -2735,7 +2735,7 @@ static test_return_t auto_eject_hosts(memcached_st *trash) for (int x= 0; x < 99; x++) { - uint32_t server_idx = memcached_generate_hash(memc, test_cases[x].key, strlen(test_cases[x].key)); + uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key)); assert(server_idx != 2); } @@ -2745,9 +2745,9 @@ static test_return_t auto_eject_hosts(memcached_st *trash) run_distribution(memc); for (int x= 0; x < 99; x++) { - uint32_t server_idx = memcached_generate_hash(memc, test_cases[x].key, strlen(test_cases[x].key)); + uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key)); char *hostname = memc->hosts[server_idx].hostname; - assert(strcmp(hostname, test_cases[x].server) == 0); + assert(strcmp(hostname, ketama_test_cases[x].server) == 0); } memcached_server_list_free(server_pool); @@ -2764,6 +2764,7 @@ static test_return_t output_ketama_weighted_keys(memcached_st *trash) memcached_st *memc= memcached_create(NULL); assert(memc); + rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1); assert(rc == MEMCACHED_SUCCESS); @@ -2776,6 +2777,10 @@ static test_return_t output_ketama_weighted_keys(memcached_st *trash) value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH); assert(value == MEMCACHED_HASH_MD5); + + assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE, + MEMCACHED_KETAMA_COMPAT_SPY) == MEMCACHED_SUCCESS); + memcached_server_st *server_pool; server_pool = memcached_servers_parse("10.0.1.1:11211,10.0.1.2:11211,10.0.1.3:11211,10.0.1.4:11211,10.0.1.5:11211,10.0.1.6:11211,10.0.1.7:11211,10.0.1.8:11211,192.168.1.1:11211,192.168.100.1:11211"); memcached_server_push(memc, server_pool); @@ -2793,7 +2798,7 @@ static test_return_t output_ketama_weighted_keys(memcached_st *trash) { char key[10]; sprintf(key, "%d", x); - + uint32_t server_idx = memcached_generate_hash(memc, key, strlen(key)); char *hostname = memc->hosts[server_idx].hostname; unsigned int port = memc->hosts[server_idx].port; @@ -4674,6 +4679,125 @@ static test_return_t jenkins_run (memcached_st *memc __attribute__((unused))) return TEST_SUCCESS; } + +static test_return_t ketama_compatibility_libmemcached(memcached_st *trash) +{ + memcached_return rc; + uint64_t value; + int x; + memcached_server_st *server_pool; + memcached_st *memc; + + (void)trash; + + memc= memcached_create(NULL); + assert(memc); + + rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1); + assert(rc == MEMCACHED_SUCCESS); + + value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED); + assert(value == 1); + + assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE, + MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED) == MEMCACHED_SUCCESS); + + assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE) == + MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED); + + server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100"); + memcached_server_push(memc, server_pool); + + /* verify that the server list was parsed okay. */ + assert(memc->number_of_hosts == 8); + assert(strcmp(server_pool[0].hostname, "10.0.1.1") == 0); + assert(server_pool[0].port == 11211); + assert(server_pool[0].weight == 600); + assert(strcmp(server_pool[2].hostname, "10.0.1.3") == 0); + assert(server_pool[2].port == 11211); + assert(server_pool[2].weight == 200); + assert(strcmp(server_pool[7].hostname, "10.0.1.8") == 0); + assert(server_pool[7].port == 11211); + assert(server_pool[7].weight == 100); + + /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets + * us test the boundary wraparound. + */ + assert(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->continuum[0].index); + + /* verify the standard ketama set. */ + for (x= 0; x < 99; x++) + { + uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key)); + char *hostname = memc->hosts[server_idx].hostname; + assert(strcmp(hostname, ketama_test_cases[x].server) == 0); + } + + memcached_server_list_free(server_pool); + memcached_free(memc); + + return TEST_SUCCESS; +} + +static test_return_t ketama_compatibility_spymemcached(memcached_st *trash) +{ + memcached_return rc; + uint64_t value; + int x; + memcached_server_st *server_pool; + memcached_st *memc; + + (void)trash; + + memc= memcached_create(NULL); + assert(memc); + + rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1); + assert(rc == MEMCACHED_SUCCESS); + + value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED); + assert(value == 1); + + assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE, + MEMCACHED_KETAMA_COMPAT_SPY) == MEMCACHED_SUCCESS); + + assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE) == + MEMCACHED_KETAMA_COMPAT_SPY); + + server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100"); + memcached_server_push(memc, server_pool); + + /* verify that the server list was parsed okay. */ + assert(memc->number_of_hosts == 8); + assert(strcmp(server_pool[0].hostname, "10.0.1.1") == 0); + assert(server_pool[0].port == 11211); + assert(server_pool[0].weight == 600); + assert(strcmp(server_pool[2].hostname, "10.0.1.3") == 0); + assert(server_pool[2].port == 11211); + assert(server_pool[2].weight == 200); + assert(strcmp(server_pool[7].hostname, "10.0.1.8") == 0); + assert(server_pool[7].port == 11211); + assert(server_pool[7].weight == 100); + + /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets + * us test the boundary wraparound. + */ + assert(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->continuum[0].index); + + /* verify the standard ketama set. */ + for (x= 0; x < 99; x++) + { + uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases_spy[x].key, strlen(ketama_test_cases_spy[x].key)); + char *hostname = memc->hosts[server_idx].hostname; + assert(strcmp(hostname, ketama_test_cases_spy[x].server) == 0); + } + + memcached_server_list_free(server_pool); + memcached_free(memc); + + return TEST_SUCCESS; +} + static test_return_t regression_bug_434484(memcached_st *memc) { if (pre_binary(memc) != MEMCACHED_SUCCESS) @@ -4885,8 +5009,8 @@ static test_return_t regression_bug_447342(memcached_st *memc) ** to do this ;-) */ memcached_quit(memc); - - /* Verify that all messages are stored, and we didn't stuff too much + + /* Verify that all messages are stored, and we didn't stuff too much * into the servers */ rc= memcached_mget(memc, (const char* const *)keys, key_length, max_keys); @@ -5226,6 +5350,12 @@ test_st regression_tests[]= { {0, 0, 0} }; +test_st ketama_compatibility[]= { + {"libmemcached", 1, ketama_compatibility_libmemcached }, + {"spymemcached", 1, ketama_compatibility_spymemcached }, + {0, 0, 0} +}; + test_st generate_tests[] ={ {"generate_pairs", 1, generate_pairs }, {"generate_data", 1, generate_data }, @@ -5332,6 +5462,7 @@ collection_st collection[] ={ {"consistent_not", 0, 0, consistent_tests}, {"consistent_ketama", pre_behavior_ketama, 0, consistent_tests}, {"consistent_ketama_weighted", pre_behavior_ketama_weighted, 0, consistent_weighted_tests}, + {"ketama_compat", 0, 0, ketama_compatibility}, {"test_hashes", 0, 0, hash_tests}, {"replication", pre_replication, 0, replication_tests}, {"replication_noblock", pre_replication_noblock, 0, replication_tests}, diff --git a/tests/ketama_test_cases.h b/tests/ketama_test_cases.h index fb6f03d8..3d770f16 100644 --- a/tests/ketama_test_cases.h +++ b/tests/ketama_test_cases.h @@ -1,108 +1,113 @@ -typedef struct { +#ifndef TESTS_KETAMA_TEST_CASES_H +#define TESTS_KETAMA_TEST_CASES_H + +static struct { const char *key; unsigned long hash1; unsigned long hash2; const char *server; -} TestCase; - -static TestCase test_cases[99] = { - { "SVa_]_V41)", 443691461UL, 445379617UL, "10.0.1.2" }, - { "*/Z;?V(.\\8", 1422915503UL, 1428303028UL, "10.0.1.4" }, +} ketama_test_cases[99]= { + { "SVa_]_V41)", 443691461UL, 445379617UL, "10.0.1.7" }, + { "*/Z;?V(.\\8", 1422915503UL, 1428303028UL, "10.0.1.1" }, { "30C1*Z*S/_", 1473165754UL, 1480075959UL, "10.0.1.2" }, { "ERR:EC58G>", 2148406511UL, 2168579133UL, "10.0.1.7" }, - { "1I=cTMNTKF", 2882686667UL, 2885206587UL, "10.0.1.4" }, + { "1I=cTMNTKF", 2882686667UL, 2885206587UL, "10.0.1.5" }, { "]VG<`I*Z8)", 1103544263UL, 1104827657UL, "10.0.1.5" }, - { "UUTC`-V159", 3716288206UL, 3727224240UL, "10.0.1.7" }, - { "@7RU6C6T+Z", 3862737685UL, 3871917949UL, "10.0.1.6" }, - { "/XLN0@+36;", 1623269830UL, 1627683651UL, "10.0.1.7" }, - { "4(`X;\\V.^c", 373546328UL, 383925769UL, "10.0.1.6" }, - { "726bW=9*a4", 4213440020UL, 4213950705UL, "10.0.1.3" }, - { "\\`)32", 536016577UL, 539988520UL, "10.0.1.7" }, { "U))Fb-(`,.", 4128682289UL, 4136854163UL, "10.0.1.7" }, { "R-08RNTaRT", 3718170086UL, 3727224240UL, "10.0.1.5" }, - { "(LHcO203I3", 1007779411UL, 1014643570UL, "10.0.1.1" }, - { "=256P+;Qc8", 3976201210UL, 3976304873UL, "10.0.1.3" }, - { "OI5XZ_BBT(", 2155922164UL, 2168579133UL, "10.0.1.5" }, - { "2TLRL/UL;:", 1086800909UL, 1095659802UL, "10.0.1.2" }, - { "WHD\\O1`ZRW", 3087923411UL, 3095471560UL, "10.0.1.1" }, - { ".=54)_c;=T", 2497691631UL, 2502731301UL, "10.0.1.6" }, - { ";GE`)FT\\4", 580747448UL, 581063326UL, "10.0.1.5" }, - { "HZAU*;P*N]", 2564670474UL, 2565697267UL, "10.0.1.1" }, + { "(LHcO203I3", 1007779411UL, 1014643570UL, "10.0.1.5" }, + { "=256P+;Qc8", 3976201210UL, 3976304873UL, "10.0.1.5" }, + { "OI5XZ_BBT(", 2155922164UL, 2168579133UL, "10.0.1.7" }, + { "2TLRL/UL;:", 1086800909UL, 1095659802UL, "10.0.1.7" }, + { "WHD\\O1`ZRW", 3087923411UL, 3095471560UL, "10.0.1.5" }, + { ".=54)_c;=T", 2497691631UL, 2502731301UL, "10.0.1.1" }, + { ";GE`)FT\\4", 580747448UL, 581063326UL, "10.0.1.2" }, + { "HZAU*;P*N]", 2564670474UL, 2565697267UL, "10.0.1.7" }, { "NZ@ZE=O84_", 533335275UL, 539988520UL, "10.0.1.7" }, - { "6,cEI`F_P>", 3972869246UL, 3974773167UL, "10.0.1.3" }, - { "c,5AQ/T5)6", 2835605783UL, 2847870057UL, "10.0.1.7" }, - { ".O,>>BT)RX", 3857978174UL, 3871917949UL, "10.0.1.7" }, - { "XY\\X::LX50", 1749241099UL, 1752196488UL, "10.0.1.7" }, - { "+550F^/.01", 3781824099UL, 3783248219UL, "10.0.1.2" }, + { "6,cEI`F_P>", 3972869246UL, 3974773167UL, "10.0.1.6" }, + { "c,5AQ/T5)6", 2835605783UL, 2847870057UL, "10.0.1.8" }, + { ".O,>>BT)RX", 3857978174UL, 3871917949UL, "10.0.1.5" }, + { "XY\\X::LX50", 1749241099UL, 1752196488UL, "10.0.1.6" }, + { "+550F^/.01", 3781824099UL, 3783248219UL, "10.0.1.6" }, { "<.X9E2S5+9", 3232479481UL, 3234387706UL, "10.0.1.7" }, - { "]\\.UH8_0a1", 2419699252UL, 2423002920UL, "10.0.1.6" }, - { "8(6=(T0/Z0", 728266737UL, 729026070UL, "10.0.1.6" }, - { "8*6a;Sc*X+", 4223431086UL, 4230156966UL, "10.0.1.5" }, - { "J5/", 2776949824UL, 2784182515UL, "10.0.1.6" }, - { "[>RZHG97Q9", 71954686UL, 72034069UL, "10.0.1.4" }, - { "J3/G[)9<^Z", 2799896459UL, 2805183696UL, "10.0.1.6" }, - { "N-)88>[O`,", 50404102UL, 51792557UL, "10.0.1.2" }, + { "aPb3E1WD4K", 2500489218UL, 2502731301UL, "10.0.1.1" }, + { "?@12R<=1BH", 1494795329UL, 1502505505UL, "10.0.1.8" }, + { "QR(a+Q=1FU", 3238535074UL, 3238996435UL, "10.0.1.6" }, + { "`C9^FV,960", 2628553463UL, 2628733766UL, "10.0.1.6" }, + { "UNHVP..^8H", 977096483UL, 977319837UL, "10.0.1.4" }, + { ":Y.2W2[(35", 2777083668UL, 2784182515UL, "10.0.1.7" }, + { "M/HV^_HZ4O", 3623390946UL, 3624445007UL, "10.0.1.7" }, + { "ZY16KQJ5/", 2776949824UL, 2784182515UL, "10.0.1.7" }, + { "[>RZHG97Q9", 71954686UL, 72034069UL, "10.0.1.6" }, + { "J3/G[)9<^Z", 2799896459UL, 2805183696UL, "10.0.1.7" }, + { "N-)88>[O`,", 50404102UL, 51792557UL, "10.0.1.5" }, { "NP:=FR\\OaA", 3837333776UL, 3837792034UL, "10.0.1.7" }, - { "`@L+W;a,O[", 1512157148UL, 1522285852UL, "10.0.1.5" }, - { "W2`P:-+1T[", 2945171975UL, 2946196424UL, "10.0.1.7" }, - { "-6G7K^YDIN", 3168617340UL, 3170513015UL, "10.0.1.5" }, - { "U>*>9ZI6V5", 668514946UL, 674097631UL, "10.0.1.5" }, + { "`@L+W;a,O[", 1512157148UL, 1522285852UL, "10.0.1.6" }, + { "W2`P:-+1T[", 2945171975UL, 2946196424UL, "10.0.1.5" }, + { "-6G7K^YDIN", 3168617340UL, 3170513015UL, "10.0.1.7" }, + { "U>*>9ZI6V5", 668514946UL, 674097631UL, "10.0.1.6" }, { ".I?^6Ic9RK", 938419020UL, 942832691UL, "10.0.1.6" }, - { "0OZH^9BKM[", 3682518606UL, 3686781297UL, "10.0.1.2" }, - { "5?50UGZ:ML", 868610882UL, 869425986UL, "10.0.1.6" }, - { "?K2NF@3=IU", 381218851UL, 383925769UL, "10.0.1.6" }, - { "YI@G-2X?UB", 3688706179UL, 3693197681UL, "10.0.1.6" }, - { "7cY", 2590140172UL, 2598117636UL, "10.0.1.5" }, - { "\\[a\\^=V_M0", 689410119UL, 698690782UL, "10.0.1.7" }, + { "\\R^7=9UCG`", 126218373UL, 129199837UL, "10.0.1.5" }, + { "1bQS5]WOXB", 1853470245UL, 1855329369UL, "10.0.1.4" }, + { "M(@X^b[L:K", 3019630308UL, 3022260113UL, "10.0.1.1" }, + { "431cBF8,YO", 1679726993UL, 1685224295UL, "10.0.1.7" }, + { "(bEIQJ:E./", 2922607787UL, 2925521819UL, "10.0.1.6" }, + { "WS/3H*)7F;", 419488232UL, 422140585UL, "10.0.1.5" }, + { "ZJF[Ia6Q)+", 3960568056UL, 3962489998UL, "10.0.1.7" }, + { "<]*QCK8U,>", 2590140172UL, 2598117636UL, "10.0.1.7" }, + { "\\[a\\^=V_M0", 689410119UL, 698690782UL, "10.0.1.6" }, { "7;RM+8J9YC", 1530175299UL, 1531107082UL, "10.0.1.7" }, - { "4*=.SPR[AV", 3928582722UL, 3928853792UL, "10.0.1.3" }, + { "4*=.SPR[AV", 3928582722UL, 3928853792UL, "10.0.1.1" }, { "-2F+^88P4U", 3023552752UL, 3025823613UL, "10.0.1.7" }, - { "X;-F`(N?9D", 570465234UL, 572485994UL, "10.0.1.5" }, - { "R=F_D-K2a]", 1287750228UL, 1290935562UL, "10.0.1.1" }, - { "X*+2aaC.EG", 3200948713UL, 3201088518UL, "10.0.1.3" }, - { "[1ZXONX2]a", 4108881567UL, 4109865744UL, "10.0.1.7" }, - { "FL;\\GWacaV", 458449508UL, 467374054UL, "10.0.1.7" }, - { "\\MQ_XNT7L-", 1259349383UL, 1259509450UL, "10.0.1.5" }, - { "VD6D0]ba_\\", 3842502950UL, 3842588691UL, "10.0.1.7" }, + { "X;-F`(N?9D", 570465234UL, 572485994UL, "10.0.1.7" }, + { "R=F_D-K2a]", 1287750228UL, 1290935562UL, "10.0.1.7" }, + { "X*+2aaC.EG", 3200948713UL, 3201088518UL, "10.0.1.5" }, + { "[1ZXONX2]a", 4108881567UL, 4109865744UL, "10.0.1.4" }, + { "FL;\\GWacaV", 458449508UL, 467374054UL, "10.0.1.4" }, + { "\\MQ_XNT7L-", 1259349383UL, 1259509450UL, "10.0.1.7" }, + { "VD6D0]ba_\\", 3842502950UL, 3842588691UL, "10.0.1.1" }, }; + +#include "ketama_test_cases_spy.h" + +#endif diff --git a/tests/ketama_test_cases_spy.h b/tests/ketama_test_cases_spy.h new file mode 100644 index 00000000..5e6a9378 --- /dev/null +++ b/tests/ketama_test_cases_spy.h @@ -0,0 +1,110 @@ +#ifndef TESTS_KETAMA_TEST_CASES_SPY_H +#define TESTS_KETAMA_TEST_CASES_SPY_H + +static struct { + const char *key; + unsigned long hash1; + unsigned long hash2; + const char *server; +} ketama_test_cases_spy[99]= { + { "SVa_]_V41)", 443691461UL, 445379617UL, "10.0.1.2" }, + { "*/Z;?V(.\\8", 1422915503UL, 1428303028UL, "10.0.1.4" }, + { "30C1*Z*S/_", 1473165754UL, 1480075959UL, "10.0.1.2" }, + { "ERR:EC58G>", 2148406511UL, 2168579133UL, "10.0.1.7" }, + { "1I=cTMNTKF", 2882686667UL, 2885206587UL, "10.0.1.4" }, + { "]VG<`I*Z8)", 1103544263UL, 1104827657UL, "10.0.1.5" }, + { "UUTC`-V159", 3716288206UL, 3727224240UL, "10.0.1.7" }, + { "@7RU6C6T+Z", 3862737685UL, 3871917949UL, "10.0.1.6" }, + { "/XLN0@+36;", 1623269830UL, 1627683651UL, "10.0.1.7" }, + { "4(`X;\\V.^c", 373546328UL, 383925769UL, "10.0.1.6" }, + { "726bW=9*a4", 4213440020UL, 4213950705UL, "10.0.1.3" }, + { "\\`)32", 536016577UL, 539988520UL, "10.0.1.7" }, + { "U))Fb-(`,.", 4128682289UL, 4136854163UL, "10.0.1.7" }, + { "R-08RNTaRT", 3718170086UL, 3727224240UL, "10.0.1.5" }, + { "(LHcO203I3", 1007779411UL, 1014643570UL, "10.0.1.1" }, + { "=256P+;Qc8", 3976201210UL, 3976304873UL, "10.0.1.3" }, + { "OI5XZ_BBT(", 2155922164UL, 2168579133UL, "10.0.1.5" }, + { "2TLRL/UL;:", 1086800909UL, 1095659802UL, "10.0.1.2" }, + { "WHD\\O1`ZRW", 3087923411UL, 3095471560UL, "10.0.1.1" }, + { ".=54)_c;=T", 2497691631UL, 2502731301UL, "10.0.1.6" }, + { ";GE`)FT\\4", 580747448UL, 581063326UL, "10.0.1.5" }, + { "HZAU*;P*N]", 2564670474UL, 2565697267UL, "10.0.1.1" }, + { "NZ@ZE=O84_", 533335275UL, 539988520UL, "10.0.1.7" }, + { "6,cEI`F_P>", 3972869246UL, 3974773167UL, "10.0.1.3" }, + { "c,5AQ/T5)6", 2835605783UL, 2847870057UL, "10.0.1.7" }, + { ".O,>>BT)RX", 3857978174UL, 3871917949UL, "10.0.1.7" }, + { "XY\\X::LX50", 1749241099UL, 1752196488UL, "10.0.1.7" }, + { "+550F^/.01", 3781824099UL, 3783248219UL, "10.0.1.2" }, + { "<.X9E2S5+9", 3232479481UL, 3234387706UL, "10.0.1.7" }, + { "]\\.UH8_0a1", 2419699252UL, 2423002920UL, "10.0.1.6" }, + { "8(6=(T0/Z0", 728266737UL, 729026070UL, "10.0.1.6" }, + { "8*6a;Sc*X+", 4223431086UL, 4230156966UL, "10.0.1.5" }, + { "J5/", 2776949824UL, 2784182515UL, "10.0.1.6" }, + { "[>RZHG97Q9", 71954686UL, 72034069UL, "10.0.1.4" }, + { "J3/G[)9<^Z", 2799896459UL, 2805183696UL, "10.0.1.6" }, + { "N-)88>[O`,", 50404102UL, 51792557UL, "10.0.1.2" }, + { "NP:=FR\\OaA", 3837333776UL, 3837792034UL, "10.0.1.7" }, + { "`@L+W;a,O[", 1512157148UL, 1522285852UL, "10.0.1.5" }, + { "W2`P:-+1T[", 2945171975UL, 2946196424UL, "10.0.1.7" }, + { "-6G7K^YDIN", 3168617340UL, 3170513015UL, "10.0.1.5" }, + { "U>*>9ZI6V5", 668514946UL, 674097631UL, "10.0.1.5" }, + { ".I?^6Ic9RK", 938419020UL, 942832691UL, "10.0.1.6" }, + { "0OZH^9BKM[", 3682518606UL, 3686781297UL, "10.0.1.2" }, + { "5?50UGZ:ML", 868610882UL, 869425986UL, "10.0.1.6" }, + { "?K2NF@3=IU", 381218851UL, 383925769UL, "10.0.1.6" }, + { "YI@G-2X?UB", 3688706179UL, 3693197681UL, "10.0.1.6" }, + { "7cY", 2590140172UL, 2598117636UL, "10.0.1.5" }, + { "\\[a\\^=V_M0", 689410119UL, 698690782UL, "10.0.1.7" }, + { "7;RM+8J9YC", 1530175299UL, 1531107082UL, "10.0.1.7" }, + { "4*=.SPR[AV", 3928582722UL, 3928853792UL, "10.0.1.3" }, + { "-2F+^88P4U", 3023552752UL, 3025823613UL, "10.0.1.7" }, + { "X;-F`(N?9D", 570465234UL, 572485994UL, "10.0.1.5" }, + { "R=F_D-K2a]", 1287750228UL, 1290935562UL, "10.0.1.1" }, + { "X*+2aaC.EG", 3200948713UL, 3201088518UL, "10.0.1.3" }, + { "[1ZXONX2]a", 4108881567UL, 4109865744UL, "10.0.1.7" }, + { "FL;\\GWacaV", 458449508UL, 467374054UL, "10.0.1.7" }, + { "\\MQ_XNT7L-", 1259349383UL, 1259509450UL, "10.0.1.5" }, + { "VD6D0]ba_\\", 3842502950UL, 3842588691UL, "10.0.1.7" }, +}; +#endif