From d4dc795f136a3a652c5b13b4d818345c6080bceb Mon Sep 17 00:00:00 2001 From: Brian Aker Date: Sat, 3 Nov 2007 18:53:21 -0700 Subject: [PATCH] fetch_result() implemented for memcached_result_st. --- ChangeLog | 1 + docs/Makefile.am | 30 ++++++++++ docs/libmemcached.pod | 3 +- docs/memcached_get.pod | 11 ++++ docs/memcached_result_st.pod | 93 ++++++++++++++++++++++++++++++ include/memcached.h | 28 ++++++--- lib/common.h | 12 ---- lib/memcached_get.c | 23 ++++---- lib/memcached_response.c | 12 ++++ lib/memcached_result.c | 41 +++++++++++++ tests/test.c | 108 ++++++++++++++++++++++++++++++++++- 11 files changed, 329 insertions(+), 33 deletions(-) create mode 100755 docs/memcached_result_st.pod create mode 100644 lib/memcached_result.c diff --git a/ChangeLog b/ChangeLog index 8b2f9a8a..ff7e498e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ * Added additional HASHing methods of FNV1_64,FNV1A_64, FNV1_32, FNV1A_32 * Added pkgconfig support * Fixed conflict with defined type in MySQL + * Added memcached_result_st structure and functions to manipulate it. 0.7 Tue Oct 30 09:24:05 PDT 2007 * Poved to poll() from select() diff --git a/docs/Makefile.am b/docs/Makefile.am index fae515c8..5d8a812b 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -99,6 +99,9 @@ memcached_flush.3: memcached_flush.pod memcached_get.3: memcached_get.pod pod2man -c "libmemcached" -r "" -s 3 memcached_get.pod > memcached_get.3 +memcached_fetch_result.3: memcached_get.pod + pod2man -c "libmemcached" -r "" -s 3 memcached_get.pod > memcached_fetch_result.3 + memcached_mget.3: memcached_get.pod pod2man -c "libmemcached" -r "" -s 3 memcached_get.pod > memcached_mget.3 @@ -159,6 +162,33 @@ memcached_stat_get_value.3: memcached_stats.pod memcached_stat_get_keys.3: memcached_stats.pod pod2man -c "libmemcached" -r "" -s 3 memcached_stats.pod > memcached_stat_get_keys.3 +memcached_result_st.3: memcached_result_st.pod + pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_st.3 + +memcached_result_create.3: memcached_result_st.pod + pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_create.3 + +memcached_result_free.3: memcached_result_st.pod + pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_free.3 + +memcached_result_key_value.3: memcached_result_st.pod + pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_key_value.3 + +memcached_result_key_length.3: memcached_result_st.pod + pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_key_length.3 + +memcached_result_value.3: memcached_result_st.pod + pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_value.3 + +memcached_result_length.3: memcached_result_st.pod + pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_length.3 + +memcached_result_flags.3: memcached_result_st.pod + pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_flags.3 + +memcached_result_cas.3: memcached_result_st.pod + pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_cas.3 + memcp.1: memcp.pod pod2man -c "libmemcached" -r "" -s 1 memcp.pod > memcp.1 diff --git a/docs/libmemcached.pod b/docs/libmemcached.pod index c139b080..36079ba5 100755 --- a/docs/libmemcached.pod +++ b/docs/libmemcached.pod @@ -54,7 +54,6 @@ Brian Aker, Ebrian@tangent.orgE =head1 SEE ALSO -memcached(1) libmemcached_examples(3) libmemcached(1) memcat(1) memcp(1) memflush(1) memrm(1) memslap(1) memstat(1) memcached_fetch(3) memcached_replace(3) memcached_server_list_free(3) libmemcached_examples(3) memcached_clone(3) memcached_free(3) memcached_server_add(3) memcached_server_push(3) memcached_add(3) memcached_get(3) memcached_server_count(3) memcached_servers_parse(3) memcached_create(3) memcached_increment(3) memcached_server_list(3) memcached_set(3) memcached_decrement(3) memcached_mget(3) memcached_server_list_append(3) memcached_strerror(3) memcached_delete(3) memcached_quit(3) memcached_server_list_count(3) memcached_verbosity(3) memcached_server_add_unix_socket(3) - +memcached(1) libmemcached_examples(3) libmemcached(1) memcat(1) memcp(1) memflush(1) memrm(1) memslap(1) memstat(1) memcached_fetch(3) memcached_replace(3) memcached_server_list_free(3) libmemcached_examples(3) memcached_clone(3) memcached_free(3) memcached_server_add(3) memcached_server_push(3) memcached_add(3) memcached_get(3) memcached_server_count(3) memcached_servers_parse(3) memcached_create(3) memcached_increment(3) memcached_server_list(3) memcached_set(3) memcached_decrement(3) memcached_mget(3) memcached_server_list_append(3) memcached_strerror(3) memcached_delete(3) memcached_quit(3) memcached_server_list_count(3) memcached_verbosity(3) memcached_server_add_unix_socket(3) memcahed_result_create(3) memcached_result_free(3) memcached_result_key_value(3) memcached_result_key_length(3) memcached_result_value(3) memcached_result_length(3) memcached_result_flags(3) memcached_result_cas(3) memcached_result_st(3) =cut diff --git a/docs/memcached_get.pod b/docs/memcached_get.pod index 1c95ec38..458a55a9 100755 --- a/docs/memcached_get.pod +++ b/docs/memcached_get.pod @@ -10,6 +10,11 @@ C Client Library for memcached (libmemcached, -lmemcached) #include + memcached_result_st * + memcached_fetch_result(memcached_st *ptr, + memcached_result_st *result, + memcached_return *error); + char *memcached_get (memcached_st *ptr, char *key, size_t key_length, size_t *value_length, @@ -51,6 +56,12 @@ a size_t pointer which will be filled with size of of the object, and a memcached_return pointer to hold any error. The object will be returned upon success and NULL will be returned on failure. +memcached_fetch_result() is used to return a memcached_result_st(3) structure +from a memcached server. The result object is forward compatible with changes +to the server. For more information please refer to the memcached_result_st(3) +help. This function will dynamically allocate a result structure for you +if you do not pass one to the function. + =head1 RETURN All objects returned must be freed by the calling application. diff --git a/docs/memcached_result_st.pod b/docs/memcached_result_st.pod new file mode 100755 index 00000000..2296b901 --- /dev/null +++ b/docs/memcached_result_st.pod @@ -0,0 +1,93 @@ +=head1 NAME + +memcahed_result_create, memcached_result_free, +memcached_result_key_value, memcached_result_key_length, +memcached_result_value, memcached_result_length, +memcached_result_flags, memcached_result_cas + + +=head1 LIBRARY + +C Client Library for memcached (libmemcached, -lmemcached) + +=head1 SYNOPSIS + + #include + + memcached_result_st *memcached_result_create(memcached_st *ptr, + memcached_result_st *result); + + void memcached_result_free(memcached_result_st *result); + + char * memcached_result_key_value(memcached_result_st *result); + + size_t memcached_result_key_length(memcached_result_st *result); + + char *memcached_result_value(memcached_result_st *ptr); + + size_t memcached_result_length(memcached_result_st *ptr); + + uint16_t memcached_result_flags(memcached_result_st *result) + + uint64_t memcached_result_cas(memcached_result_st *result); + +=head1 DESCRIPTION + +libmemcached(3) can optionally return a memcached_result_st which acts as a +result object. The result objects have added benefits over the character +pointer returns in that they are forward compatible with new return items +that future memcached servers may implement (the best currect example of +this is the CAS return iteam). The structures can also be reused which will +save on calls to malloc(3). It is suggested that you use result objects over +char * return functions. + +The structure of memcached_result_st has been encapsulated, you should not +write code to directly access members of the structure. + +memcached_result_create() will either allocate memory for a +memcached_result_st or will initialize a structure passed to it. + +memcached_result_free() will deallocate any memory attached to the +structure. If the structure was also alloacted, it will deallocate it. + +memcached_result_key_value() returns the key value associated with the +current result object. + +memcached_result_key_length() returns the key length associated with the +current result object. + +memcached_result_value() returns the result value associated with the +current result object. + +memcached_result_length() returns the result length associated with the +current result object. + +memcached_result_flags() returns the flags associated with the +current result object. + +memcached_result_cas() returns the cas associated with the +current result object. This value will only be available if the server +supports it. + + +=head1 RETURN + +Varies, see particular functions. All structures must have +memcached_result_free() called on them for cleanup purposes. Failure to +do this will result in leaked memory. + +=head1 HOME + +To find out more information please check: +L + +=head1 AUTHOR + +Brian Aker, Ebrian@tangent.orgE + +=head1 SEE ALSO + +memcached(1) libmemcached(3) memcached_strerror(3) + +=cut + diff --git a/include/memcached.h b/include/memcached.h index 06efdb12..f9176704 100644 --- a/include/memcached.h +++ b/include/memcached.h @@ -145,7 +145,8 @@ struct memcached_string_st { struct memcached_result_st { memcached_allocated is_allocated; memcached_st *root; - memcached_string_st key; + char key[MEMCACHED_MAX_KEY]; + size_t key_length; memcached_string_st value; uint16_t flags; uint64_t cas; @@ -222,7 +223,9 @@ memcached_return memcached_mget(memcached_st *ptr, char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length, size_t *value_length, uint16_t *flags, memcached_return *error); -memcached_result_st *memcached_fetch_object(memcached_st *ptr, memcached_return *error); +memcached_result_st *memcached_fetch_result(memcached_st *ptr, + memcached_result_st *result, + memcached_return *error); /* Server Public functions */ #define memcached_server_count(A) A->number_of_hosts @@ -250,12 +253,21 @@ char ** memcached_stat_get_keys(memcached_st *ptr, memcached_stat_st *stat, memcached_return *error); /* Result Struct */ -#define memcache_result_key_value(A) memcached_string_value(A->key) -#define memcache_result_key_length(A) memcached_string_length(A->key) -#define memcache_result_result_value(A) memcached_string_value(A->value) -#define memcache_result_result_length(A) memcached_string_length(A->value) -#define memcache_result_flags(A) A->flags -#define memcache_result_cas(A) A->cas +void memcached_result_free(memcached_result_st *result); +memcached_result_st *memcached_result_create(memcached_st *ptr, + memcached_result_st *result); +#define memcached_result_key_value(A) A->key +#define memcached_result_key_length(A) A->key_length +#ifdef FIX +#define memcached_result_value(A) memcached_string_value(A->value) +#define memcached_result_length(A) memcached_string_length(A->value) +#else +char *memcached_result_value(memcached_result_st *ptr); +size_t memcached_result_length(memcached_result_st *ptr); +#endif +#define memcached_result_flags(A) A->flags +#define memcached_result_cas(A) A->cas + /* Some personal debugging functions */ #ifdef HAVE_DEBUG diff --git a/lib/common.h b/lib/common.h index 31a65ea9..3a3a9695 100644 --- a/lib/common.h +++ b/lib/common.h @@ -79,17 +79,5 @@ size_t memcached_string_backspace(memcached_string_st *string, size_t remove); memcached_return memcached_string_reset(memcached_string_st *string); void memcached_string_free(memcached_string_st *string); -/* Result Struct */ -#define memcache_result_key_value(A) memcached_string_value(A->key) -#define memcache_result_key_length(A) memcached_string_length(A->key) -#define memcache_result_result_value(A) memcached_string_value(A->value) -#define memcache_result_result_length(A) memcached_string_length(A->value) -#define memcache_result_flags(A) A->flags -#define memcache_result_cas(A) A->cas - -memcached_result_st *memcached_result_create(memcached_st *ptr, - memcached_result_st *result); -void memcached_result_free(memcached_result_st *result); - #endif /* __COMMON_H__ */ diff --git a/lib/memcached_get.c b/lib/memcached_get.c index a8ece536..01f388c9 100644 --- a/lib/memcached_get.c +++ b/lib/memcached_get.c @@ -310,6 +310,7 @@ char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length, else if (*error == MEMCACHED_END) { WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */ + return NULL; } else if (*error != MEMCACHED_SUCCESS) return NULL; @@ -322,11 +323,12 @@ char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length, return NULL; } -#ifdef NOT_YET -char *memcached_fetch_result(memcached_st *ptr, memcached_result_st *result, - memcached_return *error) +memcached_result_st *memcached_fetch_result(memcached_st *ptr, + memcached_result_st *result, + memcached_return *error) { - char *value_check; + if (result == NULL) + result= memcached_result_create(ptr, NULL); while (ptr->cursor_server < ptr->number_of_hosts) { @@ -336,25 +338,26 @@ char *memcached_fetch_result(memcached_st *ptr, memcached_result_st *result, continue; } - value_check= memcached_value_fetch(ptr, key, key_length, value_length, flags, - error, 1, ptr->cursor_server); + *error= memcached_value_fetch(ptr, result->key, &result->key_length, + &result->value, + &result->flags, + 1, ptr->cursor_server); if (*error == MEMCACHED_NOTFOUND) ptr->cursor_server++; - else if (*error == MEMCACHED_END && *value_length == 0) + else if (*error == MEMCACHED_END && memcached_string_length((memcached_string_st *)(&result->value)) == 0) return NULL; else if (*error == MEMCACHED_END) { WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */ + return NULL; } else if (*error != MEMCACHED_SUCCESS) return NULL; else - return value_check; + return result; } - *value_length= 0; return NULL; } -#endif diff --git a/lib/memcached_response.c b/lib/memcached_response.c index 673ccb2f..19fa6400 100644 --- a/lib/memcached_response.c +++ b/lib/memcached_response.c @@ -96,3 +96,15 @@ memcached_return memcached_response(memcached_st *ptr, return MEMCACHED_SUCCESS; } + +char *memcached_result_value(memcached_result_st *ptr) +{ + memcached_string_st *sptr= &ptr->value; + return memcached_string_value(sptr); +} + +size_t memcached_result_length(memcached_result_st *ptr) +{ + memcached_string_st *sptr= &ptr->value; + return memcached_string_length(sptr); +} diff --git a/lib/memcached_result.c b/lib/memcached_result.c new file mode 100644 index 00000000..49f44b23 --- /dev/null +++ b/lib/memcached_result.c @@ -0,0 +1,41 @@ +/* + memcached_result_st are used to internally represent the return values from + memcached. We use a structure so that long term as identifiers are added + to memcached we will be able to absorb new attributes without having + to addjust the entire API. +*/ +#include "common.h" + +memcached_result_st *memcached_result_create(memcached_st *memc, + memcached_result_st *ptr) +{ + /* Saving malloc calls :) */ + if (ptr) + { + memset(ptr, 0, sizeof(memcached_result_st)); + ptr->is_allocated= MEMCACHED_NOT_ALLOCATED; + } + else + { + ptr= (memcached_result_st *)malloc(sizeof(memcached_result_st)); + if (!ptr) + return NULL; + memset(ptr, 0, sizeof(memcached_result_st)); + ptr->is_allocated= MEMCACHED_ALLOCATED; + } + + ptr->root= memc; + memcached_string_create(memc, &ptr->value, 0); + WATCHPOINT_ASSERT(ptr->value.string == NULL); + WATCHPOINT_ASSERT(ptr->value.is_allocated == MEMCACHED_NOT_ALLOCATED); + + return ptr; +} + +void memcached_result_free(memcached_result_st *ptr) +{ + memcached_string_free(&ptr->value); + + if (ptr->is_allocated == MEMCACHED_ALLOCATED) + free(ptr); +} diff --git a/tests/test.c b/tests/test.c index 17240107..27dd4419 100644 --- a/tests/test.c +++ b/tests/test.c @@ -384,6 +384,110 @@ void quit_test(memcached_st *memc) assert(rc == MEMCACHED_SUCCESS); } +void mget_result_test(memcached_st *memc) +{ + memcached_return rc; + char *keys[]= {"fudge", "son", "food"}; + size_t key_length[]= {5, 3, 4}; + unsigned int x; + + memcached_result_st results_obj; + memcached_result_st *results; + + results= memcached_result_create(memc, &results_obj); + assert(results); + assert(&results_obj == results); + + /* We need to empty the server before continueing test */ + rc= memcached_flush(memc, 0); + assert(rc == MEMCACHED_SUCCESS); + + rc= memcached_mget(memc, keys, key_length, 3); + assert(rc == MEMCACHED_SUCCESS); + + while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL) + { + assert(results); + } + while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL) + assert(!results); + assert(rc == MEMCACHED_NOTFOUND); + + for (x= 0; x < 3; x++) + { + rc= memcached_set(memc, keys[x], key_length[x], + keys[x], key_length[x], + (time_t)50, (uint16_t)9); + assert(rc == MEMCACHED_SUCCESS); + } + + rc= memcached_mget(memc, keys, key_length, 3); + assert(rc == MEMCACHED_SUCCESS); + + while ((results= memcached_fetch_result(memc, &results_obj, &rc))) + { + assert(results); + assert(&results_obj == results); + assert(rc == MEMCACHED_SUCCESS); + assert(memcached_result_key_length(results) == memcached_result_length(results)); + assert(!memcmp(memcached_result_key_value(results), + memcached_result_value(results), + memcached_result_length(results))); + } + + WATCHPOINT; + memcached_result_free(&results_obj); + WATCHPOINT; +} + +void mget_result_alloc_test(memcached_st *memc) +{ + memcached_return rc; + char *keys[]= {"fudge", "son", "food"}; + size_t key_length[]= {5, 3, 4}; + unsigned int x; + + memcached_result_st *results; + + /* We need to empty the server before continueing test */ + rc= memcached_flush(memc, 0); + assert(rc == MEMCACHED_SUCCESS); + + rc= memcached_mget(memc, keys, key_length, 3); + assert(rc == MEMCACHED_SUCCESS); + + while ((results= memcached_fetch_result(memc, NULL, &rc)) != NULL) + { + assert(results); + } + assert(!results); + assert(rc == MEMCACHED_NOTFOUND); + + for (x= 0; x < 3; x++) + { + rc= memcached_set(memc, keys[x], key_length[x], + keys[x], key_length[x], + (time_t)50, (uint16_t)9); + assert(rc == MEMCACHED_SUCCESS); + } + + rc= memcached_mget(memc, keys, key_length, 3); + assert(rc == MEMCACHED_SUCCESS); + + x= 0; + while ((results= memcached_fetch_result(memc, NULL, &rc))) + { + assert(results); + assert(rc == MEMCACHED_SUCCESS); + assert(memcached_result_key_length(results) == memcached_result_length(results)); + assert(!memcmp(memcached_result_key_value(results), + memcached_result_value(results), + memcached_result_length(results))); + memcached_result_free(results); + x++; + } +} + void mget_test(memcached_st *memc) { memcached_return rc; @@ -1000,7 +1104,9 @@ int main(int argc, char *argv[]) {"increment", 0, increment_test }, {"decrement", 0, decrement_test }, {"quit", 0, quit_test }, - {"mget", 0, mget_test }, + {"mget", 1, mget_test }, + {"mget_result", 1, mget_result_test }, + {"mget_result_alloc", 1, mget_result_alloc_test }, {"get_stats", 0, get_stats }, {"add_host_test", 0, add_host_test }, {"get_stats_keys", 0, get_stats_keys }, -- 2.30.2