memcache 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,575 @@
1
+ #include "ruby.h"
2
+ #include <libmemcached/memcached.h>
3
+ #include <ctype.h>
4
+
5
+ VALUE cMemcache;
6
+ VALUE cMemcacheBase;
7
+ VALUE cNativeServer;
8
+ VALUE cMemcacheError;
9
+ VALUE cMemcacheServerError;
10
+ VALUE cMemcacheClientError;
11
+ VALUE cMemcacheConnectionError;
12
+ VALUE sym_host;
13
+ VALUE sym_port;
14
+ VALUE sym_prefix;
15
+ VALUE sym_hash;
16
+ VALUE sym_hash_with_prefix;
17
+ VALUE sym_binary;
18
+ VALUE sym_servers;
19
+
20
+ ID id_default;
21
+ ID id_md5;
22
+ ID id_crc;
23
+ ID id_fnv1_64;
24
+ ID id_fnv1a_64;
25
+ ID id_fnv1_32;
26
+ ID id_fnv1a_32;
27
+ ID id_jenkins;
28
+ ID id_hsieh;
29
+ ID id_murmur;
30
+
31
+ static ID iv_memcache_flags, iv_memcache_cas;
32
+
33
+ static void mc_free(void *p) {
34
+ memcached_free(p);
35
+ }
36
+
37
+ static VALUE mc_alloc(VALUE klass) {
38
+ memcached_st *mc;
39
+ VALUE obj;
40
+
41
+ mc = memcached_create(NULL);
42
+ /* memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_VERIFY_KEY, true); */
43
+ memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_CACHE_LOOKUPS, true);
44
+
45
+ obj = Data_Wrap_Struct(klass, 0, mc_free, mc);
46
+ return obj;
47
+ }
48
+
49
+ static VALUE throw_error(memcached_return_t *error) {
50
+ memcached_st *mc;
51
+ printf("ERROR: %s\n", memcached_strerror(mc, *error));
52
+ switch(*error) {
53
+ case MEMCACHED_SERVER_ERROR: rb_raise(cMemcacheServerError, "Server error");
54
+ case MEMCACHED_CLIENT_ERROR: rb_raise(cMemcacheClientError, "Client error");
55
+ case MEMCACHED_CONNECTION_FAILURE:
56
+ case MEMCACHED_CONNECTION_BIND_FAILURE:
57
+ case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE:
58
+ rb_raise(cMemcacheConnectionError, "Connection error");
59
+ default:
60
+ rb_raise(cMemcacheError, "Memcache error");
61
+ }
62
+ return Qnil;
63
+ }
64
+
65
+ static memcached_hash_t hash_behavior(VALUE sym) {
66
+ ID id = SYM2ID(sym);
67
+
68
+ if (id == id_default ) return MEMCACHED_HASH_DEFAULT;
69
+ if (id == id_md5 ) return MEMCACHED_HASH_MD5;
70
+ if (id == id_crc ) return MEMCACHED_HASH_CRC;
71
+ if (id == id_fnv1_64 ) return MEMCACHED_HASH_FNV1_64;
72
+ if (id == id_fnv1a_64 ) return MEMCACHED_HASH_FNV1A_64;
73
+ if (id == id_fnv1_32 ) return MEMCACHED_HASH_FNV1_32;
74
+ if (id == id_fnv1a_32 ) return MEMCACHED_HASH_FNV1A_32;
75
+ if (id == id_jenkins ) return MEMCACHED_HASH_JENKINS;
76
+ if (id == id_hsieh ) return MEMCACHED_HASH_HSIEH;
77
+ if (id == id_murmur ) return MEMCACHED_HASH_MURMUR;
78
+ rb_raise(cMemcacheError, "Invalid hash behavior");
79
+ }
80
+
81
+ static VALUE mc_initialize(VALUE self, VALUE opts) {
82
+ memcached_st *mc;
83
+ VALUE hostv, portv, servers_aryv, prefixv, hashv;
84
+ char* host;
85
+ char* server;
86
+ char* hashkit;
87
+ int port, i;
88
+
89
+ Data_Get_Struct(self, memcached_st, mc);
90
+ hashv = rb_hash_aref(opts, sym_hash);
91
+ prefixv = rb_hash_aref(opts, sym_prefix);
92
+ servers_aryv = rb_hash_aref(opts, sym_servers);
93
+
94
+ if (!NIL_P(hashv))
95
+ memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_HASH, hash_behavior(hashv));
96
+
97
+ if (RTEST( rb_hash_aref(opts, sym_hash_with_prefix) ))
98
+ memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY, true);
99
+
100
+ if (RTEST( rb_hash_aref(opts, sym_binary) ))
101
+ memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, true);
102
+
103
+ if (!NIL_P(prefixv))
104
+ memcached_callback_set(mc, MEMCACHED_CALLBACK_PREFIX_KEY, STR2CSTR(prefixv));
105
+
106
+ if (!NIL_P(servers_aryv)) {
107
+ for (i = 0; i < RARRAY(servers_aryv)->len; i++) {
108
+ server = StringValuePtr(RARRAY(servers_aryv)->ptr[i]);
109
+ memcached_server_push(mc, memcached_servers_parse(server));
110
+ }
111
+ } else {
112
+ hostv = rb_hash_aref(opts, sym_host);
113
+ portv = rb_hash_aref(opts, sym_port);
114
+ host = StringValuePtr(hostv);
115
+ port = NIL_P(portv) ? MEMCACHED_DEFAULT_PORT : NUM2INT(portv);
116
+
117
+ memcached_server_add(mc, host, port);
118
+ }
119
+
120
+ return self;
121
+ }
122
+
123
+ static VALUE escape_key(VALUE key, bool* escaped) {
124
+ char* str = RSTRING_PTR(key);
125
+ uint16_t len = RSTRING_LEN(key);
126
+ char* new_str = NULL;
127
+ uint16_t new_len = len;
128
+ uint16_t i, j;
129
+
130
+ for (i = 0; i < len; i++) {
131
+ if (isspace(str[i]) || str[i] == '\\') new_len++;
132
+ }
133
+
134
+ if (new_len == len) {
135
+ if (escaped) *escaped = false;
136
+ return key;
137
+ } else {
138
+ if (escaped) *escaped = true;
139
+ key = rb_str_buf_new(new_len);
140
+ RSTRING(key)->len = new_len;
141
+ new_str = RSTRING_PTR(key);
142
+
143
+ for (i = 0, j = 0; i < len; i++, j++) {
144
+ if (isspace(str[i]) || str[i] == '\\') {
145
+ new_str[j] = '\\';
146
+ switch (str[i]) {
147
+ case ' ' : new_str[++j] = 's'; break;
148
+ case '\t' : new_str[++j] = 't'; break;
149
+ case '\n' : new_str[++j] = 'n'; break;
150
+ case '\v' : new_str[++j] = 'v'; break;
151
+ case '\f' : new_str[++j] = 'f'; break;
152
+ case '\\' : new_str[++j] = '\\'; break;
153
+ }
154
+ } else {
155
+ new_str[j] = str[i];
156
+ }
157
+ }
158
+ return key;
159
+ }
160
+ }
161
+
162
+ static VALUE unescape_key(const char* str, uint16_t len) {
163
+ uint16_t i,j;
164
+ VALUE key;
165
+ char* new_str;
166
+ uint16_t new_len = len;
167
+
168
+ for (i = 0; i < len; i++) {
169
+ if (str[i] == '\\') {
170
+ new_len--;
171
+ i++;
172
+ }
173
+ }
174
+
175
+ if (new_len == len) {
176
+ key = rb_str_new(str, len);
177
+ } else {
178
+ key = rb_str_buf_new(new_len);
179
+ RSTRING(key)->len = new_len;
180
+ new_str = RSTRING_PTR(key);
181
+
182
+ for (i = 0, j = 0; i < len; j++, i++) {
183
+ if (str[i] == '\\') {
184
+ switch (str[++i]) {
185
+ case 's' : new_str[j] = ' '; break;
186
+ case 't' : new_str[j] = '\t'; break;
187
+ case 'n' : new_str[j] = '\n'; break;
188
+ case 'v' : new_str[j] = '\v'; break;
189
+ case 'f' : new_str[j] = '\f'; break;
190
+ case '\\' : new_str[j] = '\\'; break;
191
+ }
192
+ } else {
193
+ new_str[j] = str[i];
194
+ }
195
+ }
196
+ }
197
+ return key;
198
+ }
199
+
200
+ static bool use_binary(memcached_st* mc) {
201
+ return memcached_behavior_get(mc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0;
202
+ }
203
+
204
+ static VALUE mc_get(int argc, VALUE *argv, VALUE self) {
205
+ memcached_st *mc;
206
+ VALUE cas, keys, results, key, escaped_key, value;
207
+ VALUE scalar_key = Qnil;
208
+ memcached_return status;
209
+
210
+ Data_Get_Struct(self, memcached_st, mc);
211
+ rb_scan_args(argc, argv, "11", &keys, &cas);
212
+ memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, RTEST(cas) ? 1 : 0);
213
+
214
+ if (RTEST(cas) && TYPE(keys) != T_ARRAY) {
215
+ scalar_key = keys;
216
+ keys = rb_ary_new4(1, &keys);
217
+ }
218
+
219
+ if (TYPE(keys) != T_ARRAY) {
220
+ char* str;
221
+ size_t len;
222
+ uint32_t flags;
223
+
224
+ key = use_binary(mc) ? keys : escape_key(keys, NULL);
225
+ str = memcached_get(mc, RSTRING_PTR(key), RSTRING_LEN(key), &len, &flags, &status);
226
+ if (str == NULL) return Qnil;
227
+
228
+ if (status == MEMCACHED_SUCCESS) {
229
+ value = rb_str_new(str, len);
230
+ rb_ivar_set(value, iv_memcache_flags, INT2NUM(flags));
231
+ free(str);
232
+ return value;
233
+ } else {
234
+ printf("Memcache read error: %s %u\n", memcached_strerror(mc, status), status);
235
+ }
236
+ } else {
237
+ static memcached_result_st result;
238
+ size_t num_keys, i;
239
+ const char** key_strings;
240
+ size_t* key_lengths;
241
+ bool escaped;
242
+
243
+ results = rb_hash_new();
244
+ num_keys = RARRAY_LEN(keys);
245
+ if (num_keys == 0) return results;
246
+
247
+ key_strings = (const char**) malloc(num_keys * sizeof(char *));
248
+ key_lengths = (size_t *) malloc(num_keys * sizeof(size_t));
249
+ for (i = 0; i < RARRAY(keys)->len; i++) {
250
+ key = RARRAY(keys)->ptr[i];
251
+ if (!use_binary(mc)) key = escape_key(key, &escaped);
252
+
253
+ key_lengths[i] = RSTRING_LEN(key);
254
+ key_strings[i] = RSTRING_PTR(key);
255
+ }
256
+
257
+ memcached_mget(mc, key_strings, key_lengths, num_keys);
258
+ memcached_result_create(mc, &result);
259
+
260
+ while (memcached_fetch_result(mc, &result, &status)) {
261
+ if (escaped) {
262
+ key = unescape_key(memcached_result_key_value(&result), memcached_result_key_length(&result));
263
+ } else {
264
+ key = rb_str_new(memcached_result_key_value(&result), memcached_result_key_length(&result));
265
+ }
266
+
267
+ if (status == MEMCACHED_SUCCESS) {
268
+ value = rb_str_new(memcached_result_value(&result), memcached_result_length(&result));
269
+ rb_ivar_set(value, iv_memcache_flags, INT2NUM(memcached_result_flags(&result)));
270
+ if (RTEST(cas)) rb_ivar_set(value, iv_memcache_cas, ULL2NUM(memcached_result_cas(&result)));
271
+ memcached_result_free(&result);
272
+ rb_hash_aset(results, key, value);
273
+ } else {
274
+ printf("Memcache read error: %s %u\n", memcached_strerror(mc, status), status);
275
+ }
276
+ }
277
+ free(key_strings);
278
+ free(key_lengths);
279
+ if (!NIL_P(scalar_key)) return rb_hash_aref(results, scalar_key);
280
+ return results;
281
+ }
282
+ }
283
+
284
+ VALUE mc_set(int argc, VALUE *argv, VALUE self) {
285
+ memcached_st *mc;
286
+ VALUE key, value, expiry, flags;
287
+ static memcached_return_t result;
288
+
289
+ Data_Get_Struct(self, memcached_st, mc);
290
+ rb_scan_args(argc, argv, "22", &key, &value, &expiry, &flags);
291
+
292
+ key = StringValue(key);
293
+ if (!use_binary(mc)) key = escape_key(key, NULL);
294
+ value = StringValue(value);
295
+
296
+ result = memcached_set(mc, RSTRING_PTR(key), RSTRING_LEN(key), RSTRING_PTR(value), RSTRING_LEN(value),
297
+ RTEST(expiry) ? NUM2UINT(expiry) : 0,
298
+ RTEST(flags) ? NUM2UINT(flags) : 0);
299
+
300
+ if (result == MEMCACHED_SUCCESS) {
301
+ return value;
302
+ } else {
303
+ return throw_error(&result);
304
+ }
305
+ }
306
+
307
+ static VALUE mc_cas(int argc, VALUE *argv, VALUE self) {
308
+ memcached_st *mc;
309
+ VALUE key, value, cas, expiry, flags;
310
+ static memcached_return_t result;
311
+
312
+ Data_Get_Struct(self, memcached_st, mc);
313
+ rb_scan_args(argc, argv, "32", &key, &value, &cas, &expiry, &flags);
314
+
315
+ key = StringValue(key);
316
+ value = StringValue(value);
317
+
318
+ result = memcached_cas(mc, RSTRING_PTR(key), RSTRING_LEN(key), RSTRING_PTR(value), RSTRING_LEN(value),
319
+ RTEST(expiry) ? NUM2UINT(expiry) : 0,
320
+ RTEST(flags) ? NUM2UINT(flags) : 0,
321
+ NUM2ULL(cas));
322
+
323
+ if (result == MEMCACHED_SUCCESS) {
324
+ return value;
325
+ } else if (result == MEMCACHED_NOTFOUND || result == MEMCACHED_DATA_EXISTS) {
326
+ return Qnil;
327
+ } else {
328
+ return throw_error(&result);
329
+ }
330
+ }
331
+
332
+ VALUE mc_incr(int argc, VALUE *argv, VALUE self) {
333
+ memcached_st *mc;
334
+ VALUE key, amount;
335
+ static memcached_return_t result;
336
+ uint64_t *value;
337
+
338
+ Data_Get_Struct(self, memcached_st, mc);
339
+ rb_scan_args(argc, argv, "11", &key, &amount);
340
+
341
+ key = StringValue(key);
342
+ amount = RTEST(amount) ? NUM2INT(amount) : 1;
343
+
344
+ result = memcached_increment(mc, RSTRING_PTR(key), RSTRING_LEN(key), amount, value);
345
+
346
+ if (result == MEMCACHED_SUCCESS) {
347
+ return LONG2NUM(*value);
348
+ } else if (result == MEMCACHED_NOTFOUND) {
349
+ return Qnil;
350
+ } else {
351
+ return throw_error(&result);
352
+ }
353
+ }
354
+
355
+ VALUE mc_decr(int argc, VALUE *argv, VALUE self) {
356
+ memcached_st *mc;
357
+ VALUE key, amount;
358
+ static memcached_return_t result;
359
+ uint64_t *value;
360
+
361
+ Data_Get_Struct(self, memcached_st, mc);
362
+ rb_scan_args(argc, argv, "11", &key, &amount);
363
+
364
+ key = StringValue(key);
365
+ amount = RTEST(amount) ? NUM2INT(amount) : 1;
366
+
367
+ result = memcached_decrement(mc, RSTRING_PTR(key), RSTRING_LEN(key), amount, value);
368
+
369
+ if (result == MEMCACHED_SUCCESS) {
370
+ return LONG2NUM(*value);
371
+ } else if (result == MEMCACHED_NOTFOUND) {
372
+ return Qnil;
373
+ } else {
374
+ return throw_error(&result);
375
+ }
376
+ }
377
+
378
+ VALUE mc_delete(VALUE self, VALUE key) {
379
+ memcached_st *mc;
380
+ static memcached_return_t result;
381
+
382
+ Data_Get_Struct(self, memcached_st, mc);
383
+
384
+ result = memcached_delete(mc, RSTRING_PTR(key), RSTRING_LEN(key), 0);
385
+
386
+ if (result == MEMCACHED_SUCCESS) {
387
+ return Qtrue;
388
+ } else if(result == MEMCACHED_NOTFOUND) {
389
+ return Qnil;
390
+ } else {
391
+ return throw_error(&result);
392
+ }
393
+ }
394
+
395
+ VALUE mc_add(int argc, VALUE *argv, VALUE self) {
396
+ memcached_st *mc;
397
+ VALUE key, value, expiry, flags;
398
+ static memcached_return_t result;
399
+
400
+ Data_Get_Struct(self, memcached_st, mc);
401
+ rb_scan_args(argc, argv, "22", &key, &value, &expiry, &flags);
402
+
403
+ key = StringValue(key);
404
+ value = StringValue(value);
405
+
406
+ result = memcached_add(mc, RSTRING_PTR(key), RSTRING_LEN(key), RSTRING_PTR(value), RSTRING_LEN(value),
407
+ RTEST(expiry) ? NUM2UINT(expiry) : 0,
408
+ RTEST(flags) ? NUM2UINT(flags) : 0);
409
+
410
+ if (result == MEMCACHED_SUCCESS) {
411
+ return value;
412
+ } else if(result == MEMCACHED_NOTSTORED) {
413
+ return Qnil;
414
+ } else {
415
+ return throw_error(&result);
416
+ }
417
+ }
418
+
419
+ VALUE mc_replace(int argc, VALUE *argv, VALUE self) {
420
+ memcached_st *mc;
421
+ VALUE key, value, expiry, flags;
422
+ static memcached_return_t result;
423
+
424
+ Data_Get_Struct(self, memcached_st, mc);
425
+ rb_scan_args(argc, argv, "22", &key, &value, &expiry, &flags);
426
+
427
+ key = StringValue(key);
428
+ value = StringValue(value);
429
+
430
+ result = memcached_replace(mc, RSTRING_PTR(key), RSTRING_LEN(key), RSTRING_PTR(value), RSTRING_LEN(value),
431
+ RTEST(expiry) ? NUM2UINT(expiry) : 0,
432
+ RTEST(flags) ? NUM2UINT(flags) : 0);
433
+
434
+ if (result == MEMCACHED_SUCCESS) {
435
+ return value;
436
+ } else if(result == MEMCACHED_NOTSTORED) {
437
+ return Qnil;
438
+ } else {
439
+ return throw_error(&result);
440
+ }
441
+ }
442
+
443
+ VALUE mc_append(VALUE self, VALUE key, VALUE value) {
444
+ memcached_st *mc;
445
+ static memcached_return_t result;
446
+
447
+ Data_Get_Struct(self, memcached_st, mc);
448
+
449
+ result = memcached_append(mc, RSTRING_PTR(key), RSTRING_LEN(key), RSTRING_PTR(value), RSTRING_LEN(value), 0, 0);
450
+
451
+ if (result == MEMCACHED_SUCCESS) {
452
+ return Qtrue;
453
+ } else if(result == MEMCACHED_NOTSTORED) {
454
+ return Qfalse;
455
+ } else {
456
+ return throw_error(&result);
457
+ }
458
+ }
459
+
460
+ VALUE mc_prepend(VALUE self, VALUE key, VALUE value) {
461
+ memcached_st *mc;
462
+ static memcached_return_t result;
463
+
464
+ Data_Get_Struct(self, memcached_st, mc);
465
+
466
+ result = memcached_prepend(mc, RSTRING_PTR(key), RSTRING_LEN(key), RSTRING_PTR(value), RSTRING_LEN(value), 0, 0);
467
+
468
+ if (result == MEMCACHED_SUCCESS) {
469
+ return Qtrue;
470
+ } else if(result == MEMCACHED_NOTSTORED) {
471
+ return Qfalse;
472
+ } else {
473
+ return throw_error(&result);
474
+ }
475
+ }
476
+
477
+ VALUE mc_flush_all(int argc, VALUE *argv, VALUE self) {
478
+ memcached_st *mc;
479
+ VALUE delay;
480
+ static memcached_return_t result;
481
+
482
+ Data_Get_Struct(self, memcached_st, mc);
483
+ rb_scan_args(argc, argv, "01", &delay);
484
+
485
+ result = memcached_flush(mc, RTEST(delay) ? NUM2UINT(delay) : 0);
486
+
487
+ if (result == MEMCACHED_SUCCESS) {
488
+ return Qnil;
489
+ } else {
490
+ return throw_error(&result);
491
+ }
492
+ }
493
+
494
+ VALUE mc_set_prefix(VALUE self, VALUE prefix) {
495
+ memcached_st *mc;
496
+ static memcached_return_t result;
497
+ Data_Get_Struct(self, memcached_st, mc);
498
+
499
+ if (NIL_P(prefix)) {
500
+ result = memcached_callback_set(mc, MEMCACHED_CALLBACK_PREFIX_KEY, NULL);
501
+ } else {
502
+ prefix = StringValue(prefix);
503
+ result = memcached_callback_set(mc, MEMCACHED_CALLBACK_PREFIX_KEY, STR2CSTR(prefix));
504
+ }
505
+ return prefix;
506
+ }
507
+
508
+ VALUE mc_get_prefix(VALUE self) {
509
+ memcached_st *mc;
510
+ static memcached_return_t result;
511
+ char* prefix;
512
+
513
+ Data_Get_Struct(self, memcached_st, mc);
514
+ prefix = (char*) memcached_callback_get(mc, MEMCACHED_CALLBACK_PREFIX_KEY, &result);
515
+
516
+ return prefix ? rb_str_new2(prefix) : Qnil;
517
+ }
518
+
519
+ VALUE mc_close(VALUE self) {
520
+ memcached_st *mc;
521
+ Data_Get_Struct(self, memcached_st, mc);
522
+ memcached_quit(mc);
523
+ }
524
+
525
+ void Init_native_server() {
526
+ sym_host = ID2SYM(rb_intern("host"));
527
+ sym_port = ID2SYM(rb_intern("port"));
528
+ sym_prefix = ID2SYM(rb_intern("prefix"));
529
+ sym_hash = ID2SYM(rb_intern("hash"));
530
+ sym_hash_with_prefix = ID2SYM(rb_intern("hash_with_prefix"));
531
+ sym_binary = ID2SYM(rb_intern("binary"));
532
+ sym_servers = ID2SYM(rb_intern("servers"));
533
+
534
+ iv_memcache_flags = rb_intern("@memcache_flags");
535
+ iv_memcache_cas = rb_intern("@memcache_cas");
536
+
537
+ id_default = rb_intern("default");
538
+ id_md5 = rb_intern("md5");
539
+ id_crc = rb_intern("crc");
540
+ id_fnv1_64 = rb_intern("fnv1_64");
541
+ id_fnv1a_64 = rb_intern("fnv1a_64");
542
+ id_fnv1_32 = rb_intern("fnv1_32");
543
+ id_fnv1a_32 = rb_intern("fnv1a_32");
544
+ id_jenkins = rb_intern("jenkins");
545
+ id_hsieh = rb_intern("hsieh");
546
+ id_murmur = rb_intern("murmur");
547
+
548
+ cMemcache = rb_define_class("Memcache", rb_cObject);
549
+
550
+ cMemcacheError = rb_define_class_under(cMemcache, "Error", rb_eStandardError);
551
+ cMemcacheServerError = rb_define_class_under(cMemcache, "ServerError", cMemcacheError);
552
+ cMemcacheClientError = rb_define_class_under(cMemcache, "ClientError", cMemcacheError);
553
+ cMemcacheConnectionError = rb_define_class_under(cMemcache, "ConnectionError", cMemcacheError);
554
+
555
+ cMemcacheBase = rb_define_class_under(cMemcache, "Base", rb_cObject);
556
+ cNativeServer = rb_define_class_under(cMemcache, "NativeServer", cMemcacheBase);
557
+ rb_define_alloc_func(cNativeServer, mc_alloc);
558
+ rb_define_method(cNativeServer, "initialize", mc_initialize, 1);
559
+
560
+ rb_define_method(cNativeServer, "get", mc_get, -1);
561
+ rb_define_method(cNativeServer, "set", mc_set, -1);
562
+ rb_define_method(cNativeServer, "add", mc_add, -1);
563
+ rb_define_method(cNativeServer, "cas", mc_cas, -1);
564
+ rb_define_method(cNativeServer, "replace", mc_replace, -1);
565
+ rb_define_method(cNativeServer, "incr", mc_incr, -1);
566
+ rb_define_method(cNativeServer, "decr", mc_decr, -1);
567
+ rb_define_method(cNativeServer, "append", mc_append, 2);
568
+ rb_define_method(cNativeServer, "prepend", mc_prepend, 2);
569
+ rb_define_method(cNativeServer, "delete", mc_delete, 1);
570
+ rb_define_method(cNativeServer, "close", mc_close, 0);
571
+ rb_define_method(cNativeServer, "flush_all", mc_flush_all, -1);
572
+
573
+ rb_define_method(cNativeServer, "prefix=", mc_set_prefix, 1);
574
+ rb_define_method(cNativeServer, "prefix", mc_get_prefix, 0);
575
+ }
@@ -0,0 +1,65 @@
1
+ class Memcache
2
+ class Base
3
+ attr_accessor :prefix
4
+
5
+ def clear
6
+ flush_all
7
+ end
8
+
9
+ # Default implementations based on get and set.
10
+
11
+ def gets(keys)
12
+ get(keys, true)
13
+ end
14
+
15
+ def incr(key, amount = 1)
16
+ value = get(key)
17
+ return unless value
18
+ return unless value =~ /^\d+$/
19
+
20
+ value = value.to_i + amount
21
+ value = 0 if value < 0
22
+ set(key, value.to_s)
23
+ value
24
+ end
25
+
26
+ def decr(key, amount = 1)
27
+ incr(key, -amount)
28
+ end
29
+
30
+ def add(key, value, expiry = 0, flags = 0)
31
+ return nil if get(key)
32
+ set(key, value, expiry)
33
+ end
34
+
35
+ def cas(key, value, cas, expiry = 0, flags = 0)
36
+ # No cas implementation yet, just do a set for now.
37
+ set(key, value, expiry, flags)
38
+ end
39
+
40
+ def replace(key, value, expiry = 0, flags = 0)
41
+ return nil if get(key).nil?
42
+ set(key, value, expiry)
43
+ end
44
+
45
+ def append(key, value)
46
+ existing = get(key)
47
+ return false if existing.nil?
48
+ set(key, existing + value) && true
49
+ end
50
+
51
+ def prepend(key, value)
52
+ existing = get(key)
53
+ return false if existing.nil?
54
+ set(key, value + existing) && true
55
+ end
56
+
57
+ protected
58
+
59
+ def cache_key(key)
60
+ key = "#{prefix}#{key}"
61
+ raise ArgumentError, "key too long #{key.inspect}" if key.length > 250
62
+ key
63
+ end
64
+ end
65
+ end