#include <memcached.h>
#include "common.h"
+/* Protoypes (static) */
+static memcached_return server_add(memcached_st *ptr, char *hostname,
+ unsigned int port,
+ memcached_connection type);
+
+#define MEMCACHED_WHEEL_SIZE 1024
+#define MEMCACHED_STRIDE 4
+static void rebalance_wheel(memcached_st *ptr)
+{
+ unsigned int x;
+ unsigned int y;
+ unsigned int latch;
+
+ /* Seed the Wheel */
+ memset(ptr->wheel, 0, sizeof(unsigned int) * MEMCACHED_WHEEL_SIZE);
+
+ for (latch= y= x= 0; x < MEMCACHED_WHEEL_SIZE; x++, latch++)
+ {
+ if (latch == MEMCACHED_STRIDE)
+ {
+ y++;
+ if (y == ptr->number_of_hosts)
+ y= 0;
+ latch= 0;
+ }
+
+ ptr->wheel[x]= y;
+ }
+}
+
+static 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);
+ host->root= ptr ? ptr : NULL;
+ host->port= port;
+ host->fd= -1;
+ host->type= type;
+ host->read_ptr= host->read_buffer;
+ host->sockaddr_inited= MEMCACHED_NOT_ALLOCATED;
+}
+
+void server_list_free(memcached_st *ptr, memcached_server_st *servers)
+{
+ unsigned int x;
+
+ if (servers == NULL)
+ return;
+
+ for (x= 0; x < servers->count; x++)
+ if (servers[x].address_info)
+ freeaddrinfo(servers[x].address_info);
+
+ if (ptr && ptr->call_free)
+ ptr->call_free(ptr, servers);
+ else
+ free(servers);
+}
+
memcached_return memcached_server_push(memcached_st *ptr, memcached_server_st *list)
{
unsigned int x;
- unsigned int count;
+ uint16_t count;
memcached_server_st *new_host_list;
if (!list)
return MEMCACHED_SUCCESS;
- for (count= 0; list[count].hostname; count++);
+ count= list[0].count;
- new_host_list=
- (memcached_server_st *)realloc(ptr->hosts,
- sizeof(memcached_server_st) * (count + ptr->number_of_hosts + 1));
+ if (ptr->call_realloc)
+ new_host_list=
+ (memcached_server_st *)ptr->call_realloc(ptr, ptr->hosts,
+ sizeof(memcached_server_st) * (count + ptr->number_of_hosts));
+ else
+ new_host_list=
+ (memcached_server_st *)realloc(ptr->hosts,
+ sizeof(memcached_server_st) * (count + ptr->number_of_hosts));
if (!new_host_list)
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
ptr->hosts= new_host_list;
- for (x= 0; list[x].hostname; x++)
+ for (x= 0; x < count; x++)
{
- ptr->hosts[ptr->number_of_hosts].hostname= strdup(list[x].hostname);
- ptr->hosts[ptr->number_of_hosts].port= list[x].port;
- ptr->hosts[ptr->number_of_hosts].fd= list[x].fd;
+ WATCHPOINT_ASSERT(list[x].hostname[0] != 0);
+ host_reset(ptr, &ptr->hosts[ptr->number_of_hosts], list[x].hostname,
+ list[x].port, list[x].type);
ptr->number_of_hosts++;
}
- memset(&ptr->hosts[ptr->number_of_hosts], 0, sizeof(memcached_server_st));
+ ptr->hosts[0].count= ptr->number_of_hosts;
+
+ rebalance_wheel(ptr);
return MEMCACHED_SUCCESS;
}
-memcached_return memcached_server_add(memcached_st *ptr, char *hostname, unsigned int port)
+memcached_return memcached_server_add_unix_socket(memcached_st *ptr, char *filename)
{
- memcached_server_st *new_host_list;
- char *new_hostname;
- LIBMEMCACHED_MEMCACHED_SERVER_ADD_START();
+ if (!filename)
+ return MEMCACHED_FAILURE;
+
+ return server_add(ptr, filename, 0, MEMCACHED_CONNECTION_UNIX_SOCKET);
+}
+memcached_return memcached_server_add_udp(memcached_st *ptr,
+ char *hostname,
+ unsigned int port)
+{
if (!port)
port= MEMCACHED_DEFAULT_PORT;
if (!hostname)
hostname= "localhost";
+ return server_add(ptr, hostname, port, MEMCACHED_CONNECTION_UDP);
+}
- if (ptr->number_of_hosts)
- {
- new_host_list= (memcached_server_st *)realloc(ptr->hosts,
- sizeof(memcached_server_st) * (ptr->number_of_hosts+1));
- if (!new_host_list)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- memset(&new_host_list[ptr->number_of_hosts], 0, sizeof(memcached_server_st));
- }
- else
- {
- new_host_list=
- (memcached_server_st *)malloc(sizeof(memcached_server_st) * 2);
- if (!new_host_list)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- memset(new_host_list, 0, sizeof(memcached_server_st) * 2);
- }
+memcached_return memcached_server_add(memcached_st *ptr,
+ char *hostname,
+ unsigned int port)
+{
+ if (!port)
+ port= MEMCACHED_DEFAULT_PORT;
- ptr->hosts= new_host_list;
+ if (!hostname)
+ hostname= "localhost";
+
+ return server_add(ptr, hostname, port, MEMCACHED_CONNECTION_TCP);
+}
+
+static memcached_return server_add(memcached_st *ptr, char *hostname,
+ unsigned int port,
+ memcached_connection type)
+{
+ memcached_server_st *new_host_list;
+ LIBMEMCACHED_MEMCACHED_SERVER_ADD_START();
- new_hostname=
- (char *)malloc(sizeof(char) * (strlen(hostname)+1));
- if (!new_hostname)
+ if (ptr->call_realloc)
+ new_host_list= (memcached_server_st *)ptr->call_realloc(ptr, ptr->hosts,
+ sizeof(memcached_server_st) * (ptr->number_of_hosts+1));
+ else
+ new_host_list= (memcached_server_st *)realloc(ptr->hosts,
+ sizeof(memcached_server_st) * (ptr->number_of_hosts+1));
+ if (new_host_list == NULL)
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- memset(new_hostname, 0, strlen(hostname)+1);
- memcpy(new_hostname, hostname, strlen(hostname));
- ptr->hosts[ptr->number_of_hosts].hostname= new_hostname;
- ptr->hosts[ptr->number_of_hosts].port= port;
- ptr->hosts[ptr->number_of_hosts].fd= -1;
+ ptr->hosts= new_host_list;
+
+ host_reset(ptr, &ptr->hosts[ptr->number_of_hosts], hostname, port, type);
ptr->number_of_hosts++;
+ ptr->hosts[0].count++;
+
+ rebalance_wheel(ptr);
LIBMEMCACHED_MEMCACHED_SERVER_ADD_END();
{
unsigned int count;
memcached_server_st *new_host_list;
- char *new_hostname;
- if (!hostname)
- return ptr;
+ if (hostname == NULL || error == NULL)
+ return NULL;
if (!port)
port= MEMCACHED_DEFAULT_PORT;
- /* Always count so that we keep a free host at the end */
- if (ptr)
+ /* Increment count for hosts */
+ count= 1;
+ if (ptr != NULL)
{
- for (count= 0; ptr[count].hostname; count++);
- count+= 2;
- new_host_list= (memcached_server_st *)realloc(ptr, sizeof(memcached_server_st) * count);
- if (!new_host_list)
- goto error;
- memset(&new_host_list[count-1], 0, sizeof(memcached_server_st));
- }
- else
+ count+= ptr[0].count;
+ }
+
+ new_host_list= (memcached_server_st *)realloc(ptr, sizeof(memcached_server_st) * count);
+ if (!new_host_list)
{
- count= 2;
- new_host_list= (memcached_server_st *)malloc(sizeof(memcached_server_st) * count);
- if (!new_host_list)
- goto error;
- memset(new_host_list, 0, sizeof(memcached_server_st) * 2);
+ *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return NULL;
}
- new_hostname= strdup(hostname);
+ host_reset(NULL, &new_host_list[count-1], hostname, port, MEMCACHED_CONNECTION_TCP);
- if (!new_hostname)
- goto error;
+ /* Backwards compatibility hack */
+ new_host_list[0].count++;
- new_host_list[count-2].hostname= new_hostname;
- new_host_list[count-2].port= port;
- new_host_list[count-2].fd= -1;
*error= MEMCACHED_SUCCESS;
return new_host_list;
-error:
- *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- return NULL;
}
unsigned int memcached_server_list_count(memcached_server_st *ptr)
{
- unsigned int x;
+ if (ptr == NULL)
+ return 0;
- for (x= 0; ptr[x].hostname; x++);
-
- return x;
+ return ptr[0].count;
}
void memcached_server_list_free(memcached_server_st *ptr)
{
- unsigned int x;
-
- for (x= 0; ptr[x].hostname; x++)
- free(ptr[x].hostname);
-
- free(ptr);
+ server_list_free(NULL, ptr);
}