pogocache-ruby 0.1.0

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,526 @@
1
+ #include <ruby.h>
2
+ #include "pogocache.h"
3
+
4
+ // Ruby module and class definitions
5
+ static VALUE mPogocache;
6
+ static VALUE cExtension;
7
+ static VALUE ePogoError;
8
+
9
+ // Data type for wrapping pogocache struct
10
+ typedef struct {
11
+ struct pogocache *cache;
12
+ } pogocache_wrapper_t;
13
+
14
+ // Cleanup function for garbage collection
15
+ static void pogocache_free_wrapper(void *ptr) {
16
+ pogocache_wrapper_t *wrapper = (pogocache_wrapper_t*)ptr;
17
+ if (wrapper && wrapper->cache) {
18
+ pogocache_free(wrapper->cache);
19
+ wrapper->cache = NULL;
20
+ }
21
+ free(wrapper);
22
+ }
23
+
24
+ static const rb_data_type_t pogocache_data_type = {
25
+ "Pogocache",
26
+ {0, pogocache_free_wrapper, 0},
27
+ 0, 0,
28
+ RUBY_TYPED_FREE_IMMEDIATELY
29
+ };
30
+
31
+ // Helper function to get pogocache from Ruby object
32
+ static pogocache_wrapper_t* get_pogocache_wrapper(VALUE self) {
33
+ pogocache_wrapper_t *wrapper;
34
+ TypedData_Get_Struct(self, pogocache_wrapper_t, &pogocache_data_type, wrapper);
35
+ if (!wrapper->cache) {
36
+ rb_raise(ePogoError, "Pogocache instance has been freed");
37
+ }
38
+ return wrapper;
39
+ }
40
+
41
+ // Helper function to convert Ruby hash to pogocache_opts
42
+ static struct pogocache_opts* hash_to_opts(VALUE opts_hash) {
43
+ static struct pogocache_opts opts;
44
+ memset(&opts, 0, sizeof(opts));
45
+
46
+ // Set defaults
47
+ opts.nshards = 65536;
48
+ opts.loadfactor = 75;
49
+
50
+ if (NIL_P(opts_hash)) {
51
+ return &opts;
52
+ }
53
+
54
+ Check_Type(opts_hash, T_HASH);
55
+
56
+ VALUE val;
57
+
58
+ // usecas
59
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("usecas")));
60
+ if (!NIL_P(val)) opts.usecas = RTEST(val);
61
+
62
+ // nosixpack
63
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("nosixpack")));
64
+ if (!NIL_P(val)) opts.nosixpack = RTEST(val);
65
+
66
+ // noevict
67
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("noevict")));
68
+ if (!NIL_P(val)) opts.noevict = RTEST(val);
69
+
70
+ // allowshrink
71
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("allowshrink")));
72
+ if (!NIL_P(val)) opts.allowshrink = RTEST(val);
73
+
74
+ // usethreadbatch
75
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("usethreadbatch")));
76
+ if (!NIL_P(val)) opts.usethreadbatch = RTEST(val);
77
+
78
+ // nshards
79
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("nshards")));
80
+ if (!NIL_P(val)) opts.nshards = NUM2INT(val);
81
+
82
+ // loadfactor
83
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("loadfactor")));
84
+ if (!NIL_P(val)) opts.loadfactor = NUM2INT(val);
85
+
86
+ // seed
87
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("seed")));
88
+ if (!NIL_P(val)) opts.seed = NUM2ULL(val);
89
+
90
+ return &opts;
91
+ }
92
+
93
+ // Initialize a new Pogocache instance
94
+ // Pogocache.new(opts = {})
95
+ static VALUE pogocache_initialize(int argc, VALUE *argv, VALUE self) {
96
+ VALUE opts_hash;
97
+ rb_scan_args(argc, argv, "01", &opts_hash);
98
+
99
+ struct pogocache_opts *opts = hash_to_opts(opts_hash);
100
+ struct pogocache *cache = pogocache_new(opts);
101
+
102
+ if (!cache) {
103
+ rb_raise(ePogoError, "Failed to create pogocache instance");
104
+ }
105
+
106
+ pogocache_wrapper_t *wrapper = malloc(sizeof(pogocache_wrapper_t));
107
+ wrapper->cache = cache;
108
+
109
+ DATA_PTR(self) = wrapper;
110
+ return self;
111
+ }
112
+
113
+ // Store a key-value pair
114
+ // extension.store(key, value, opts = {})
115
+ static VALUE pogocache_store_rb(int argc, VALUE *argv, VALUE self) {
116
+ VALUE key, value, opts_hash;
117
+ rb_scan_args(argc, argv, "21", &key, &value, &opts_hash);
118
+
119
+ pogocache_wrapper_t *wrapper = get_pogocache_wrapper(self);
120
+
121
+ // Convert Ruby strings to C strings
122
+ Check_Type(key, T_STRING);
123
+ Check_Type(value, T_STRING);
124
+
125
+ const char *key_ptr = RSTRING_PTR(key);
126
+ size_t key_len = RSTRING_LEN(key);
127
+ const char *value_ptr = RSTRING_PTR(value);
128
+ size_t value_len = RSTRING_LEN(value);
129
+
130
+ // Parse options
131
+ struct pogocache_store_opts opts;
132
+ memset(&opts, 0, sizeof(opts));
133
+
134
+ if (!NIL_P(opts_hash)) {
135
+ Check_Type(opts_hash, T_HASH);
136
+
137
+ VALUE val;
138
+
139
+ // ttl
140
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("ttl")));
141
+ if (!NIL_P(val)) opts.ttl = NUM2LL(val);
142
+
143
+ // expires
144
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("expires")));
145
+ if (!NIL_P(val)) opts.expires = NUM2LL(val);
146
+
147
+ // flags
148
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("flags")));
149
+ if (!NIL_P(val)) opts.flags = NUM2UINT(val);
150
+
151
+ // cas
152
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("cas")));
153
+ if (!NIL_P(val)) opts.cas = NUM2ULL(val);
154
+
155
+ // nx (only set if not exists)
156
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("nx")));
157
+ if (!NIL_P(val)) opts.nx = RTEST(val);
158
+
159
+ // xx (only set if exists)
160
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("xx")));
161
+ if (!NIL_P(val)) opts.xx = RTEST(val);
162
+
163
+ // keepttl
164
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("keepttl")));
165
+ if (!NIL_P(val)) opts.keepttl = RTEST(val);
166
+
167
+ // casop
168
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("casop")));
169
+ if (!NIL_P(val)) opts.casop = RTEST(val);
170
+ }
171
+
172
+ int result = pogocache_store(wrapper->cache, key_ptr, key_len, value_ptr, value_len, &opts);
173
+ return INT2NUM(result);
174
+ }
175
+
176
+ // Load callback data structure
177
+ typedef struct {
178
+ VALUE result_hash;
179
+ bool found;
180
+ } load_callback_data_t;
181
+
182
+ // Callback function for pogocache_load
183
+ static void load_entry_callback(int shard, int64_t time, const void *key, size_t keylen,
184
+ const void *value, size_t valuelen, int64_t expires,
185
+ uint32_t flags, uint64_t cas, struct pogocache_update **update,
186
+ void *udata) {
187
+ load_callback_data_t *data = (load_callback_data_t*)udata;
188
+
189
+ data->result_hash = rb_hash_new();
190
+ data->found = true;
191
+
192
+ rb_hash_aset(data->result_hash, ID2SYM(rb_intern("key")),
193
+ rb_str_new((const char*)key, keylen));
194
+ rb_hash_aset(data->result_hash, ID2SYM(rb_intern("value")),
195
+ rb_str_new((const char*)value, valuelen));
196
+ rb_hash_aset(data->result_hash, ID2SYM(rb_intern("expires")), LL2NUM(expires));
197
+ rb_hash_aset(data->result_hash, ID2SYM(rb_intern("flags")), UINT2NUM(flags));
198
+ rb_hash_aset(data->result_hash, ID2SYM(rb_intern("cas")), ULL2NUM(cas));
199
+ rb_hash_aset(data->result_hash, ID2SYM(rb_intern("shard")), INT2NUM(shard));
200
+ rb_hash_aset(data->result_hash, ID2SYM(rb_intern("time")), LL2NUM(time));
201
+ }
202
+
203
+ // Load a value by key
204
+ // extension.load(key, opts = {})
205
+ static VALUE pogocache_load_rb(int argc, VALUE *argv, VALUE self) {
206
+ VALUE key, opts_hash;
207
+ rb_scan_args(argc, argv, "11", &key, &opts_hash);
208
+
209
+ pogocache_wrapper_t *wrapper = get_pogocache_wrapper(self);
210
+
211
+ Check_Type(key, T_STRING);
212
+ const char *key_ptr = RSTRING_PTR(key);
213
+ size_t key_len = RSTRING_LEN(key);
214
+
215
+ struct pogocache_load_opts opts;
216
+ memset(&opts, 0, sizeof(opts));
217
+
218
+ load_callback_data_t callback_data;
219
+ callback_data.result_hash = Qnil;
220
+ callback_data.found = false;
221
+
222
+ opts.entry = load_entry_callback;
223
+ opts.udata = &callback_data;
224
+
225
+ if (!NIL_P(opts_hash)) {
226
+ Check_Type(opts_hash, T_HASH);
227
+
228
+ VALUE val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("notouch")));
229
+ if (!NIL_P(val)) opts.notouch = RTEST(val);
230
+ }
231
+
232
+ int result = pogocache_load(wrapper->cache, key_ptr, key_len, &opts);
233
+ if (result != POGOCACHE_FOUND) {
234
+ return Qnil;
235
+ }
236
+
237
+ if (callback_data.found) {
238
+ return callback_data.result_hash;
239
+ } else {
240
+ return Qnil;
241
+ }
242
+ }
243
+
244
+ // Delete a key
245
+ // extension.delete(key, opts = {})
246
+ static VALUE pogocache_delete_rb(int argc, VALUE *argv, VALUE self) {
247
+ VALUE key, opts_hash;
248
+ rb_scan_args(argc, argv, "11", &key, &opts_hash);
249
+
250
+ pogocache_wrapper_t *wrapper = get_pogocache_wrapper(self);
251
+
252
+ Check_Type(key, T_STRING);
253
+ const char *key_ptr = RSTRING_PTR(key);
254
+ size_t key_len = RSTRING_LEN(key);
255
+
256
+ struct pogocache_delete_opts opts;
257
+ memset(&opts, 0, sizeof(opts));
258
+
259
+ int result = pogocache_delete(wrapper->cache, key_ptr, key_len, &opts);
260
+ return INT2NUM(result);
261
+ }
262
+
263
+ // Get cache count
264
+ // extension.count(opts = {})
265
+ static VALUE pogocache_count_rb(int argc, VALUE *argv, VALUE self) {
266
+ VALUE opts_hash;
267
+ rb_scan_args(argc, argv, "01", &opts_hash);
268
+
269
+ pogocache_wrapper_t *wrapper = get_pogocache_wrapper(self);
270
+
271
+ struct pogocache_count_opts opts;
272
+ memset(&opts, 0, sizeof(opts));
273
+
274
+ if (!NIL_P(opts_hash)) {
275
+ Check_Type(opts_hash, T_HASH);
276
+
277
+ VALUE val;
278
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("oneshard")));
279
+ if (!NIL_P(val)) opts.oneshard = RTEST(val);
280
+
281
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("oneshardidx")));
282
+ if (!NIL_P(val)) opts.oneshardidx = NUM2INT(val);
283
+ }
284
+
285
+ size_t count = pogocache_count(wrapper->cache, &opts);
286
+ return SIZET2NUM(count);
287
+ }
288
+
289
+ // Get cache memory size
290
+ // extension.size(opts = {})
291
+ static VALUE pogocache_size_rb(int argc, VALUE *argv, VALUE self) {
292
+ VALUE opts_hash;
293
+ rb_scan_args(argc, argv, "01", &opts_hash);
294
+
295
+ pogocache_wrapper_t *wrapper = get_pogocache_wrapper(self);
296
+
297
+ struct pogocache_size_opts opts;
298
+ memset(&opts, 0, sizeof(opts));
299
+
300
+ if (!NIL_P(opts_hash)) {
301
+ Check_Type(opts_hash, T_HASH);
302
+
303
+ VALUE val;
304
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("oneshard")));
305
+ if (!NIL_P(val)) opts.oneshard = RTEST(val);
306
+
307
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("oneshardidx")));
308
+ if (!NIL_P(val)) opts.oneshardidx = NUM2INT(val);
309
+
310
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("entriesonly")));
311
+ if (!NIL_P(val)) opts.entriesonly = RTEST(val);
312
+ }
313
+
314
+ size_t size = pogocache_size(wrapper->cache, &opts);
315
+ return SIZET2NUM(size);
316
+ }
317
+
318
+ // Clear the cache
319
+ // extension.clear(opts = {})
320
+ static VALUE pogocache_clear_rb(int argc, VALUE *argv, VALUE self) {
321
+ VALUE opts_hash;
322
+ rb_scan_args(argc, argv, "01", &opts_hash);
323
+
324
+ pogocache_wrapper_t *wrapper = get_pogocache_wrapper(self);
325
+
326
+ struct pogocache_clear_opts opts;
327
+ memset(&opts, 0, sizeof(opts));
328
+
329
+ if (!NIL_P(opts_hash)) {
330
+ Check_Type(opts_hash, T_HASH);
331
+
332
+ VALUE val;
333
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("oneshard")));
334
+ if (!NIL_P(val)) opts.oneshard = RTEST(val);
335
+
336
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("oneshardidx")));
337
+ if (!NIL_P(val)) opts.oneshardidx = NUM2INT(val);
338
+ }
339
+
340
+ pogocache_clear(wrapper->cache, &opts);
341
+ return Qnil;
342
+ }
343
+
344
+ // Sweep expired entries
345
+ // extension.sweep(opts = {})
346
+ static VALUE pogocache_sweep_rb(int argc, VALUE *argv, VALUE self) {
347
+ VALUE opts_hash;
348
+ rb_scan_args(argc, argv, "01", &opts_hash);
349
+
350
+ pogocache_wrapper_t *wrapper = get_pogocache_wrapper(self);
351
+
352
+ struct pogocache_sweep_opts opts;
353
+ memset(&opts, 0, sizeof(opts));
354
+
355
+ if (!NIL_P(opts_hash)) {
356
+ Check_Type(opts_hash, T_HASH);
357
+
358
+ VALUE val;
359
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("oneshard")));
360
+ if (!NIL_P(val)) opts.oneshard = RTEST(val);
361
+
362
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("oneshardidx")));
363
+ if (!NIL_P(val)) opts.oneshardidx = NUM2INT(val);
364
+ }
365
+
366
+ size_t swept = 0, kept = 0;
367
+ pogocache_sweep(wrapper->cache, &swept, &kept, &opts);
368
+
369
+ VALUE result = rb_hash_new();
370
+ rb_hash_aset(result, ID2SYM(rb_intern("swept")), SIZET2NUM(swept));
371
+ rb_hash_aset(result, ID2SYM(rb_intern("kept")), SIZET2NUM(kept));
372
+
373
+ return result;
374
+ }
375
+
376
+ // Iterator callback data
377
+ typedef struct {
378
+ VALUE result_array;
379
+ VALUE proc;
380
+ } iter_callback_data_t;
381
+
382
+ // Callback function for iteration
383
+ static int iter_entry_callback(int shard, int64_t time, const void *key, size_t keylen,
384
+ const void *value, size_t valuelen, int64_t expires,
385
+ uint32_t flags, uint64_t cas, void *udata) {
386
+ iter_callback_data_t *data = (iter_callback_data_t*)udata;
387
+
388
+ VALUE entry_hash = rb_hash_new();
389
+ rb_hash_aset(entry_hash, ID2SYM(rb_intern("key")),
390
+ rb_str_new((const char*)key, keylen));
391
+ rb_hash_aset(entry_hash, ID2SYM(rb_intern("value")),
392
+ rb_str_new((const char*)value, valuelen));
393
+ rb_hash_aset(entry_hash, ID2SYM(rb_intern("expires")), LL2NUM(expires));
394
+ rb_hash_aset(entry_hash, ID2SYM(rb_intern("flags")), UINT2NUM(flags));
395
+ rb_hash_aset(entry_hash, ID2SYM(rb_intern("cas")), ULL2NUM(cas));
396
+ rb_hash_aset(entry_hash, ID2SYM(rb_intern("shard")), INT2NUM(shard));
397
+ rb_hash_aset(entry_hash, ID2SYM(rb_intern("time")), LL2NUM(time));
398
+
399
+ if (!NIL_P(data->proc)) {
400
+ VALUE result = rb_funcall(data->proc, rb_intern("call"), 1, entry_hash);
401
+ return NUM2INT(result);
402
+ } else {
403
+ rb_ary_push(data->result_array, entry_hash);
404
+ return POGOCACHE_ITER_CONTINUE;
405
+ }
406
+ }
407
+
408
+ // Iterate over cache entries
409
+ // extension.each(opts = {}) { |entry| ... }
410
+ // extension.each(opts = {}) # returns array
411
+ static VALUE pogocache_each_rb(int argc, VALUE *argv, VALUE self) {
412
+ VALUE opts_hash, proc;
413
+ rb_scan_args(argc, argv, "01&", &opts_hash, &proc);
414
+
415
+ pogocache_wrapper_t *wrapper = get_pogocache_wrapper(self);
416
+
417
+ struct pogocache_iter_opts opts;
418
+ memset(&opts, 0, sizeof(opts));
419
+
420
+ iter_callback_data_t callback_data;
421
+ callback_data.result_array = rb_ary_new();
422
+ callback_data.proc = proc;
423
+
424
+ opts.entry = iter_entry_callback;
425
+ opts.udata = &callback_data;
426
+
427
+ if (!NIL_P(opts_hash)) {
428
+ Check_Type(opts_hash, T_HASH);
429
+
430
+ VALUE val;
431
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("oneshard")));
432
+ if (!NIL_P(val)) opts.oneshard = RTEST(val);
433
+
434
+ val = rb_hash_aref(opts_hash, ID2SYM(rb_intern("oneshardidx")));
435
+ if (!NIL_P(val)) opts.oneshardidx = NUM2INT(val);
436
+ }
437
+
438
+ pogocache_iter(wrapper->cache, &opts);
439
+
440
+ if (!NIL_P(proc)) {
441
+ return self;
442
+ } else {
443
+ return callback_data.result_array;
444
+ }
445
+ }
446
+
447
+ // Get number of shards
448
+ // extension.nshards
449
+ static VALUE pogocache_nshards_rb(VALUE self) {
450
+ pogocache_wrapper_t *wrapper = get_pogocache_wrapper(self);
451
+ int nshards = pogocache_nshards(wrapper->cache);
452
+ return INT2NUM(nshards);
453
+ }
454
+
455
+ // Get current time
456
+ // Pogocache.now
457
+ static VALUE pogocache_now_rb(VALUE self) {
458
+ int64_t now = pogocache_now();
459
+ return LL2NUM(now);
460
+ }
461
+ static VALUE pogocache_alloc(VALUE klass) {
462
+ pogocache_wrapper_t *wrapper = malloc(sizeof(pogocache_wrapper_t));
463
+ wrapper->cache = NULL;
464
+ return TypedData_Wrap_Struct(klass, &pogocache_data_type, wrapper);
465
+ }
466
+
467
+ // Extension initialization
468
+ void Init_pogocache_ruby(void) {
469
+ // Define module
470
+ mPogocache = rb_define_module("Pogocache");
471
+
472
+ // Define Cache class
473
+ cExtension = rb_define_class_under(mPogocache, "Extension", rb_cObject);
474
+ rb_define_alloc_func(cExtension, pogocache_alloc);
475
+
476
+ // Define exception class
477
+ ePogoError = rb_define_class_under(mPogocache, "Error", rb_eStandardError);
478
+
479
+ // Instance methods
480
+ rb_define_method(cExtension, "initialize", pogocache_initialize, -1);
481
+ rb_define_method(cExtension, "store", pogocache_store_rb, -1);
482
+ rb_define_method(cExtension, "load", pogocache_load_rb, -1);
483
+ rb_define_method(cExtension, "delete", pogocache_delete_rb, -1);
484
+ rb_define_method(cExtension, "count", pogocache_count_rb, -1);
485
+ rb_define_method(cExtension, "size", pogocache_size_rb, -1);
486
+ rb_define_method(cExtension, "clear", pogocache_clear_rb, -1);
487
+ rb_define_method(cExtension, "sweep", pogocache_sweep_rb, -1);
488
+ rb_define_method(cExtension, "each", pogocache_each_rb, -1);
489
+ rb_define_method(cExtension, "nshards", pogocache_nshards_rb, 0);
490
+
491
+ // Convenience aliases
492
+ rb_define_alias(cExtension, "[]", "load");
493
+ rb_define_alias(cExtension, "[]=", "store");
494
+ rb_define_alias(cExtension, "length", "count");
495
+
496
+ // Module methods
497
+ rb_define_module_function(mPogocache, "now", pogocache_now_rb, 0);
498
+
499
+ // Constants
500
+ rb_define_const(mPogocache, "INSERTED", INT2NUM(POGOCACHE_INSERTED));
501
+ rb_define_const(mPogocache, "REPLACED", INT2NUM(POGOCACHE_REPLACED));
502
+ rb_define_const(mPogocache, "FOUND", INT2NUM(POGOCACHE_FOUND));
503
+ rb_define_const(mPogocache, "NOTFOUND", INT2NUM(POGOCACHE_NOTFOUND));
504
+ rb_define_const(mPogocache, "DELETED", INT2NUM(POGOCACHE_DELETED));
505
+ rb_define_const(mPogocache, "FINISHED", INT2NUM(POGOCACHE_FINISHED));
506
+ rb_define_const(mPogocache, "CANCELED", INT2NUM(POGOCACHE_CANCELED));
507
+ rb_define_const(mPogocache, "NOMEM", INT2NUM(POGOCACHE_NOMEM));
508
+
509
+ // Time constants
510
+ rb_define_const(mPogocache, "NANOSECOND", LL2NUM(POGOCACHE_NANOSECOND));
511
+ rb_define_const(mPogocache, "MICROSECOND", LL2NUM(POGOCACHE_MICROSECOND));
512
+ rb_define_const(mPogocache, "MILLISECOND", LL2NUM(POGOCACHE_MILLISECOND));
513
+ rb_define_const(mPogocache, "SECOND", LL2NUM(POGOCACHE_SECOND));
514
+ rb_define_const(mPogocache, "MINUTE", LL2NUM(POGOCACHE_MINUTE));
515
+ rb_define_const(mPogocache, "HOUR", LL2NUM(POGOCACHE_HOUR));
516
+
517
+ // Iterator constants
518
+ rb_define_const(mPogocache, "ITER_CONTINUE", INT2NUM(POGOCACHE_ITER_CONTINUE));
519
+ rb_define_const(mPogocache, "ITER_STOP", INT2NUM(POGOCACHE_ITER_STOP));
520
+ rb_define_const(mPogocache, "ITER_DELETE", INT2NUM(POGOCACHE_ITER_DELETE));
521
+
522
+ // Eviction reason constants
523
+ rb_define_const(mPogocache, "REASON_EXPIRED", INT2NUM(POGOCACHE_REASON_EXPIRED));
524
+ rb_define_const(mPogocache, "REASON_LOWMEM", INT2NUM(POGOCACHE_REASON_LOWMEM));
525
+ rb_define_const(mPogocache, "REASON_CLEARED", INT2NUM(POGOCACHE_REASON_CLEARED));
526
+ }
@@ -0,0 +1,84 @@
1
+ class Pogocache::Cache
2
+ def initialize(options = {})
3
+ @extension = Pogocache::Extension.new(Pogocache.configuration.default_opts.merge(options))
4
+ end
5
+
6
+ def set(key, value, options = {})
7
+ @extension.store(encode(key), encode(value), options)
8
+ end
9
+
10
+ def get(key)
11
+ decode(@extension.load(encode(key))&.dig(:value))
12
+ end
13
+
14
+ def entry(key)
15
+ @extension.load(encode(key))&.tap do
16
+ it[:key] = decode(it[:key])
17
+ it[:value] = decode(it[:value])
18
+ end
19
+ end
20
+
21
+ def delete(key)
22
+ @extension.delete(encode(key))
23
+ end
24
+
25
+ def [](key)
26
+ get(key)
27
+ end
28
+
29
+ def []=(key, value)
30
+ set(key, value)
31
+ end
32
+
33
+ def fetch(key, &block)
34
+ value = get(key)
35
+ return value if value
36
+
37
+ block&.call
38
+ end
39
+
40
+ def count
41
+ @extension.count
42
+ end
43
+ alias_method(:size, :count)
44
+
45
+ def bytesize
46
+ @extension.size
47
+ end
48
+
49
+ def clear
50
+ @extension.clear
51
+ end
52
+
53
+ def sweep
54
+ @extension.sweep
55
+ end
56
+
57
+ def each(opts = {}, &block)
58
+ if block_given?
59
+ retval = []
60
+ @extension.each(opts) do
61
+ retval << yield(decode(it[:key]), decode(it[:value]))
62
+
63
+ Pogocache::ITER_CONTINUE # standard:disable Lint/Void
64
+ end
65
+ retval
66
+ else
67
+ @extension.each(opts)
68
+ end
69
+ end
70
+
71
+ def nshards = @extension.nshards
72
+
73
+ private
74
+
75
+ def encode(obj)
76
+ Marshal.dump(obj)
77
+ end
78
+
79
+ def decode(str)
80
+ return nil if str.nil? || str.empty?
81
+
82
+ Marshal.load(str)
83
+ end
84
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pogocache
4
+ # Global configuration for pogocache
5
+ class Configuration
6
+ attr_accessor :default_opts
7
+
8
+ def initialize
9
+ @default_opts = {}
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pogocache
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "pogocache_ruby"
4
+ require_relative "pogocache-ruby/version"
5
+ require_relative "pogocache-ruby/configuration"
6
+ require_relative "pogocache-ruby/cache"
7
+
8
+ module Pogocache
9
+ class << self
10
+ def configuration
11
+ @configuration ||= Configuration.new
12
+ end
13
+
14
+ def configure
15
+ yield(configuration)
16
+ end
17
+ end
18
+ end