Brian Aker, brian@tangent.org -- Client Library, Tools
Mark Atwood, -- Tools
-Patrick Galbraith, -- Whatever help Brian needs
+Patrick Galbraith, -- C++ Interface
+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
#release versioning
MEMCACHED_MAJOR_VERSION=0
-MEMCACHED_MINOR_VERSION=14
+MEMCACHED_MINOR_VERSION=15
MEMCACHED_MICRO_VERSION=0
#API version
=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.
=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,
#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
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;
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;
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)
{
char *buffer, size_t length, char with_flush)
{
size_t original_length;
+ char* buffer_ptr;
original_length= length;
+ buffer_ptr= buffer;
while (length)
{
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)
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;
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),
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;
}
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),
if (rc == MEMCACHED_NOTFOUND)
errors++;
else
+ {
+ WATCHPOINT_ERROR(rc);
assert(0);
+ }
continue;
}
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;
{"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 },
{"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}
};