New version update
[m6w6/libmemcached] / libmemcached / memcached_hosts.c
1 #include "common.h"
2
3 /* Protoypes (static) */
4 static memcached_return server_add(memcached_st *ptr, char *hostname,
5 unsigned int port,
6 memcached_connection type);
7
8 #define MEMCACHED_WHEEL_SIZE 1024
9 #define MEMCACHED_STRIDE 4
10 static void rebalance_wheel(memcached_st *ptr)
11 {
12 unsigned int x;
13 unsigned int y;
14 unsigned int latch;
15
16 /* Seed the Wheel */
17 memset(ptr->wheel, 0, sizeof(unsigned int) * MEMCACHED_WHEEL_SIZE);
18
19 for (latch= y= x= 0; x < MEMCACHED_WHEEL_SIZE; x++, latch++)
20 {
21 if (latch == MEMCACHED_STRIDE)
22 {
23 y++;
24 if (y == ptr->number_of_hosts)
25 y= 0;
26 latch= 0;
27 }
28
29 ptr->wheel[x]= y;
30 }
31 }
32
33 static int compare_servers(const void *p1, const void *p2)
34 {
35 int return_value;
36 memcached_server_st *a= (memcached_server_st *)p1;
37 memcached_server_st *b= (memcached_server_st *)p2;
38
39 return_value= strcmp(a->hostname, b->hostname);
40
41 if (return_value == 0)
42 {
43 if (a->port > b->port)
44 return_value++;
45 else
46 return_value--;
47 }
48
49 return return_value;
50 }
51
52 static void host_reset(memcached_st *ptr, memcached_server_st *host,
53 char *hostname, unsigned int port,
54 memcached_connection type)
55 {
56 memset(host, 0, sizeof(memcached_server_st));
57 strncpy(host->hostname, hostname, MEMCACHED_MAX_HOST_LENGTH - 1);
58 host->root= ptr ? ptr : NULL;
59 host->port= port;
60 host->fd= -1;
61 host->type= type;
62 host->read_ptr= host->read_buffer;
63 if (ptr)
64 host->next_retry= ptr->retry_timeout;
65 host->sockaddr_inited= MEMCACHED_NOT_ALLOCATED;
66 }
67
68 void server_list_free(memcached_st *ptr, memcached_server_st *servers)
69 {
70 unsigned int x;
71
72 if (servers == NULL)
73 return;
74
75 for (x= 0; x < servers->count; x++)
76 if (servers[x].address_info)
77 freeaddrinfo(servers[x].address_info);
78
79 if (ptr && ptr->call_free)
80 ptr->call_free(ptr, servers);
81 else
82 free(servers);
83 }
84
85 memcached_return memcached_server_push(memcached_st *ptr, memcached_server_st *list)
86 {
87 unsigned int x;
88 uint16_t count;
89 memcached_server_st *new_host_list;
90
91 if (!list)
92 return MEMCACHED_SUCCESS;
93
94 count= list[0].count;
95
96 if (ptr->call_realloc)
97 new_host_list=
98 (memcached_server_st *)ptr->call_realloc(ptr, ptr->hosts,
99 sizeof(memcached_server_st) * (count + ptr->number_of_hosts));
100 else
101 new_host_list=
102 (memcached_server_st *)realloc(ptr->hosts,
103 sizeof(memcached_server_st) * (count + ptr->number_of_hosts));
104
105 if (!new_host_list)
106 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
107
108 ptr->hosts= new_host_list;
109
110 for (x= 0; x < count; x++)
111 {
112 WATCHPOINT_ASSERT(list[x].hostname[0] != 0);
113 host_reset(ptr, &ptr->hosts[ptr->number_of_hosts], list[x].hostname,
114 list[x].port, list[x].type);
115 ptr->number_of_hosts++;
116 }
117 ptr->hosts[0].count= ptr->number_of_hosts;
118
119 if (ptr->number_of_hosts > 1)
120 qsort(ptr->hosts, ptr->number_of_hosts, sizeof(memcached_server_st), compare_servers);
121
122 rebalance_wheel(ptr);
123
124 return MEMCACHED_SUCCESS;
125 }
126
127 memcached_return memcached_server_add_unix_socket(memcached_st *ptr, char *filename)
128 {
129 if (!filename)
130 return MEMCACHED_FAILURE;
131
132 return server_add(ptr, filename, 0, MEMCACHED_CONNECTION_UNIX_SOCKET);
133 }
134
135 memcached_return memcached_server_add_udp(memcached_st *ptr,
136 char *hostname,
137 unsigned int port)
138 {
139 if (!port)
140 port= MEMCACHED_DEFAULT_PORT;
141
142 if (!hostname)
143 hostname= "localhost";
144
145 return server_add(ptr, hostname, port, MEMCACHED_CONNECTION_UDP);
146 }
147
148 memcached_return memcached_server_add(memcached_st *ptr,
149 char *hostname,
150 unsigned int port)
151 {
152 if (!port)
153 port= MEMCACHED_DEFAULT_PORT;
154
155 if (!hostname)
156 hostname= "localhost";
157
158 return server_add(ptr, hostname, port, MEMCACHED_CONNECTION_TCP);
159 }
160
161 static memcached_return server_add(memcached_st *ptr, char *hostname,
162 unsigned int port,
163 memcached_connection type)
164 {
165 memcached_server_st *new_host_list;
166 LIBMEMCACHED_MEMCACHED_SERVER_ADD_START();
167
168
169 if (ptr->call_realloc)
170 new_host_list= (memcached_server_st *)ptr->call_realloc(ptr, ptr->hosts,
171 sizeof(memcached_server_st) * (ptr->number_of_hosts+1));
172 else
173 new_host_list= (memcached_server_st *)realloc(ptr->hosts,
174 sizeof(memcached_server_st) * (ptr->number_of_hosts+1));
175 if (new_host_list == NULL)
176 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
177
178 ptr->hosts= new_host_list;
179
180 host_reset(ptr, &ptr->hosts[ptr->number_of_hosts], hostname, port, type);
181 ptr->number_of_hosts++;
182 ptr->hosts[0].count++;
183
184 if (ptr->number_of_hosts > 1)
185 qsort(ptr->hosts, ptr->number_of_hosts, sizeof(memcached_server_st), compare_servers);
186
187 rebalance_wheel(ptr);
188
189 LIBMEMCACHED_MEMCACHED_SERVER_ADD_END();
190
191 return MEMCACHED_SUCCESS;
192 }
193
194 memcached_server_st *memcached_server_list_append(memcached_server_st *ptr,
195 char *hostname, unsigned int port,
196 memcached_return *error)
197 {
198 unsigned int count;
199 memcached_server_st *new_host_list;
200
201 if (hostname == NULL || error == NULL)
202 return NULL;
203
204 if (!port)
205 port= MEMCACHED_DEFAULT_PORT;
206
207 /* Increment count for hosts */
208 count= 1;
209 if (ptr != NULL)
210 {
211 count+= ptr[0].count;
212 }
213
214 new_host_list= (memcached_server_st *)realloc(ptr, sizeof(memcached_server_st) * count);
215 if (!new_host_list)
216 {
217 *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
218 return NULL;
219 }
220
221 host_reset(NULL, &new_host_list[count-1], hostname, port, MEMCACHED_CONNECTION_TCP);
222
223 /* Backwards compatibility hack */
224 new_host_list[0].count++;
225
226 count= new_host_list[0].count;
227
228 if (new_host_list[0].count > 1)
229 qsort(new_host_list, count, sizeof(memcached_server_st), compare_servers);
230
231 new_host_list[0].count= count;
232
233
234 *error= MEMCACHED_SUCCESS;
235 return new_host_list;
236 }
237
238 unsigned int memcached_server_list_count(memcached_server_st *ptr)
239 {
240 if (ptr == NULL)
241 return 0;
242
243 return ptr[0].count;
244 }
245
246 void memcached_server_list_free(memcached_server_st *ptr)
247 {
248 server_list_free(NULL, ptr);
249 }