More Cleanup
[m6w6/libmemcached] / libmemcached / server.c
1 /* LibMemcached
2 * Copyright (C) 2006-2009 Brian Aker
3 * All rights reserved.
4 *
5 * Use and distribution licensed under the BSD license. See
6 * the COPYING file in the parent directory for full text.
7 *
8 * Summary: String structure used for libmemcached.
9 *
10 */
11
12 /*
13 This is a partial implementation for fetching/creating memcached_server_st objects.
14 */
15 #include "common.h"
16
17 static inline void _server_init(memcached_server_st *self, const memcached_st *root,
18 const char *hostname, in_port_t port,
19 uint32_t weight, memcached_connection_t type)
20 {
21 self->options.sockaddr_inited= false;
22 self->number_of_hosts= 0;
23 self->cursor_active= 0;
24 self->port= port;
25 self->cached_errno= 0;
26 self->fd= -1;
27 self->io_bytes_sent= 0;
28 self->server_failure_counter= 0;
29 self->weight= weight;
30 self->state.is_corked= false;
31 self->major_version= 0;
32 self->micro_version= 0;
33 self->minor_version= 0;
34 self->type= type;
35 self->read_ptr= self->read_buffer;
36 self->cached_server_error= NULL;
37 self->read_buffer_length= 0;
38 self->read_data_length= 0;
39 self->write_buffer_offset= 0;
40 self->address_info= NULL;
41
42 if (root)
43 {
44 self->next_retry= root->retry_timeout;
45 }
46 else
47 {
48 self->next_retry= 0;
49 }
50
51 self->root= root;
52 self->limit_maxbytes= 0;
53 if (hostname == NULL)
54 self->hostname[0]= 0;
55 else
56 strncpy(self->hostname, hostname, MEMCACHED_MAX_HOST_LENGTH - 1);
57 }
58
59 static memcached_server_st *_server_create(memcached_server_st *self, const memcached_st *memc)
60 {
61 if (self == NULL)
62 {
63 self= (memcached_server_st *)libmemcached_malloc(memc, sizeof(memcached_server_st));
64
65 if (! self)
66 return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
67
68 self->options.is_allocated= true;
69 }
70 else
71 {
72 self->options.is_allocated= false;
73 }
74
75 self->options.is_initialized= true;
76
77 return self;
78 }
79
80 memcached_server_st *memcached_server_create_with(const memcached_st *memc, memcached_server_st *self,
81 const char *hostname, in_port_t port,
82 uint32_t weight, memcached_connection_t type)
83 {
84 self= _server_create(self, memc);
85
86 if (self == NULL)
87 return NULL;
88
89 _server_init(self, memc, hostname, port, weight, type);
90
91
92 if (type == MEMCACHED_CONNECTION_UDP)
93 {
94 self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
95 memcached_io_init_udp_header(self, 0);
96 }
97
98 return self;
99 }
100
101 void memcached_server_free(memcached_server_st *self)
102 {
103 memcached_quit_server(self, 0);
104
105 if (self->cached_server_error)
106 free(self->cached_server_error);
107
108 if (self->address_info)
109 freeaddrinfo(self->address_info);
110
111 if (memcached_is_allocated(self))
112 {
113 libmemcached_free(self->root, self);
114 }
115 else
116 {
117 self->options.is_initialized= false;
118 }
119 }
120
121 /*
122 If we do not have a valid object to clone from, we toss an error.
123 */
124 memcached_server_st *memcached_server_clone(memcached_server_st *destination,
125 const memcached_server_st *source)
126 {
127 /* We just do a normal create if source is missing */
128 if (source == NULL)
129 return NULL;
130
131 destination= memcached_server_create_with(source->root, destination,
132 source->hostname, source->port, source->weight,
133 source->type);
134 if (destination != NULL)
135 {
136 destination->cached_errno= source->cached_errno;
137
138 if (source->cached_server_error)
139 destination->cached_server_error= strdup(source->cached_server_error);
140 }
141
142 return destination;
143
144 }
145
146 memcached_return_t memcached_server_cursor(memcached_st *ptr,
147 memcached_server_fn *callback,
148 void *context,
149 uint32_t number_of_callbacks)
150 {
151 uint32_t y;
152
153 for (y= 0; y < memcached_server_count(ptr); y++)
154 {
155 uint32_t x;
156 memcached_server_instance_st *instance=
157 memcached_server_instance_fetch(ptr, y);
158
159 for (x= 0; x < number_of_callbacks; x++)
160 {
161 unsigned int iferror;
162
163 iferror= (*callback[x])(ptr, instance, context);
164
165 if (iferror)
166 continue;
167 }
168 }
169
170 return MEMCACHED_SUCCESS;
171 }
172
173 memcached_server_st *memcached_server_by_key(memcached_st *ptr, const char *key, size_t key_length, memcached_return_t *error)
174 {
175 uint32_t server_key;
176 memcached_server_instance_st *instance;
177
178 *error= memcached_validate_key_length(key_length,
179 ptr->flags.binary_protocol);
180 unlikely (*error != MEMCACHED_SUCCESS)
181 return NULL;
182
183 unlikely (memcached_server_count(ptr) == 0)
184 {
185 *error= MEMCACHED_NO_SERVERS;
186 return NULL;
187 }
188
189 if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
190 {
191 *error= MEMCACHED_BAD_KEY_PROVIDED;
192 return NULL;
193 }
194
195 server_key= memcached_generate_hash(ptr, key, key_length);
196 instance= memcached_server_instance_fetch(ptr, server_key);
197
198 return memcached_server_clone(NULL, instance);
199
200 }
201
202 const char *memcached_server_error(memcached_server_st *ptr)
203 {
204 return ptr
205 ? ptr->cached_server_error
206 : NULL;
207 }
208
209 void memcached_server_error_reset(memcached_server_st *ptr)
210 {
211 ptr->cached_server_error[0]= 0;
212 }
213
214 memcached_server_st *memcached_server_get_last_disconnect(memcached_st *ptr)
215 {
216 return ptr->last_disconnected_server;
217 }
218
219 uint32_t memcached_server_list_count(memcached_server_st *ptr)
220 {
221 return (ptr == NULL)
222 ? 0
223 : memcached_servers_count(ptr);
224 }
225
226 void memcached_server_list_free(memcached_server_st *ptr)
227 {
228 server_list_free(NULL, ptr);
229 }
230
231 /**
232 @todo allow lists to query themselves even if they lack a root
233 */
234 memcached_return_t memcached_server_remove(memcached_server_st *st_ptr)
235 {
236 uint32_t x, host_index;
237 memcached_st *root= (memcached_st *)st_ptr->root;
238 memcached_server_st *list;
239
240 if (root == NULL)
241 return MEMCACHED_FAILURE;
242
243 list= memcached_server_list(root);
244
245 for (x= 0, host_index= 0; x < memcached_server_count(root); x++)
246 {
247 if (strncmp(list[x].hostname, st_ptr->hostname, MEMCACHED_MAX_HOST_LENGTH) != 0 || list[x].port != st_ptr->port)
248 {
249 if (host_index != x)
250 memcpy(list+host_index, list+x, sizeof(memcached_server_st));
251 host_index++;
252 }
253 }
254 root->number_of_hosts= host_index;
255
256 if (st_ptr->address_info)
257 {
258 freeaddrinfo(st_ptr->address_info);
259 st_ptr->address_info= NULL;
260 }
261 run_distribution(root);
262
263 return MEMCACHED_SUCCESS;
264 }