* Cleanup compile warnings.
* Fix issues in partitioning by keys.
+ * Fixed "fail case" to make sure when calling memcached_clone() no
+ memcached_st is over written.
+ * New memcached_server_by_key() method for finding a server from
+ a key.
+ * memcached_server_free() was added for freeing server structures.
+
0.23 Sun Sep 7 08:13:59 PDT 2008
* Added strings.h header for Solaris 9
(or initialized). On an allocation failure, it returns NULL.
memcached_clone() returns a pointer to the memcached_st that was created
-(or initialized). On an allocation failure, it returns NULL.
+(or initialized). On an allocation failure, it returns NULL. If you pass in
+a preallocated structure it must be cleared first (aka memset()).
=head1 HOME
memcached_server_push (memcached_st *ptr,
memcached_server_st *list);
+ memcached_server_st *
+ memcached_server_by_key (memcached_st *ptr,
+ const char *key, size_t key_length,
+ memcached_return *error);
+
=head1 DESCRIPTION
libmemcached(3) performs operations on a list of hosts. The order of these
copy is made of structure so the list provided (and any operations on
the list) are not saved.
+memcached_server_by_key() allows you to provide a key and retrieve the
+server which would be used for assignment. This structure is cloned
+from its original structure and must be freed. If NULL is returned you
+should consult *error. The returning structure should be freed with
+memcached_server_free().
+
=head1 RETURN
Varies, see particular functions.
extern uint64_t ntohll(uint64_t);
extern uint64_t htonll(uint64_t);
+void host_reset(memcached_st *ptr, memcached_server_st *host,
+ char *hostname, unsigned int port,
+ memcached_connection type);
+
#endif /* __COMMON_H__ */
}
/*
- clone is the destination, while ptr is the structure to clone.
- If ptr is NULL the call is the same as if a memcached_create() was
+ clone is the destination, while source is the structure to clone.
+ If source is NULL the call is the same as if a memcached_create() was
called.
*/
-memcached_st *memcached_clone(memcached_st *clone, memcached_st *ptr)
+memcached_st *memcached_clone(memcached_st *clone, memcached_st *source)
{
memcached_return rc= MEMCACHED_SUCCESS;
memcached_st *new_clone;
- if (ptr == NULL)
+ if (source == NULL)
return memcached_create(clone);
- if (ptr->is_allocated == MEMCACHED_USED)
+ if (clone && clone->is_allocated == MEMCACHED_USED)
{
- WATCHPOINT_ASSERT(0);
return NULL;
}
if (new_clone == NULL)
return NULL;
- if (ptr->hosts)
- rc= memcached_server_push(new_clone, ptr->hosts);
+ if (source->hosts)
+ rc= memcached_server_push(new_clone, source->hosts);
if (rc != MEMCACHED_SUCCESS)
{
}
- new_clone->flags= ptr->flags;
- new_clone->send_size= ptr->send_size;
- new_clone->recv_size= ptr->recv_size;
- new_clone->poll_timeout= ptr->poll_timeout;
- new_clone->connect_timeout= ptr->connect_timeout;
- new_clone->retry_timeout= ptr->retry_timeout;
- new_clone->distribution= ptr->distribution;
- new_clone->hash= ptr->hash;
- new_clone->hash_continuum= ptr->hash_continuum;
- new_clone->user_data= ptr->user_data;
-
- new_clone->snd_timeout= ptr->snd_timeout;
- new_clone->rcv_timeout= ptr->rcv_timeout;
-
- new_clone->on_clone= ptr->on_clone;
- new_clone->on_cleanup= ptr->on_cleanup;
- new_clone->call_free= ptr->call_free;
- new_clone->call_malloc= ptr->call_malloc;
- new_clone->call_realloc= ptr->call_realloc;
- new_clone->get_key_failure= ptr->get_key_failure;
- new_clone->delete_trigger= ptr->delete_trigger;
-
- if (ptr->prefix_key[0] != 0)
+ new_clone->flags= source->flags;
+ new_clone->send_size= source->send_size;
+ new_clone->recv_size= source->recv_size;
+ new_clone->poll_timeout= source->poll_timeout;
+ new_clone->connect_timeout= source->connect_timeout;
+ new_clone->retry_timeout= source->retry_timeout;
+ new_clone->distribution= source->distribution;
+ new_clone->hash= source->hash;
+ new_clone->hash_continuum= source->hash_continuum;
+ new_clone->user_data= source->user_data;
+
+ new_clone->snd_timeout= source->snd_timeout;
+ new_clone->rcv_timeout= source->rcv_timeout;
+
+ 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->get_key_failure= source->get_key_failure;
+ new_clone->delete_trigger= source->delete_trigger;
+
+ if (source->prefix_key[0] != 0)
{
- strcpy(new_clone->prefix_key, ptr->prefix_key);
- new_clone->prefix_key_length= ptr->prefix_key_length;
+ strcpy(new_clone->prefix_key, source->prefix_key);
+ new_clone->prefix_key_length= source->prefix_key_length;
}
rc= run_distribution(new_clone);
return NULL;
}
- if (ptr->on_clone)
- ptr->on_clone(ptr, new_clone);
+ if (source->on_clone)
+ source->on_clone(source, new_clone);
return new_clone;
}
memcached_callback flag,
memcached_return *error);
-memcached_return memcached_server_cursor(memcached_st *ptr,
- memcached_server_function *callback,
- void *context,
- unsigned int number_of_callbacks);
-
#ifdef __cplusplus
}
return MEMCACHED_SUCCESS;
}
-static void host_reset(memcached_st *ptr, memcached_server_st *host,
- char *hostname, unsigned int port,
- memcached_connection type)
+void host_reset(memcached_st *ptr, memcached_server_st *host,
+ char *hostname, unsigned int port,
+ memcached_connection type)
{
memset(host, 0, sizeof(memcached_server_st));
strncpy(host->hostname, hostname, MEMCACHED_MAX_HOST_LENGTH - 1);
/* in case of death shutdown to avoid blocking at close() */
r= shutdown(ptr->fd, SHUT_RDWR);
- WATCHPOINT_ASSERT(r == 0);
+
+#ifdef HAVE_DEBUG
+ if (r && errno != ENOTCONN)
+ {
+ WATCHPOINT_ERRNO(errno);
+ WATCHPOINT_ASSERT(errno);
+ }
+#endif
r= close(ptr->fd);
WATCHPOINT_ASSERT(r == 0);
+/*
+ This is a partial implementation for fetching/creating memcached_server_st objects.
+*/
#include "common.h"
+memcached_server_st *memcached_server_create(memcached_st *memc, memcached_server_st *ptr)
+{
+ if (ptr == NULL)
+ {
+ ptr= (memcached_server_st *)malloc(sizeof(memcached_server_st));
+
+ if (!ptr)
+ return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+
+ memset(ptr, 0, sizeof(memcached_server_st));
+ ptr->is_allocated= MEMCACHED_ALLOCATED;
+ }
+ else
+ {
+ memset(ptr, 0, sizeof(memcached_server_st));
+ }
+
+ ptr->root= memc;
+
+ return ptr;
+}
+
+void memcached_server_free(memcached_server_st *ptr)
+{
+ if (ptr->is_allocated == MEMCACHED_ALLOCATED)
+ {
+ if (ptr->root && ptr->root->call_free)
+ ptr->root->call_free(ptr->root, ptr);
+ else
+ free(ptr);
+ }
+ else
+ ptr->is_allocated= MEMCACHED_USED;
+}
+
+/*
+ If we do not have a valid object to clone from, we toss an error.
+*/
+memcached_server_st *memcached_server_clone(memcached_server_st *clone, memcached_server_st *ptr)
+{
+ memcached_server_st *new_clone;
+
+ /* We just do a normal create if ptr is missing */
+ if (ptr == NULL)
+ return NULL;
+
+ if (clone && clone->is_allocated == MEMCACHED_USED)
+ {
+ WATCHPOINT_ASSERT(0);
+ return NULL;
+ }
+
+ new_clone= memcached_server_create(ptr->root, clone);
+
+ if (new_clone == NULL)
+ return NULL;
+
+ new_clone->root= ptr->root;
+
+ host_reset(new_clone->root, new_clone,
+ ptr->hostname, ptr->port,
+ ptr->type);
+
+ return new_clone;
+}
+
memcached_return memcached_server_cursor(memcached_st *ptr,
memcached_server_function *callback,
void *context,
return MEMCACHED_SUCCESS;
}
+
+memcached_server_st *memcached_server_by_key(memcached_st *ptr, const char *key, size_t key_length, memcached_return *error)
+{
+ uint32_t server_key;
+
+ unlikely (key_length == 0)
+ {
+ *error= MEMCACHED_NO_KEY_PROVIDED;
+ return NULL;
+ }
+
+ unlikely (ptr->number_of_hosts == 0)
+ {
+ *error= MEMCACHED_NO_SERVERS;
+ return NULL;
+ }
+
+ if ((ptr->flags & MEM_VERIFY_KEY) && (memcachd_key_test((char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+ {
+ *error= MEMCACHED_BAD_KEY_PROVIDED;
+ return NULL;
+ }
+
+ server_key= memcached_generate_hash(ptr, key, key_length);
+
+ return memcached_server_clone(NULL, &ptr->hosts[server_key]);
+
+}
#endif
struct memcached_server_st {
+ memcached_allocated is_allocated;
char hostname[MEMCACHED_MAX_HOST_LENGTH];
unsigned int port;
int fd;
#define memcached_server_list(A) (A)->hosts
#define memcached_server_response_count(A) (A)->cursor_active
+memcached_return memcached_server_cursor(memcached_st *ptr,
+ memcached_server_function *callback,
+ void *context,
+ unsigned int number_of_callbacks);
+
+memcached_server_st *memcached_server_by_key(memcached_st *ptr, const char *key,
+ size_t key_length, memcached_return *error);
+
+/* These should not currently be used by end users */
+memcached_server_st *memcached_server_create(memcached_st *memc, memcached_server_st *ptr);
+void memcached_server_free(memcached_server_st *ptr);
+memcached_server_st *memcached_server_clone(memcached_server_st *clone, memcached_server_st *ptr);
+
#ifdef __cplusplus
}
{
memcached_st declared_clone;
memcached_st *clone;
+ memset(&declared_clone, 0 , sizeof(memcached_st));
clone= memcached_clone(&declared_clone, NULL);
assert(clone);
memcached_free(clone);
{
memcached_st declared_clone;
memcached_st *clone;
+ memset(&declared_clone, 0 , sizeof(memcached_st));
clone= memcached_clone(&declared_clone, memc);
assert(clone);
memcached_free(clone);