volatile_map 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.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +81 -0
- data/Rakefile +16 -0
- data/ext/volatile_map/extconf.rb +11 -0
- data/ext/volatile_map/test_helpers.c +20 -0
- data/ext/volatile_map/test_helpers.h +7 -0
- data/ext/volatile_map/volatile_map.c +252 -0
- data/ext/volatile_map/volatile_map.h +15 -0
- data/lib/volatile_map/version.rb +5 -0
- metadata +54 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 1a675867ad0e08a4b1766a57ce25d811c838e61eb7fae00deac361d4ab201ffa
|
|
4
|
+
data.tar.gz: 9cdb03fb55c6cdd4c55878334262fb44be1cb5ccfa8d70073728774034ac235a
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 014fb93aee4fd8cf86a78c2e514f4fd5f40c9d389d9a84393c3b4ec62cf9b81411a628b0356f9b2211bf7d275683994229a97cbeb9847e80343e519aa95d8c54
|
|
7
|
+
data.tar.gz: aee837e05d68f3e6aab4fa7e0f2fe7b46f64bbea6e64f588e7f887fc84f555545d23258fce0d8e22a3b5e26a16bc99635eded24790ba9a0e29745d99e6fdf71b
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
"volatile_map" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
|
|
4
|
+
|
|
5
|
+
* Participants will be tolerant of opposing views.
|
|
6
|
+
* Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
|
|
7
|
+
* When interpreting the words and actions of others, participants should always assume good intentions.
|
|
8
|
+
* Behaviour which can be reasonably considered harassment will not be tolerated.
|
|
9
|
+
|
|
10
|
+
If you have any concerns about behaviour within this project, please contact us at ["mehmetemininac@gmail.com"](mailto:"mehmetemininac@gmail.com").
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mehmet Emin INAC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# VolatileMap
|
|
2
|
+
|
|
3
|
+
`VolatileMap` is a Ruby C extension that provides a `Hash`-like container whose
|
|
4
|
+
entries automatically expire. Each instance has a TTL (time-to-live, in
|
|
5
|
+
seconds); entries older than the TTL are evicted on the next garbage-collection
|
|
6
|
+
cycle, and also lazily on read access. Reading or writing an entry refreshes
|
|
7
|
+
its timestamp, so frequently-touched keys stay alive.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Add to your Gemfile:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
gem "volatile_map"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or install directly:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
gem install volatile_map
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
require "volatile_map"
|
|
27
|
+
|
|
28
|
+
# TTL is in seconds (Float or Integer)
|
|
29
|
+
cache = VolatileMap.new(0.5)
|
|
30
|
+
|
|
31
|
+
cache["session"] = { user_id: 42 }
|
|
32
|
+
cache["session"] # => { user_id: 42 }
|
|
33
|
+
cache.key?("session") # => true
|
|
34
|
+
cache.size # => 1
|
|
35
|
+
|
|
36
|
+
sleep 1
|
|
37
|
+
GC.start # sweep happens just after GC
|
|
38
|
+
|
|
39
|
+
cache.size # => 0
|
|
40
|
+
cache["session"] # => nil
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### API
|
|
44
|
+
|
|
45
|
+
- `VolatileMap.new(ttl)` — construct a map with the given TTL in seconds.
|
|
46
|
+
- `map[key] = value` — store a value; resets the entry's timestamp.
|
|
47
|
+
- `map[key]` — retrieve a value; returns `nil` if missing or expired.
|
|
48
|
+
Refreshes the timestamp on a hit.
|
|
49
|
+
- `map.delete(key)` — remove a key; returns the prior value or `nil`.
|
|
50
|
+
- `map.key?(key)` — `true` if the key exists and has not expired.
|
|
51
|
+
Also evicts and refreshes like `[]`.
|
|
52
|
+
- `map.size` — number of entries currently stored.
|
|
53
|
+
- `map.ttl` — the configured TTL in seconds.
|
|
54
|
+
|
|
55
|
+
### Semantics
|
|
56
|
+
|
|
57
|
+
- TTL is measured against a monotonic clock (`CLOCK_MONOTONIC`), so wall-clock
|
|
58
|
+
jumps do not affect expiry.
|
|
59
|
+
- Eviction happens at two points:
|
|
60
|
+
1. After every GC cycle (via a postponed job that scans the internal hash).
|
|
61
|
+
2. Lazily on read (`[]`, `key?`) so entries cannot outlive their TTL even if
|
|
62
|
+
no GC has run since they expired.
|
|
63
|
+
- Writes (`[]=`) and successful reads (`[]`, `key?` returning true) refresh the
|
|
64
|
+
entry's timestamp.
|
|
65
|
+
|
|
66
|
+
### Caveats
|
|
67
|
+
|
|
68
|
+
- The map strongly retains its keys and values until they expire. It is not a
|
|
69
|
+
weak-reference container.
|
|
70
|
+
- Not Ractor-shareable in this release.
|
|
71
|
+
- Not thread-safe; wrap with your own mutex if you mutate from multiple threads.
|
|
72
|
+
|
|
73
|
+
## Development
|
|
74
|
+
|
|
75
|
+
Run `bin/setup` to install dependencies, then `rake compile` to build the
|
|
76
|
+
extension and `rake spec` to run the tests.
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
The gem is available as open source under the terms of the
|
|
81
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rspec/core/rake_task"
|
|
5
|
+
require "rake/extensiontask"
|
|
6
|
+
|
|
7
|
+
ENV["VOLATILE_MAP_TEST_HELPERS"] = "1" unless ENV["NO_TEST_ENV"]
|
|
8
|
+
|
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
10
|
+
|
|
11
|
+
Rake::ExtensionTask.new "volatile_map" do |ext|
|
|
12
|
+
ext.lib_dir = "lib"
|
|
13
|
+
ext.ext_dir = 'ext/volatile_map'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
task default: [:compile, :spec]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#include "test_helpers.h"
|
|
2
|
+
|
|
3
|
+
static double test_time;
|
|
4
|
+
|
|
5
|
+
int test_clock_gettime(clockid_t _clk_id, struct timespec *tp) {
|
|
6
|
+
tp->tv_sec = (int)test_time;
|
|
7
|
+
tp->tv_nsec = 0;
|
|
8
|
+
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
VALUE vm_set_time(VALUE _klass, VALUE time) {
|
|
13
|
+
test_time = NUM2DBL(time);
|
|
14
|
+
|
|
15
|
+
return time;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
void init_test_helpers(VALUE klass) {
|
|
19
|
+
rb_define_singleton_method(klass, "set_test_clock!", vm_set_time, 1);
|
|
20
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#include <time.h>
|
|
2
|
+
#include "volatile_map.h"
|
|
3
|
+
|
|
4
|
+
#ifdef VOLATILE_MAP_TEST_HELPERS
|
|
5
|
+
#include "test_helpers.h"
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#ifndef MAX
|
|
9
|
+
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
static VolatileMap **vm_dirty_array = NULL;
|
|
13
|
+
static size_t vm_dirty_len = 0;
|
|
14
|
+
static size_t vm_dirty_capacity = 0;
|
|
15
|
+
static size_t vm_live_count = 0;
|
|
16
|
+
|
|
17
|
+
#ifdef HAVE_RB_POSTPONED_JOB_PREREGISTER
|
|
18
|
+
static rb_postponed_job_handle_t vm_drain_job_handle;
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
struct vm_drain_ctx {
|
|
22
|
+
double now;
|
|
23
|
+
double ttl;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
static double now_seconds(void) {
|
|
27
|
+
struct timespec ts;
|
|
28
|
+
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
29
|
+
|
|
30
|
+
return (double)ts.tv_sec + (double)ts.tv_nsec / 1e9;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static bool is_stale(double ttl, VALUE entry, double now) {
|
|
34
|
+
double ts = NUM2DBL(RARRAY_AREF(entry, 1));
|
|
35
|
+
|
|
36
|
+
return (now - ts) > ttl;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static int drain_entry(VALUE _key, VALUE entry, VALUE arg) {
|
|
40
|
+
struct vm_drain_ctx *ctx = (struct vm_drain_ctx *)arg;
|
|
41
|
+
|
|
42
|
+
if(!RB_TYPE_P(entry, T_ARRAY) || RARRAY_LEN(entry) < 2) return ST_CONTINUE;
|
|
43
|
+
|
|
44
|
+
if(is_stale(ctx->ttl, entry, ctx->now)) return ST_DELETE;
|
|
45
|
+
|
|
46
|
+
return ST_CONTINUE;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static void vm_drain_dirty(void *_ptr) {
|
|
50
|
+
double now = now_seconds();
|
|
51
|
+
|
|
52
|
+
for(size_t i = 0; i < vm_dirty_len; i++) {
|
|
53
|
+
VolatileMap *vm = vm_dirty_array[i];
|
|
54
|
+
|
|
55
|
+
if(RHASH_SIZE(vm->storage) == 0) continue;
|
|
56
|
+
|
|
57
|
+
struct vm_drain_ctx ctx = { now, vm->ttl };
|
|
58
|
+
|
|
59
|
+
rb_hash_foreach(vm->storage, drain_entry, (VALUE)&ctx);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
vm_dirty_len = 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static inline void schedule_draining(void) {
|
|
66
|
+
#ifdef HAVE_RB_POSTPONED_JOB_PREREGISTER
|
|
67
|
+
rb_postponed_job_trigger(vm_drain_job_handle);
|
|
68
|
+
#else
|
|
69
|
+
rb_postponed_job_register_one(0, vm_drain_dirty, NULL);
|
|
70
|
+
#endif
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static void rb_mark_volatile_map(void *ptr) {
|
|
74
|
+
VolatileMap *vm = (VolatileMap *)ptr;
|
|
75
|
+
|
|
76
|
+
rb_gc_mark_movable(vm->storage);
|
|
77
|
+
|
|
78
|
+
if(RHASH_SIZE(vm->storage) > 0 && vm_dirty_len < vm_dirty_capacity) {
|
|
79
|
+
vm_dirty_array[vm_dirty_len++] = vm;
|
|
80
|
+
|
|
81
|
+
schedule_draining();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static void rb_free_volatile_map(void *ptr) {
|
|
86
|
+
VolatileMap *vm = (VolatileMap *)ptr;
|
|
87
|
+
|
|
88
|
+
xfree(vm);
|
|
89
|
+
|
|
90
|
+
if(vm_live_count > 0) vm_live_count--;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static void rb_compact_volatile_map(void *ptr) {
|
|
94
|
+
VolatileMap *vm = (VolatileMap *)ptr;
|
|
95
|
+
|
|
96
|
+
vm->storage = rb_gc_location(vm->storage);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static size_t rb_size_volatile_map(const void *ptr) {
|
|
100
|
+
VolatileMap *vm = (VolatileMap *)ptr;
|
|
101
|
+
|
|
102
|
+
return sizeof(VolatileMap) + rb_funcall(vm->storage, rb_intern("size"), 0);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const rb_data_type_t volatile_map_type = {
|
|
106
|
+
"VolatileMap",
|
|
107
|
+
{
|
|
108
|
+
rb_mark_volatile_map,
|
|
109
|
+
rb_free_volatile_map,
|
|
110
|
+
rb_size_volatile_map,
|
|
111
|
+
rb_compact_volatile_map
|
|
112
|
+
},
|
|
113
|
+
0,
|
|
114
|
+
0,
|
|
115
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
static void ensure_dirty_capacity(void) {
|
|
119
|
+
if(vm_dirty_capacity >= vm_live_count) return;
|
|
120
|
+
|
|
121
|
+
size_t new_cap = MAX((size_t)8, vm_live_count * 2);
|
|
122
|
+
|
|
123
|
+
vm_dirty_array = (VolatileMap **)xrealloc(vm_dirty_array, new_cap * sizeof(VolatileMap *));
|
|
124
|
+
vm_dirty_capacity = new_cap;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
VALUE alloc_volatile_map(VALUE klass) {
|
|
128
|
+
VolatileMap *vm;
|
|
129
|
+
VALUE obj = TypedData_Make_Struct(klass, VolatileMap, &volatile_map_type, vm);
|
|
130
|
+
|
|
131
|
+
vm->storage = rb_hash_new();
|
|
132
|
+
vm->ttl = 0.0;
|
|
133
|
+
vm_live_count++;
|
|
134
|
+
|
|
135
|
+
ensure_dirty_capacity();
|
|
136
|
+
|
|
137
|
+
return obj;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static VolatileMap *vm_get(VALUE self) {
|
|
141
|
+
VolatileMap *vm;
|
|
142
|
+
TypedData_Get_Struct(self, VolatileMap, &volatile_map_type, vm);
|
|
143
|
+
|
|
144
|
+
return vm;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static VALUE vm_initialize(VALUE self, VALUE ttl) {
|
|
148
|
+
VolatileMap *vm = vm_get(self);
|
|
149
|
+
double ttl_value = NUM2DBL(ttl);
|
|
150
|
+
|
|
151
|
+
if(ttl_value <= 0.0) rb_raise(rb_eArgError, "TTL must be positive");
|
|
152
|
+
|
|
153
|
+
vm->ttl = ttl_value;
|
|
154
|
+
|
|
155
|
+
return self;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static VALUE vm_ttl(VALUE self) {
|
|
159
|
+
return DBL2NUM(vm_get(self)->ttl);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
static VALUE vm_aset(VALUE self, VALUE key, VALUE value) {
|
|
163
|
+
VolatileMap *vm = vm_get(self);
|
|
164
|
+
VALUE entry = rb_ary_new_from_args(2, value, DBL2NUM(now_seconds()));
|
|
165
|
+
|
|
166
|
+
rb_hash_aset(vm->storage, key, entry);
|
|
167
|
+
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static VALUE vm_aref(VALUE self, VALUE key) {
|
|
172
|
+
VolatileMap *vm = vm_get(self);
|
|
173
|
+
VALUE entry = rb_hash_lookup2(vm->storage, key, Qundef);
|
|
174
|
+
|
|
175
|
+
if(entry == Qundef) return Qnil;
|
|
176
|
+
|
|
177
|
+
double now = now_seconds();
|
|
178
|
+
|
|
179
|
+
if(is_stale(vm->ttl, entry, now)) {
|
|
180
|
+
rb_hash_delete(vm->storage, key);
|
|
181
|
+
|
|
182
|
+
return Qnil;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
rb_ary_store(entry, 1, DBL2NUM(now));
|
|
186
|
+
|
|
187
|
+
return RARRAY_AREF(entry, 0);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
static VALUE vm_delete(VALUE self, VALUE key) {
|
|
191
|
+
VolatileMap *vm = vm_get(self);
|
|
192
|
+
VALUE entry = rb_hash_delete(vm->storage, key);
|
|
193
|
+
|
|
194
|
+
if(NIL_P(entry) || !RB_TYPE_P(entry, T_ARRAY) || RARRAY_LEN(entry) < 1) return Qnil;
|
|
195
|
+
|
|
196
|
+
return RARRAY_AREF(entry, 0);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static VALUE vm_size(VALUE self) {
|
|
200
|
+
VolatileMap *vm = vm_get(self);
|
|
201
|
+
|
|
202
|
+
if(NIL_P(vm->storage)) return INT2FIX(0);
|
|
203
|
+
|
|
204
|
+
return ULONG2NUM(RHASH_SIZE(vm->storage));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
static VALUE vm_key(VALUE self, VALUE key) {
|
|
208
|
+
VolatileMap *vm = vm_get(self);
|
|
209
|
+
VALUE entry = rb_hash_lookup2(vm->storage, key, Qundef);
|
|
210
|
+
|
|
211
|
+
if(entry == Qundef) return Qfalse;
|
|
212
|
+
|
|
213
|
+
double now = now_seconds();
|
|
214
|
+
|
|
215
|
+
if(is_stale(vm->ttl, entry, now)) {
|
|
216
|
+
rb_hash_delete(vm->storage, key);
|
|
217
|
+
|
|
218
|
+
return Qfalse;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
rb_ary_store(entry, 1, DBL2NUM(now));
|
|
222
|
+
|
|
223
|
+
return Qtrue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
void Init_volatile_map(void) {
|
|
227
|
+
rb_require("volatile_map/version");
|
|
228
|
+
|
|
229
|
+
VALUE volatile_map_class = rb_define_class("VolatileMap", rb_cObject);
|
|
230
|
+
|
|
231
|
+
rb_define_alloc_func(volatile_map_class, alloc_volatile_map);
|
|
232
|
+
|
|
233
|
+
rb_define_method(volatile_map_class, "initialize", vm_initialize, 1);
|
|
234
|
+
rb_define_method(volatile_map_class, "ttl", vm_ttl, 0);
|
|
235
|
+
rb_define_method(volatile_map_class, "[]=", vm_aset, 2);
|
|
236
|
+
rb_define_method(volatile_map_class, "[]", vm_aref, 1);
|
|
237
|
+
rb_define_method(volatile_map_class, "delete", vm_delete, 1);
|
|
238
|
+
rb_define_method(volatile_map_class, "size", vm_size, 0);
|
|
239
|
+
rb_define_method(volatile_map_class, "length", vm_size, 0);
|
|
240
|
+
rb_define_method(volatile_map_class, "key?", vm_key, 1);
|
|
241
|
+
rb_define_method(volatile_map_class, "has_key?", vm_key, 1);
|
|
242
|
+
rb_define_method(volatile_map_class, "include?", vm_key, 1);
|
|
243
|
+
rb_define_method(volatile_map_class, "member?", vm_key, 1);
|
|
244
|
+
|
|
245
|
+
#ifdef VOLATILE_MAP_TEST_HELPERS
|
|
246
|
+
init_test_helpers(volatile_map_class);
|
|
247
|
+
#endif
|
|
248
|
+
|
|
249
|
+
#ifdef HAVE_RB_POSTPONED_JOB_PREREGISTER
|
|
250
|
+
vm_drain_job_handle = rb_postponed_job_preregister(0, vm_drain_dirty, NULL);
|
|
251
|
+
#endif
|
|
252
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#ifndef VOLATILE_MAP_H
|
|
2
|
+
#define VOLATILE_MAP_H
|
|
3
|
+
|
|
4
|
+
#include <ruby.h>
|
|
5
|
+
#include <ruby/debug.h>
|
|
6
|
+
|
|
7
|
+
typedef struct volatile_map_struct {
|
|
8
|
+
VALUE storage;
|
|
9
|
+
double ttl;
|
|
10
|
+
} VolatileMap;
|
|
11
|
+
|
|
12
|
+
VALUE alloc_volatile_map(VALUE klass);
|
|
13
|
+
void Init_volatile_map(void);
|
|
14
|
+
|
|
15
|
+
#endif
|
metadata
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: volatile_map
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Mehmet Emin INAC
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: This gem implement a volatile Hash like object which expires its keys
|
|
13
|
+
based on given TTL.
|
|
14
|
+
email:
|
|
15
|
+
- mehmetemininac@gmail.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions:
|
|
18
|
+
- ext/volatile_map/extconf.rb
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- CODE_OF_CONDUCT.md
|
|
22
|
+
- LICENSE.txt
|
|
23
|
+
- README.md
|
|
24
|
+
- Rakefile
|
|
25
|
+
- ext/volatile_map/extconf.rb
|
|
26
|
+
- ext/volatile_map/test_helpers.c
|
|
27
|
+
- ext/volatile_map/test_helpers.h
|
|
28
|
+
- ext/volatile_map/volatile_map.c
|
|
29
|
+
- ext/volatile_map/volatile_map.h
|
|
30
|
+
- lib/volatile_map/version.rb
|
|
31
|
+
homepage: https://github.com/meinac/volatile_map
|
|
32
|
+
licenses:
|
|
33
|
+
- MIT
|
|
34
|
+
metadata:
|
|
35
|
+
homepage_uri: https://github.com/meinac/volatile_map
|
|
36
|
+
source_code_uri: https://github.com/meinac/volatile_map
|
|
37
|
+
rdoc_options: []
|
|
38
|
+
require_paths:
|
|
39
|
+
- lib
|
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
42
|
+
- - ">="
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: 3.2.0
|
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '0'
|
|
50
|
+
requirements: []
|
|
51
|
+
rubygems_version: 4.0.10
|
|
52
|
+
specification_version: 4
|
|
53
|
+
summary: Implements a volatile Hash like object.
|
|
54
|
+
test_files: []
|