Merge in local trunk
[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
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 memcached_error_t *error= (struct memcached_error_t *)libmemcached_malloc(&memc, sizeof(struct memcached_error_t));
79 if (not error) // Bad business if this happens
80 return;
81
82 error->root= &memc;
83 error->query_id= memc.query_id;
84 error->rc= rc;
85 error->local_errno= local_errno;
86
87 if (str)
88 {
89 size_t length= str->size > (size_t)MAX_ERROR_LENGTH ? MAX_ERROR_LENGTH : str->size;
90 error->size= length;
91 memcpy(error->message, str->c_str, error->size);
92 error->message[error->size]= 0;
93 }
94 else
95 {
96 error->size= 0;
97 }
98
99 error->next= memc.error_messages;
100 memc.error_messages= error;
101 }
102
103 memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc, const char *at, const char *str, size_t length)
104 {
105 memcached_string_t tmp= { str, length };
106 return memcached_set_error(memc, rc, at, tmp);
107 }
108
109 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at, const char *str, size_t length)
110 {
111 memcached_string_t tmp= { str, length };
112 return memcached_set_error(self, rc, at, tmp);
113 }
114
115 memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc, const char *at, memcached_string_t& str)
116 {
117 if (memcached_success(rc))
118 return MEMCACHED_SUCCESS;
119
120 _set(memc, &str, rc, at);
121
122 return rc;
123 }
124
125 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at, memcached_string_t& str)
126 {
127 if (memcached_success(rc))
128 return MEMCACHED_SUCCESS;
129
130 char hostname_port_message[MAX_ERROR_LENGTH];
131 int size;
132 if (str.size)
133 {
134 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "%.*s, host: %s:%d",
135 memcached_string_printf(str),
136 self.hostname, int(self.port));
137 }
138 else
139 {
140 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
141 self.hostname, int(self.port));
142 }
143
144 memcached_string_t error_host= { hostname_port_message, size };
145
146 if (not self.root)
147 return rc;
148
149 _set(*self.root, &error_host, rc, at);
150
151 return rc;
152 }
153
154 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at)
155 {
156 if (memcached_success(rc))
157 return MEMCACHED_SUCCESS;
158
159 char hostname_port[NI_MAXHOST +NI_MAXSERV + sizeof("host : ")];
160 int size= snprintf(hostname_port, sizeof(hostname_port), "host: %s:%d", self.hostname, int(self.port));
161
162 memcached_string_t error_host= { hostname_port, 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_st& self, memcached_return_t rc, const char *at)
173 {
174 if (memcached_success(rc))
175 return MEMCACHED_SUCCESS;
176
177 _set(self, NULL, rc, at);
178
179 return rc;
180 }
181
182 memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at, const char *str, size_t length)
183 {
184 memcached_string_t tmp= { str, length };
185 return memcached_set_errno(self, local_errno, at, tmp);
186 }
187
188 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at, const char *str, size_t length)
189 {
190 memcached_string_t tmp= { str, length };
191 return memcached_set_errno(self, local_errno, at, tmp);
192 }
193
194 memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at)
195 {
196 if (not local_errno)
197 return MEMCACHED_SUCCESS;
198
199 memcached_return_t rc= MEMCACHED_ERRNO;
200 _set(self, NULL, rc, at, local_errno);
201
202 return rc;
203 }
204
205 memcached_return_t memcached_set_errno(memcached_st& memc, int local_errno, const char *at, memcached_string_t& str)
206 {
207 if (not local_errno)
208 return MEMCACHED_SUCCESS;
209
210 memcached_return_t rc= MEMCACHED_ERRNO;
211 _set(memc, &str, rc, at, local_errno);
212
213 return rc;
214 }
215
216 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at, memcached_string_t& str)
217 {
218 if (not local_errno)
219 return MEMCACHED_SUCCESS;
220
221 char hostname_port_message[MAX_ERROR_LENGTH];
222 int size;
223 if (str.size)
224 {
225 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "%.*s, host: %s:%d",
226 memcached_string_printf(str),
227 self.hostname, int(self.port));
228 }
229 else
230 {
231 size= snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
232 self.hostname, int(self.port));
233 }
234
235 memcached_string_t error_host= { hostname_port_message, size };
236
237 self.cached_errno= local_errno; // Store in the actual server
238
239 memcached_return_t rc= MEMCACHED_ERRNO;
240 if (not self.root)
241 return rc;
242
243 _set(*self.root, &error_host, rc, at, local_errno);
244
245 return rc;
246 }
247
248 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at)
249 {
250 if (not local_errno)
251 return MEMCACHED_SUCCESS;
252
253 char hostname_port_message[MAX_ERROR_LENGTH];
254 int size = snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d",
255 self.hostname, int(self.port));
256
257 memcached_string_t error_host= { hostname_port_message, size };
258
259 self.cached_errno= local_errno; // Store in the actual server
260
261 memcached_return_t rc= MEMCACHED_ERRNO;
262 if (not self.root)
263 return rc;
264
265 _set(*self.root, &error_host, rc, at, local_errno);
266
267 return rc;
268 }
269
270 static void _error_print(const memcached_error_t *error)
271 {
272 if (not error)
273 return;
274
275 if (not error->size)
276 {
277 fprintf(stderr, "%s\n", memcached_strerror(NULL, error->rc) );
278 }
279 else
280 {
281 fprintf(stderr, "%s %s\n", memcached_strerror(NULL, error->rc), error->message);
282 }
283
284 _error_print(error->next);
285 }
286
287 void memcached_error_print(const memcached_st *self)
288 {
289 if (not self)
290 return;
291
292 _error_print(self->error_messages);
293 }
294
295 static void _error_free(memcached_error_t *error)
296 {
297 if (not error)
298 return;
299
300 _error_free(error->next);
301
302 if (error && error->root)
303 {
304 libmemcached_free(error->root, error);
305 }
306 else if (error)
307 {
308 free(error);
309 }
310 }
311
312 void memcached_error_free(memcached_st *self)
313 {
314 if (not self)
315 return;
316
317 _error_free(self->error_messages);
318 self->error_messages= NULL;
319 }
320
321 const char *memcached_last_error_message(memcached_st *memc)
322 {
323 if (not memc)
324 return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
325
326 if (not memc->error_messages)
327 return memcached_strerror(memc, MEMCACHED_SUCCESS);
328
329 if (not memc->error_messages->size)
330 return memcached_strerror(memc, memc->error_messages->rc);
331
332 return memc->error_messages->message;
333 }
334
335 memcached_return_t memcached_last_error(memcached_st *memc)
336 {
337 if (not memc)
338 return MEMCACHED_INVALID_ARGUMENTS;
339
340 if (not memc->error_messages)
341 return MEMCACHED_SUCCESS;
342
343 return memc->error_messages->rc;
344 }
345
346 int memcached_last_error_errno(memcached_st *memc)
347 {
348 if (not memc)
349 return 0;
350
351 if (not memc->error_messages)
352 return 0;
353
354 return memc->error_messages->local_errno;
355 }