fetch_result() implemented for memcached_result_st.
authorBrian Aker <brian@tangent.org>
Sun, 4 Nov 2007 01:53:21 +0000 (18:53 -0700)
committerBrian Aker <brian@tangent.org>
Sun, 4 Nov 2007 01:53:21 +0000 (18:53 -0700)
ChangeLog
docs/Makefile.am
docs/libmemcached.pod
docs/memcached_get.pod
docs/memcached_result_st.pod [new file with mode: 0755]
include/memcached.h
lib/common.h
lib/memcached_get.c
lib/memcached_response.c
lib/memcached_result.c [new file with mode: 0644]
tests/test.c

index 8b2f9a8a50d2f38c7217e7412b62e30a7f58aa58..ff7e498e4f69e7ee38e678a2357da4c5fc78b229 100644 (file)
--- 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()
index fae515c8e0ed0acc06cdcc118fcdb74c70a65f2c..5d8a812b8d5886af5d74d6ddac7e901cc98faa37 100644 (file)
@@ -99,6 +99,9 @@ memcached_flush.3: memcached_flush.pod
 memcached_get.3: memcached_get.pod\r
        pod2man -c "libmemcached" -r "" -s 3 memcached_get.pod > memcached_get.3\r
 \r
+memcached_fetch_result.3: memcached_get.pod\r
+       pod2man -c "libmemcached" -r "" -s 3 memcached_get.pod > memcached_fetch_result.3\r
+\r
 memcached_mget.3: memcached_get.pod\r
        pod2man -c "libmemcached" -r "" -s 3 memcached_get.pod > memcached_mget.3\r
 \r
@@ -159,6 +162,33 @@ memcached_stat_get_value.3: memcached_stats.pod
 memcached_stat_get_keys.3: memcached_stats.pod\r
        pod2man -c "libmemcached" -r "" -s 3 memcached_stats.pod > memcached_stat_get_keys.3\r
 \r
+memcached_result_st.3: memcached_result_st.pod\r
+       pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_st.3\r
+\r
+memcached_result_create.3: memcached_result_st.pod\r
+       pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_create.3\r
+\r
+memcached_result_free.3: memcached_result_st.pod\r
+       pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_free.3\r
+\r
+memcached_result_key_value.3: memcached_result_st.pod\r
+       pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_key_value.3\r
+\r
+memcached_result_key_length.3: memcached_result_st.pod\r
+       pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_key_length.3\r
+\r
+memcached_result_value.3: memcached_result_st.pod\r
+       pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_value.3\r
+\r
+memcached_result_length.3: memcached_result_st.pod\r
+       pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_length.3\r
+\r
+memcached_result_flags.3: memcached_result_st.pod\r
+       pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_flags.3\r
+\r
+memcached_result_cas.3: memcached_result_st.pod\r
+       pod2man -c "libmemcached" -r "" -s 3 memcached_result_st.pod > memcached_result_cas.3\r
+\r
 memcp.1: memcp.pod\r
        pod2man -c "libmemcached" -r "" -s 1 memcp.pod > memcp.1\r
 \r
index c139b0809e1589abb5f34b80c521b1fe8e27782b..36079ba5aaa4815a21ca79f18ec2ce9db18672d1 100755 (executable)
@@ -54,7 +54,6 @@ 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)
-
+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
 
index 1c95ec38ca22d3ce32234d52199fb09797987033..458a55a9571479a6ea58bfe382ad9d27e4bd011e 100755 (executable)
@@ -10,6 +10,11 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
+  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 (executable)
index 0000000..2296b90
--- /dev/null
@@ -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.h>
+
+  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<http://tangent.org/552/libmemcached.html>
+
+=head1 AUTHOR
+
+Brian Aker, E<lt>brian@tangent.orgE<gt>
+
+=head1 SEE ALSO
+
+memcached(1) libmemcached(3) memcached_strerror(3)
+
+=cut
+
index 06efdb12501727d81c9f6908ed12d2116dbf0f5a..f9176704231e628373aa2bb40f5964cf6e5197b3 100644 (file)
@@ -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
index 31a65ea9aad0fa490cc3a7d013faf4176d4844c2..3a3a969525b80d389727db60fef2720ccda94aee 100644 (file)
@@ -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__ */
index a8ece5361ac3a08f18c6f6b383f23606a95f0c09..01f388c91069e68ef9383de0fc00cfeed393f1f5 100644 (file)
@@ -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
index 673ccb2f6aed105c9e7c661ca3a2e486813bb694..19fa640076045faa1bdf0cdd5cbfbbad092e9cd1 100644 (file)
@@ -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 (file)
index 0000000..49f44b2
--- /dev/null
@@ -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);
+}
index 17240107e8ee045ba6dd27f873623557132ad1f5..27dd4419e39aa56b1a1e5d875100869f638e7c74 100644 (file)
@@ -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 },