* Added append binary test.
* Added MEMCACHED_BEHAVIOR_CACHE_LOOKUPS behavior so that you can save on
multiple DNS lookups.
+ * Added CAS support, though this is optional and must be enabled during
+ runtime.
0.9 Thu Nov 15 07:44:00 PST 2007
* fix for when no servers are definied.
memcached_append.3\\r
memcached_behavior_get.3\\r
memcached_behavior_set.3\\r
+ memcached_cas.3\\r
memcached_clone.3\\r
memcached_create.3\\r
memcached_decrement.3\\r
memcached_set.3: memcached_set.pod\r
pod2man -c "libmemcached" -r "" -s 3 memcached_set.pod > memcached_set.3\r
\r
+memcached_cas.3: memcached_set.pod\r
+ pod2man -c "libmemcached" -r "" -s 3 memcached_set.pod > memcached_cas.3\r
+\r
memcached_replace.3: memcached_set.pod\r
pod2man -c "libmemcached" -r "" -s 3 memcached_set.pod > memcached_replace.3\r
\r
Memcached can cache named lookups so that DNS lookups are made only once.
+=item MEMCACHED_BEHAVIOR_SUPPORT_CAS
+
+Support CAS operations (this is not enabled by default at this point in the server since it imposes a slight performance penalty).
+
=back
=head1 RETURN
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);
=head1 DESCRIPTION
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.
+memcached_cas() overwrites data in the server as long as the "cas" value is
+still the same in the server. You can get the cas value of a result by
+calling memcached_result_cas() on a memcached_result_st(3) structure. At the point
+that this note was written cas is still buggy in memached. Turning on support
+for it in libmemcached(3) is optional. Please see memcached_set() for
+information on how to do this.
+
+If you are looking for performance, memcached_set() with non-blocking IO is
+the fastest way to store data on the server.
=head1 RETURN
MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE,
MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE,
MEMCACHED_BEHAVIOR_CACHE_LOOKUPS,
+ MEMCACHED_BEHAVIOR_SUPPORT_CAS,
} memcached_behavior;
typedef enum {
MEM_USE_KETAMA= (1 << 4),
MEM_USE_CRC= (1 << 5),
MEM_USE_CACHE_LOOKUPS= (1 << 6),
+ MEM_SUPPORT_CAS= (1 << 7),
} memcached_flags;
/* Hashing algo */
{
switch (flag)
{
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
+ set_behavior_flag(ptr, MEM_SUPPORT_CAS, data);
+ break;
case MEMCACHED_BEHAVIOR_NO_BLOCK:
set_behavior_flag(ptr, MEM_NO_BLOCK, data);
break;
switch (flag)
{
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
+ temp_flag= MEM_SUPPORT_CAS;
+ break;
case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
temp_flag= MEM_USE_CACHE_LOOKUPS;
break;
static memcached_return memcached_value_fetch(memcached_st *ptr, char *key, size_t *key_length,
memcached_string_st *value,
uint16_t *flags,
+ uint64_t *cas,
char load_key,
unsigned int server_key)
{
if (end_ptr == string_ptr)
goto read_error;
- /* Skip past the \r\n */
- string_ptr+= 2;
+ /* Skip spaces */
+ if (*string_ptr == '\r')
+ {
+ /* Skip past the \r\n */
+ string_ptr+= 2;
+ }
+ else
+ {
+ string_ptr++;
+ for (next_ptr= string_ptr; end_ptr > string_ptr && *string_ptr != ' '; string_ptr++);
+ if (cas)
+ *cas= (size_t)strtoll(next_ptr, &string_ptr, 10);
+ }
if (end_ptr < string_ptr)
goto read_error;
goto error;
*error= memcached_value_fetch(ptr, key, &key_length, result_buffer,
- flags, 0, server_key);
+ flags, NULL, 0, server_key);
*value_length= memcached_string_length(result_buffer);
if (*error == MEMCACHED_END && *value_length == 0)
{
{
unsigned int x;
memcached_return rc= MEMCACHED_NOTFOUND;
+ char *get_command= "get ";
+ uint8_t get_command_length= 4
+
LIBMEMCACHED_MEMCACHED_MGET_START();
ptr->cursor_server= 0;
if (ptr->number_of_hosts == 0)
return MEMCACHED_NO_SERVERS;
+ if (ptr->flags & MEM_SUPPORT_CAS)
+ {
+ get_command= "gets ";
+ get_command_length= 5;
+ }
+
for (x= 0; x < number_of_keys; x++)
{
unsigned int server_key;
{
rc= memcached_connect(ptr, server_key);
- if ((memcached_io_write(ptr, server_key, "get ", 4, 0)) == -1)
+ if ((memcached_io_write(ptr, server_key, get_command, get_command_length, 0)) == -1)
{
memcached_quit_server(ptr, server_key);
rc= MEMCACHED_SOME_ERRORS;
}
*error = memcached_value_fetch(ptr, key, key_length, result_buffer,
- flags, 1, ptr->cursor_server);
+ flags, NULL, 1, ptr->cursor_server);
*value_length= memcached_string_length(result_buffer);
if (*error == MEMCACHED_NOTFOUND)
continue;
}
+ result->cas= 0; /* We do this so we do not send in any junk */
*error= memcached_value_fetch(ptr, result->key, &result->key_length,
&result->value,
&result->flags,
+ &result->cas,
1, ptr->cursor_server);
if (*error == MEMCACHED_NOTFOUND)
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);
+ else
+ 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 (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
{
%{_mandir}/man3/memcached_append.3.gz
%{_mandir}/man3/memcached_behavior_get.3.gz
%{_mandir}/man3/memcached_behavior_set.3.gz
+%{_mandir}/man3/memcached_cas.3.gz
%{_mandir}/man3/memcached_clone.3.gz
%{_mandir}/man3/memcached_create.3.gz
%{_mandir}/man3/memcached_decrement.3.gz
return 0;
}
+uint8_t cas2_test(memcached_st *memc)
+{
+ memcached_return rc;
+ char *keys[]= {"fudge", "son", "food"};
+ size_t key_length[]= {5, 3, 4};
+ char *value= "we the people";
+ size_t value_length= strlen("we the people");
+ unsigned int x;
+ memcached_result_st results_obj;
+ memcached_result_st *results;
+ unsigned int set= 1;
+
+ rc= memcached_flush(memc, 0);
+ assert(rc == MEMCACHED_SUCCESS);
+
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, &set);
+
+ 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);
+
+ results= memcached_result_create(memc, &results_obj);
+
+ results= memcached_fetch_result(memc, &results_obj, &rc);
+ assert(results);
+ assert(results->cas);
+ assert(rc == MEMCACHED_SUCCESS);
+ 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 cas_test(memcached_st *memc)
{
memcached_return rc;
size_t value_length= strlen("we the people");
memcached_result_st results_obj;
memcached_result_st *results;
+ unsigned int set= 1;
rc= memcached_flush(memc, 0);
assert(rc == MEMCACHED_SUCCESS);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, &set);
+
rc= memcached_set(memc, key, strlen(key),
value, strlen(value),
(time_t)0, (uint16_t)0);
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")));
test_st version_1_2_3[] ={
{"append", 0, append_test },
{"prepend", 0, prepend_test },
-// {"cas", 0, cas_test },
+ {"cas", 0, cas_test },
+ {"cas2", 0, cas2_test },
{"append_binary", 0, append_binary_test },
{0, 0, 0}
};