* Work on the UDP protocol
* Added get_by_key, set_by_key tests for C++ API
* Fix for limit_maxbytes to be 64bit in stats
+ * Added Atom Smasher test (scale baby, scale!)
+ * Servers are now sorted, meaning that servers are now ordered so that
+ clients with the same lists, will have same distribution. (Idea from
+ Ross McFarland). MEMCACHED_BEHAVIOR_SORT_HOSTS was added to enable
+ this support.
+ * Added MEMCACHED_BAD_KEY_PROVIDED error for auto, set, and get operations
+ when the library is compiled with --enable-debug. This additional code
+ will test for bad keys.
0.15 Tue Jan 29 14:55:44 PST 2008
* More work on the C++ API.
Tim Bunce - Perl Driver work and feedback on API
Kevin Dalley - Bug Fixes
Patrick Galbraith - work on C++ interface
+Ross McFarland - Idea for sorting servers.
connection. Quiting the connection or closing down the connection will also
cause the buffered data to be pushed to the remote connection.
+=item MEMCACHED_BEHAVIOR_SORT_HOSTS
+
+Enabling this will cause hosts that are added to be placed in the host list in
+sorted order. This will defeat consisten hashing.
+
=back
=head1 RETURN
MEMCACHED_FETCH_NOTFINISHED,
MEMCACHED_TIMEOUT,
MEMCACHED_BUFFERED,
+ MEMCACHED_BAD_KEY_PROVIDED,
MEMCACHED_MAXIMUM_RETURN, /* Always add new error code before */
} memcached_return;
MEMCACHED_BEHAVIOR_DISTRIBUTION,
MEMCACHED_BEHAVIOR_BUFFER_REQUESTS,
MEMCACHED_BEHAVIOR_USER_DATA,
+ MEMCACHED_BEHAVIOR_SORT_HOSTS,
} memcached_behavior;
typedef enum {
memcached_hosts.c \
memcached_io.c \
md5.c \
+ memcached_key.c \
memcached_quit.c \
memcached_parse.c \
memcached_response.c \
#include <fcntl.h>
#include <sys/un.h>
#include <netinet/tcp.h>
-#include "libmemcached_config.h"
+#include <libmemcached_config.h>
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
MEM_USE_CACHE_LOOKUPS= (1 << 6),
MEM_SUPPORT_CAS= (1 << 7),
MEM_BUFFER_REQUESTS= (1 << 8),
+ MEM_USE_SORT_HOSTS= (1 << 9),
} memcached_flags;
/* Hashing algo */
memcached_result_st *result);
void server_list_free(memcached_st *ptr, memcached_server_st *servers);
+memcached_return key_proof(char **keys, size_t *key_length,
+ unsigned int number_of_keys);
+
+#ifdef HAVE_DEBUG
+#define key_test(A,B,C) key_proof(A,B,C)
+#else
+#define key_test(A,B,C) MEMCACHED_SUCCESS
+#endif
#endif /* __COMMON_H__ */
if (ptr->hosts == NULL || ptr->number_of_hosts == 0)
return MEMCACHED_NO_SERVERS;
+ if (key_test(&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)
+ return MEMCACHED_BAD_KEY_PROVIDED;
+
server_key= memcached_generate_hash(ptr, key, key_length);
send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
case MEMCACHED_BEHAVIOR_KETAMA:
set_behavior_flag(ptr, MEM_USE_KETAMA, data);
break;
+ case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+ set_behavior_flag(ptr, MEM_USE_SORT_HOSTS, data);
+ break;
case MEMCACHED_BEHAVIOR_USER_DATA:
ptr->user_data= data;
break;
case MEMCACHED_BEHAVIOR_KETAMA:
temp_flag= MEM_USE_KETAMA;
break;
+ case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+ temp_flag= MEM_USE_SORT_HOSTS;
+ break;
case MEMCACHED_BEHAVIOR_USER_DATA:
return 0;
//return (unsigned long long)ptr->user_data;
if (ptr->number_of_hosts == 0)
return MEMCACHED_NO_SERVERS;
+ if (key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED)
+ return MEMCACHED_BAD_KEY_PROVIDED;
+
if (ptr->flags & MEM_SUPPORT_CAS)
{
get_command= "gets ";
}
}
+static int compare_servers(const void *p1, const void *p2)
+{
+ int return_value;
+ memcached_server_st *a= (memcached_server_st *)p1;
+ memcached_server_st *b= (memcached_server_st *)p2;
+
+ return_value= strcmp(a->hostname, b->hostname);
+
+ if (return_value == 0)
+ {
+ if (a->port > b->port)
+ return_value++;
+ else
+ return_value--;
+ }
+
+ return return_value;
+}
+
static void host_reset(memcached_st *ptr, memcached_server_st *host,
char *hostname, unsigned int port,
memcached_connection type)
}
ptr->hosts[0].count= ptr->number_of_hosts;
+ if (ptr->number_of_hosts > 1)
+ qsort(ptr->hosts, ptr->number_of_hosts, sizeof(memcached_server_st), compare_servers);
+
rebalance_wheel(ptr);
return MEMCACHED_SUCCESS;
ptr->number_of_hosts++;
ptr->hosts[0].count++;
+ if (ptr->number_of_hosts > 1)
+ qsort(ptr->hosts, ptr->number_of_hosts, sizeof(memcached_server_st), compare_servers);
+
rebalance_wheel(ptr);
LIBMEMCACHED_MEMCACHED_SERVER_ADD_END();
/* Backwards compatibility hack */
new_host_list[0].count++;
+ count= new_host_list[0].count;
+
+ if (new_host_list[0].count > 1)
+ qsort(new_host_list, count, sizeof(memcached_server_st), compare_servers);
+
+ new_host_list[0].count= count;
+
*error= MEMCACHED_SUCCESS;
return new_host_list;
if (ptr->number_of_hosts == 0)
return MEMCACHED_NO_SERVERS;
+ if (key_test(&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)
+ return MEMCACHED_BAD_KEY_PROVIDED;
+
server_key= memcached_generate_hash(ptr, master_key, master_key_length);
if (cas)
return "ACTION QUEUED";
case MEMCACHED_TIMEOUT:
return "A TIMEOUT OCCURRED";
+ case MEMCACHED_BAD_KEY_PROVIDED:
+ return "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE";
case MEMCACHED_MAXIMUM_RETURN:
return "Gibberish returned!";
default:
#define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers."
/* Global Thread counter */
-unsigned int thread_counter;
+volatile unsigned int thread_counter;
pthread_mutex_t counter_mutex;
pthread_cond_t count_threshhold;
-unsigned int master_wakeup;
+volatile unsigned int master_wakeup;
pthread_mutex_t sleeper_mutex;
pthread_cond_t sleep_threshhold;
#include "test.h"
+/* Number of items generated for tests */
#define GLOBAL_COUNT 100000
-#define TEST_COUNTER 100000
+
+/* Number of times to run the test loop */
+#define TEST_COUNTER 500000
static uint32_t global_count;
static pairs_st *global_pairs;
{
unsigned int x;
memcached_return rc;
+ char *return_value;
+ size_t return_value_length;
+ uint32_t flags;
+infinite:
+ for (x= 0; x < TEST_COUNTER; x++)
{
- char *return_value;
- size_t return_value_length;
- uint32_t flags;
-
- for (x= 0; x < TEST_COUNTER; x++)
- {
- uint32_t test_bit;
- uint8_t which;
+ uint32_t test_bit;
+ uint8_t which;
- test_bit= random() % GLOBAL_COUNT;
- which= random() % 2;
+ test_bit= random() % GLOBAL_COUNT;
+ which= random() % 2;
- if (which == 0)
- {
- return_value= memcached_get(memc, global_keys[test_bit], global_keys_length[test_bit],
- &return_value_length, &flags, &rc);
- if (rc == MEMCACHED_SUCCESS && return_value)
- free(return_value);
- else
- WATCHPOINT_ERROR(rc);
- }
+ if (which == 0)
+ {
+ return_value= memcached_get(memc, global_keys[test_bit], global_keys_length[test_bit],
+ &return_value_length, &flags, &rc);
+ if (rc == MEMCACHED_SUCCESS && return_value)
+ free(return_value);
+ else if (rc == MEMCACHED_NOTFOUND)
+ continue;
else
{
- rc= memcached_set(memc, global_pairs[test_bit].key,
- global_pairs[test_bit].key_length,
- global_pairs[test_bit].value,
- global_pairs[test_bit].value_length,
- 0, 0);
- if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
- {
- WATCHPOINT_ERROR(rc);
- WATCHPOINT_ASSERT(0);
- }
+ WATCHPOINT_ERROR(rc);
+ WATCHPOINT_ASSERT(rc);
+ }
+ }
+ else
+ {
+ rc= memcached_set(memc, global_pairs[test_bit].key,
+ global_pairs[test_bit].key_length,
+ global_pairs[test_bit].value,
+ global_pairs[test_bit].value_length,
+ 0, 0);
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
+ {
+ WATCHPOINT_ERROR(rc);
+ WATCHPOINT_ASSERT(0);
}
}
}
+ if (getenv("MEMCACHED_ATOM_BURIN_IN"))
+ goto infinite;
+
return 0;
}
return MEMCACHED_SUCCESS;
}
-test_st generate_tests[] ={
+test_st smash_tests[] ={
{"generate_pairs", 1, generate_pairs },
+ {"drizzle", 1, drizzle },
{"cleanup", 1, cleanup_pairs },
{0, 0, 0}
};
collection_st collection[] ={
- {"generate", 0, 0, generate_tests},
- {"generate_hsieh", pre_hsieh, 0, generate_tests},
- {"generate_hsieh_consistent", enable_consistent, 0, generate_tests},
- {"generate_md5", pre_md5, 0, generate_tests},
- {"generate_nonblock", pre_nonblock, 0, generate_tests},
+ {"smash", 0, 0, smash_tests},
+ {"smash_hsieh", pre_hsieh, 0, smash_tests},
+ {"smash_hsieh_consistent", enable_consistent, 0, smash_tests},
+ {"smash_md5", pre_md5, 0, smash_tests},
+ {"smash_nonblock", pre_nonblock, 0, smash_tests},
{0, 0, 0, 0}
};
return 0;
}
+uint8_t server_sort_test(memcached_st *ptr)
+{
+ unsigned int setting;
+ memcached_server_st *server_list;
+ memcached_return rc;
+
+ setting= 1;
+ memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_SORT_HOSTS, &setting);
+
+ server_list= memcached_server_list_append(NULL, "arg", 0, &rc);
+ assert(server_list);
+
+ server_list= memcached_server_list_append(server_list, "localhost", 0, &rc);
+ assert(server_list);
+
+ server_list= memcached_server_list_append(server_list, "c", 0, &rc);
+ assert(server_list);
+
+ server_list= memcached_server_list_append(server_list, "abba", 0, &rc);
+ assert(server_list);
+
+ free(server_list);
+
+ return 0;
+}
+
uint8_t allocation_test(memcached_st *not_used)
{
memcached_st *memc;
return 0;
}
+uint8_t bad_key_test(memcached_st *memc)
+{
+#ifdef HAVE_DEBUG
+ memcached_return rc;
+ char *key= "foo bad";
+ char *string;
+ size_t string_length;
+ uint32_t flags;
+
+ string= memcached_get(memc, key, strlen(key),
+ &string_length, &flags, &rc);
+ assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
+ assert(string_length == 0);
+ assert(!string);
+#endif
+
+ return 0;
+}
+
uint8_t get_test(memcached_st *memc)
{
memcached_return rc;
{"init", 0, init_test },
{"allocation", 0, allocation_test },
{"server_list_null_test", 0, server_list_null_test},
+ {"server_sort", 0, server_sort_test},
{"clone_test", 0, clone_test },
{"error", 0, error_test },
{"set", 0, set_test },
{"behavior_test", 0, get_stats_keys },
{"callback_test", 0, get_stats_keys },
{"version_string_test", 0, version_string_test},
+ {"bad_key", 1, bad_key_test },
{0, 0, 0}
};