Read through caching function.
author <brian@gir-2.local> <>
Tue, 18 Mar 2008 05:39:12 +0000 (22:39 -0700)
committer <brian@gir-2.local> <>
Tue, 18 Mar 2008 05:39:12 +0000 (22:39 -0700)
14 files changed:
docs/libmemcached.pod
docs/memcached_callback.pod
docs/memcached_result_st.pod
libmemcached/memcached.c
libmemcached/memcached.h
libmemcached/memcached_callback.c
libmemcached/memcached_connect.c
libmemcached/memcached_constants.h
libmemcached/memcached_fetch.c
libmemcached/memcached_get.c
libmemcached/memcached_result.c
libmemcached/memcached_result.h
libmemcached/memcached_types.h
tests/function.c

index 1700cf5b386b9350fcd47b7ff9dc7b35d556038d..1e63c8ce178f345ff4467b9209858a4f2af5ca61 100755 (executable)
@@ -121,7 +121,7 @@ Brian Aker, E<lt>brian@tangent.orgE<gt>
 
 =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
 
index 7d3fe7306e631d3013826ed2159866e90327c5e3..56ba4e29c6a4e3bbb1a4554f0986d92105d4b0f0 100755 (executable)
@@ -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
 
index 89d4e81612556bdcb59a03fdcc0077ef705b2184..bd8e21fa377412978e2473587d100b308112f949 100755 (executable)
@@ -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
 
index 9d0f81e8b31d200be1bf6591f7149393e0625150..2c8cef75b61c5926bde3ec40128b7cc6595769c1 100644 (file)
@@ -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);
index 2aba39c00ecbe3ac1fbe9fbab4f4caa21f76aa1d..bbf82e231367e74d2de518cd8bad26f5c08f6f15 100644 (file)
@@ -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;
index 95d6a384836666c2c15e2d52250f02ac73221a27..ad21c10d500422289f9ac427b8bfb4b88268f622 100644 (file)
@@ -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;
index 7edcce8565925da6cdc63a53e4ab161823eb45ed..5531ad792d47175439d22c469138dbdb99575872 100644 (file)
@@ -1,5 +1,6 @@
 #include "common.h"
 #include <poll.h>
+#include <sys/time.h>
 
 static memcached_return set_hostinfo(memcached_server_st *server)
 {
index 65192bfbbc67f1471751e434dd82c51702059a18..6f3909b6be029726cb00b20dcbfefafa86a94001 100644 (file)
@@ -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 {
index 37cec5d30366a857b9e99f7e7424170a5ff75326..303e8cc3ae4d68a7f5c4f31f1ad39099454e5fc3 100644 (file)
@@ -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
   {
index 8cc7ce30b04adee6eb7d62555ed9fd90b0c8ecd4..354f7bb89cc8b93d1ae3fa77416481e849ea1b25 100644 (file)
@@ -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, 
index cf3894bef3b7545fcdaca9be56d6e1883f25b2a3..0860e792e528f6ae3de02b725e03a8ce27454fa2 100644 (file)
@@ -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)
index 1c229ecbf777525ca5c58309c550b2b39093d163..2b08d39603bc7bd7c7f2a8de0e7e970ad3ae570d 100644 (file)
@@ -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
 }
index 76f5171dc538d74992bbbae8bda7ada34276cea0..6db4ba451c920b7c8d2822381b4a606d78c1783f 100644 (file)
@@ -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
 }
index bcf08fe6c8cdd54dd586830204b2ca2568c81b6a..d356fb93083e5890864abf4cb247821eb3843c52 100644 (file)
@@ -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}
 };