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
 
 
 =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
 
 
 =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. 
 
 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
 =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);
 
 
 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.
 =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);
 
 
 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.
 =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);
 
 
 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
 
 
 =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);
 
 
   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 
 =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.
 
 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
 
 
 =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->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);
 
   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_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;
 #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;
     }
       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;
   }
   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;
     }
       *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;
   default:
       WATCHPOINT_ASSERT(0);
       *error= MEMCACHED_FAILURE;
index 7edcce8565925da6cdc63a53e4ab161823eb45ed..5531ad792d47175439d22c469138dbdb99575872 100644 (file)
@@ -1,5 +1,6 @@
 #include "common.h"
 #include <poll.h>
 #include "common.h"
 #include <poll.h>
+#include <sys/time.h>
 
 static memcached_return set_hostinfo(memcached_server_st *server)
 {
 
 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_MALLOC_FUNCTION,
   MEMCACHED_CALLBACK_REALLOC_FUNCTION,
   MEMCACHED_CALLBACK_FREE_FUNCTION,
+  MEMCACHED_CALLBACK_GET_FAILURE,
 } memcached_callback;
 
 typedef enum {
 } 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;
 
 
   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 " */
 
   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;
   {
     /* Skip past the \r\n */
     string_ptr+= 2;
-    result->cas= 0;
   }
   else
   {
   }
   else
   {
index 8cc7ce30b04adee6eb7d62555ed9fd90b0c8ecd4..354f7bb89cc8b93d1ae3fa77416481e849ea1b25 100644 (file)
@@ -38,7 +38,46 @@ char *memcached_get_by_key(memcached_st *ptr,
     *error= MEMCACHED_NOTFOUND;
 
   if (value == NULL)
     *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;
     return NULL;
+  }
 
   (void)memcached_fetch(ptr, NULL, NULL, 
                         &dummy_length, &dummy_flags, 
 
   (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;
 }
 
   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)
 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;
   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);
   /* 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
 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
 #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
 }
 
 #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 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
 }
 
 #ifdef __cplusplus
 }
index bcf08fe6c8cdd54dd586830204b2ca2568c81b6a..d356fb93083e5890864abf4cb247821eb3843c52 100644 (file)
@@ -522,6 +522,50 @@ uint8_t bad_key_test(memcached_st *memc)
   return 0;
 }
 
   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;
 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 },
   {"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}
 };
 
   {0, 0, 0}
 };