Merged
author <patg@patg.net> <>
Wed, 30 Jan 2008 12:27:01 +0000 (07:27 -0500)
committer <patg@patg.net> <>
Wed, 30 Jan 2008 12:27:01 +0000 (07:27 -0500)
AUTHORS
ChangeLog
configure.ac
docs/memcached_behavior.pod
docs/memcached_callback.pod
include/memcached.h
lib/memcached_fetch.c
lib/memcached_io.c
lib/memcached_response.c
tests/function.c

diff --git a/AUTHORS b/AUTHORS
index f60c8e6664f5820ff13a0f3040bce21cfe96c9bf..f6c0bbafcc5d617dece99faedfd84fb36530309d 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,3 +1,3 @@
 Brian Aker, brian@tangent.org -- Client Library, Tools
 Mark Atwood, -- Tools
-Patrick Galbraith, -- Whatever help Brian needs
+Patrick Galbraith, -- C++ Interface
index cfbf0cdc6df14007ac9b2fe131e596f0daa7b1e5..9b6fc66baf730818e480e5e21186584913abcafd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+0.15 Tue Jan 29 14:55:44 PST 2008
+  * More work on the C++ API.
+  * Bug fixes around block corner cases.
   * Slight performance increase in both read() and write().
 
 0.14 Tue Jan 22 06:21:49 PST 2008
index 8264aff2451fb6edc2b1a23f1e9403c195e1cd1b..4eb75e2a18b21811759ed762f989440286d4a6b3 100644 (file)
@@ -7,7 +7,7 @@ MEMCACHED_LIBRARY_NAME=libmemcached
 
 #release versioning
 MEMCACHED_MAJOR_VERSION=0
-MEMCACHED_MINOR_VERSION=14
+MEMCACHED_MINOR_VERSION=15
 MEMCACHED_MICRO_VERSION=0
 
 #API version
index 04d6e06016226fd7564a5e09d1244e6d6fd951dc..25986cdf9082fdba76406d70fd082be2828c0dcb 100755 (executable)
@@ -76,7 +76,8 @@ Modify the timeout value that is used by poll(). The default value is -1. An sig
 =item MEMCACHED_BEHAVIOR_USER_DATA
 
 This allows you to store a pointer to a specifc piece of data. This can be
-retrieved from inside of memcached_fetch_exectue(). Cloning a memcached_st
+retrieved from inside of memcached_fetch_execute(). Cloning a memcached_st
+
 will copy the pointer to the clone. This was deprecated in 0.14 in favor
 of memcached_callback_set(3). This will be removed in 0.15.
 
index 17d138ff79fa459cd9d9e181e267c486ba84a77f..7d3fe7306e631d3013826ed2159866e90327c5e3 100755 (executable)
@@ -47,7 +47,7 @@ point of its execution all connections have been closed.
 =item MEMCACHED_CALLBACK_USER_DATA
 
 This allows you to store a pointer to a specifc piece of data. This can be
-retrieved from inside of memcached_fetch_exectue(). Cloning a memcached_st
+retrieved from inside of memcached_fetch_execute(). Cloning a memcached_st
 will copy the pointer to the clone.
 
 =item  MEMCACHED_CALLBACK_MALLOC_FUNCTION,
index 7d86925f962784361cd59a02a0cf35a261b302f9..cb74fe9d8aeea575aee099c608cadd6dad318cd8 100644 (file)
@@ -433,7 +433,7 @@ size_t memcached_result_length(memcached_result_st *ptr);
 #define WATCHPOINT_STRING(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__,A);fflush(stdout);
 #define WATCHPOINT_STRING_LENGTH(A,B) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %.*s\n", __FILE__, __LINE__,__func__,(int)B,A);fflush(stdout);
 #define WATCHPOINT_NUMBER(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %zu\n", __FILE__, __LINE__,__func__,(size_t)(A));fflush(stdout);
-#define WATCHPOINT_ERRNO(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__, strerror(A));A= 0;fflush(stdout);
+#define WATCHPOINT_ERRNO(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__, strerror(A));fflush(stdout);
 #define WATCHPOINT_ASSERT(A) assert((A));
 #else
 #define WATCHPOINT
