Test cleanup, extended error system to record host.
[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, int local_errno= 0)
53 {
54 WATCHPOINT_ASSERT(memc);
55 if (not memc)
56 return;
57
58 if (memc->error_messages && memc->error_messages->query_id != memc->query_id)
59 {
60 memcached_error_free(memc);
61 }
62
63 if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE or rc == MEMCACHED_ERRNO)
64 {
65 local_errno= errno;
66 rc= MEMCACHED_ERRNO;
67 }
68
69 memcached_error_t *error;
70 error= (struct memcached_error_t *)libmemcached_malloc(memc, sizeof(struct memcached_error_t));
71
72 if (not error)
73 return;
74
75 error->root= memc;
76 error->query_id= memc->query_id;
77 error->rc= rc;
78 error->local_errno= local_errno;
79
80 if (str)
81 {
82 size_t length= str->size > (size_t)MAX_ERROR_LENGTH ? MAX_ERROR_LENGTH : str->size;
83 error->size= length;
84 memcpy(error->message, str->c_str, error->size);
85 error->message[error->size]= 0;
86 }
87 else
88 {
89 error->size= 0;
90 }
91
92 error->next= memc->error_messages;
93 memc->error_messages= error;
94 }
95
96 memcached_return_t memcached_set_error_string(memcached_st *memc, memcached_return_t rc, const char *str, size_t length)
97 {
98 memcached_string_t tmp;
99 tmp.c_str= str;
100 tmp.size= length;
101 return memcached_set_error_message(memc, rc, &tmp);
102 }
103
104 memcached_return_t memcached_set_error_message(memcached_st *memc, memcached_return_t rc, memcached_string_t *str)
105 {
106 if (rc == MEMCACHED_SUCCESS)
107 return MEMCACHED_SUCCESS;
108
109 _set(memc, str, rc);
110
111 return rc;
112 }
113
114 memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc)
115 {
116 if (rc == MEMCACHED_SUCCESS)
117 return MEMCACHED_SUCCESS;
118
119 char hostname_port[NI_MAXHOST +NI_MAXSERV + sizeof("host : ")];
120 int size= snprintf(hostname_port, sizeof(hostname_port), "host: %s:%d", self.hostname, int(self.port));
121
122 memcached_string_t error_host= { size, hostname_port };
123
124 _set((memcached_st*)self.root, &error_host, rc);
125
126 return rc;
127 }
128
129 memcached_return_t memcached_set_error(memcached_st* self, memcached_return_t rc)
130 {
131 if (memcached_success(rc))
132 return MEMCACHED_SUCCESS;
133
134 _set(self, NULL, rc);
135
136 return rc;
137 }
138
139 memcached_return_t memcached_set_error(memcached_st& self, memcached_return_t rc)
140 {
141 if (memcached_success(rc))
142 return MEMCACHED_SUCCESS;
143
144 _set(&self, NULL, rc);
145
146 return rc;
147 }
148
149 memcached_return_t memcached_set_errno(memcached_st *memc, int local_errno, memcached_string_t *str)
150 {
151 memcached_return_t rc= MEMCACHED_ERRNO;
152 _set(memc, str, rc, local_errno);
153
154 return rc;
155 }
156
157 memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, memcached_string_t *)
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= { size, hostname_port };
163
164 self.cached_errno= local_errno;
165 memcached_return_t rc= MEMCACHED_ERRNO;
166 _set((memcached_st*)self.root, &error_host, rc, local_errno);
167
168 return rc;
169 }
170
171 static void _error_print(const memcached_error_t *error)
172 {
173 if (not error)
174 return;
175
176 if (not error->size)
177 {
178 fprintf(stderr, "%s\n", memcached_strerror(NULL, error->rc) );
179 }
180 else
181 {
182 fprintf(stderr, "%s %s\n", memcached_strerror(NULL, error->rc), error->message);
183 }
184
185 _error_print(error->next);
186 }
187
188 void memcached_error_print(const memcached_st *self)
189 {
190 if (not self)
191 return;
192
193 _error_print(self->error_messages);
194 }
195
196 static void _error_free(memcached_error_t *error)
197 {
198 if (not error)
199 return;
200
201 _error_free(error->next);
202
203 if (error && error->root)
204 {
205 libmemcached_free(error->root, error);
206 }
207 else if (error)
208 {
209 free(error);
210 }
211 }
212
213 void memcached_error_free(memcached_st *self)
214 {
215 if (not self)
216 return;
217
218 _error_free(self->error_messages);
219 self->error_messages= NULL;
220 }
221
222 const char *memcached_last_error_message(memcached_st *memc)
223 {
224 if (not memc)
225 return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
226
227 if (not memc->error_messages)
228 return memcached_strerror(memc, MEMCACHED_SUCCESS);
229
230 if (not memc->error_messages->size)
231 return memcached_strerror(memc, memc->error_messages->rc);
232
233 return memc->error_messages->message;
234 }
235
236 memcached_return_t memcached_last_error(memcached_st *memc)
237 {
238 if (not memc)
239 return MEMCACHED_INVALID_ARGUMENTS;
240
241 if (not memc->error_messages)
242 return MEMCACHED_SUCCESS;
243
244 return memc->error_messages->rc;
245 }
246
247 int memcached_last_error_errno(memcached_st *memc)
248 {
249 if (not memc)
250 return 0;
251
252 if (not memc->error_messages)
253 return 0;
254
255 return memc->error_messages->local_errno;
256 }