Removed memory leak by releasing the items when I'm done using them
[m6w6/libmemcached] / example / interface_v1.c
1 /* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 /**
3 * This file contains an implementation of the callback interface for level 1
4 * in the protocol library. If you compare the implementation with the one
5 * in interface_v0.c you will see that this implementation is much easier and
6 * hides all of the protocol logic and let you focus on the application
7 * logic. One "problem" with this layer is that it is synchronous, so that
8 * you will not receive the next command before a answer to the previous
9 * command is being sent.
10 */
11 #include <assert.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <netdb.h>
15 #include <netinet/tcp.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <libmemcached/protocol_handler.h>
24 #include <libmemcached/byteorder.h>
25 #include "storage.h"
26
27 static protocol_binary_response_status add_handler(const void *cookie,
28 const void *key,
29 uint16_t keylen,
30 const void *data,
31 uint32_t datalen,
32 uint32_t flags,
33 uint32_t exptime,
34 uint64_t *cas)
35 {
36 (void)cookie;
37 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
38 struct item* item= get_item(key, keylen);
39 if (item == NULL)
40 {
41 item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
42 if (item == 0)
43 {
44 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
45 }
46 else
47 {
48 put_item(item);
49 *cas= item->cas;
50 release_item(item);
51 }
52 }
53 else
54 {
55 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
56 }
57
58 return rval;
59 }
60
61 static protocol_binary_response_status append_handler(const void *cookie,
62 const void *key,
63 uint16_t keylen,
64 const void* val,
65 uint32_t vallen,
66 uint64_t cas,
67 uint64_t *result_cas) {
68 (void)cookie;
69 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
70
71 struct item *item= get_item(key, keylen);
72 struct item *nitem;
73
74 if (item == NULL)
75 {
76 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
77 }
78 else if (cas != 0 && cas != item->cas)
79 {
80 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
81 }
82 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
83 item->flags, item->exp)) == NULL)
84 {
85 release_item(item);
86 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
87 }
88 else
89 {
90 memcpy(nitem->data, item->data, item->size);
91 memcpy(((char*)(nitem->data)) + item->size, val, vallen);
92 release_item(item);
93 delete_item(key, keylen);
94 put_item(nitem);
95 *result_cas= nitem->cas;
96 release_item(nitem);
97 }
98
99 return rval;
100 }
101
102 static protocol_binary_response_status decrement_handler(const void *cookie,
103 const void *key,
104 uint16_t keylen,
105 uint64_t delta,
106 uint64_t initial,
107 uint32_t expiration,
108 uint64_t *result,
109 uint64_t *result_cas) {
110 (void)cookie;
111 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
112 uint64_t val= initial;
113 struct item *item= get_item(key, keylen);
114
115 if (item != NULL)
116 {
117 if (delta > *(uint64_t*)item->data)
118 val= 0;
119 else
120 val= *(uint64_t*)item->data - delta;
121
122 expiration= (uint32_t)item->exp;
123 release_item(item);
124 delete_item(key, keylen);
125 }
126
127 item= create_item(key, keylen, NULL, sizeof(initial), 0, (time_t)expiration);
128 if (item == 0)
129 {
130 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
131 }
132 else
133 {
134 memcpy(item->data, &val, sizeof(val));
135 put_item(item);
136 *result= val;
137 *result_cas= item->cas;
138 release_item(item);
139 }
140
141 return rval;
142 }
143
144 static protocol_binary_response_status delete_handler(const void *cookie,
145 const void *key,
146 uint16_t keylen,
147 uint64_t cas) {
148 (void)cookie;
149 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
150
151 if (cas != 0)
152 {
153 struct item *item= get_item(key, keylen);
154 if (item != NULL)
155 {
156 if (item->cas != cas)
157 {
158 release_item(item);
159 return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
160 }
161 release_item(item);
162 }
163 }
164
165 if (!delete_item(key, keylen))
166 {
167 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
168 }
169
170 return rval;
171 }
172
173
174 static protocol_binary_response_status flush_handler(const void *cookie,
175 uint32_t when) {
176
177 (void)cookie;
178 flush(when);
179 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
180 }
181
182 static protocol_binary_response_status get_handler(const void *cookie,
183 const void *key,
184 uint16_t keylen,
185 memcached_binary_protocol_get_response_handler response_handler) {
186 struct item *item= get_item(key, keylen);
187
188 if (item == NULL)
189 {
190 return PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
191 }
192
193 protocol_binary_response_status rc;
194 rc= response_handler(cookie, key, (uint16_t)keylen,
195 item->data, (uint32_t)item->size, item->flags,
196 item->cas);
197 release_item(item);
198 return rc;
199 }
200
201 static protocol_binary_response_status increment_handler(const void *cookie,
202 const void *key,
203 uint16_t keylen,
204 uint64_t delta,
205 uint64_t initial,
206 uint32_t expiration,
207 uint64_t *result,
208 uint64_t *result_cas) {
209 (void)cookie;
210 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
211 uint64_t val= initial;
212 struct item *item= get_item(key, keylen);
213
214 if (item != NULL)
215 {
216 val= (*(uint64_t*)item->data) + delta;
217 expiration= (uint32_t)item->exp;
218 release_item(item);
219 delete_item(key, keylen);
220 }
221
222 item= create_item(key, keylen, NULL, sizeof(initial), 0, (time_t)expiration);
223 if (item == NULL)
224 {
225 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
226 }
227 else
228 {
229 char buffer[1024] = {0};
230 memcpy(buffer, key, keylen);
231 memcpy(item->data, &val, sizeof(val));
232 put_item(item);
233 *result= val;
234 *result_cas= item->cas;
235 release_item(item);
236 }
237
238 return rval;
239 }
240
241 static protocol_binary_response_status noop_handler(const void *cookie) {
242 (void)cookie;
243 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
244 }
245
246 static protocol_binary_response_status prepend_handler(const void *cookie,
247 const void *key,
248 uint16_t keylen,
249 const void* val,
250 uint32_t vallen,
251 uint64_t cas,
252 uint64_t *result_cas) {
253 (void)cookie;
254 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
255
256 struct item *item= get_item(key, keylen);
257 struct item *nitem= NULL;
258
259 if (item == NULL)
260 {
261 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
262 }
263 else if (cas != 0 && cas != item->cas)
264 {
265 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
266 }
267 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
268 item->flags, item->exp)) == NULL)
269 {
270 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
271 }
272 else
273 {
274 memcpy(nitem->data, val, vallen);
275 memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
276 release_item(item);
277 item= NULL;
278 delete_item(key, keylen);
279 put_item(nitem);
280 *result_cas= nitem->cas;
281 }
282
283 if (item)
284 release_item(item);
285
286 if (nitem)
287 release_item(nitem);
288
289 return rval;
290 }
291
292 static protocol_binary_response_status quit_handler(const void *cookie) {
293 (void)cookie;
294 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
295 }
296
297 static protocol_binary_response_status replace_handler(const void *cookie,
298 const void *key,
299 uint16_t keylen,
300 const void* data,
301 uint32_t datalen,
302 uint32_t flags,
303 uint32_t exptime,
304 uint64_t cas,
305 uint64_t *result_cas) {
306 (void)cookie;
307 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
308 struct item* item= get_item(key, keylen);
309
310 if (item == NULL)
311 {
312 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
313 }
314 else if (cas == 0 || cas == item->cas)
315 {
316 release_item(item);
317 delete_item(key, keylen);
318 item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
319 if (item == 0)
320 {
321 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
322 }
323 else
324 {
325 put_item(item);
326 *result_cas= item->cas;
327 release_item(item);
328 }
329 }
330 else
331 {
332 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
333 release_item(item);
334 }
335
336 return rval;
337 }
338
339 static protocol_binary_response_status set_handler(const void *cookie,
340 const void *key,
341 uint16_t keylen,
342 const void* data,
343 uint32_t datalen,
344 uint32_t flags,
345 uint32_t exptime,
346 uint64_t cas,
347 uint64_t *result_cas) {
348 (void)cookie;
349 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
350
351 if (cas != 0)
352 {
353 struct item* item= get_item(key, keylen);
354 if (item != NULL && cas != item->cas)
355 {
356 /* Invalid CAS value */
357 release_item(item);
358 return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
359 }
360 }
361
362 delete_item(key, keylen);
363 struct item* item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
364 if (item == 0)
365 {
366 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
367 }
368 else
369 {
370 put_item(item);
371 *result_cas= item->cas;
372 release_item(item);
373 }
374
375 return rval;
376 }
377
378 static protocol_binary_response_status stat_handler(const void *cookie,
379 const void *key,
380 uint16_t keylen,
381 memcached_binary_protocol_stat_response_handler response_handler) {
382 (void)key;
383 (void)keylen;
384 /* Just return an empty packet */
385 return response_handler(cookie, NULL, 0, NULL, 0);
386 }
387
388 static protocol_binary_response_status version_handler(const void *cookie,
389 memcached_binary_protocol_version_response_handler response_handler) {
390 const char *version= "0.1.1";
391 return response_handler(cookie, version, (uint32_t)strlen(version));
392 }
393
394 struct memcached_binary_protocol_callback_st interface_v1_impl= {
395 .interface_version= 1,
396 .interface.v1= {
397 .add= add_handler,
398 .append= append_handler,
399 .decrement= decrement_handler,
400 .delete= delete_handler,
401 .flush= flush_handler,
402 .get= get_handler,
403 .increment= increment_handler,
404 .noop= noop_handler,
405 .prepend= prepend_handler,
406 .quit= quit_handler,
407 .replace= replace_handler,
408 .set= set_handler,
409 .stat= stat_handler,
410 .version= version_handler
411 }
412 };