4c6bfc069c949f5f4dda3fc9209968ec6289707a
[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(org::libmemcached::Instance& server, memcached_st& memc)
54 {
55 if (server.error_messages and 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 #if 0
77 static int error_log_fd= -1;
78 #endif
79
80 static void _set(memcached_st& memc, memcached_string_t *str, memcached_return_t &rc, const char *at, int local_errno= 0)
81 {
82 if (memc.error_messages && memc.error_messages->query_id != memc.query_id)
83 {
84 memcached_error_free(memc);
85 }
86
87 // For memory allocation we use our error since it is a bit more specific
88 if (local_errno == ENOMEM and rc == MEMCACHED_ERRNO)
89 {
90 rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
91 }
92
93 if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
94 {
95 local_errno= ENOMEM;
96 }
97
98 if (rc == MEMCACHED_ERRNO and not local_errno)
99 {
100 local_errno= errno;
101 rc= MEMCACHED_ERRNO;
102 }
103
104 if (rc == MEMCACHED_ERRNO and local_errno == ENOTCONN)
105 {
106 rc= MEMCACHED_CONNECTION_FAILURE;
107 }
108
109 if (rc == MEMCACHED_ERRNO and local_errno == ECONNRESET)
110 {
111 rc= MEMCACHED_CONNECTION_FAILURE;
112 }
113
114 if (local_errno == EINVAL)
115 {
116 rc= MEMCACHED_INVALID_ARGUMENTS;
117 }
118
119 if (local_errno == ECONNREFUSED)
120 {
121 rc= MEMCACHED_CONNECTION_FAILURE;
122 }
123
124 memcached_error_t *error= libmemcached_xmalloc(&memc, memcached_error_t);
125 if (error == NULL) // Bad business if this happens
126 {
127 return;
128 }
129
130 error->root= &memc;
131 error->query_id= memc.query_id;
132 error->rc= rc;
133 error->local_errno= local_errno;
134
135 const char *errmsg_ptr;
136 char errmsg[MAX_ERROR_LENGTH];
137 errmsg[0]= 0;
138 errmsg_ptr= errmsg;
139
140 if (local_errno)
141 {
142 #ifdef STRERROR_R_CHAR_P
143 errmsg_ptr= strerror_r(local_errno, errmsg, sizeof(errmsg));
144 #elif defined(HAVE_STRERROR_R) && HAVE_STRERROR_R
145 strerror_r(local_errno, errmsg, sizeof(errmsg));
146 errmsg_ptr= errmsg;
147 #elif defined(HAVE_STRERROR) && HAVE_STRERROR
148 snprintf(errmsg, sizeof(errmsg), "%s", strerror(local_errno));
149 errmsg_ptr= errmsg;
150 #endif
151 }
152
153
154 if (str and str->size and local_errno)
155 {
156 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s(%s), %.*s -> %s",
157 error->root,
158 memcached_strerror(&memc, rc),
159 errmsg_ptr,
160 memcached_string_printf(*str), at);
161 }
162 else if (local_errno)
163 {
164 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s(%s) -> %s",
165 error->root,
166 memcached_strerror(&memc, rc),
167 errmsg_ptr,
168 at);
169 }
170 else if (rc == MEMCACHED_PARSE_ERROR and str and str->size)
171 {
172 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %.*s -> %s",
173 error->root,
174 int(str->size), str->c_str, at);
175 }
176 else if (str and str->size)
177 {
178 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s, %.*s -> %s",
179 error->root,
180 memcached_strerror(&memc, rc),
181 int(str->size), str->c_str, at);
182 }
183 else
184 {
185 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s -> %s",
186 error->root,
187 memcached_strerror(&memc, rc), at);
188 }
189
190 error->next= memc.error_messages;
191 memc.error_messages= error;
192
193 #if 0
194 if (error_log_fd == -1)
195 {
196 // unlink("/tmp/libmemcachd.log");
197 if ((error_log_fd= open("/tmp/libmemcachd.log", O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0)
198 {
199 perror("open");
200 error_log_fd= -1;
201 }
202 }
203 ::write(error_log_fd, error->message, error->size);
204 ::write(error_log_fd, "\n", 1);
205 #endif
206 }
207
208 memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc, const char *at, const char *str, size_t length)
209 {
210 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
211 memcached_string_t tmp= { str, length };
212 return memcached_set_error(memc, rc, at, tmp);
213 }
214
215 memcached_return_t memcached_set_error(org::libmemcached::Instance& self, memcached_return_t rc, const char *at, const char *str, size_t length)
216 {
217 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
218 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a Instance");
219
220 memcached_string_t tmp= { str, length };
221 return memcached_set_error(self, rc, at, tmp);
222 }
223
224 #ifndef __INTEL_COMPILER
225 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
226 #endif
227
228 memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc, const char *at, memcached_string_t& str)
229 {
230 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
231 if (memcached_fatal(rc) == false)
232 {
233 return rc;
234 }
235
236 _set(memc, &str, rc, at);
237
238 return rc;
239 }
240
241 memcached_return_t memcached_set_parser_error(memcached_st& memc,
242 const char *at,
243 const char *format, ...)
244 {
245 va_list args;
246
247 char buffer[BUFSIZ];
248 va_start(args, format);
249 int length= vsnprintf(buffer, sizeof(buffer), format, args);
250 va_end(args);
251
252 return memcached_set_error(memc, MEMCACHED_PARSE_ERROR, at, buffer, length);
253 }
254
255 static inline size_t append_host_to_string(org::libmemcached::Instance& self, char* buffer, const size_t buffer_length)
256 {
257 size_t size= 0;
258 switch (self.type)
259 {
260 case MEMCACHED_CONNECTION_TCP:
261 case MEMCACHED_CONNECTION_UDP:
262 size+= snprintf(buffer, buffer_length, " host: %s:%d",
263 self.hostname, int(self.port()));
264 break;
265
266 case MEMCACHED_CONNECTION_UNIX_SOCKET:
267 size+= snprintf(buffer, buffer_length, " socket: %s",
268 self.hostname);
269 break;
270 }
271
272 return size;
273 }
274
275 memcached_return_t memcached_set_error(org::libmemcached::Instance& self, memcached_return_t rc, const char *at, memcached_string_t& str)
276 {
277 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
278 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a org::libmemcached::Instance");
279 if (memcached_fatal(rc) == false and rc != MEMCACHED_CLIENT_ERROR)
280 {
281 return rc;
282 }
283
284 char hostname_port_message[MAX_ERROR_LENGTH];
285 char* hostname_port_message_ptr= hostname_port_message;
286 int size= 0;
287 if (str.size)
288 {
289 size= snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ",
290 memcached_string_printf(str));
291 hostname_port_message_ptr+= size;
292 }
293
294 size+= append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) -size);
295
296 memcached_string_t error_host= { hostname_port_message, size_t(size) };
297
298 assert_msg(self.root, "Programmer error, root was not set on instance");
299 if (self.root == NULL)
300 {
301 return rc;
302 }
303
304 _set(*self.root, &error_host, rc, at);
305 _set(self, (*self.root));
306 assert(self.root->error_messages);
307 assert(self.error_messages);
308 assert(self.error_messages->rc == self.root->error_messages->rc);
309
310 return rc;
311 }
312
313 memcached_return_t memcached_set_error(org::libmemcached::Instance& self, memcached_return_t rc, const char *at)
314 {
315 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a org::libmemcached::Instance");
316 if (memcached_fatal(rc) == false)
317 {
318 return rc;
319 }
320
321 char hostname_port[MEMCACHED_NI_MAXHOST +MEMCACHED_NI_MAXSERV + sizeof("host : ")];
322 size_t size= append_host_to_string(self, hostname_port, sizeof(hostname_port));
323
324 memcached_string_t error_host= { hostname_port, size};
325
326 if (self.root == NULL)
327 {
328 return rc;
329 }
330
331 _set(*self.root, &error_host, rc, at);
332 _set(self, *self.root);
333
334 return rc;
335 }
336
337 memcached_return_t memcached_set_error(memcached_st& self, memcached_return_t rc, const char *at)
338 {
339 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
340 if (memcached_fatal(rc) == false)
341 {
342 return rc;
343 }
344
345 _set(self, NULL, rc, at);
346
347 return rc;
348 }
349
350 memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at, const char *str, size_t length)
351 {
352 memcached_string_t tmp= { str, length };
353 return memcached_set_errno(self, local_errno, at, tmp);
354 }
355
356 memcached_return_t memcached_set_errno(org::libmemcached::Instance& self, int local_errno, const char *at, const char *str, size_t length)
357 {
358 memcached_string_t tmp= { str, length };
359 return memcached_set_errno(self, local_errno, at, tmp);
360 }
361
362 memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at)
363 {
364 if (local_errno == 0)
365 {
366 return MEMCACHED_SUCCESS;
367 }
368
369 memcached_return_t rc= MEMCACHED_ERRNO;
370 _set(self, NULL, rc, at, local_errno);
371
372 return rc;
373 }
374
375 memcached_return_t memcached_set_errno(memcached_st& memc, int local_errno, const char *at, memcached_string_t& str)
376 {
377 if (local_errno == 0)
378 {
379 return MEMCACHED_SUCCESS;
380 }
381
382 memcached_return_t rc= MEMCACHED_ERRNO;
383 _set(memc, &str, rc, at, local_errno);
384
385 return rc;
386 }
387
388 memcached_return_t memcached_set_errno(org::libmemcached::Instance& self, int local_errno, const char *at, memcached_string_t& str)
389 {
390 if (local_errno == 0)
391 {
392 return MEMCACHED_SUCCESS;
393 }
394
395 char hostname_port_message[MAX_ERROR_LENGTH];
396 char* hostname_port_message_ptr= hostname_port_message;
397 size_t size= 0;
398 if (str.size)
399 {
400 size= snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ", memcached_string_printf(str));
401 }
402 size+= append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) -size);
403
404 memcached_string_t error_host= { hostname_port_message, size };
405
406 memcached_return_t rc= MEMCACHED_ERRNO;
407 if (self.root == NULL)
408 {
409 return rc;
410 }
411
412 _set(*self.root, &error_host, rc, at, local_errno);
413 _set(self, (*self.root));
414
415 #if 0
416 if (self.root->error_messages->rc != self.error_messages->rc)
417 {
418 fprintf(stderr, "%s:%d %s != %s\n", __FILE__, __LINE__,
419 memcached_strerror(NULL, self.root->error_messages->rc),
420 memcached_strerror(NULL, self.error_messages->rc));
421 }
422 #endif
423
424 return rc;
425 }
426
427 memcached_return_t memcached_set_errno(org::libmemcached::Instance& self, int local_errno, const char *at)
428 {
429 if (local_errno == 0)
430 {
431 return MEMCACHED_SUCCESS;
432 }
433
434 char hostname_port_message[MAX_ERROR_LENGTH];
435 size_t size= append_host_to_string(self, hostname_port_message, sizeof(hostname_port_message));
436
437 memcached_string_t error_host= { hostname_port_message, size };
438
439 memcached_return_t rc= MEMCACHED_ERRNO;
440 if (self.root == NULL)
441 {
442 return rc;
443 }
444
445 _set(*self.root, &error_host, rc, at, local_errno);
446 _set(self, (*self.root));
447
448 return rc;
449 }
450
451 static void _error_print(const memcached_error_t *error)
452 {
453 if (error == NULL)
454 {
455 return;
456 }
457
458 if (error->size == 0)
459 {
460 fprintf(stderr, "\t%s\n", memcached_strerror(NULL, error->rc) );
461 }
462 else
463 {
464 fprintf(stderr, "\t%s %s\n", memcached_strerror(NULL, error->rc), error->message);
465 }
466
467 _error_print(error->next);
468 }
469
470 void memcached_error_print(const memcached_st *self)
471 {
472 if (self == NULL)
473 {
474 return;
475 }
476
477 _error_print(self->error_messages);
478
479 for (uint32_t x= 0; x < memcached_server_count(self); x++)
480 {
481 org::libmemcached::Instance* instance= memcached_instance_by_position(self, x);
482
483 _error_print(instance->error_messages);
484 }
485 }
486
487 static void _error_free(memcached_error_t *error)
488 {
489 if (error)
490 {
491 _error_free(error->next);
492
493 libmemcached_free(error->root, error);
494 }
495 }
496
497 void memcached_error_free(memcached_st& self)
498 {
499 _error_free(self.error_messages);
500 self.error_messages= NULL;
501 }
502
503 void memcached_error_free(org::libmemcached::Instance& self)
504 {
505 _error_free(self.error_messages);
506 self.error_messages= NULL;
507 }
508
509 void memcached_error_free(memcached_server_st& self)
510 {
511 _error_free(self.error_messages);
512 self.error_messages= NULL;
513 }
514
515 const char *memcached_error(const memcached_st *memc)
516 {
517 return memcached_last_error_message(memc);
518 }
519
520 const char *memcached_last_error_message(const memcached_st *memc)
521 {
522 if (memc)
523 {
524 if (memc->error_messages)
525 {
526 if (memc->error_messages->size == 0)
527 {
528 return memc->error_messages->message;
529 }
530
531 return memcached_strerror(memc, memc->error_messages->rc);
532 }
533
534 return memcached_strerror(memc, MEMCACHED_SUCCESS);
535 }
536
537 return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
538 }
539
540 bool memcached_has_current_error(memcached_st &memc)
541 {
542 if (memc.error_messages
543 and memc.error_messages->query_id == memc.query_id
544 and memcached_failed(memc.error_messages->rc))
545 {
546 return true;
547 }
548
549 return false;
550 }
551
552 bool memcached_has_current_error(org::libmemcached::Instance& server)
553 {
554 return memcached_has_current_error(*(server.root));
555 }
556
557 memcached_return_t memcached_last_error(const memcached_st *memc)
558 {
559 if (memc)
560 {
561 if (memc->error_messages)
562 {
563 return memc->error_messages->rc;
564 }
565
566 return MEMCACHED_SUCCESS;
567 }
568
569 return MEMCACHED_INVALID_ARGUMENTS;
570 }
571
572 int memcached_last_error_errno(const memcached_st *memc)
573 {
574 if (memc == NULL)
575 {
576 return 0;
577 }
578
579 if (memc->error_messages == NULL)
580 {
581 return 0;
582 }
583
584 return memc->error_messages->local_errno;
585 }
586
587 const char *memcached_server_error(const memcached_server_instance_st server)
588 {
589 if (server == NULL)
590 {
591 return NULL;
592 }
593
594 if (server->error_messages == NULL)
595 {
596 return memcached_strerror(server->root, MEMCACHED_SUCCESS);
597 }
598
599 if (server->error_messages->size == 0)
600 {
601 return memcached_strerror(server->root, server->error_messages->rc);
602 }
603
604 return server->error_messages->message;
605 }
606
607
608 memcached_error_t *memcached_error_copy(const org::libmemcached::Instance& server)
609 {
610 if (server.error_messages == NULL)
611 {
612 return NULL;
613 }
614
615 memcached_error_t *error= libmemcached_xmalloc(server.root, memcached_error_t);
616 memcpy(error, server.error_messages, sizeof(memcached_error_t));
617 error->next= NULL;
618
619 return error;
620 }
621
622 memcached_return_t memcached_server_error_return(memcached_server_instance_st ptr)
623 {
624 if (ptr == NULL)
625 {
626 return MEMCACHED_INVALID_ARGUMENTS;
627 }
628
629 if (ptr and ptr->error_messages)
630 {
631 return ptr->error_messages->rc;
632 }
633
634 return MEMCACHED_SUCCESS;
635 }
636
637 memcached_return_t memcached_instance_error_return(org::libmemcached::Instance* instance)
638 {
639 if (instance == NULL)
640 {
641 return MEMCACHED_INVALID_ARGUMENTS;
642 }
643
644 if (instance and instance->error_messages)
645 {
646 return instance->error_messages->rc;
647 }
648
649 return MEMCACHED_SUCCESS;
650 }