Update tests, improved UDP performance.
[awesomized/libmemcached] / libmemcached / error.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * LibMemcached
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * 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 #include <cstdarg>
40
41 #define MAX_ERROR_LENGTH 2048
42 struct memcached_error_t
43 {
44 memcached_st *root;
45 uint64_t query_id;
46 struct memcached_error_t *next;
47 memcached_return_t rc;
48 int local_errno;
49 size_t size;
50 char message[MAX_ERROR_LENGTH];
51 };
52
53 static void _set(memcached_server_st& server, memcached_st& memc)
54 {
55 if (server.error_messages && server.error_messages->query_id != server.root->query_id)
56 {
57 memcached_error_free(server);
58 }
59
60 if (memc.error_messages == NULL)
61 {
62 return;
63 }
64
65 memcached_error_t *error= libmemcached_xmalloc(&memc, memcached_error_t);
66 if (error == NULL) // Bad business if this happens
67 {
68 return;
69 }
70
71 memcpy(error, memc.error_messages, sizeof(memcached_error_t));
72 error->next= server.error_messages;
73 server.error_messages= error;
74 }
75
76 static void _set(memcached_st& memc, memcached_string_t *str, memcached_return_t &rc, const char *at, int local_errno= 0)
77 {
78 if (memc.error_messages && memc.error_messages->query_id != memc.query_id)
79 {
80 memcached_error_free(memc);
81 }
82
83 // For memory allocation we use our error since it is a bit more specific
84 if (local_errno == ENOMEM and rc == MEMCACHED_ERRNO)
85 {
86 rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
87 }
88
89 if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
90 {
91 local_errno= ENOMEM;
92 }
93
94 if (rc == MEMCACHED_ERRNO and not local_errno)
95 {
96 local_errno= errno;
97 rc= MEMCACHED_ERRNO;
98 }
99
100 if (rc == MEMCACHED_ERRNO and local_errno == ENOTCONN)
101 {
102 rc= MEMCACHED_CONNECTION_FAILURE;
103 }
104
105 if (local_errno == EINVAL)
106 {
107 rc= MEMCACHED_INVALID_ARGUMENTS;
108 }
109
110 if (local_errno == ECONNREFUSED)
111 {
112 rc= MEMCACHED_CONNECTION_FAILURE;
113 }
114
115 memcached_error_t *error= libmemcached_xmalloc(&memc, memcached_error_t);
116 if (error == NULL) // Bad business if this happens
117 {
118 return;
119 }
120
121 error->root= &memc;
122 error->query_id= memc.query_id;
123 error->rc= rc;
124 error->local_errno= local_errno;
125
126 const char *errmsg_ptr;
127 char errmsg[MAX_ERROR_LENGTH];
128 errmsg[0]= 0;
129 errmsg_ptr= errmsg;
130
131 if (local_errno)
132 {
133 #ifdef STRERROR_R_CHAR_P
134 errmsg_ptr= strerror_r(local_errno, errmsg, sizeof(errmsg));
135 #else
136 strerror_r(local_errno, errmsg, sizeof(errmsg));
137 errmsg_ptr= errmsg;
138 #endif
139 }
140
141
142 if (str and str->size and local_errno)
143 {
144 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s(%s), %.*s -> %s",
145 memcached_strerror(&memc, rc),
146 errmsg_ptr,
147 memcached_string_printf(*str), at);
148 }
149 else if (local_errno)
150 {
151 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s(%s) -> %s",
152 memcached_strerror(&memc, rc),
153 errmsg_ptr,
154 at);
155 }
156 else if (rc == MEMCACHED_PARSE_ERROR and str and str->size)
157 {
158 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%.*s -> %s",
159 int(str->size), str->c_str, at);
160 }
161 else if (str and str->size)
162 {
163 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s, %.*s -> %s",
164 memcached_strerror(&memc, rc),
165 int(str->size), str->c_str, at);
166 }
167 else
168 {
169 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s -> %s",
170 memcached_strerror(&memc, rc), at);
171 }
172
173 error->next= memc.error_messages;
174 memc.error_messages= error;
175 }
176
177 memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc, const char *at, const char *str, size_t length)
178 {
179 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
180 memcached_string_t tmp= { str, length };
181 return memcached_set_error(memc, rc, at, tmp);
182 }
183
184 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at, const char *str, size_t length)
185 {
186 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
187 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_server_st");
188 memcached_string_t tmp= { str, length };
189 return memcached_set_error(self, rc, at, tmp);
190 }
191
192 memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc, const char *at, memcached_string_t& str)
193 {
194 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
195 if (memcached_success(rc))
196 {
197 return rc;
198 }
199
200 _set(memc, &str, rc, at);
201
202 return rc;
203 }
204
205 memcached_return_t memcached_set_parser_error(memcached_st& memc,
206 const char *at,
207 const char *format, ...)
208 {
209 va_list args;
210
211 char buffer[BUFSIZ];
212 va_start(args, format);
213 int length= vsnprintf(buffer, sizeof(buffer), format, args);
214 va_end(args);
215
216 return memcached_set_error(memc, MEMCACHED_PARSE_ERROR, at, buffer, length);
217 }
218
219 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at, memcached_string_t& str)
220 {
221 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
222 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_server_st");
223 if (memcached_success(rc))
224 {
225 return rc;
226 }
227
228 char hostname_port_message[MAX_ERROR_LENGTH];
229 int size;
230 if (str.size)
231 {
232 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "%.*s, host: %s:%d",
233 memcached_string_printf(str),
234 self.hostname, int(self.port));
235 }
236 else
237 {
238 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
239 self.hostname, int(self.port));
240 }
241
242 memcached_string_t error_host= { hostname_port_message, size };
243
244 assert(self.root);
245 if (self.root == NULL)
246 {
247 return rc;
248 }
249
250 _set(*self.root, &error_host, rc, at);
251 _set(self, (*self.root));
252 assert(self.root->error_messages);
253 assert(self.error_messages);
254
255 return rc;
256 }
257
258 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at)
259 {
260 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_server_st");
261 if (memcached_success(rc))
262 {
263 return rc;
264 }
265
266 char hostname_port[NI_MAXHOST +NI_MAXSERV + sizeof("host : ")];
267 int size= snprintf(hostname_port, sizeof(hostname_port), "host: %s:%d", self.hostname, int(self.port));
268
269 memcached_string_t error_host= { hostname_port, size};
270
271 if (self.root == NULL)
272 {
273 return rc;
274 }
275
276 _set(*self.root, &error_host, rc, at);
277 _set(self, *self.root);
278
279 return rc;
280 }
281
282 memcached_return_t memcached_set_error(memcached_st& self, memcached_return_t rc, const char *at)
283 {
284 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
285 if (memcached_success(rc))
286 {
287 return rc;
288 }
289
290 _set(self, NULL, rc, at);
291
292 return rc;
293 }
294
295 memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at, const char *str, size_t length)
296 {
297 memcached_string_t tmp= { str, length };
298 return memcached_set_errno(self, local_errno, at, tmp);
299 }
300
301 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at, const char *str, size_t length)
302 {
303 memcached_string_t tmp= { str, length };
304 return memcached_set_errno(self, local_errno, at, tmp);
305 }
306
307 memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at)
308 {
309 if (local_errno == 0)
310 {
311 return MEMCACHED_SUCCESS;
312 }
313
314 memcached_return_t rc= MEMCACHED_ERRNO;
315 _set(self, NULL, rc, at, local_errno);
316
317 return rc;
318 }
319
320 memcached_return_t memcached_set_errno(memcached_st& memc, int local_errno, const char *at, memcached_string_t& str)
321 {
322 if (local_errno == 0)
323 {
324 return MEMCACHED_SUCCESS;
325 }
326
327 memcached_return_t rc= MEMCACHED_ERRNO;
328 _set(memc, &str, rc, at, local_errno);
329
330 return rc;
331 }
332
333 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at, memcached_string_t& str)
334 {
335 if (local_errno == 0)
336 {
337 return MEMCACHED_SUCCESS;
338 }
339
340 char hostname_port_message[MAX_ERROR_LENGTH];
341 int size;
342 if (str.size)
343 {
344 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "%.*s, host: %s:%d",
345 memcached_string_printf(str),
346 self.hostname, int(self.port));
347 }
348 else
349 {
350 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
351 self.hostname, int(self.port));
352 }
353
354 memcached_string_t error_host= { hostname_port_message, size };
355
356 memcached_return_t rc= MEMCACHED_ERRNO;
357 if (not self.root)
358 return rc;
359
360 _set(*self.root, &error_host, rc, at, local_errno);
361 _set(self, (*self.root));
362
363 return rc;
364 }
365
366 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at)
367 {
368 if (local_errno == 0)
369 {
370 return MEMCACHED_SUCCESS;
371 }
372
373 char hostname_port_message[MAX_ERROR_LENGTH];
374 int size = snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
375 self.hostname, int(self.port));
376
377 memcached_string_t error_host= { hostname_port_message, size };
378
379 memcached_return_t rc= MEMCACHED_ERRNO;
380 if (not self.root)
381 return rc;
382
383 _set(*self.root, &error_host, rc, at, local_errno);
384 _set(self, (*self.root));
385
386 return rc;
387 }
388
389 static void _error_print(const memcached_error_t *error)
390 {
391 if (error == NULL)
392 {
393 return;
394 }
395
396 if (error->size == 0)
397 {
398 fprintf(stderr, "\t%s\n", memcached_strerror(NULL, error->rc) );
399 }
400 else
401 {
402 fprintf(stderr, "\t%s %s\n", memcached_strerror(NULL, error->rc), error->message);
403 }
404
405 _error_print(error->next);
406 }
407
408 void memcached_error_print(const memcached_st *self)
409 {
410 if (self == NULL)
411 {
412 return;
413 }
414
415 _error_print(self->error_messages);
416
417 for (uint32_t x= 0; x < memcached_server_count(self); x++)
418 {
419 memcached_server_instance_st instance= memcached_server_instance_by_position(self, x);
420
421 _error_print(instance->error_messages);
422 }
423 }
424
425 static void _error_free(memcached_error_t *error)
426 {
427 if (not error)
428 {
429 return;
430 }
431
432 _error_free(error->next);
433
434 if (error && error->root)
435 {
436 libmemcached_free(error->root, error);
437 }
438 else if (error)
439 {
440 free(error);
441 }
442 }
443
444 void memcached_error_free(memcached_st& self)
445 {
446 _error_free(self.error_messages);
447 self.error_messages= NULL;
448 }
449
450 void memcached_error_free(memcached_server_st& self)
451 {
452 _error_free(self.error_messages);
453 self.error_messages= NULL;
454 }
455
456 const char *memcached_last_error_message(memcached_st *memc)
457 {
458 if (memc == NULL)
459 {
460 return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
461 }
462
463 if (memc->error_messages == NULL)
464 {
465 return memcached_strerror(memc, MEMCACHED_SUCCESS);
466 }
467
468 if (memc->error_messages->size == 0)
469 {
470 return memcached_strerror(memc, memc->error_messages->rc);
471 }
472
473 return memc->error_messages->message;
474 }
475
476 bool memcached_has_current_error(memcached_st &memc)
477 {
478 if (memc.error_messages
479 and memc.error_messages->query_id == memc.query_id
480 and memcached_failed(memc.error_messages->rc))
481 {
482 return true;
483 }
484
485 return false;
486 }
487
488 bool memcached_has_current_error(memcached_server_st& server)
489 {
490 return memcached_has_current_error(*(server.root));
491 }
492
493 memcached_return_t memcached_last_error(memcached_st *memc)
494 {
495 if (memc == NULL)
496 {
497 return MEMCACHED_INVALID_ARGUMENTS;
498 }
499
500 if (not memc->error_messages)
501 return MEMCACHED_SUCCESS;
502
503 return memc->error_messages->rc;
504 }
505
506 int memcached_last_error_errno(memcached_st *memc)
507 {
508 if (memc == NULL)
509 {
510 return 0;
511 }
512
513 if (not memc->error_messages)
514 {
515 return 0;
516 }
517
518 return memc->error_messages->local_errno;
519 }
520
521 const char *memcached_server_error(memcached_server_instance_st server)
522 {
523 if (server == NULL)
524 {
525 return NULL;
526 }
527
528 if (not server->error_messages)
529 return memcached_strerror(server->root, MEMCACHED_SUCCESS);
530
531 if (not server->error_messages->size)
532 return memcached_strerror(server->root, server->error_messages->rc);
533
534 return server->error_messages->message;
535 }
536
537
538 memcached_error_t *memcached_error_copy(const memcached_server_st& server)
539 {
540 if (server.error_messages == NULL)
541 {
542 return NULL;
543 }
544
545 memcached_error_t *error= libmemcached_xmalloc(server.root, memcached_error_t);
546 memcpy(error, server.error_messages, sizeof(memcached_error_t));
547 error->next= NULL;
548
549 return error;
550 }
551
552 memcached_return_t memcached_server_error_return(memcached_server_instance_st ptr)
553 {
554 if (ptr == NULL)
555 {
556 return MEMCACHED_INVALID_ARGUMENTS;
557 }
558
559 if (ptr and ptr->error_messages)
560 {
561 return ptr->error_messages->rc;
562 }
563
564 return MEMCACHED_SUCCESS;
565 }