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