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