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