index 6c4d393afe483d6b19cf0b8e63950ca22359f643..19f60870bc9d49408342f8bd1101efd9e564711e 100644 (file)
@@ -10,6 +10,9 @@ memcached_return value_fetch(memcached_server_st *ptr,
   char *end_ptr;
   char *next_ptr;
   size_t value_length;
+  size_t read_length;
+  size_t to_read;
+  char *value_ptr;
 
   end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
 
@@ -78,51 +81,40 @@ memcached_return value_fetch(memcached_server_st *ptr,
   if (end_ptr < string_ptr)
     goto read_error;
 
-  if (value_length)
+  /* We add two bytes so that we can walk the \r\n */
+  rc= memcached_string_check(&result->value, value_length+2);
+  if (rc != MEMCACHED_SUCCESS)
   {
-    size_t read_length;
-    size_t to_read;
-    char *value_ptr;
-
-    /* We add two bytes so that we can walk the \r\n */
-    rc= memcached_string_check(&result->value, value_length+2);
-    if (rc != MEMCACHED_SUCCESS)
-    {
-      value_length= 0;
-      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-    }
-
-    value_ptr= memcached_string_value(&result->value);
-    read_length= 0;
-    /* 
-      We read the \r\n into the string since not doing so is more 
-      cycles then the waster of memory to do so.
-
-      We are null terminating through, which will most likely make
-      some people lazy about using the return length.
-    */
-    to_read= (value_length) + 2;
-
-    read_length= memcached_io_read(ptr, value_ptr, to_read);
-
-    if (read_length != (size_t)(value_length + 2))
-    {
-      goto read_error;
-    }
+    value_length= 0;
+    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+  }
 
-    /* This next bit blows the API, but this is internal....*/
-    {
-      char *char_ptr;
-      char_ptr= memcached_string_value(&result->value);;
-      char_ptr[value_length]= 0;
-      char_ptr[value_length + 1]= 0;
-      memcached_string_set_length(&result->value, value_length);
-    }
+  value_ptr= memcached_string_value(&result->value);
+  read_length= 0;
+  /* 
+    We read the \r\n into the string since not doing so is more 
+    cycles then the waster of memory to do so.
+
+    We are null terminating through, which will most likely make
+    some people lazy about using the return length.
+  */
+  to_read= (value_length) + 2;
+  read_length= memcached_io_read(ptr, value_ptr, to_read);
+  if (read_length != (size_t)(value_length + 2))
+  {
+    goto read_error;
+  }
 
-    return MEMCACHED_SUCCESS;
+/* This next bit blows the API, but this is internal....*/
+  {
+    char *char_ptr;
+    char_ptr= memcached_string_value(&result->value);;
+    char_ptr[value_length]= 0;
+    char_ptr[value_length + 1]= 0;
+    memcached_string_set_length(&result->value, value_length);
   }
 
-  return rc;
+  return MEMCACHED_SUCCESS;
 
 read_error:
   return MEMCACHED_PARTIAL_READ;
index 9e63fe73f1c45c609894f0761ff2dde343c8ce42..bb53f08ec023b9d1273812abd7ae74d12e7d3b90 100644 (file)
@@ -86,14 +86,14 @@ ssize_t memcached_io_read(memcached_server_st *ptr,
     uint8_t found_eof= 0;
     if (!ptr->read_buffer_length)
     {
-      size_t data_read;
+      ssize_t data_read;
 
       while (1)
       {
         data_read= read(ptr->fd, 
                         ptr->read_buffer, 
                         MEMCACHED_MAX_BUFFER);
-        if (data_read)
+        if (data_read > 0)
           break;
         else if (data_read == -1)
         {
@@ -162,8 +162,10 @@ ssize_t memcached_io_write(memcached_server_st *ptr,
                            char *buffer, size_t length, char with_flush)
 {
   size_t original_length;
+  char* buffer_ptr;
 
   original_length= length;
+  buffer_ptr= buffer;
 
   while (length)
   {
@@ -175,8 +177,9 @@ ssize_t memcached_io_write(memcached_server_st *ptr,
 
     should_write= (should_write < length) ? should_write : length;
 
-    memcpy(write_ptr, buffer, should_write);
+    memcpy(write_ptr, buffer_ptr, should_write);
     ptr->write_buffer_offset+= should_write;
+    buffer_ptr+= should_write;
     length-= should_write;
 
     if (ptr->write_buffer_offset == MEMCACHED_MAX_BUFFER)
index 4b29a1cbbec259211ef3800954a580f13f4512f9..956107932615034853f4d12748137f052e759e40 100644 (file)
@@ -32,9 +32,10 @@ memcached_return memcached_response(memcached_server_st *ptr,
 
     while (1)
     {
-      unsigned int read_length;
+      ssize_t read_length;
 
       read_length= memcached_io_read(ptr, buffer_ptr, 1);
+      WATCHPOINT_ASSERT(isgraph(*buffer_ptr) || isspace(*buffer_ptr));
 
       if (read_length != 1)
         return  MEMCACHED_UNKNOWN_READ_FAILURE;
index b2bcd4ad5f1499087530703962e49d44255d7b34..9c18645d19422e90b21f1023cd1e037ccd2b4a56 100644 (file)
@@ -355,6 +355,9 @@ uint8_t add_test(memcached_st *memc)
   memcached_return rc;
   char *key= "foo";
   char *value= "when we sanitize";
+  unsigned long long setting_value;
+
+  setting_value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK);
 
   rc= memcached_set(memc, key, strlen(key), 
                     value, strlen(value),
@@ -364,7 +367,12 @@ uint8_t add_test(memcached_st *memc)
   rc= memcached_add(memc, key, strlen(key), 
                     value, strlen(value),
                     (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_NOTSTORED);
+
+  /* Too many broken OS'es have broken loopback in async, so we can't be sure of the result */
+  if (setting_value)
+    assert(rc == MEMCACHED_NOTSTORED || MEMCACHED_STORED);
+  else
+    assert(rc == MEMCACHED_NOTSTORED);
 
   return 0;
 }
@@ -384,6 +392,12 @@ uint8_t replace_test(memcached_st *memc)
   memcached_return rc;
   char *key= "foo";
   char *value= "when we sanitize";
+  char *original= "first we insert some data";
+
+  rc= memcached_set(memc, key, strlen(key), 
+                    original, strlen(original),
+                    (time_t)0, (uint32_t)0);
+  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
 
   rc= memcached_replace(memc, key, strlen(key), 
                     value, strlen(value),
@@ -1147,7 +1161,10 @@ uint8_t user_supplied_bug2(memcached_st *memc)
       if (rc == MEMCACHED_NOTFOUND)
         errors++;
       else
+      {
+        WATCHPOINT_ERROR(rc);
         assert(0);
+      }
 
       continue;
     }
@@ -1643,6 +1660,91 @@ uint8_t user_supplied_bug12(memcached_st *memc)
   return 0;
 }
 
+/*
+  Bug found where command total one more than MEMCACHED_MAX_BUFFER
+  set key34567890 0 0 8169 \r\n is sent followed by buffer of size 8169, followed by 8169
+ */
+uint8_t user_supplied_bug13(memcached_st *memc)
+{
+  char key[] = "key34567890";
+  char *overflow;
+  memcached_return rc;
+  size_t overflowSize;
+
+  char commandFirst[]= "set key34567890 0 0 ";
+  char commandLast[] = " \r\n"; /* first line of command sent to server */
+  size_t commandLength;
+  size_t testSize;
+
+  commandLength = strlen(commandFirst) + strlen(commandLast) + 4; /* 4 is number of characters in size, probably 8196 */
+
+  overflowSize = MEMCACHED_MAX_BUFFER - commandLength;
+
+  for (testSize= overflowSize - 1; testSize < overflowSize + 1; testSize++)
+  {
+    overflow= malloc(testSize);
+    assert(overflow != NULL);
+
+    memset(overflow, 'x', testSize);
+    rc= memcached_set(memc, key, strlen(key),
+                      overflow, testSize, 0, 0);
+    assert(rc == MEMCACHED_SUCCESS);
+    free(overflow);
+  }
+
+  return 0;
+}
+
+
+/*
+  Test values of many different sizes
+  Bug found where command total one more than MEMCACHED_MAX_BUFFER
+  set key34567890 0 0 8169 \r\n
+  is sent followed by buffer of size 8169, followed by 8169
+ */
+uint8_t user_supplied_bug14(memcached_st *memc)
+{
+  int setter= 1;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, &setter);
+  memcached_return rc;
+  char *key= "foo";
+  char *value;
+  size_t value_length= 18000;
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+  unsigned int x;
+  size_t current_length;
+
+  value = (char*)malloc(value_length);
+  assert(value);
+
+  for (x= 0; x < value_length; x++)
+    value[x] = (char) (x % 127);
+
+  for (current_length= 1; current_length < value_length; current_length++)
+  {
+    rc= memcached_set(memc, key, strlen(key), 
+                      value, current_length,
+                      (time_t)0, (uint32_t)0);
+    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+    string= memcached_get(memc, key, strlen(key),
+                          &string_length, &flags, &rc);
+
+    assert(rc == MEMCACHED_SUCCESS);
+    assert(string);
+    assert(string_length == current_length);
+    assert(!memcmp(string, value, string_length));
+
+    free(string);
+  }
+
+  free(value);
+
+  return 0;
+}
+
 uint8_t result_static(memcached_st *memc)
 {
   memcached_result_st result;
@@ -2215,7 +2317,7 @@ test_st tests[] ={
   {"set2", 0, set_test2 },
   {"set3", 0, set_test3 },
   {"add", 1, add_test },
-  {"replace", 0, replace_test },
+  {"replace", 1, replace_test },
   {"delete", 1, delete_test },
   {"get", 1, get_test },
   {"get2", 0, get_test2 },
@@ -2281,6 +2383,8 @@ test_st user_tests[] ={
   {"user_supplied_bug10", 1, user_supplied_bug10 },
   {"user_supplied_bug11", 1, user_supplied_bug11 },
   {"user_supplied_bug12", 1, user_supplied_bug12 },
+  {"user_supplied_bug13", 1, user_supplied_bug13 },
+  {"user_supplied_bug14", 1, user_supplied_bug14 },
   {0, 0, 0}
 };