*
*/
-#include <config.h>
-
#include "libmemcached/common.h"
struct memcached_array_st
{
+ memcached_st *root;
size_t size;
char c_str[];
};
-memcached_array_st *memcached_strcpy(const char *str, size_t str_length)
+memcached_array_st *memcached_array_clone(memcached_st *memc, const memcached_array_st *original)
+{
+ if (! original)
+ return NULL;
+
+ return memcached_strcpy(memc, original->c_str, original->size);
+}
+
+memcached_array_st *memcached_strcpy(memcached_st *memc, const char *str, size_t str_length)
{
- memcached_array_st *array= (struct memcached_array_st *)malloc(sizeof(struct memcached_array_st) +str_length +1);
+ memcached_array_st *array= (struct memcached_array_st *)libmemcached_malloc(memc, sizeof(struct memcached_array_st) +str_length +1);
+
+ if (! array)
+ return NULL;
- array->size= str_length;
+ array->root= memc;
+ array->size= str_length -1; // We don't count the NULL ending
memcpy(array->c_str, str, str_length);
- array->c_str[str_length]= 0;
+ array->c_str[str_length +1]= 0;
return array;
}
void memcached_array_free(memcached_array_st *array)
{
- WATCHPOINT_ASSERT(array);
- if (array)
+ if (! array)
+ return;
+
+ WATCHPOINT_ASSERT(array->root);
+ if (array && array->root)
+ {
+ libmemcached_free(array->root, array);
+ }
+ else if (array)
+ {
free(array);
+ }
+}
+
+size_t memcached_array_size(memcached_array_st *array)
+{
+ if (! array)
+ return 0;
+
+ return array->size;
+}
+
+const char *memcached_array_string(memcached_array_st *array)
+{
+ if (! array)
+ return NULL;
+
+ return array->c_str;
}
#endif
LIBMEMCACHED_LOCAL
-memcached_array_st *memcached_strcpy(const char *str, size_t str_length);
+memcached_array_st *memcached_array_clone(memcached_st *memc, const memcached_array_st *original);
+
+LIBMEMCACHED_LOCAL
+memcached_array_st *memcached_strcpy(memcached_st *memc, const char *str, size_t str_length);
LIBMEMCACHED_LOCAL
void memcached_array_free(memcached_array_st *array);
+LIBMEMCACHED_LOCAL
+size_t memcached_array_size(memcached_array_st *array);
+
+LIBMEMCACHED_LOCAL
+const char *memcached_array_string(memcached_array_st *array);
+
+#ifdef __cplusplus
+#define memcached_print_array(X) static_cast<int>(memcached_array_size(X)), memcached_array_string(X)
+#else
+#define memcached_print_array(X) (int)memcached_array_size((X)), memcached_array_string((X))
+#endif
+
#ifdef __cplusplus
} // extern "C"
*
*/
-#include "common.h"
+#include "libmemcached/common.h"
static memcached_return_t text_incr_decr(memcached_st *ptr,
const char *verb,
int send_length;
send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
"%s %.*s%.*s %" PRIu64 "%s\r\n", verb,
- (int)ptr->prefix_key_length,
- ptr->prefix_key,
+ memcached_print_array(ptr->prefix_key),
(int)key_length, key,
offset, no_reply ? " noreply" : "");
if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
request.message.header.request.magic= PROTOCOL_BINARY_REQ;
request.message.header.request.opcode= cmd;
- request.message.header.request.keylen= htons((uint16_t)(key_length + ptr->prefix_key_length));
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
request.message.header.request.extlen= 20;
request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)(key_length + ptr->prefix_key_length + request.message.header.request.extlen));
+ request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key) +request.message.header.request.extlen));
request.message.body.delta= htonll(offset);
request.message.body.initial= htonll(initial);
request.message.body.expiration= htonl((uint32_t) expiration);
struct libmemcached_io_vector_st vector[]=
{
{ .length= sizeof(request.bytes), .buffer= request.bytes },
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= ptr->prefix_key },
{ .length= key_length, .buffer= key }
};
size_t key_length= strlen(key);
if (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)
- {
- return MEMCACHED_BAD_KEY_PROVIDED;
- }
+ return memcached_set_error(ptr, MEMCACHED_BAD_KEY_PROVIDED, NULL);
- if ((key_length > MEMCACHED_PREFIX_KEY_MAX_SIZE -1)
- || (strncpy(ptr->prefix_key, key, MEMCACHED_PREFIX_KEY_MAX_SIZE) == NULL))
- {
- ptr->prefix_key_length= 0;
- return MEMCACHED_BAD_KEY_PROVIDED;
- }
- else
- {
- ptr->prefix_key_length= key_length;
- }
+ if ((key_length > MEMCACHED_PREFIX_KEY_MAX_SIZE -1))
+ return memcached_set_error(ptr, MEMCACHED_KEY_TOO_BIG, NULL);
+
+ memcached_array_free(ptr->prefix_key);
+ ptr->prefix_key= memcached_strcpy(ptr, (const char *)data, strlen((const char*)data));
+
+ f (! ptr->prefix_key)
+ return memcached_set_error(ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, NULL);
}
else
{
- ptr->prefix_key[0]= 0;
- ptr->prefix_key_length= 0;
+ memcached_array_free(ptr->prefix_key);
+ ptr->prefix_key= NULL;
}
break;
{
case MEMCACHED_CALLBACK_PREFIX_KEY:
{
- if (ptr->prefix_key_length)
+ if (ptr->prefix_key)
{
*error= MEMCACHED_SUCCESS;
- return (void *)ptr->prefix_key;
+ return (void *)memcached_array_string(ptr->prefix_key);
}
else
{
#include "libmemcached/io.h"
#include "libmemcached/do.h"
#include "libmemcached/internal.h"
+#include "libmemcached/array.h"
#include "libmemcached/libmemcached_probes.h"
#include "libmemcached/memcached/protocol_binary.h"
#include "libmemcached/byteorder.h"
}
send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
"delete %.*s%.*s %u%s\r\n",
- (int)ptr->prefix_key_length,
- ptr->prefix_key,
+ memcached_print_array(ptr->prefix_key),
(int) key_length, key,
(uint32_t)expiration,
no_reply ? " noreply" :"" );
{
send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
"delete %.*s%.*s%s\r\n",
- (int)ptr->prefix_key_length,
- ptr->prefix_key,
+ memcached_print_array(ptr->prefix_key),
(int)key_length, key, no_reply ? " noreply" :"");
}
request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
else
request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
- request.message.header.request.keylen= htons((uint16_t)(key_length + ptr->prefix_key_length));
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)(key_length + ptr->prefix_key_length));
+ request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key)));
if (ptr->flags.use_udp && ! flush)
{
struct libmemcached_io_vector_st vector[]=
{
{ .length= sizeof(request.bytes), .buffer= request.bytes},
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
{ .length= key_length, .buffer= key },
};
struct libmemcached_io_vector_st vector[]=
{
{ .length= get_command_length, .buffer= get_command },
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
{ .length= key_length[x], .buffer= keys[x] },
{ .length= 1, .buffer= " " }
};
return vk;
}
- request.message.header.request.keylen= htons((uint16_t)(key_length[x] + ptr->prefix_key_length));
+ request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key)));
request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + ptr->prefix_key_length));
+ request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + memcached_array_size(ptr->prefix_key)));
struct libmemcached_io_vector_st vector[]=
{
{ .length= sizeof(request.bytes), .buffer= request.bytes },
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
{ .length= key_length[x], .buffer= keys[x] }
};
.message.header.request= {
.magic= PROTOCOL_BINARY_REQ,
.opcode= PROTOCOL_BINARY_CMD_GETK,
- .keylen= htons((uint16_t)(key_length[x] + ptr->prefix_key_length)),
+ .keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key))),
.datatype= PROTOCOL_BINARY_RAW_BYTES,
- .bodylen= htonl((uint32_t)(key_length[x] + ptr->prefix_key_length))
+ .bodylen= htonl((uint32_t)(key_length[x] + memcached_array_size(ptr->prefix_key)))
}
};
struct libmemcached_io_vector_st vector[]=
{
{ .length= sizeof(request.bytes), .buffer= request.bytes },
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
{ .length= key_length[x], .buffer= keys[x] }
};
if (ptr->flags.hash_with_prefix_key)
{
- size_t temp_length= ptr->prefix_key_length + key_length;
+ size_t temp_length= memcached_array_size(ptr->prefix_key) + key_length;
char temp[temp_length];
if (temp_length > MEMCACHED_MAX_KEY -1)
return EXIT_SUCCESS;
- strncpy(temp, ptr->prefix_key, ptr->prefix_key_length);
- strncpy(temp + ptr->prefix_key_length, key, key_length);
+ strncpy(temp, memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
+ strncpy(temp + memcached_array_size(ptr->prefix_key), key, key_length);
return generate_hash(ptr, temp, temp_length);
}
self->user_data= NULL;
self->next_distribution_rebuild= 0;
- self->prefix_key_length= 0;
self->number_of_replicas= 0;
hash_ptr= hashkit_create(&self->distribution_hashkit);
if (! hash_ptr)
self->sasl.is_allocated= false;
self->error_messages= NULL;
+ self->prefix_key= NULL;
return true;
}
if (ptr->continuum)
libmemcached_free(ptr, ptr->continuum);
+ memcached_array_free(ptr->prefix_key);
+ ptr->prefix_key= NULL;
+
memcached_error_free(ptr);
if (ptr->sasl.callbacks)
}
- if (source->prefix_key_length)
- {
- strcpy(new_clone->prefix_key, source->prefix_key);
- new_clone->prefix_key_length= source->prefix_key_length;
- }
+ new_clone->prefix_key= memcached_array_clone(new_clone, source->prefix_key);
#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
if (source->sasl.callbacks)
int recv_size;
void *user_data;
time_t next_distribution_rebuild; // Ketama
- size_t prefix_key_length;
uint32_t number_of_replicas;
hashkit_st distribution_hashkit;
memcached_result_st result;
memcached_callback_st *callbacks;
struct memcached_sasl_st sasl;
struct memcached_error_st *error_messages;
- char prefix_key[MEMCACHED_PREFIX_KEY_MAX_SIZE];
+ struct memcached_array_st *prefix_key;
struct {
bool is_allocated:1;
} options;
key= result->item_key;
result->key_length= 0;
- for (prefix_length= ptr->root->prefix_key_length; !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
+ for (prefix_length= memcached_array_size(ptr->root->prefix_key); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
{
if (prefix_length == 0)
{
check_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
"%s %.*s%.*s %u %llu %lu %llu%s\r\n",
storage_op_string(verb),
- (int)ptr->prefix_key_length,
- ptr->prefix_key,
+ memcached_print_array(ptr->prefix_key),
(int)key_length, key, flags,
(unsigned long long)expiration, (unsigned long)value_length,
(unsigned long long)cas,
memcpy(buffer_ptr, command, strlen(command));
/* Copy in the key prefix, switch to the buffer_ptr */
- buffer_ptr= memcpy((buffer_ptr + strlen(command)), ptr->prefix_key, ptr->prefix_key_length);
+ buffer_ptr= memcpy((buffer_ptr + strlen(command)), memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
/* Copy in the key, adjust point if a key prefix was used. */
- buffer_ptr= memcpy(buffer_ptr + (ptr->prefix_key_length ? ptr->prefix_key_length : 0),
+ buffer_ptr= memcpy(buffer_ptr + memcached_array_size(ptr->prefix_key),
key, key_length);
buffer_ptr+= key_length;
buffer_ptr[0]= ' ';
request.message.header.request.magic= PROTOCOL_BINARY_REQ;
request.message.header.request.opcode= get_com_code(verb, noreply);
- request.message.header.request.keylen= htons((uint16_t)(key_length + ptr->prefix_key_length));
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
if (verb == APPEND_OP || verb == PREPEND_OP)
send_length -= 8; /* append & prepend does not contain extras! */
request.message.body.expiration= htonl((uint32_t)expiration);
}
- request.message.header.request.bodylen= htonl((uint32_t) (key_length + ptr->prefix_key_length + value_length +
+ request.message.header.request.bodylen= htonl((uint32_t) (key_length + memcached_array_size(ptr->prefix_key) + value_length +
request.message.header.request.extlen));
if (cas)
struct libmemcached_io_vector_st vector[]=
{
{ .length= send_length, .buffer= request.bytes },
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
{ .length= key_length, .buffer= key },
{ .length= value_length, .buffer= value }
};
/* Test a clean set */
rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, (void *)key);
- test_true(rc == MEMCACHED_SUCCESS);
+ test_true_got(rc == MEMCACHED_SUCCESS, memcached_last_error_message(memc));
value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+ test_true(value);
test_true(memcmp(value, key, 4) == 0);
test_true(rc == MEMCACHED_SUCCESS);
test_true(rc == MEMCACHED_SUCCESS);
value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+ test_false(value);
test_true(rc == MEMCACHED_FAILURE);
/* Now setup for main test */
test_true(rc == MEMCACHED_SUCCESS);
value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+ test_true(value);
test_true(rc == MEMCACHED_SUCCESS);
test_true(memcmp(value, key, 4) == 0);
test_true(rc == MEMCACHED_SUCCESS);
value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+ test_false(value);
test_true(rc == MEMCACHED_FAILURE);
test_true(value == NULL);