memcache 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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