Merge in fix for additional logic for timeouts.
[m6w6/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 <cassert>
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(memcached_st& memc, memcached_string_t *str, memcached_return_t &rc, const char *at, int local_errno= 0)
54 {
55 (void)at;
56 if (memc.error_messages && memc.error_messages->query_id != memc.query_id)
57 {
58 memcached_error_free(&memc);
59 }
60
61 // For memory allocation we use our error since it is a bit more specific
62 if (local_errno == ENOMEM and rc == MEMCACHED_ERRNO)
63 {
64 local_errno= ENOMEM;
65 rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
66 }
67
68 if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
69 {
70 local_errno= ENOMEM;
71 }
72
73 if (rc == MEMCACHED_ERRNO and not local_errno)
74 {
75 local_errno= errno;
76 rc= MEMCACHED_ERRNO;
77 }
78
79 if (rc == MEMCACHED_ERRNO and local_errno == ENOTCONN)
80 {
81 rc= MEMCACHED_CONNECTION_FAILURE;
82 }
83
84 memcached_error_t *error= (struct memcached_error_t *)libmemcached_malloc(&memc, sizeof(struct memcached_error_t));
85 if (not error) // Bad business if this happens
86 return;
87
88 error->root= &memc;
89 error->query_id= memc.query_id;
90 error->rc= rc;
91 error->local_errno= local_errno;
92
93 if (str and str->size and local_errno)
94 {
95 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s(%s), %.*s -> %s",
96 memcached_strerror(&memc, rc),
97 strerror(local_errno),
98 memcached_string_printf(*str), at);
99 }
100 else if (local_errno)
101 {
102 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s(%s) -> %s",
103 memcached_strerror(&memc, rc),
104 strerror(local_errno), at);
105 }
106 else if (str and str->size)
107 {
108 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s, %.*s -> %s",
109 memcached_strerror(&memc, rc),
110 int(str->size), str->c_str, at);
111 }
112 else
113 {
114 error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "%s -> %s",
115 memcached_strerror(&memc, rc), at);
116 }
117
118 error->next= memc.error_messages;
119 memc.error_messages= error;
120 }
121
122 memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc, const char *at, const char *str, size_t length)
123 {
124 assert(rc != MEMCACHED_ERRNO);
125 memcached_string_t tmp= { str, length };
126 return memcached_set_error(memc, rc, at, tmp);
127 }
128
129 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at, const char *str, size_t length)
130 {
131 assert(rc != MEMCACHED_ERRNO);
132 memcached_string_t tmp= { str, length };
133 return memcached_set_error(self, rc, at, tmp);
134 }
135
136 memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc, const char *at, memcached_string_t& str)
137 {
138 assert(rc != MEMCACHED_ERRNO);
139 if (memcached_success(rc))
140 return MEMCACHED_SUCCESS;
141
142 _set(memc, &str, rc, at);
143
144 return rc;
145 }
146
147 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at, memcached_string_t& str)
148 {
149 assert(rc != MEMCACHED_ERRNO);
150 if (memcached_success(rc))
151 return MEMCACHED_SUCCESS;
152
153 char hostname_port_message[MAX_ERROR_LENGTH];
154 int size;
155 if (str.size)
156 {
157 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "%.*s, host: %s:%d",
158 memcached_string_printf(str),
159 self.hostname, int(self.port));
160 }
161 else
162 {
163 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
164 self.hostname, int(self.port));
165 }
166
167 memcached_string_t error_host= { hostname_port_message, size };
168
169 if (not self.root)
170 return rc;
171
172 _set(*self.root, &error_host, rc, at);
173
174 return rc;
175 }
176
177 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at)
178 {
179 assert(rc != MEMCACHED_ERRNO);
180 if (memcached_success(rc))
181 return MEMCACHED_SUCCESS;
182
183 char hostname_port[NI_MAXHOST +NI_MAXSERV + sizeof("host : ")];
184 int size= snprintf(hostname_port, sizeof(hostname_port), "host: %s:%d", self.hostname, int(self.port));
185
186 memcached_string_t error_host= { hostname_port, size};
187
188 if (not self.root)
189 return rc;
190
191 _set(*self.root, &error_host, rc, at);
192
193 return rc;
194 }
195
196 memcached_return_t memcached_set_error(memcached_st& self, memcached_return_t rc, const char *at)
197 {
198 assert(rc != MEMCACHED_ERRNO);
199 if (memcached_success(rc))
200 return MEMCACHED_SUCCESS;
201
202 _set(self, NULL, rc, at);
203
204 return rc;
205 }
206
207 memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at, const char *str, size_t length)
208 {
209 memcached_string_t tmp= { str, length };
210 return memcached_set_errno(self, local_errno, at, tmp);
211 }
212
213 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at, const char *str, size_t length)
214 {
215 memcached_string_t tmp= { str, length };
216 return memcached_set_errno(self, local_errno, at, tmp);
217 }
218
219 memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at)
220 {
221 if (not local_errno)
222 return MEMCACHED_SUCCESS;
223
224 memcached_return_t rc= MEMCACHED_ERRNO;
225 _set(self, NULL, rc, at, local_errno);
226
227 return rc;
228 }
229
230 memcached_return_t memcached_set_errno(memcached_st& memc, int local_errno, const char *at, memcached_string_t& str)
231 {
232 if (not local_errno)
233 return MEMCACHED_SUCCESS;
234
235 memcached_return_t rc= MEMCACHED_ERRNO;
236 _set(memc, &str, rc, at, local_errno);
237
238 return rc;
239 }
240
241 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at, memcached_string_t& str)
242 {
243 if (not local_errno)
244 return MEMCACHED_SUCCESS;
245
246 char hostname_port_message[MAX_ERROR_LENGTH];
247 int size;
248 if (str.size)
249 {
250 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "%.*s, host: %s:%d",
251 memcached_string_printf(str),
252 self.hostname, int(self.port));
253 }
254 else
255 {
256 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
257 self.hostname, int(self.port));
258 }
259
260 memcached_string_t error_host= { hostname_port_message, size };
261
262 self.cached_errno= local_errno; // Store in the actual server
263
264 memcached_return_t rc= MEMCACHED_ERRNO;
265 if (not self.root)
266 return rc;
267
268 _set(*self.root, &error_host, rc, at, local_errno);
269
270 return rc;
271 }
272
273 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at)
274 {
275 if (not local_errno)
276 return MEMCACHED_SUCCESS;
277
278 char hostname_port_message[MAX_ERROR_LENGTH];
279 int size = snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
280 self.hostname, int(self.port));
281
282 memcached_string_t error_host= { hostname_port_message, size };
283
284 self.cached_errno= local_errno; // Store in the actual server
285
286 memcached_return_t rc= MEMCACHED_ERRNO;
287 if (not self.root)
288 return rc;
289
290 _set(*self.root, &error_host, rc, at, local_errno);
291
292 return rc;
293 }
294
295 static void _error_print(const memcached_error_t *error)
296 {
297 if (not error)
298 return;
299
300 if (not error->size)
301 {
302 fprintf(stderr, "%s\n", memcached_strerror(NULL, error->rc) );
303 }
304 else
305 {
306 fprintf(stderr, "%s %s\n", memcached_strerror(NULL, error->rc), error->message);
307 }
308
309 _error_print(error->next);
310 }
311
312 void memcached_error_print(const memcached_st *self)
313 {
314 if (not self)
315 return;
316
317 _error_print(self->error_messages);
318 }
319
320 static void _error_free(memcached_error_t *error)
321 {
322 if (not error)
323 return;
324
325 _error_free(error->next);
326
327 if (error && error->root)
328 {
329 libmemcached_free(error->root, error);
330 }
331 else if (error)
332 {
333 free(error);
334 }
335 }
336
337 void memcached_error_free(memcached_st *self)
338 {
339 if (not self)
340 return;
341
342 _error_free(self->error_messages);
343 self->error_messages= NULL;
344 }
345
346 const char *memcached_last_error_message(memcached_st *memc)
347 {
348 if (not memc)
349 return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
350
351 if (not memc->error_messages)
352 return memcached_strerror(memc, MEMCACHED_SUCCESS);
353
354 if (not memc->error_messages->size)
355 return memcached_strerror(memc, memc->error_messages->rc);
356
357 return memc->error_messages->message;
358 }
359
360
361 bool memcached_has_current_error(memcached_st &memc)
362 {
363 if (memc.error_messages
364 and memc.error_messages->query_id == memc.query_id
365 and memcached_failed(memc.error_messages->rc))
366 {
367 return true;
368 }
369
370 return false;
371 }
372
373 memcached_return_t memcached_last_error(memcached_st *memc)
374 {
375 if (not memc)
376 return MEMCACHED_INVALID_ARGUMENTS;
377
378 if (not memc->error_messages)
379 return MEMCACHED_SUCCESS;
380
381 return memc->error_messages->rc;
382 }
383
384 int memcached_last_error_errno(memcached_st *memc)
385 {
386 if (not memc)
387 return 0;
388
389 if (not memc->error_messages)
390 return 0;
391
392 return memc->error_messages->local_errno;
393 }