0.38
+ * Modified memcached_set_memory_allocators() so that it requires a context
+ pointer.
+
* memcached_clone() now runs 5 times faster.
* Functions used for callbacks are now given const memcached_st.
MEMORY_ALLOCATORS_PAGES= \
memcached_get_memory_allocators.pop \
- memcached_set_memory_allocators.pop
+ memcached_set_memory_allocators.pop \
+ memcached_set_memory_allocators_context.pop
BUILT_SOURCES += ${MEMORY_ALLOCATORS_PAGES}
POOL_PAGES= \
=head1 NAME
-memcached_set_memory_allocators, memcached_get_memory_allocators - Manage memory allocator functions
+memcached_set_memory_allocators, memcached_get_memory_allocators, memcached_set_memory_allocators_context - Manage memory allocator functions
=head1 LIBRARY
memcached_malloc_fn mem_malloc,
memcached_free_fn mem_free,
memcached_realloc_fn mem_realloc,
- memcached_calloc_fn mem_calloc);
+ memcached_calloc_fn mem_calloc,
+ void *context);
void
memcached_get_memory_allocators (memcached_st *ptr,
memcached_realloc_fn *mem_realloc,
memcached_calloc_fn *mem_calloc);
+ void *
+ memcached_get_memory_allocators_context(const memcached_st *ptr);
+
void *
- (*memcached_malloc_fn) (memcached_st *ptr, const size_t size);
+ (*memcached_malloc_fn) (memcached_st *ptr, const size_t size,
+ void *context);
void *
(*memcached_realloc_fn) (memcached_st *ptr, void *mem,
- const size_t size);
+ const size_t size,
+ void *context);
void
- (*memcached_free_fn) (memcached_st *ptr, void *mem);
+ (*memcached_free_fn) (memcached_st *ptr, void *mem,
+ void *context);
void *
- (*memcached_calloc_fn) (memcached_st *ptr, size_t nelem,
- const size_t elsize);
+ (*memcached_calloc_fn) (memcached_st *ptr,
+ size_t nelem,
+ const size_t elsize,
+ void *context);
=head1 DESCRIPTION
memcached_get_memory_allocators() is used to get the currently used memory
allocators by a mamcached handle.
+memcached_get_memory_allocators_context() returns the void * that was
+passed in during the call to memcached_set_memory_allocators().
+
The first argument to the memory allocator functions is a pointer to a
-memcached structure, and you may use the memcached_set_user_data() and
-memcached_get_user_data() to store a user-specific value to each memcached
-structure.
+memcached structure, the is passed as const and you will need to clone
+it in order to make use of any operation which would modify it.
+
+=head1 NOTES
+
+In version 0.38 all functions were modified to have a context void pointer
+passed to them. This was so that customer allocators could have their
+own space for memory.
=head1 RETURN
=head1 AUTHOR
Trond Norbye, E<lt>trond.norbye@gmail.comE<gt>
+Brian Aker, E<lt>brian@tangent.orf<gt>
=head1 SEE ALSO
#include "common.h"
-void libmemcached_free(const memcached_st *ptr, void *mem)
+void _libmemcached_free(const memcached_st *ptr, void *mem, void *context)
{
(void) ptr;
+ (void) context;
free(mem);
}
-void *libmemcached_malloc(const memcached_st *ptr, size_t size)
+void *_libmemcached_malloc(const memcached_st *ptr, size_t size, void *context)
{
(void) ptr;
+ (void) context;
return malloc(size);
}
-void *libmemcached_realloc(const memcached_st *ptr, void *mem, size_t size)
+void *_libmemcached_realloc(const memcached_st *ptr, void *mem, size_t size, void *context)
{
(void) ptr;
+ (void) context;
return realloc(mem, size);
}
-void *libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size)
+void *_libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size, void *context)
{
- if (ptr->call_malloc != libmemcached_malloc)
+ if (ptr->allocators.malloc != _libmemcached_malloc)
{
- void *ret = libmemcached_malloc(ptr, nelem * size);
+ void *ret = _libmemcached_malloc(ptr, nelem * size, context);
if (ret != NULL)
memset(ret, 0, nelem * size);
return calloc(nelem, size);
}
+static const struct _allocators_st global_default_allocator= {
+ .calloc= _libmemcached_calloc,
+ .context= NULL,
+ .free= _libmemcached_free,
+ .malloc= _libmemcached_malloc,
+ .realloc= _libmemcached_realloc
+};
+
+struct _allocators_st memcached_allocators_return_default(void)
+{
+ return global_default_allocator;
+}
+
memcached_return_t memcached_set_memory_allocators(memcached_st *ptr,
memcached_malloc_fn mem_malloc,
memcached_free_fn mem_free,
memcached_realloc_fn mem_realloc,
- memcached_calloc_fn mem_calloc)
+ memcached_calloc_fn mem_calloc,
+ void *context)
{
/* All should be set, or none should be set */
if (mem_malloc == NULL && mem_free == NULL && mem_realloc == NULL && mem_calloc == NULL)
{
- ptr->call_malloc= libmemcached_malloc;
- ptr->call_free= libmemcached_free;
- ptr->call_realloc= libmemcached_realloc;
- ptr->call_calloc= libmemcached_calloc;
+ ptr->allocators= memcached_allocators_return_default();
}
else if (mem_malloc == NULL || mem_free == NULL || mem_realloc == NULL || mem_calloc == NULL)
{
}
else
{
- ptr->call_malloc= mem_malloc;
- ptr->call_free= mem_free;
- ptr->call_realloc= mem_realloc;
- ptr->call_calloc= mem_calloc;
+ ptr->allocators.malloc= mem_malloc;
+ ptr->allocators.free= mem_free;
+ ptr->allocators.realloc= mem_realloc;
+ ptr->allocators.calloc= mem_calloc;
+ ptr->allocators.context= context;
}
return MEMCACHED_SUCCESS;
}
+void *memcached_get_memory_allocators_context(const memcached_st *ptr)
+{
+ return ptr->allocators.context;
+}
+
void memcached_get_memory_allocators(const memcached_st *ptr,
memcached_malloc_fn *mem_malloc,
memcached_free_fn *mem_free,
memcached_realloc_fn *mem_realloc,
memcached_calloc_fn *mem_calloc)
{
- *mem_malloc= ptr->call_malloc;
- *mem_free= ptr->call_free;
- *mem_realloc= ptr->call_realloc;
- *mem_calloc= ptr->call_calloc;
+ *mem_malloc= ptr->allocators.malloc;
+ *mem_free= ptr->allocators.free;
+ *mem_realloc= ptr->allocators.realloc;
+ *mem_calloc= ptr->allocators.calloc;
}
memcached_malloc_fn mem_malloc,
memcached_free_fn mem_free,
memcached_realloc_fn mem_realloc,
- memcached_calloc_fn mem_calloc);
+ memcached_calloc_fn mem_calloc,
+ void *context);
LIBMEMCACHED_API
void memcached_get_memory_allocators(const memcached_st *ptr,
memcached_realloc_fn *mem_realloc,
memcached_calloc_fn *mem_calloc);
+LIBMEMCACHED_API
+void *memcached_get_memory_allocators_context(const memcached_st *ptr);
+
+LIBMEMCACHED_LOCAL
+void _libmemcached_free(const memcached_st *ptr, void *mem, void *context);
+
LIBMEMCACHED_LOCAL
-void libmemcached_free(const memcached_st *ptr, void *mem);
+void *_libmemcached_malloc(const memcached_st *ptr, const size_t size, void *context);
LIBMEMCACHED_LOCAL
-void *libmemcached_malloc(const memcached_st *ptr, const size_t size);
+void *_libmemcached_realloc(const memcached_st *ptr, void *mem, const size_t size, void *context);
LIBMEMCACHED_LOCAL
-void *libmemcached_realloc(const memcached_st *ptr, void *mem, const size_t size);
+void *_libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size, void *context);
LIBMEMCACHED_LOCAL
-void *libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size);
+struct _allocators_st memcached_allocators_return_default(void);
#ifdef __cplusplus
#endif
}
+static inline void libmemcached_free(const memcached_st *ptr, void *mem)
+{
+ ptr->allocators.free(ptr, mem, ptr->allocators.context);
+}
+
+static inline void *libmemcached_malloc(const memcached_st *ptr, const size_t size)
+{
+ return ptr->allocators.malloc(ptr, size, ptr->allocators.context);
+}
+
+static inline void *libmemcached_realloc(const memcached_st *ptr, void *mem, const size_t size)
+{
+ return ptr->allocators.realloc(ptr, mem, size, ptr->allocators.context);
+}
+
+static inline void *libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size)
+{
+ return ptr->allocators.calloc(ptr, nelem, size, ptr->allocators.context);
+}
+
+
#endif /* LIBMEMCACHED_COMMON_H */
uint32_t* hash;
bool* dead_servers;
- hash= ptr->call_malloc(ptr, sizeof(uint32_t) * number_of_keys);
- dead_servers= ptr->call_calloc(ptr, memcached_server_count(ptr), sizeof(bool));
+ hash= libmemcached_malloc(ptr, sizeof(uint32_t) * number_of_keys);
+ dead_servers= libmemcached_calloc(ptr, memcached_server_count(ptr), sizeof(bool));
if (hash == NULL || dead_servers == NULL)
{
- ptr->call_free(ptr, hash);
- ptr->call_free(ptr, dead_servers);
+ libmemcached_free(ptr, hash);
+ libmemcached_free(ptr, dead_servers);
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
}
rc= replication_binary_mget(ptr, hash, dead_servers, keys,
key_length, number_of_keys);
- ptr->call_free(ptr, hash);
- ptr->call_free(ptr, dead_servers);
+ libmemcached_free(ptr, hash);
+ libmemcached_free(ptr, dead_servers);
return MEMCACHED_SUCCESS;
}
{
memcached_continuum_item_st *new_ptr;
- new_ptr= ptr->call_realloc(ptr, ptr->continuum,
- sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);
+ new_ptr= libmemcached_realloc(ptr, ptr->continuum,
+ sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);
if (new_ptr == 0)
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
return MEMCACHED_SUCCESS;
count= memcached_servers_count(list);
- new_host_list= ptr->call_realloc(ptr, memcached_server_list(ptr),
- sizeof(memcached_server_instance_st) * (count + memcached_server_count(ptr)));
+ new_host_list= libmemcached_realloc(ptr, memcached_server_list(ptr),
+ sizeof(memcached_server_instance_st) * (count + memcached_server_count(ptr)));
if (! new_host_list)
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
|| ( (type == MEMCACHED_CONNECTION_UDP) && (! ptr->flags.use_udp) ) )
return MEMCACHED_INVALID_HOST_PROTOCOL;
- new_host_list= ptr->call_realloc(ptr, memcached_server_list(ptr),
- sizeof(memcached_server_instance_st) * (ptr->number_of_hosts + 1));
+ new_host_list= libmemcached_realloc(ptr, memcached_server_list(ptr),
+ sizeof(memcached_server_instance_st) * (ptr->number_of_hosts + 1));
if (new_host_list == NULL)
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
self->continuum= NULL;
- memcached_set_memory_allocators(self, NULL, NULL, NULL, NULL);
+ memcached_set_memory_allocators(self, NULL, NULL, NULL, NULL, NULL);
+ self->allocators= memcached_allocators_return_default();
self->on_clone= NULL;
self->on_cleanup= NULL;
if (ptr)
{
- ptr->call_free(ptr, servers);
+ libmemcached_free(ptr, servers);
}
else
{
ptr->on_cleanup(ptr);
if (ptr->continuum)
- ptr->call_free(ptr, ptr->continuum);
+ libmemcached_free(ptr, ptr->continuum);
if (memcached_is_allocated(ptr))
{
- ptr->call_free(ptr, ptr);
+ libmemcached_free(ptr, ptr);
}
}
new_clone->on_clone= source->on_clone;
new_clone->on_cleanup= source->on_cleanup;
- new_clone->call_free= source->call_free;
- new_clone->call_malloc= source->call_malloc;
- new_clone->call_realloc= source->call_realloc;
- new_clone->call_calloc= source->call_calloc;
+
+ new_clone->allocators= source->allocators;
+
new_clone->get_key_failure= source->get_key_failure;
new_clone->delete_trigger= source->delete_trigger;
new_clone->server_failure_limit= source->server_failure_limit;
memcached_result_st result;
memcached_continuum_item_st *continuum; // Ketama
- memcached_free_fn call_free;
- memcached_malloc_fn call_malloc;
- memcached_realloc_fn call_realloc;
- memcached_calloc_fn call_calloc;
+ struct _allocators_st {
+ memcached_calloc_fn calloc;
+ memcached_free_fn free;
+ memcached_malloc_fn malloc;
+ memcached_realloc_fn realloc;
+ void *context;
+ } allocators;
memcached_clone_fn on_clone;
memcached_cleanup_fn on_cleanup;
memory in the struct, which is important, for something that
rarely should happen?
*/
- rel_ptr= (char *)ptr->root->call_realloc(ptr->root,
- ptr->cached_server_error,
- (size_t) (endptr - startptr + 1));
+ rel_ptr= (char *)libmemcached_realloc(ptr->root,
+ ptr->cached_server_error,
+ (size_t) (endptr - startptr + 1));
if (rel_ptr == NULL)
{
}
else
{
- ptr= memc->call_calloc(memc, 1, sizeof(memcached_result_st));
+ ptr= libmemcached_calloc(memc, 1, sizeof(memcached_result_st));
if (ptr == NULL)
return NULL;
if (memcached_is_allocated(ptr))
{
- if (ptr->root != NULL)
- {
- ptr->root->call_free(ptr->root, ptr);
- }
- else
- {
- free(ptr);
- }
+ WATCHPOINT_ASSERT(ptr->root); // Without a root, that means that result was not properly initialized.
+ libmemcached_free(ptr->root, ptr);
}
else
{
{
if (self == NULL)
{
- self= (memcached_server_st *)memc->call_malloc(memc, sizeof(memcached_server_st));
+ self= (memcached_server_st *)libmemcached_malloc(memc, sizeof(memcached_server_st));
if (! self)
return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
if (memcached_is_allocated(self))
{
- self->root->call_free(self->root, self);
+ libmemcached_free(self->root, self);
}
else
{
return NULL;
}
- ret= ptr->call_malloc(ptr, (size_t) (length + 1));
+ ret= libmemcached_malloc(ptr, (size_t) (length + 1));
memcpy(ret, buffer, (size_t) length);
ret[length]= '\0';
return NULL;
}
- stats= ptr->call_calloc(ptr, memcached_server_count(ptr), sizeof(memcached_stat_st));
+ stats= libmemcached_calloc(ptr, memcached_server_count(ptr), sizeof(memcached_stat_st));
stats->root= ptr;
We make a copy of the keys since at some point in the not so distant future
we will add support for "found" keys.
*/
-char ** memcached_stat_get_keys(memcached_st *ptr, memcached_stat_st *memc_stat,
+char ** memcached_stat_get_keys(memcached_st *ptr,
+ memcached_stat_st *memc_stat,
memcached_return_t *error)
{
- (void) memc_stat;
char **list;
size_t length= sizeof(memcached_stat_keys);
- list= ptr->call_malloc(ptr, length);
+ (void)memc_stat;
+#if 0
+ list= libmemcached_malloc(memc_stat ? memc_stat->root : ptr, length);
+#endif
+ list= libmemcached_malloc(ptr, length);
if (!list)
{
if (memc_stat->root)
{
- memc_stat->root->call_free(ptr, memc_stat);
+ libmemcached_free(memc_stat->root, memc_stat);
}
else if (ptr)
{
- ptr->call_free(ptr, memc_stat);
+ libmemcached_free(ptr, memc_stat);
}
else
{
if (new_size < need)
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- new_value= string->root->call_realloc(string->root, string->string, new_size);
+ new_value= libmemcached_realloc(string->root, string->string, new_size);
if (new_value == NULL)
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
}
else
{
- self= memc->call_malloc(memc, sizeof(memcached_string_st));
+ self= libmemcached_malloc(memc, sizeof(memcached_string_st));
if (self == NULL)
{
rc= _string_check(self, initial_size);
if (rc != MEMCACHED_SUCCESS)
{
- memc->call_free(memc, self);
+ libmemcached_free(memc, self);
return NULL;
}
if (memcached_string_length(string) == 0)
return NULL;
- c_ptr= string->root->call_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char));
+ c_ptr= libmemcached_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char));
if (c_ptr == NULL)
return NULL;
if (ptr->string)
{
- ptr->root->call_free(ptr->root, ptr->string);
+ libmemcached_free(ptr->root, ptr->string);
}
if (memcached_is_allocated(ptr))
{
- ptr->root->call_free(ptr->root, ptr);
+ libmemcached_free(ptr->root, ptr);
}
else
{
/**
Memory allocation functions.
*/
-typedef void (*memcached_free_fn)(const memcached_st *ptr, void *mem);
-typedef void *(*memcached_malloc_fn)(const memcached_st *ptr, const size_t size);
-typedef void *(*memcached_realloc_fn)(const memcached_st *ptr, void *mem, const size_t size);
-typedef void *(*memcached_calloc_fn)(const memcached_st *ptr, size_t nelem, const size_t elsize);
+typedef void (*memcached_free_fn)(const memcached_st *ptr, void *mem, void *context);
+typedef void *(*memcached_malloc_fn)(const memcached_st *ptr, const size_t size, void *context);
+typedef void *(*memcached_realloc_fn)(const memcached_st *ptr, void *mem, const size_t size, void *context);
+typedef void *(*memcached_calloc_fn)(const memcached_st *ptr, size_t nelem, const size_t elsize, void *context);
typedef memcached_return_t (*memcached_execute_fn)(const memcached_st *ptr, memcached_result_st *result, void *context);
typedef memcached_return_t (*memcached_server_fn)(const memcached_st *ptr, memcached_server_st *server, void *context);
memc_clone= memcached_clone(NULL, memc);
test_true(memc_clone);
- test_true(memc_clone->call_free == memc->call_free);
- test_true(memc_clone->call_malloc == memc->call_malloc);
- test_true(memc_clone->call_realloc == memc->call_realloc);
- test_true(memc_clone->call_calloc == memc->call_calloc);
+ { // Test allocators
+ test_true(memc_clone->allocators.free == memc->allocators.free);
+ test_true(memc_clone->allocators.malloc == memc->allocators.malloc);
+ test_true(memc_clone->allocators.realloc == memc->allocators.realloc);
+ test_true(memc_clone->allocators.calloc == memc->allocators.calloc);
+ }
+
test_true(memc_clone->connect_timeout == memc->connect_timeout);
test_true(memc_clone->delete_trigger == memc->delete_trigger);
test_true(memc_clone->distribution == memc->distribution);
}
-static void my_free(const memcached_st *ptr __attribute__((unused)), void *mem)
+static void my_free(const memcached_st *ptr __attribute__((unused)), void *mem, void *context)
{
+ (void) context;
#ifdef HARD_MALLOC_TESTS
void *real_ptr= (mem == NULL) ? mem : (void*)((caddr_t)mem - 8);
free(real_ptr);
}
-static void *my_malloc(const memcached_st *ptr __attribute__((unused)), const size_t size)
+static void *my_malloc(const memcached_st *ptr __attribute__((unused)), const size_t size, void *context)
{
+ (void)context;
#ifdef HARD_MALLOC_TESTS
void *ret= malloc(size + 8);
if (ret != NULL)
}
-static void *my_realloc(const memcached_st *ptr __attribute__((unused)), void *mem, const size_t size)
+static void *my_realloc(const memcached_st *ptr __attribute__((unused)), void *mem, const size_t size, void *context)
{
+ (void)context;
#ifdef HARD_MALLOC_TESTS
void *real_ptr= (mem == NULL) ? NULL : (void*)((caddr_t)mem - 8);
void *nmem= realloc(real_ptr, size + 8);
}
-static void *my_calloc(const memcached_st *ptr __attribute__((unused)), size_t nelem, const size_t size)
+static void *my_calloc(const memcached_st *ptr __attribute__((unused)), size_t nelem, const size_t size, void *context)
{
+ (void)context;
#ifdef HARD_MALLOC_TESTS
void *mem= my_malloc(ptr, nelem * size);
if (mem)
{
memcached_return_t rc;
rc= memcached_set_memory_allocators(memc, NULL, my_free,
- my_realloc, my_calloc);
+ my_realloc, my_calloc, NULL);
test_true(rc == MEMCACHED_FAILURE);
rc= memcached_set_memory_allocators(memc, my_malloc, my_free,
- my_realloc, my_calloc);
+ my_realloc, my_calloc, NULL);
memcached_malloc_fn mem_malloc;
memcached_free_fn mem_free;