Also work t make this a release.
-0.9
+0.9 Thu Nov 15 07:44:00 PST 2007
* fix for when no servers are definied.
* different buffers are now kept for different connections to
speed up async efforts
* Fixed bug in cases where zero length keys were provided
* Thread cleanup issue in memslap
* No hostname lookup on reconnect
+ * Fix for flag settings (was doing hex by accident!)
+ * Support for 1.2.4 server additions "prepend" and "append" added.
+ * Added memcached_version()... not sure if I will make this public
+ or not.
0.8 Mon Nov 5 10:40:41 PST 2007
* Adding support for CRC hash method
memslap.1\\r
memstat.1\\r
memcached_add.3\\r
+ memcached_append.3\\r
memcached_behavior_get.3\\r
memcached_behavior_set.3\\r
memcached_clone.3\\r
memcached_decrement.3\\r
memcached_delete.3\\r
memcached_fetch.3\\r
+ memcached_fetch_result.3\\r
memcached_free.3\\r
memcached_get.3\\r
memcached_increment.3\\r
memcached_mget.3\\r
+ memcached_prepend.3\\r
memcached_replace.3\\r
memcached_server_add.3\\r
memcached_server_count.3\\r
memcached_add.3: memcached_set.pod\r
pod2man -c "libmemcached" -r "" -s 3 memcached_set.pod > memcached_add.3\r
\r
+memcached_prepend.3: memcached_set.pod\r
+ pod2man -c "libmemcached" -r "" -s 3 memcached_set.pod > memcached_prepend.3\r
+\r
+memcached_append.3: memcached_set.pod\r
+ pod2man -c "libmemcached" -r "" -s 3 memcached_set.pod > memcached_append.3\r
+\r
memcached_delete.3: memcached_delete.pod\r
pod2man -c "libmemcached" -r "" -s 3 memcached_delete.pod > memcached_delete.3\r
\r
=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(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)
=cut
time_t expiration,
uint16_t flags);
+ memcached_return
+ memcached_prepend(memcached_st *ptr,
+ char *key, size_t key_length,
+ char *value, size_t value_length,
+ time_t expiration,
+ uint16_t flags)
+
+ memcached_return
+ memcached_append(memcached_st *ptr,
+ char *key, size_t key_length,
+ char *value, size_t value_length,
+ time_t expiration,
+ uint16_t flags)
+
=head1 DESCRIPTION
memcached_set(), memcached_add(), and memcached_replace() are all used to
memcached_add() adds an object to the server. If the object is found on the
server an error occurs, otherwise the value is stored.
+memcached_prepend() places a segment of data before the last piece of data
+stored. Currently expiration and key are not used in the server.
+
+memcached_append() places a segment of data at the end of the last piece of
+data stored. Currently expiration and key are not used in the server.
+
memcached_set() with non-blocking IO is the fastest way to store data on the
server.
typedef struct memcached_string_st memcached_string_st;
typedef struct memcached_server_st memcached_server_st;
+#define MEMCACHED_VERSION_STRING 12
#define MEMCACHED_DEFAULT_PORT 11211
#define MEMCACHED_DEFAULT_COMMAND_SIZE 350
#define SMALL_STRING_LEN 1024
char *read_ptr;
struct sockaddr_in servAddr;
memcached_connection type;
+ uint8_t major_version;
+ uint8_t minor_version;
+ uint8_t micro_version;
};
struct memcached_stat_st {
unsigned int uptime;
unsigned int threads;
time_t time;
- char version[8];
+ char version[MEMCACHED_VERSION_STRING];
unsigned int pointer_size;
unsigned int rusage_user;
unsigned int rusage_system;
char *value, size_t value_length,
time_t expiration,
uint16_t flags);
+memcached_return memcached_append(memcached_st *ptr,
+ char *key, size_t key_length,
+ char *value, size_t value_length,
+ time_t expiration,
+ uint16_t flags);
+memcached_return memcached_prepend(memcached_st *ptr,
+ char *key, size_t key_length,
+ char *value, size_t value_length,
+ time_t expiration,
+ uint16_t flags);
+memcached_return memcached_cas(memcached_st *ptr,
+ char *key, size_t key_length,
+ char *value, size_t value_length,
+ time_t expiration,
+ uint16_t flags,
+ uint64_t cas);
/* Get functions */
char *memcached_get(memcached_st *ptr, char *key, size_t key_length,
memcached_string.c \
memcached_stats.c \
memcached_strerror.c \
- memcached_verbosity.c
+ memcached_verbosity.c \
+ memcached_version.c
+
libmemcached_la_LIBADD =
libmemcached_la_LDFLAGS = -version-info $(MEMCACHED_LIBRARY_VERSION)
void memcached_string_free(memcached_string_st *string);
memcached_return memcached_do(memcached_st *ptr, unsigned int server_key, char *commmand,
size_t command_length, char with_flush);
+memcached_return memcached_version(memcached_st *ptr);
+
#endif /* __COMMON_H__ */
memcached_return rc;
ssize_t sent_length;
+ WATCHPOINT_ASSERT(command_length);
WATCHPOINT_ASSERT(command);
if (ptr->hosts[server_key].cursor_active)
switch(buffer[0])
{
- case 'V': /* VALUE */
+ case 'V': /* VALUE || VERSION */
return MEMCACHED_SUCCESS;
case 'O': /* OK */
return MEMCACHED_SUCCESS;
SET_OP,
REPLACE_OP,
ADD_OP,
+ PREPEND_OP,
+ APPEND_OP,
+ CAS_OP,
} memcached_storage_action;
/* Inline this */
-#define storage_op_string(A) A == SET_OP ? "set" : ( A == REPLACE_OP ? "replace" : "add")
-
-static memcached_return memcached_send(memcached_st *ptr,
- char *key, size_t key_length,
- char *value, size_t value_length,
- time_t expiration,
- uint16_t flags,
- memcached_storage_action verb)
+char *storage_op_string(memcached_storage_action verb)
+{
+ switch (verb)
+ {
+ case SET_OP:
+ return "set";
+ case REPLACE_OP:
+ return "replace";
+ case ADD_OP:
+ return "add";
+ case PREPEND_OP:
+ return "prepend";
+ case APPEND_OP:
+ return "append";
+ case CAS_OP:
+ return "cas";
+ };
+
+ return SET_OP;
+}
+
+static inline memcached_return memcached_send(memcached_st *ptr,
+ char *key, size_t key_length,
+ char *value, size_t value_length,
+ time_t expiration,
+ uint16_t flags,
+ uint64_t cas,
+ memcached_storage_action verb)
{
char to_write;
size_t write_length;
return rc;
- write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "%s %.*s %u %llu %zu\r\n", storage_op_string(verb),
- (int)key_length, key, flags,
- (unsigned long long)expiration, value_length);
+ if (cas)
+ write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "%s %.*s %u %llu %zu\r\n", storage_op_string(verb),
+ (int)key_length, key, flags,
+ (unsigned long long)expiration, value_length);
+ else
+ write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "%s %.*s %u %llu %zu %llu\r\n", storage_op_string(verb),
+ (int)key_length, key, flags,
+ (unsigned long long)expiration, value_length,
+ (unsigned long long)cas);
+
if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
{
rc= MEMCACHED_WRITE_FAILURE;
{
rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
}
-
if (rc == MEMCACHED_STORED)
return MEMCACHED_SUCCESS;
else
memcached_return memcached_set(memcached_st *ptr, char *key, size_t key_length,
char *value, size_t value_length,
time_t expiration,
- uint16_t flags)
+ uint16_t flags)
{
memcached_return rc;
LIBMEMCACHED_MEMCACHED_SET_START();
rc= memcached_send(ptr, key, key_length, value, value_length,
- expiration, flags, SET_OP);
+ expiration, flags, 0, SET_OP);
LIBMEMCACHED_MEMCACHED_SET_END();
return rc;
}
-memcached_return memcached_add(memcached_st *ptr, char *key, size_t key_length,
+memcached_return memcached_add(memcached_st *ptr,
+ char *key, size_t key_length,
char *value, size_t value_length,
time_t expiration,
- uint16_t flags)
+ uint16_t flags)
{
memcached_return rc;
LIBMEMCACHED_MEMCACHED_ADD_START();
rc= memcached_send(ptr, key, key_length, value, value_length,
- expiration, flags, ADD_OP);
+ expiration, flags, 0, ADD_OP);
LIBMEMCACHED_MEMCACHED_ADD_END();
return rc;
}
-memcached_return memcached_replace(memcached_st *ptr, char *key, size_t key_length,
+memcached_return memcached_replace(memcached_st *ptr,
+ char *key, size_t key_length,
char *value, size_t value_length,
time_t expiration,
- uint16_t flags)
+ uint16_t flags)
{
memcached_return rc;
LIBMEMCACHED_MEMCACHED_REPLACE_START();
rc= memcached_send(ptr, key, key_length, value, value_length,
- expiration, flags, REPLACE_OP);
+ expiration, flags, 0, REPLACE_OP);
LIBMEMCACHED_MEMCACHED_REPLACE_END();
return rc;
}
+
+memcached_return memcached_prepend(memcached_st *ptr,
+ char *key, size_t key_length,
+ char *value, size_t value_length,
+ time_t expiration,
+ uint16_t flags)
+{
+ memcached_return rc;
+ rc= memcached_send(ptr, key, key_length, value, value_length,
+ expiration, flags, 0, PREPEND_OP);
+ return rc;
+}
+
+memcached_return memcached_append(memcached_st *ptr,
+ char *key, size_t key_length,
+ char *value, size_t value_length,
+ time_t expiration,
+ uint16_t flags)
+{
+ memcached_return rc;
+ rc= memcached_send(ptr, key, key_length, value, value_length,
+ expiration, flags, 0, APPEND_OP);
+ return rc;
+}
+
+memcached_return memcached_cas(memcached_st *ptr,
+ char *key, size_t key_length,
+ char *value, size_t value_length,
+ time_t expiration,
+ uint16_t flags,
+ uint64_t cas)
+{
+ memcached_return rc;
+ rc= memcached_send(ptr, key, key_length, value, value_length,
+ expiration, flags, cas, APPEND_OP);
+ return rc;
+}
--- /dev/null
+#include "common.h"
+
+memcached_return memcached_version(memcached_st *ptr)
+{
+ unsigned int x;
+ size_t send_length;
+ memcached_return rc;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ char *response_ptr;
+
+ send_length= strlen("version\r\n");
+ memcpy(buffer, "version\r\n", send_length);
+
+ rc= MEMCACHED_SUCCESS;
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ memcached_return rrc;
+
+ rrc= memcached_do(ptr, x, buffer, send_length, 1);
+ if (rrc != MEMCACHED_SUCCESS)
+ {
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+
+ rrc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, x);
+ if (rrc != MEMCACHED_SUCCESS)
+ rc= MEMCACHED_SOME_ERRORS;
+
+ /* Find the space, and then move one past it to copy version */
+ response_ptr= index(buffer, ' ');
+ response_ptr++;
+
+ ptr->hosts[x].major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+ response_ptr= index(response_ptr, '.');
+ response_ptr++;
+ ptr->hosts[x].minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+ response_ptr= index(response_ptr, '.');
+ response_ptr++;
+ ptr->hosts[x].micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+ }
+
+ return rc;
+}
%{_libdir}/libmemcached.la
%{_libdir}/libmemcached.so
%{_libdir}/libmemcached.so.1
-%{_libdir}/libmemcached.so.1.0.0
+%{_libdir}/libmemcached.so.1.0.1
%{_libdir}/pkgconfig/libmemcached.pc
%{_mandir}/man1/memcat.1.gz
%{_mandir}/man1/memcp.1.gz
%{_mandir}/man3/libmemcached.3.gz
%{_mandir}/man3/libmemcached_examples.3.gz
%{_mandir}/man3/memcached_add.3.gz
+%{_mandir}/man3/memcached_append.3.gz
%{_mandir}/man3/memcached_behavior_get.3.gz
%{_mandir}/man3/memcached_behavior_set.3.gz
%{_mandir}/man3/memcached_clone.3.gz
%{_mandir}/man3/memcached_decrement.3.gz
%{_mandir}/man3/memcached_delete.3.gz
%{_mandir}/man3/memcached_fetch.3.gz
+%{_mandir}/man3/memcached_fetch_result.3.gz
%{_mandir}/man3/memcached_free.3.gz
%{_mandir}/man3/memcached_get.3.gz
%{_mandir}/man3/memcached_increment.3.gz
%{_mandir}/man3/memcached_mget.3.gz
+%{_mandir}/man3/memcached_prepend.3.gz
%{_mandir}/man3/memcached_quit.3.gz
%{_mandir}/man3/memcached_replace.3.gz
%{_mandir}/man3/memcached_server_add.3.gz
return 0;
}
+uint8_t append_test(memcached_st *memc)
+{
+ memcached_return rc;
+ char *key= "fig";
+ char *value= "we";
+ size_t value_length;
+ uint16_t flags;
+
+ rc= memcached_flush(memc, 0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ rc= memcached_set(memc, key, strlen(key),
+ value, strlen(value),
+ (time_t)0, (uint16_t)0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ rc= memcached_append(memc, key, strlen(key),
+ " the", strlen(" the"),
+ (time_t)0, (uint16_t)0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ rc= memcached_append(memc, key, strlen(key),
+ " people", strlen(" people"),
+ (time_t)0, (uint16_t)0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ value= memcached_get(memc, key, strlen(key),
+ &value_length, &flags, &rc);
+ assert(!memcmp(value, "we the people", strlen("we the people")));
+ assert(strlen("we the people") == value_length);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ return 0;
+}
+
+uint8_t cas_test(memcached_st *memc)
+{
+ memcached_return rc;
+ char *key= "fun";
+ size_t key_length= strlen("fun");
+ char *value= "we the people";
+ size_t value_length= strlen("we the people");
+ memcached_result_st results_obj;
+ memcached_result_st *results;
+
+ rc= memcached_flush(memc, 0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ rc= memcached_set(memc, key, strlen(key),
+ value, strlen(value),
+ (time_t)0, (uint16_t)0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ rc= memcached_mget(memc, &key, &key_length, 1);
+
+ results= memcached_result_create(memc, &results_obj);
+
+ results= memcached_fetch_result(memc, &results_obj, &rc);
+ assert(results);
+ assert(rc == MEMCACHED_SUCCESS);
+ WATCHPOINT_NUMBER(memcached_result_cas(results));
+ WATCHPOINT_ASSERT(memcached_result_cas(results));
+
+ assert(!memcmp(value, "we the people", strlen("we the people")));
+ assert(strlen("we the people") == value_length);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ memcached_result_free(&results_obj);
+
+ return 0;
+}
+
+uint8_t prepend_test(memcached_st *memc)
+{
+ memcached_return rc;
+ char *key= "fig";
+ char *value= "people";
+ size_t value_length;
+ uint16_t flags;
+
+ rc= memcached_flush(memc, 0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ rc= memcached_set(memc, key, strlen(key),
+ value, strlen(value),
+ (time_t)0, (uint16_t)0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ rc= memcached_prepend(memc, key, strlen(key),
+ "the ", strlen("the "),
+ (time_t)0, (uint16_t)0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ rc= memcached_prepend(memc, key, strlen(key),
+ "we ", strlen("we "),
+ (time_t)0, (uint16_t)0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ value= memcached_get(memc, key, strlen(key),
+ &value_length, &flags, &rc);
+ assert(!memcmp(value, "we the people", strlen("we the people")));
+ assert(strlen("we the people") == value_length);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ return 0;
+}
+
uint8_t add_test(memcached_st *memc)
{
memcached_return rc;
return MEMCACHED_SUCCESS;
}
+memcached_return check_for_1_2_3(memcached_st *memc)
+{
+ memcached_version(memc);
+
+ if (memc->hosts[0].major_version >= 1 &&
+ memc->hosts[0].minor_version >= 2 &&
+ memc->hosts[0].micro_version >= 4)
+ return MEMCACHED_SUCCESS;
+
+ return MEMCACHED_FAILURE;
+}
+
memcached_return pre_unix_socket(memcached_st *memc)
{
memcached_return rc;
{0, 0, 0}
};
+test_st version_1_2_3[] ={
+ {"append", 0, append_test },
+ {"prepend", 0, prepend_test },
+// {"cas", 0, cas_test },
+ {0, 0, 0}
+};
+
test_st user_tests[] ={
{"user_supplied_bug1", 0, user_supplied_bug1 },
{"user_supplied_bug2", 0, user_supplied_bug2 },
{"unix_socket", pre_unix_socket, 0, tests},
{"unix_socket_nodelay", pre_nodelay, 0, tests},
// {"udp", pre_udp, 0, tests},
+ {"version_1_2_3", check_for_1_2_3, 0, version_1_2_3},
{"string", 0, 0, string_tests},
{"result", 0, 0, result_tests},
{"user", 0, 0, user_tests},
{"generate", 0, 0, generate_tests},
+ {"generate_nonblock", pre_nonblock, 0, generate_tests},
{0, 0, 0, 0}
};