From: Date: Tue, 18 Mar 2008 05:39:12 +0000 (-0700) Subject: Read through caching function. X-Git-Tag: _20~1^2~47 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=3b706525e1b66b907905bb9eddd7fd824e8311de;p=m6w6%2Flibmemcached Read through caching function. --- diff --git a/docs/libmemcached.pod b/docs/libmemcached.pod index 1700cf5b..1e63c8ce 100755 --- a/docs/libmemcached.pod +++ b/docs/libmemcached.pod @@ -121,7 +121,7 @@ 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) 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) memcached_append(3) memcached_prepend(3) memcached_fetch_result(3) memerror(1) memcached_get_by_key(3) memcached_mget_by_key(3) memcached_delete_by_key(3) memcached_fetch_execute(3) memcached_callback_get(3) memcached_callback_set(3) memcached_version(3) memcached_lib_version(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) memcached_append(3) memcached_prepend(3) memcached_fetch_result(3) memerror(1) memcached_get_by_key(3) memcached_mget_by_key(3) memcached_delete_by_key(3) memcached_fetch_execute(3) memcached_callback_get(3) memcached_callback_set(3) memcached_version(3) memcached_lib_version(3) memcached_result_set_value(3) =cut diff --git a/docs/memcached_callback.pod b/docs/memcached_callback.pod index 7d3fe730..56ba4e29 100755 --- a/docs/memcached_callback.pod +++ b/docs/memcached_callback.pod @@ -32,6 +32,9 @@ function set by memcached_callback_set(). memcached_callback_set() changes the function/structure assigned by a callback flag. No connections are reset. +You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for any +of the callbacks + =over 4 =item MEMCACHED_CALLBACK_CLEANUP_FUNCTION @@ -57,8 +60,6 @@ The prototype for this is: void *(*memcached_malloc_function)(memcached_st *ptr, const size_t size); -You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for malloc. - =item MEMCACHED_CALLBACK_REALLOC_FUNCTION, This alllows yout to pass in a customized version of realloc that will be used instead of the builtin realloc(3) call. @@ -66,8 +67,6 @@ The prototype for this is: void *(*memcached_realloc_function)(memcached_st *ptr, void *mem, const size_t size); -You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for realloc. - =item MEMCACHED_CALLBACK_FREE_FUNCTION, This alllows yout to pass in a customized version of realloc that will be used instead of the builtin free(3) call. @@ -75,7 +74,17 @@ The prototype for this is: typedef void (*memcached_free_function)(memcached_st *ptr, void *mem); -You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for realloc. +=item MEMCACHED_CALLBACK_GET_FAILURE, + +This function implements the read through cache behavior. On failure of retrieval this callback will be called. +You are responsible for populating the result object provided. This result object will then be stored in the server and +returned to the calling process. You must clone the memcached_st in order to +make use of it. The value will be stored only if you return +MEMCACHED_SUCCESS or MEMCACHED_BUFFERED. Returning MEMCACHED_BUFFERED will +cause the object to be buffered and not sent immediatly (if this is the default behavior based on your connection setup this will happen automatically). + +The prototype for this is: +memcached_return (*memcached_trigger_key)(memcached_st *ptr, char *key, size_t key_length, memcached_result_st *result); =back diff --git a/docs/memcached_result_st.pod b/docs/memcached_result_st.pod index 89d4e816..bd8e21fa 100755 --- a/docs/memcached_result_st.pod +++ b/docs/memcached_result_st.pod @@ -31,6 +31,13 @@ C Client Library for memcached (libmemcached, -lmemcached) uint64_t memcached_result_cas(memcached_result_st *result); + memcached_return memcached_result_set_value (memcached_result_st *ptr, + char *value, size_t length) + + void memcached_result_set_flags(memcached_result_st *ptr, uint32_t flags) + + void memcached_result_set_expiration(memcached_result_st *ptr, time_t) + =head1 DESCRIPTION libmemcached(3) can optionally return a memcached_result_st which acts as a @@ -69,6 +76,16 @@ memcached_result_cas() returns the cas associated with the current result object. This value will only be available if the server supports it. +memcached_result_set_value() takes a byte array and a size and sets +the result to this value. This function is used for trigger responses. + +void memcached_result_set_flags() takes a result structure and stores +a new value for the flags field. + +void memcached_result_set_expiration(A) takes a result structure and stores +a new value for the expiration field (this is only used by read through +triggers). + =head1 RETURN diff --git a/libmemcached/memcached.c b/libmemcached/memcached.c index 9d0f81e8..2c8cef75 100644 --- a/libmemcached/memcached.c +++ b/libmemcached/memcached.c @@ -102,6 +102,7 @@ memcached_st *memcached_clone(memcached_st *clone, memcached_st *ptr) new_clone->call_free= ptr->call_free; new_clone->call_malloc= ptr->call_malloc; new_clone->call_realloc= ptr->call_realloc; + new_clone->get_key_failure= ptr->get_key_failure; if (ptr->on_clone) ptr->on_clone(ptr, new_clone); diff --git a/libmemcached/memcached.h b/libmemcached/memcached.h index 2aba39c0..bbf82e23 100644 --- a/libmemcached/memcached.h +++ b/libmemcached/memcached.h @@ -91,6 +91,7 @@ struct memcached_st { memcached_free_function call_free; memcached_malloc_function call_malloc; memcached_realloc_function call_realloc; + memcached_trigger_key get_key_failure; #ifdef NOT_USED /* Future Use */ uint8_t replicas; memcached_return warning; diff --git a/libmemcached/memcached_callback.c b/libmemcached/memcached_callback.c index 95d6a384..ad21c10d 100644 --- a/libmemcached/memcached_callback.c +++ b/libmemcached/memcached_callback.c @@ -48,6 +48,12 @@ memcached_return memcached_callback_set(memcached_st *ptr, ptr->call_free= func; break; } + case MEMCACHED_CALLBACK_GET_FAILURE: + { + memcached_trigger_key func= (memcached_trigger_key)data; + ptr->get_key_failure= func; + break; + } default: return MEMCACHED_FAILURE; } @@ -95,6 +101,11 @@ void *memcached_callback_get(memcached_st *ptr, *error= ptr->call_free ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; return (void *)ptr->call_free; } + case MEMCACHED_CALLBACK_GET_FAILURE: + { + *error= ptr->get_key_failure ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; + return (void *)ptr->get_key_failure; + } default: WATCHPOINT_ASSERT(0); *error= MEMCACHED_FAILURE; diff --git a/libmemcached/memcached_connect.c b/libmemcached/memcached_connect.c index 7edcce85..5531ad79 100644 --- a/libmemcached/memcached_connect.c +++ b/libmemcached/memcached_connect.c @@ -1,5 +1,6 @@ #include "common.h" #include +#include static memcached_return set_hostinfo(memcached_server_st *server) { diff --git a/libmemcached/memcached_constants.h b/libmemcached/memcached_constants.h index 65192bfb..6f3909b6 100644 --- a/libmemcached/memcached_constants.h +++ b/libmemcached/memcached_constants.h @@ -90,6 +90,7 @@ typedef enum { MEMCACHED_CALLBACK_MALLOC_FUNCTION, MEMCACHED_CALLBACK_REALLOC_FUNCTION, MEMCACHED_CALLBACK_FREE_FUNCTION, + MEMCACHED_CALLBACK_GET_FAILURE, } memcached_callback; typedef enum { diff --git a/libmemcached/memcached_fetch.c b/libmemcached/memcached_fetch.c index 37cec5d3..303e8cc3 100644 --- a/libmemcached/memcached_fetch.c +++ b/libmemcached/memcached_fetch.c @@ -16,9 +16,7 @@ memcached_return value_fetch(memcached_server_st *ptr, end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE; - result->key_length= 0; - result->flags= 0; - memcached_string_reset(&result->value); + memcached_result_reset(result); string_ptr= buffer; string_ptr+= 6; /* "VALUE " */ @@ -69,7 +67,6 @@ memcached_return value_fetch(memcached_server_st *ptr, { /* Skip past the \r\n */ string_ptr+= 2; - result->cas= 0; } else { diff --git a/libmemcached/memcached_get.c b/libmemcached/memcached_get.c index 8cc7ce30..354f7bb8 100644 --- a/libmemcached/memcached_get.c +++ b/libmemcached/memcached_get.c @@ -38,7 +38,46 @@ char *memcached_get_by_key(memcached_st *ptr, *error= MEMCACHED_NOTFOUND; if (value == NULL) + { + if (ptr->get_key_failure) + { + memcached_return rc; + + memcached_result_reset(&ptr->result); + rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result); + + /* On all failure drop to returning NULL */ + if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) + { + uint8_t latch; /* We use latch to track the state of the original socket */ + + if (rc == MEMCACHED_BUFFERED) + { + latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS); + if (latch == 0) + memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1); + } + + rc= memcached_set(ptr, key, key_length, + memcached_result_value(&ptr->result), + memcached_result_length(&ptr->result), + 0, memcached_result_flags(&ptr->result)); + + if (rc == MEMCACHED_BUFFERED && latch == 0) + memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0); + + if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) + { + *error= rc; + *value_length= memcached_result_length(&ptr->result); + *flags= memcached_result_flags(&ptr->result); + return memcached_string_c_copy(&ptr->result.value); + } + } + } + return NULL; + } (void)memcached_fetch(ptr, NULL, NULL, &dummy_length, &dummy_flags, diff --git a/libmemcached/memcached_result.c b/libmemcached/memcached_result.c index cf3894be..0860e792 100644 --- a/libmemcached/memcached_result.c +++ b/libmemcached/memcached_result.c @@ -36,6 +36,23 @@ memcached_result_st *memcached_result_create(memcached_st *memc, return ptr; } +void memcached_result_reset(memcached_result_st *ptr) +{ + ptr->key_length= 0; + memcached_string_reset(&ptr->value); + ptr->flags= 0; + ptr->cas= 0; + ptr->expiration= 0; +} + +/* + NOTE turn into macro +*/ +memcached_return memcached_result_set_value(memcached_result_st *ptr, char *value, size_t length) +{ + return memcached_string_append(&ptr->value, value, length); +} + void memcached_result_free(memcached_result_st *ptr) { if (ptr == NULL) diff --git a/libmemcached/memcached_result.h b/libmemcached/memcached_result.h index 1c229ecb..2b08d396 100644 --- a/libmemcached/memcached_result.h +++ b/libmemcached/memcached_result.h @@ -21,11 +21,13 @@ struct memcached_result_st { memcached_string_st value; uint32_t flags; uint64_t cas; + time_t expiration; /* Add result callback function */ }; /* Result Struct */ void memcached_result_free(memcached_result_st *result); +void memcached_result_reset(memcached_result_st *ptr); memcached_result_st *memcached_result_create(memcached_st *ptr, memcached_result_st *result); #define memcached_result_key_value(A) (A)->key @@ -39,6 +41,9 @@ size_t memcached_result_length(memcached_result_st *ptr); #endif #define memcached_result_flags(A) (A)->flags #define memcached_result_cas(A) (A)->cas +memcached_return memcached_result_set_value(memcached_result_st *ptr, char *value, size_t length); +void memcached_result_set_flags(A,B) (A)->flags= B +void memcached_result_set_expiration(A) (A)->expiration #ifdef __cplusplus } diff --git a/libmemcached/memcached_types.h b/libmemcached/memcached_types.h index 76f5171d..6db4ba45 100644 --- a/libmemcached/memcached_types.h +++ b/libmemcached/memcached_types.h @@ -25,6 +25,9 @@ typedef void *(*memcached_malloc_function)(memcached_st *ptr, const size_t size) typedef void *(*memcached_realloc_function)(memcached_st *ptr, void *mem, const size_t size); typedef memcached_return (*memcached_execute_function)(memcached_st *ptr, memcached_result_st *result, void *context); typedef memcached_return (*memcached_server_function)(memcached_st *ptr, memcached_server_st *server, void *context); +typedef memcached_return (*memcached_trigger_key)(memcached_st *ptr, + char *key, size_t key_length, + memcached_result_st *result); #ifdef __cplusplus } diff --git a/tests/function.c b/tests/function.c index bcf08fe6..d356fb93 100644 --- a/tests/function.c +++ b/tests/function.c @@ -522,6 +522,50 @@ uint8_t bad_key_test(memcached_st *memc) return 0; } +#define READ_THROUGH_VALUE "set for me" +memcached_return read_through_trigger(memcached_st *memc, + char *key, size_t key_length, + memcached_result_st *result) +{ + + return memcached_result_set_value(result, READ_THROUGH_VALUE, strlen(READ_THROUGH_VALUE)); +} + +uint8_t read_through(memcached_st *memc) +{ + memcached_return rc; + char *key= "foo"; + char *string; + size_t string_length; + uint32_t flags; + + string= memcached_get(memc, key, strlen(key), + &string_length, &flags, &rc); + + assert(rc == MEMCACHED_NOTFOUND); + assert(string_length == 0); + assert(!string); + + rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_GET_FAILURE, read_through_trigger); + assert(rc == MEMCACHED_SUCCESS); + + string= memcached_get(memc, key, strlen(key), + &string_length, &flags, &rc); + + assert(rc == MEMCACHED_SUCCESS); + assert(string_length == strlen(READ_THROUGH_VALUE)); + assert(!strcmp(READ_THROUGH_VALUE, string)); + + string= memcached_get(memc, key, strlen(key), + &string_length, &flags, &rc); + + assert(rc == MEMCACHED_SUCCESS); + assert(string_length == strlen(READ_THROUGH_VALUE)); + assert(!strcmp(READ_THROUGH_VALUE, string)); + + return 0; +} + uint8_t get_test(memcached_st *memc) { memcached_return rc; @@ -2467,6 +2511,7 @@ test_st tests[] ={ {"version_string_test", 0, version_string_test}, {"bad_key", 1, bad_key_test }, {"memcached_server_cursor", 1, memcached_server_cursor_test }, + {"read_through", 1, read_through }, {0, 0, 0} };