ab17926e67cf27d3941fffd111eec606def06a29
[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 }
220
221 #if 0
222 if (error_log_fd == -1)
223 {
224 // unlink("/tmp/libmemcachd.log");
225 if ((error_log_fd= open("/tmp/libmemcachd.log", O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0)
226 {
227 perror("open");
228 error_log_fd= -1;
229 }
230 }
231 ::write(error_log_fd, error->message, error->size);
232 ::write(error_log_fd, "\n", 1);
233 #endif
234 }
235
236 memcached_return_t memcached_set_error(Memcached& memc, memcached_return_t rc, const char *at, const char *str, size_t length)
237 {
238 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
239 memcached_string_t tmp= { str, length };
240 return memcached_set_error(memc, rc, at, tmp);
241 }
242
243 memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at, const char *str, size_t length)
244 {
245 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
246 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a Instance");
247
248 memcached_string_t tmp= { str, length };
249 return memcached_set_error(self, rc, at, tmp);
250 }
251
252 #ifndef __INTEL_COMPILER
253 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
254 #endif
255
256 memcached_return_t memcached_set_error(Memcached& memc, memcached_return_t rc, const char *at, memcached_string_t& str)
257 {
258 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
259 if (memcached_fatal(rc))
260 {
261 _set(memc, &str, rc, at);
262 }
263
264 return rc;
265 }
266
267 memcached_return_t memcached_set_parser_error(Memcached& memc,
268 const char *at,
269 const char *format, ...)
270 {
271 va_list args;
272
273 char buffer[BUFSIZ];
274 va_start(args, format);
275 int length= vsnprintf(buffer, sizeof(buffer), format, args);
276 va_end(args);
277
278 return memcached_set_error(memc, MEMCACHED_PARSE_ERROR, at, buffer, length);
279 }
280
281 static inline size_t append_host_to_string(memcached_instance_st& self, char* buffer, const size_t buffer_length)
282 {
283 size_t size= 0;
284 switch (self.type)
285 {
286 case MEMCACHED_CONNECTION_TCP:
287 case MEMCACHED_CONNECTION_UDP:
288 size+= snprintf(buffer, buffer_length, " host: %s:%d",
289 self.hostname(), int(self.port()));
290 break;
291
292 case MEMCACHED_CONNECTION_UNIX_SOCKET:
293 size+= snprintf(buffer, buffer_length, " socket: %s",
294 self.hostname());
295 break;
296 }
297
298 return size;
299 }
300
301 memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at, memcached_string_t& str)
302 {
303 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
304 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_instance_st");
305 if (memcached_fatal(rc) == false and rc != MEMCACHED_CLIENT_ERROR)
306 {
307 return rc;
308 }
309
310 char hostname_port_message[MAX_ERROR_LENGTH];
311 char* hostname_port_message_ptr= hostname_port_message;
312 int size= 0;
313 if (str.size)
314 {
315 size= snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ",
316 memcached_string_printf(str));
317 hostname_port_message_ptr+= size;
318 }
319
320 size+= append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) -size);
321
322 memcached_string_t error_host= { hostname_port_message, size_t(size) };
323
324 assert_msg(self.root, "Programmer error, root was not set on instance");
325 if (self.root)
326 {
327 _set(*self.root, &error_host, rc, at);
328 _set(self, (*self.root));
329 assert(self.error_messages);
330 assert(self.root->error_messages);
331 assert(self.error_messages->rc == self.root->error_messages->rc);
332 }
333
334 return rc;
335 }
336
337 memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at)
338 {
339 assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_instance_st");
340 if (memcached_fatal(rc) == false)
341 {
342 return rc;
343 }
344
345 char hostname_port[MEMCACHED_NI_MAXHOST +MEMCACHED_NI_MAXSERV + sizeof("host : ")];
346 size_t size= append_host_to_string(self, hostname_port, sizeof(hostname_port));
347
348 memcached_string_t error_host= { hostname_port, size};
349
350 if (self.root)
351 {
352 _set(*self.root, &error_host, rc, at);
353 _set(self, *self.root);
354 }
355
356 return rc;
357 }
358
359 memcached_return_t memcached_set_error(Memcached& self, memcached_return_t rc, const char *at)
360 {
361 assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
362 if (memcached_fatal(rc) == false)
363 {
364 return rc;
365 }
366
367 _set(self, NULL, rc, at);
368
369 return rc;
370 }
371
372 memcached_return_t memcached_set_errno(Memcached& self, int local_errno, const char *at, const char *str, size_t length)
373 {
374 memcached_string_t tmp= { str, length };
375 return memcached_set_errno(self, local_errno, at, tmp);
376 }
377
378 memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at, const char *str, size_t length)
379 {
380 memcached_string_t tmp= { str, length };
381 return memcached_set_errno(self, local_errno, at, tmp);
382 }
383
384 memcached_return_t memcached_set_errno(Memcached& self, int local_errno, const char *at)
385 {
386 if (local_errno == 0)
387 {
388 return MEMCACHED_SUCCESS;
389 }
390
391 memcached_return_t rc= MEMCACHED_ERRNO;
392 _set(self, NULL, rc, at, local_errno);
393
394 return rc;
395 }
396
397 memcached_return_t memcached_set_errno(Memcached& memc, int local_errno, const char *at, memcached_string_t& str)
398 {
399 if (local_errno == 0)
400 {
401 return MEMCACHED_SUCCESS;
402 }
403
404 memcached_return_t rc= MEMCACHED_ERRNO;
405 _set(memc, &str, rc, at, local_errno);
406
407 return rc;
408 }
409
410 memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at, memcached_string_t& str)
411 {
412 if (local_errno == 0)
413 {
414 return MEMCACHED_SUCCESS;
415 }
416
417 char hostname_port_message[MAX_ERROR_LENGTH];
418 char* hostname_port_message_ptr= hostname_port_message;
419 size_t size= 0;
420 if (str.size)
421 {
422 size= snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ", memcached_string_printf(str));
423 }
424 size+= append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) -size);
425
426 memcached_string_t error_host= { hostname_port_message, size };
427
428 memcached_return_t rc= MEMCACHED_ERRNO;
429 if (self.root == NULL)
430 {
431 return rc;
432 }
433
434 _set(*self.root, &error_host, rc, at, local_errno);
435 _set(self, (*self.root));
436
437 #if 0
438 if (self.root->error_messages->rc != self.error_messages->rc)
439 {
440 fprintf(stderr, "%s:%d %s != %s\n", __FILE__, __LINE__,
441 memcached_strerror(NULL, self.root->error_messages->rc),
442 memcached_strerror(NULL, self.error_messages->rc));
443 }
444 #endif
445
446 return rc;
447 }
448
449 memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at)
450 {
451 if (local_errno == 0)
452 {
453 return MEMCACHED_SUCCESS;
454 }
455
456 char hostname_port_message[MAX_ERROR_LENGTH];
457 size_t size= append_host_to_string(self, hostname_port_message, sizeof(hostname_port_message));
458
459 memcached_string_t error_host= { hostname_port_message, size };
460
461 memcached_return_t rc= MEMCACHED_ERRNO;
462 if (self.root == NULL)
463 {
464 return rc;
465 }
466
467 _set(*self.root, &error_host, rc, at, local_errno);
468 _set(self, (*self.root));
469
470 return rc;
471 }
472
473 static void _error_print(const memcached_error_t *error)
474 {
475 if (error == NULL)
476 {
477 return;
478 }
479
480 if (error->size == 0)
481 {
482 fprintf(stderr, "\t%s\n", memcached_strerror(NULL, error->rc) );
483 }
484 else
485 {
486 fprintf(stderr, "\t%s %s\n", memcached_strerror(NULL, error->rc), error->message);
487 }
488
489 _error_print(error->next);
490 }
491
492 void memcached_error_print(const Memcached *shell)
493 {
494 const Memcached* self= memcached2Memcached(shell);
495 if (self == NULL)
496 {
497 return;
498 }
499
500 _error_print(self->error_messages);
501
502 for (uint32_t x= 0; x < memcached_server_count(self); x++)
503 {
504 memcached_instance_st* instance= memcached_instance_by_position(self, x);
505
506 _error_print(instance->error_messages);
507 }
508 }
509
510 static void _error_free(memcached_error_t *error)
511 {
512 if (error)
513 {
514 _error_free(error->next);
515
516 libmemcached_free(error->root, error);
517 }
518 }
519
520 void memcached_error_free(Memcached& self)
521 {
522 _error_free(self.error_messages);
523 self.error_messages= NULL;
524 }
525
526 void memcached_error_free(memcached_instance_st& self)
527 {
528 _error_free(self.error_messages);
529 self.error_messages= NULL;
530 }
531
532 void memcached_error_free(memcached_server_st& self)
533 {
534 _error_free(self.error_messages);
535 self.error_messages= NULL;
536 }
537
538 const char *memcached_error(const memcached_st *memc)
539 {
540 return memcached_last_error_message(memc);
541 }
542
543 const char *memcached_last_error_message(const memcached_st *shell)
544 {
545 const Memcached* memc= memcached2Memcached(shell);
546 if (memc)
547 {
548 if (memc->error_messages)
549 {
550 if (memc->error_messages->size and memc->error_messages->message[0])
551 {
552 return memc->error_messages->message;
553 }
554
555 return memcached_strerror(memc, memc->error_messages->rc);
556 }
557
558 return memcached_strerror(memc, MEMCACHED_SUCCESS);
559 }
560
561 return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
562 }
563
564 bool memcached_has_current_error(Memcached &memc)
565 {
566 if (memc.error_messages
567 and memc.error_messages->query_id == memc.query_id
568 and memcached_failed(memc.error_messages->rc))
569 {
570 return true;
571 }
572
573 return false;
574 }
575
576 bool memcached_has_current_error(memcached_instance_st& server)
577 {
578 return memcached_has_current_error(*(server.root));
579 }
580
581 memcached_return_t memcached_last_error(const memcached_st *shell)
582 {
583 const Memcached* memc= memcached2Memcached(shell);
584 if (memc)
585 {
586 if (memc->error_messages)
587 {
588 return memc->error_messages->rc;
589 }
590
591 return MEMCACHED_SUCCESS;
592 }
593
594 return MEMCACHED_INVALID_ARGUMENTS;
595 }
596
597 int memcached_last_error_errno(const memcached_st *shell)
598 {
599 const Memcached* memc= memcached2Memcached(shell);
600 if (memc == NULL)
601 {
602 return 0;
603 }
604
605 if (memc->error_messages == NULL)
606 {
607 return 0;
608 }
609
610 return memc->error_messages->local_errno;
611 }
612
613 const char *memcached_server_error(const memcached_instance_st * server)
614 {
615 if (server == NULL)
616 {
617 return NULL;
618 }
619
620 if (server->error_messages == NULL)
621 {
622 return memcached_strerror(server->root, MEMCACHED_SUCCESS);
623 }
624
625 if (server->error_messages->size == 0)
626 {
627 return memcached_strerror(server->root, server->error_messages->rc);
628 }
629
630 return server->error_messages->message;
631 }
632
633
634 memcached_error_t *memcached_error_copy(const memcached_instance_st& server)
635 {
636 if (server.error_messages == NULL)
637 {
638 return NULL;
639 }
640
641 memcached_error_t *error= libmemcached_xmalloc(server.root, memcached_error_t);
642 memcpy(error, server.error_messages, sizeof(memcached_error_t));
643 error->next= NULL;
644
645 return error;
646 }
647
648 memcached_return_t memcached_server_error_return(const memcached_instance_st * ptr)
649 {
650 if (ptr == NULL)
651 {
652 return MEMCACHED_INVALID_ARGUMENTS;
653 }
654
655 if (ptr and ptr->error_messages)
656 {
657 return ptr->error_messages->rc;
658 }
659
660 return MEMCACHED_SUCCESS;
661 }
662
663 memcached_return_t memcached_instance_error_return(memcached_instance_st* instance)
664 {
665 if (instance == NULL)
666 {
667 return MEMCACHED_INVALID_ARGUMENTS;
668 }
669
670 if (instance and instance->error_messages)
671 {
672 return instance->error_messages->rc;
673 }
674
675 return MEMCACHED_SUCCESS;
676 }