Remove exposed C++ namespace.
[awesomized/libmemcached] / libmemcached / instance.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Libmemcached library
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2006-2009 Brian Aker All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38 #include <libmemcached/common.h>
39
40 static inline void _server_init(memcached_instance_st* self, Memcached *root,
41 const memcached_string_t& hostname,
42 in_port_t port,
43 uint32_t weight, memcached_connection_t type)
44 {
45 self->options.is_shutting_down= false;
46 self->options.is_dead= false;
47 self->options.ready= false;
48 self->_events= 0;
49 self->_revents= 0;
50 self->cursor_active_= 0;
51 self->port_= port;
52 self->fd= INVALID_SOCKET;
53 self->io_bytes_sent= 0;
54 self->request_id= 0;
55 self->server_failure_counter= 0;
56 self->server_failure_counter_query_id= 0;
57 self->weight= weight ? weight : 1; // 1 is the default weight value
58 self->io_wait_count.read= 0;
59 self->io_wait_count.write= 0;
60 self->io_wait_count.timeouts= 0;
61 self->io_wait_count._bytes_read= 0;
62 self->major_version= UINT8_MAX;
63 self->micro_version= UINT8_MAX;
64 self->minor_version= UINT8_MAX;
65 self->type= type;
66 self->error_messages= NULL;
67 self->read_ptr= self->read_buffer;
68 self->read_buffer_length= 0;
69 self->read_data_length= 0;
70 self->write_buffer_offset= 0;
71 self->address_info= NULL;
72 self->address_info_next= NULL;
73
74 self->state= MEMCACHED_SERVER_STATE_NEW;
75 self->next_retry= 0;
76
77 self->root= root;
78 if (root)
79 {
80 self->version= ++root->server_info.version;
81 }
82 else
83 {
84 self->version= UINT_MAX;
85 }
86 self->limit_maxbytes= 0;
87 self->hostname(hostname);
88 }
89
90 static memcached_instance_st* _server_create(memcached_instance_st* self, const memcached_st *memc)
91 {
92 if (self == NULL)
93 {
94 self= libmemcached_xmalloc(memc, memcached_instance_st);
95
96 if (self == NULL)
97 {
98 return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
99 }
100
101 self->options.is_allocated= true;
102 }
103 else
104 {
105 self->options.is_allocated= false;
106 }
107
108 self->options.is_initialized= true;
109
110 return self;
111 }
112
113 void memcached_instance_st::events(short arg)
114 {
115 if ((_events | arg) == _events)
116 {
117 return;
118 }
119
120 _events|= arg;
121 }
122
123 void memcached_instance_st::revents(short arg)
124 {
125 if (arg)
126 {
127 options.ready= true;
128 }
129
130 _revents= arg;
131 _events&= short(~arg);
132 }
133
134 memcached_instance_st* __instance_create_with(memcached_st *memc,
135 memcached_instance_st* self,
136 const memcached_string_t& hostname,
137 const in_port_t port,
138 uint32_t weight,
139 const memcached_connection_t type)
140 {
141 if (memcached_is_valid_servername(hostname) == false)
142 {
143 memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid hostname provided"));
144 return NULL;
145 }
146
147 self= _server_create(self, memc);
148
149 if (self == NULL)
150 {
151 return NULL;
152 }
153
154 _server_init(self, const_cast<memcached_st *>(memc), hostname, port, weight, type);
155
156 if (memc and memcached_is_udp(memc))
157 {
158 self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
159 memcached_io_init_udp_header(self, 0);
160 }
161
162 return self;
163 }
164
165 void __instance_free(memcached_instance_st* self)
166 {
167 memcached_quit_server(self, false);
168
169 self->clear_addrinfo();
170 assert(self->address_info_next == NULL);
171
172 memcached_error_free(*self);
173
174 if (memcached_is_allocated(self))
175 {
176 libmemcached_free(self->root, self);
177 }
178 else
179 {
180 self->options.is_initialized= false;
181 }
182 }
183
184 void memcached_instance_free(memcached_instance_st* self)
185 {
186 if (self)
187 {
188 __instance_free(self);
189 }
190 }
191
192 memcached_return_t memcached_server_cursor(const memcached_st* shell,
193 const memcached_server_fn *callback,
194 void *context,
195 uint32_t number_of_callbacks)
196 {
197 const Memcached* memc= memcached2Memcached(shell);
198 memcached_return_t rc;
199 if (memcached_failed(rc= initialize_const_query(memc)))
200 {
201 return rc;
202 }
203
204 size_t errors= 0;
205 for (uint32_t x= 0; x < memcached_instance_list_count(memc); x++)
206 {
207 memcached_instance_st* instance= memcached_instance_by_position(memc, x);
208
209 for (uint32_t y= 0; y < number_of_callbacks; y++)
210 {
211 memcached_return_t ret= (*callback[y])(memc, instance, context);
212
213 if (memcached_failed(ret))
214 {
215 errors++;
216 continue;
217 }
218 }
219 }
220
221 return errors ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
222 }
223
224 memcached_return_t memcached_server_execute(memcached_st *memc,
225 memcached_server_execute_fn callback,
226 void *context)
227 {
228 if (callback == NULL)
229 {
230 return MEMCACHED_INVALID_ARGUMENTS;
231 }
232
233 bool some_errors= false;;
234 for (uint32_t x= 0; x < memcached_instance_list_count(memc); x++)
235 {
236 memcached_instance_st* instance= memcached_instance_fetch(memc, x);
237
238 memcached_return_t rc= (*callback)(memc, instance, context);
239 if (rc == MEMCACHED_INVALID_ARGUMENTS)
240 {
241 return rc;
242 }
243 else if (memcached_fatal(rc))
244 {
245 some_errors= true;
246 }
247 }
248
249 (void)some_errors;
250 return MEMCACHED_SUCCESS;
251 }
252
253 const memcached_instance_st * memcached_server_by_key(memcached_st *shell,
254 const char *key,
255 size_t key_length,
256 memcached_return_t *error)
257 {
258 Memcached* memc= memcached2Memcached(shell);
259 memcached_return_t unused;
260 if (error == NULL)
261 {
262 error= &unused;
263 }
264
265
266 memcached_return_t rc;
267 if (memcached_failed(rc= initialize_const_query(memc)))
268 {
269 *error= rc;
270 return NULL;
271 }
272
273 if (memcached_failed((memcached_key_test(*memc, (const char **)&key, &key_length, 1))))
274 {
275 *error= memcached_last_error(memc);
276 return NULL;
277 }
278
279 uint32_t server_key= memcached_generate_hash(memc, key, key_length);
280 return memcached_instance_by_position(memc, server_key);
281 }
282
283 /*
284 If we do not have a valid object to clone from, we toss an error.
285 */
286 static memcached_instance_st* memcached_instance_clone(memcached_instance_st* source)
287 {
288 /* We just do a normal create if source is missing */
289 if (source == NULL)
290 {
291 return NULL;
292 }
293
294 memcached_string_t hostname_= { memcached_string_make_from_cstr(source->hostname()) };
295 return __instance_create_with(source->root,
296 NULL,
297 hostname_,
298 source->port(), source->weight,
299 source->type);
300 }
301
302 void set_last_disconnected_host(memcached_instance_st* self)
303 {
304 assert(self->root);
305 if (self->root)
306 {
307 if (memcached_server_get_last_disconnect(self->root) and
308 memcached_server_get_last_disconnect(self->root)->version == self->version)
309 {
310 return;
311 }
312
313 // const_cast
314 memcached_st *root= (memcached_st *)self->root;
315
316 memcached_instance_free((memcached_instance_st*)(root->last_disconnected_server));
317
318 // We set is_parsing so that no lookup happens
319 root->state.is_parsing= true;
320 root->last_disconnected_server= memcached_instance_clone(self);
321 root->state.is_parsing= false;
322
323 ((memcached_instance_st*)memcached_server_get_last_disconnect(root))->version= self->version;
324 }
325 }
326
327 const memcached_instance_st * memcached_server_get_last_disconnect(const memcached_st *shell)
328 {
329 const Memcached* self= memcached2Memcached(shell);
330 if (self)
331 {
332 return (const memcached_instance_st *)self->last_disconnected_server;
333 }
334
335 return 0;
336 }
337
338 void memcached_instance_next_retry(const memcached_instance_st * self, const time_t absolute_time)
339 {
340 WATCHPOINT_ASSERT(self);
341 if (self)
342 {
343 ((memcached_instance_st*)self)->next_retry= absolute_time;
344 }
345 }
346
347 bool memcached_instance_st::valid() const
348 {
349 if (fd == INVALID_SOCKET)
350 {
351 return false;
352 }
353
354 return true;
355 }
356
357 bool memcached_instance_st::is_shutting_down() const
358 {
359 return options.is_shutting_down;
360 }