From: Brian Aker Date: Wed, 15 Jul 2009 18:00:22 +0000 (-0700) Subject: Merge Monty X-Git-Tag: 0.32~14 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=4bad80470c3895cf00f65359e6b8fa180ec9520f;hp=8edeaed834e4a4396fb60647cdee7850c9c81de7;p=awesomized%2Flibmemcached Merge Monty --- diff --git a/ChangeLog b/ChangeLog index 57659935..950364b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ + * Added Twitter's memcached_server_error() functions. + * Fix for OSX compiles in development builds. + * Updated C++ interface. + 0.31 Fri Jul 10 09:02:50 PDT 2009 * Added support or HA via replication. * malloc() removed for server key usage. diff --git a/clients/generator.c b/clients/generator.c index 091b2808..cd1a17bf 100644 --- a/clients/generator.c +++ b/clients/generator.c @@ -13,13 +13,18 @@ static const char ALPHANUMERICS[]= #define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1) +static size_t get_alpha_num(void) +{ + return (size_t)random() % ALPHANUMERICS_SIZE; +} + static void get_random_string(char *buffer, size_t size) { char *buffer_ptr= buffer; while (--size) - *buffer_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE]; - *buffer_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE]; + *buffer_ptr++= ALPHANUMERICS[get_alpha_num()]; + *buffer_ptr++= ALPHANUMERICS[get_alpha_num()]; } void pairs_free(pairs_st *pairs) diff --git a/docs/memcached_server_st.pod b/docs/memcached_server_st.pod index 0e6e7067..08ff7785 100644 --- a/docs/memcached_server_st.pod +++ b/docs/memcached_server_st.pod @@ -23,6 +23,10 @@ C Client Library for memcached (libmemcached, -lmemcached) memcached_server_st *memcached_servers_parse (const char *server_strings); + const char *memcached_server_error(memcached_server_st *ptr); + + void memcached_server_error_reset(memcached_server_st *ptr); + =head1 DESCRIPTION libmemcached(3) operates on a list of hosts which are stored in @@ -44,6 +48,12 @@ command line applications, and parse it to an array of memcached_server_st. The example is "localhost, foo:555, foo, bar". All hosts except foo:555 will be set to the default port, while that host will have a port of 555. +memcached_server_error() can be used to look at the text of the last error +message sent by the server to to the client. Use memcached_server_error_reset() +to reset the message (this does not currently free up the memory associated +with the message). + + =head1 RETURN Varies, see particular functions. diff --git a/libmemcached/memcached.hh b/libmemcached/memcached.hh index d13ca23a..52ce4105 100644 --- a/libmemcached/memcached.hh +++ b/libmemcached/memcached.hh @@ -1,175 +1,353 @@ -#include "libmemcached/memcached.h" -#include -#include +#include + +#include +#include class Memcached { - memcached_st memc; - memcached_result_st result; - public: - Memcached() : memc(), result() + Memcached() + : + memc(), + result() { memcached_create(&memc); } - Memcached(memcached_st *clone) : memc(), result() + Memcached(memcached_st *clone) + : + memc(), + result() { memcached_clone(&memc, clone); } - char *fetch (char *key, size_t *key_length, size_t *value_length) + + ~Memcached() { - uint32_t flags; - memcached_return rc; + memcached_free(&memc); + } - return memcached_fetch(&memc, key, key_length, - value_length, &flags, &rc); + bool fetch(std::string &key, + std::string &ret_val, + size_t *key_length, + size_t *value_length, + uint32_t *flags, + memcached_return *rc) + { + char ret_key[MEMCACHED_MAX_KEY]; + char *value= memcached_fetch(&memc, ret_key, key_length, + value_length, flags, rc); + if (value) + { + ret_val.assign(value); + key.assign(ret_key); + return true; + } + return false; } - char *get(const char *key, size_t *value_length) + + std::string get(const std::string &key, size_t *value_length) { uint32_t flags; memcached_return rc; + std::string ret_val; - return memcached_get(&memc, key, strlen(key), - value_length, &flags, &rc); + char *value= memcached_get(&memc, key.c_str(), key.length(), + value_length, &flags, &rc); + if (value) + { + ret_val.assign(value); + } + return ret_val; } - char *get_by_key(const char *master_key, const char *key, - size_t *value_length) + std::string get_by_key(const std::string &master_key, + const std::string &key, + size_t *value_length) { uint32_t flags; memcached_return rc; + std::string ret_val; - return memcached_get_by_key(&memc, master_key, strlen(master_key), - key, strlen(key), - value_length, &flags, &rc); + char *value= memcached_get_by_key(&memc, master_key.c_str(), master_key.length(), + key.c_str(), key.length(), + value_length, &flags, &rc); + if (value) + { + ret_val.assign(value); + } + return ret_val; } - memcached_return mget(const char **keys, size_t *key_length, - unsigned int number_of_keys) + bool mget(std::vector &keys) { + std::vector real_keys; + std::vector key_len; + /* + * Construct an array which will contain the length + * of each of the strings in the input vector. Also, to + * interface with the memcached C API, we need to convert + * the vector of std::string's to a vector of char *. + */ + real_keys.reserve(keys.size()); + key_len.reserve(keys.size()); + + std::vector::iterator it= keys.begin(); + + while (it != keys.end()) + { + real_keys.push_back(const_cast((*it).c_str())); + key_len.push_back((*it).length()); + ++it; + } + + /* + * If the std::vector of keys is empty then we cannot + * call memcached_mget as we will get undefined behavior. + */ + if (!real_keys.empty()) + { + memcached_return rc= memcached_mget(&memc, &real_keys[0], &key_len[0], + static_cast(real_keys.size())); + return (rc == MEMCACHED_SUCCESS); + } - return memcached_mget(&memc, keys, key_length, number_of_keys); + return false; } - memcached_return set(const char *key, const char *value, size_t value_length) + bool set(const std::string &key, + const std::string &value, + time_t expiration, + uint32_t flags) { - return memcached_set(&memc, key, strlen(key), - value, value_length, - time_t(0), uint32_t(0)); + memcached_return rc= memcached_set(&memc, + key.c_str(), key.length(), + value.c_str(), value.length(), + expiration, flags); + return (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); } - memcached_return set_by_key(const char *master_key, const char *key, - const char *value, size_t value_length) + bool set_all(std::vector &keys, + std::vector &values, + time_t expiration, + uint32_t flags) { - return memcached_set_by_key(&memc, master_key, strlen(master_key), - key, strlen(key), - value, value_length, - time_t(0), - uint32_t(0) ); + if (keys.size() != values.size()) + { + return false; + } + bool retval= true; + std::vector::iterator key_it= keys.begin(); + std::vector::iterator val_it= values.begin(); + while (key_it != keys.end()) + { + retval= set((*key_it), (*val_it), expiration, flags); + if (retval == false) + { + return retval; + } + ++key_it; + ++val_it; + } + return retval; } - memcached_return - increment(const char *key, unsigned int offset, uint64_t *value) + + bool set_by_key(const std::string &master_key, + const std::string &key, + const std::string &value, + time_t expiration, + uint32_t flags) { - return memcached_increment(&memc, key, strlen(key), - offset, value); + memcached_return rc= memcached_set_by_key(&memc, master_key.c_str(), + master_key.length(), + key.c_str(), key.length(), + value.c_str(), value.length(), + expiration, + flags); + return (rc == MEMCACHED_SUCCESS); } - memcached_return - decrement(const char *key, unsigned int offset, uint64_t *value) + + bool increment(const std::string &key, unsigned int offset, uint64_t *value) + { + memcached_return rc= memcached_increment(&memc, key.c_str(), key.length(), + offset, value); + return (rc == MEMCACHED_SUCCESS); + } + + bool decrement(const std::string &key, unsigned int offset, uint64_t *value) { - return memcached_decrement(&memc, key, strlen(key), - offset, value); + memcached_return rc= memcached_decrement(&memc, key.c_str(), + key.length(), + offset, value); + return (rc == MEMCACHED_SUCCESS); } - memcached_return add(const char *key, const char *value, size_t value_length) + bool add(const std::string &key, const std::string &value) { - return memcached_add(&memc, key, strlen(key), value, value_length, 0, 0); + memcached_return rc= memcached_add(&memc, key.c_str(), key.length(), + value.c_str(), value.length(), 0, 0); + return (rc == MEMCACHED_SUCCESS); } - memcached_return add_by_key(const char *master_key, const char *key, - const char *value, size_t value_length) + + bool add_by_key(const std::string &master_key, + const std::string &key, + const std::string &value) { - return memcached_add_by_key(&memc, master_key, strlen(master_key), - key, strlen(key), - value, value_length, - 0, 0); + memcached_return rc= memcached_add_by_key(&memc, + master_key.c_str(), + master_key.length(), + key.c_str(), + key.length(), + value.c_str(), + value.length(), + 0, 0); + return (rc == MEMCACHED_SUCCESS); } - memcached_return replace(const char *key, const char *value, - size_t value_length) + bool replace(const std::string &key, const std::string &value) { - return memcached_replace(&memc, key, strlen(key), - value, value_length, - 0, 0); + memcached_return rc= memcached_replace(&memc, key.c_str(), key.length(), + value.c_str(), value.length(), + 0, 0); + return (rc == MEMCACHED_SUCCESS); } - memcached_return replace_by_key(const char *master_key, const char *key, - const char *value, size_t value_length) + + bool replace_by_key(const std::string &master_key, + const std::string &key, + const std::string &value) { - return memcached_replace_by_key(&memc, master_key, strlen(master_key), - key, strlen(key), - value, value_length, 0, 0); + memcached_return rc= memcached_replace_by_key(&memc, + master_key.c_str(), + master_key.length(), + key.c_str(), + key.length(), + value.c_str(), + value.length(), + 0, 0); + return (rc == MEMCACHED_SUCCESS); } - memcached_return prepend(const char *key, const char *value, - size_t value_length) + bool prepend(const std::string &key, const std::string &value) { - return memcached_prepend(&memc, key, strlen(key), - value, value_length, 0, 0); + memcached_return rc= memcached_prepend(&memc, key.c_str(), key.length(), + value.c_str(), value.length(), 0, 0); + return (rc == MEMCACHED_SUCCESS); } - memcached_return prepend_by_key(const char *master_key, const char *key, - const char *value, size_t value_length) + + bool prepend_by_key(const std::string &master_key, + const std::string &key, + const std::string &value) { - return memcached_prepend_by_key(&memc, master_key, strlen(master_key), - key, strlen(key), - value, value_length, - 0, - 0); + memcached_return rc= memcached_prepend_by_key(&memc, + master_key.c_str(), + master_key.length(), + key.c_str(), + key.length(), + value.c_str(), + value.length(), + 0, + 0); + return (rc == MEMCACHED_SUCCESS); } - memcached_return append(const char *key, const char *value, - size_t value_length) + bool append(const std::string &key, const std::string &value) { - return memcached_append(&memc, key, strlen(key), - value, value_length, 0, 0); + memcached_return rc= memcached_append(&memc, + key.c_str(), + key.length(), + value.c_str(), + value.length(), + 0, 0); + return (rc == MEMCACHED_SUCCESS); } - memcached_return append_by_key(const char *master_key, const char *key, - const char *value, size_t value_length) + + bool append_by_key(const std::string &master_key, + const std::string &key, + const std::string &value) { - return memcached_append_by_key(&memc, - master_key, strlen(master_key), - key, strlen(key), - value, value_length, 0, 0); + memcached_return rc= memcached_append_by_key(&memc, + master_key.c_str(), + master_key.length(), + key.c_str(), + key.length(), + value.c_str(), + value.length(), + 0, 0); + return (rc == MEMCACHED_SUCCESS); } - memcached_return cas(const char *key, const char *value, - size_t value_length, uint64_t cas_arg) + + bool cas(const std::string &key, + const std::string &value, + uint64_t cas_arg) { - return memcached_cas(&memc, key, strlen(key), - value, value_length, 0, 0, cas_arg); + memcached_return rc= memcached_cas(&memc, key.c_str(), key.length(), + value.c_str(), value.length(), + 0, 0, cas_arg); + return (rc == MEMCACHED_SUCCESS); } - memcached_return cas_by_key(const char *master_key, const char *key, - const char *value, size_t value_length, - uint64_t cas_arg) + + bool cas_by_key(const std::string &master_key, + const std::string &key, + const std::string &value, + uint64_t cas_arg) { - return memcached_cas_by_key(&memc, - master_key, strlen(master_key), - key, strlen(key), - value, value_length, - 0, 0, cas_arg); + memcached_return rc= memcached_cas_by_key(&memc, + master_key.c_str(), + master_key.length(), + key.c_str(), + key.length(), + value.c_str(), + value.length(), + 0, 0, cas_arg); + return (rc == MEMCACHED_SUCCESS); } + // using 'remove' vs. 'delete' since 'delete' is a keyword - memcached_return remove(const char *key) + bool remove(const std::string &key) { - return memcached_delete (&memc, key, strlen(key), 0); + memcached_return rc= memcached_delete(&memc, key.c_str(), key.length(), 0); + return (rc == MEMCACHED_SUCCESS); + } + bool delete_by_key(const std::string &master_key, + const std::string &key) + { + memcached_return rc= memcached_delete_by_key(&memc, + master_key.c_str(), + master_key.length(), + key.c_str(), + key.length(), + 0); + return (rc == MEMCACHED_SUCCESS); } - memcached_return delete_by_key(const char *master_key, const char *key) + + bool flush(time_t expiration) { - return memcached_delete_by_key(&memc, master_key, strlen(master_key), - key, strlen(key), 0); + memcached_return rc= memcached_flush(&memc, expiration); + return (rc == MEMCACHED_SUCCESS); } - ~Memcached() + + bool fetch_execute(memcached_execute_function *callback, + void *context, + unsigned int num_of_callbacks) { - memcached_free(&memc); + memcached_return rc= memcached_fetch_execute(&memc, + callback, + context, + num_of_callbacks); + return (rc == MEMCACHED_SUCCESS); } + + const std::string lib_version() const + { + const char *ver= memcached_lib_version(); + const std::string version(ver); + return version; + } + +private: + memcached_st memc; + memcached_result_st result; }; diff --git a/libmemcached/memcached_response.c b/libmemcached/memcached_response.c index 1ea0c725..ba0691b5 100644 --- a/libmemcached/memcached_response.c +++ b/libmemcached/memcached_response.c @@ -237,8 +237,34 @@ static memcached_return textual_read_one_response(memcached_server_st *ptr, memcached_server_response_increment(ptr); return MEMCACHED_STAT; } - else if (buffer[1] == 'E') - return MEMCACHED_SERVER_ERROR; + else if (buffer[1] == 'E') /* SERVER_ERROR */ + { + char *rel_ptr; + char *startptr= buffer + 13, *endptr= startptr; + + while (*endptr != '\r' && *endptr != '\n') endptr++; + + /* + Yes, we could make this "efficent" but to do that we would need + to maintain more state for the size of the buffer. Why waste + memory in the struct, which is important, for something that + rarely should happen? + */ + rel_ptr= (char *)ptr->root->call_realloc(ptr->root, ptr->cached_server_error, endptr - startptr + 1); + + if (rel_ptr == NULL) + { + /* If we happened to have some memory, we just null it since we don't know the size */ + if (ptr->cached_server_error) + ptr->cached_server_error[0]= 0; + return MEMCACHED_SERVER_ERROR; + } + ptr->cached_server_error= rel_ptr; + + memcpy(ptr->cached_server_error, startptr, endptr - startptr); + ptr->cached_server_error[endptr - startptr]= 0; + return MEMCACHED_SERVER_ERROR; + } else if (buffer[1] == 'T') return MEMCACHED_STORED; else diff --git a/libmemcached/memcached_server.c b/libmemcached/memcached_server.c index 11e5988a..7b9c2117 100644 --- a/libmemcached/memcached_server.c +++ b/libmemcached/memcached_server.c @@ -53,11 +53,11 @@ void memcached_server_free(memcached_server_st *ptr) { memcached_quit_server(ptr, 0); + if (ptr->cached_server_error) + free(ptr->cached_server_error); + if (ptr->address_info) - { freeaddrinfo(ptr->address_info); - ptr->address_info= NULL; - } if (ptr->is_allocated) ptr->root->call_free(ptr->root, ptr); @@ -70,14 +70,24 @@ void memcached_server_free(memcached_server_st *ptr) */ memcached_server_st *memcached_server_clone(memcached_server_st *clone, memcached_server_st *ptr) { + memcached_server_st *rv= NULL; + /* We just do a normal create if ptr is missing */ if (ptr == NULL) return NULL; - /* TODO We should check return type */ - return memcached_server_create_with(ptr->root, clone, - ptr->hostname, ptr->port, ptr->weight, - ptr->type); + rv = memcached_server_create_with(ptr->root, clone, + ptr->hostname, ptr->port, ptr->weight, + ptr->type); + if (rv != NULL) + { + rv->cached_errno= ptr->cached_errno; + if (ptr->cached_server_error) + rv->cached_server_error= strdup(ptr->cached_server_error); + } + + return rv; + } memcached_return memcached_server_cursor(memcached_st *ptr, @@ -131,3 +141,16 @@ memcached_server_st *memcached_server_by_key(memcached_st *ptr, const char *key return memcached_server_clone(NULL, &ptr->hosts[server_key]); } + +const char *memcached_server_error(memcached_server_st *ptr) +{ + if (ptr) + return ptr->cached_server_error; + else + return NULL; +} + +void memcached_server_error_reset(memcached_server_st *ptr) +{ + ptr->cached_server_error[0]= 0; +} diff --git a/libmemcached/memcached_server.h b/libmemcached/memcached_server.h index 8076877e..ec1014a6 100644 --- a/libmemcached/memcached_server.h +++ b/libmemcached/memcached_server.h @@ -29,6 +29,7 @@ struct memcached_server_st { uint8_t minor_version; memcached_connection type; char *read_ptr; + char *cached_server_error; size_t read_buffer_length; size_t read_data_length; size_t write_buffer_offset; @@ -57,6 +58,12 @@ LIBMEMCACHED_API memcached_server_st *memcached_server_by_key(memcached_st *ptr, const char *key, size_t key_length, memcached_return *error); +LIBMEMCACHED_API +const char *memcached_server_error(memcached_server_st *ptr); + +LIBMEMCACHED_API +void memcached_server_error_reset(memcached_server_st *ptr); + /* These should not currently be used by end users */ /* TODO: Is the above comment valid? If so, how can we unit test these if they * aren't exported. If not, we should remove the comment */ diff --git a/tests/plus.cpp b/tests/plus.cpp index d3674d6c..23b5cf17 100644 --- a/tests/plus.cpp +++ b/tests/plus.cpp @@ -16,87 +16,184 @@ #include "test.h" +#include + +using namespace std; + extern "C" { - test_return basic_test(memcached_st *memc); - uint8_t increment_test(memcached_st *memc); - test_return basic_master_key_test(memcached_st *memc); void *world_create(void); void world_destroy(void *p); } -test_return basic_test(memcached_st *memc) +static test_return basic_test(memcached_st *memc) { Memcached foo(memc); - const char *value_set= "This is some data"; - char *value; + const string value_set("This is some data"); + string value; size_t value_length; - foo.set("mine", value_set, strlen(value_set)); + foo.set("mine", value_set, 0, 0); value= foo.get("mine", &value_length); - assert((memcmp(value, value_set, value_length) == 0)); + assert((memcmp(value.c_str(), value_set.c_str(), value_length) == 0)); return TEST_SUCCESS; } -uint8_t increment_test(memcached_st *memc) +static test_return increment_test(memcached_st *memc) { Memcached mcach(memc); - memcached_return rc; - const char *key= "inctest"; - const char *inc_value= "1"; - char *ret_value; + bool rc; + const string key("inctest"); + const string inc_value("1"); + string ret_value; uint64_t int_inc_value; uint64_t int_ret_value; size_t value_length; - mcach.set(key, inc_value, strlen(inc_value)); + mcach.set(key, inc_value, 0, 0); ret_value= mcach.get(key, &value_length); - printf("\nretvalue %s\n",ret_value); - int_inc_value= uint64_t(atol(inc_value)); - int_ret_value= uint64_t(atol(ret_value)); + printf("\nretvalue %s\n",ret_value.c_str()); + int_inc_value= uint64_t(atol(inc_value.c_str())); + int_ret_value= uint64_t(atol(ret_value.c_str())); assert(int_ret_value == int_inc_value); rc= mcach.increment(key, 1, &int_ret_value); - assert(rc == MEMCACHED_SUCCESS); + assert(rc == true); assert(int_ret_value == 2); rc= mcach.increment(key, 1, &int_ret_value); - assert(rc == MEMCACHED_SUCCESS); + assert(rc == true); assert(int_ret_value == 3); rc= mcach.increment(key, 5, &int_ret_value); - assert(rc == MEMCACHED_SUCCESS); + assert(rc == true); assert(int_ret_value == 8); - return 0; + return TEST_SUCCESS; } -test_return basic_master_key_test(memcached_st *memc) +static test_return basic_master_key_test(memcached_st *memc) { - Memcached foo(memc); - const char *value_set= "Data for server A"; - const char *master_key_a= "server-a"; - const char *master_key_b= "server-b"; - const char *key= "xyz"; - char *value; + Memcached foo(memc); + const string value_set("Data for server A"); + const string master_key_a("server-a"); + const string master_key_b("server-b"); + const string key("xyz"); + string value; size_t value_length; - foo.set_by_key(master_key_a, key, value_set, strlen(value_set)); + foo.set_by_key(master_key_a, key, value_set, 0, 0); value= foo.get_by_key(master_key_a, key, &value_length); - assert((memcmp(value, value_set, value_length) == 0)); + assert((memcmp(value.c_str(), value_set.c_str(), value_length) == 0)); value= foo.get_by_key(master_key_b, key, &value_length); - assert((memcmp(value, value_set, value_length) == 0)); + assert((memcmp(value.c_str(), value_set.c_str(), value_length) == 0)); + + return TEST_SUCCESS; +} + +/* Count the results */ +static memcached_return callback_counter(memcached_st *ptr __attribute__((unused)), + memcached_result_st *result __attribute__((unused)), + void *context) +{ + unsigned int *counter= static_cast(context); + + *counter= *counter + 1; + + return MEMCACHED_SUCCESS; +} + +static test_return mget_result_function(memcached_st *memc) +{ + Memcached mc(memc); + bool rc; + string key1("fudge"); + string key2("son"); + string key3("food"); + vector keys; + keys.reserve(3); + keys.push_back(key1); + keys.push_back(key2); + keys.push_back(key3); + unsigned int counter; + memcached_execute_function callbacks[1]; + + /* We need to empty the server before we continue the test */ + rc= mc.flush(0); + rc= mc.set_all(keys, keys, 50, 9); + assert(rc == true); + + rc= mc.mget(keys); + assert(rc == true); + + callbacks[0]= &callback_counter; + counter= 0; + rc= mc.fetch_execute(callbacks, static_cast(&counter), 1); + + assert(counter == 3); return TEST_SUCCESS; } +static test_return mget_test(memcached_st *memc) +{ + Memcached mc(memc); + bool rc; + memcached_return mc_rc; + vector keys; + keys.reserve(3); + keys.push_back("fudge"); + keys.push_back("son"); + keys.push_back("food"); + uint32_t flags; + + string return_key; + size_t return_key_length; + string return_value; + size_t return_value_length; + + /* We need to empty the server before we continue the test */ + rc= mc.flush(0); + assert(rc == true); + + rc= mc.mget(keys); + assert(rc == true); + + while (mc.fetch(return_key, return_value, &return_key_length, + &return_value_length, &flags, &mc_rc)) + { + assert(return_value.length() != 0); + } + assert(return_value_length == 0); + assert(mc_rc == MEMCACHED_END); + + rc= mc.set_all(keys, keys, 50, 9); + assert(rc == true); + + rc= mc.mget(keys); + assert(rc == true); + + while ((mc.fetch(return_key, return_value, &return_key_length, + &return_value_length, &flags, &mc_rc))) + { + assert(return_value.length() != 0); + assert(mc_rc == MEMCACHED_SUCCESS); + assert(return_key_length == return_value_length); + assert(!memcmp(return_value.c_str(), return_key.c_str(), return_value_length)); + } + + return TEST_SUCCESS; +} test_st tests[] ={ - {"basic", 0, basic_test }, - {"basic_master_key", 0, basic_master_key_test }, + { "basic", 0, basic_test }, + { "basic_master_key", 0, basic_master_key_test }, + { "increment_test", 0, increment_test }, + { "mget", 1, mget_test }, + { "mget_result_function", 1, mget_result_function }, {0, 0, 0} };