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