localmemcache 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/src/lmc_valloc.c ADDED
@@ -0,0 +1,324 @@
1
+ /*
2
+ * Copyright (c) 2009, Sven C. Koehler
3
+ */
4
+
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <sys/types.h>
8
+ #include <sys/stat.h>
9
+ #include <string.h>
10
+ #include <unistd.h>
11
+ #include <fcntl.h>
12
+ #include <sys/mman.h>
13
+
14
+ #include "lmc_valloc.h"
15
+
16
+ #include "lmc_lock.h"
17
+
18
+ typedef struct {
19
+ size_t next;
20
+ size_t size;
21
+ } mem_chunk_descriptor_t;
22
+
23
+ mem_chunk_descriptor_t *md_first_free(void *base) {
24
+ mem_descriptor_t *md = base;
25
+ return md->first_free == 0 ? 0 : base + md->first_free;
26
+ }
27
+
28
+ void lmc_dump_chunk(void *base, mem_chunk_descriptor_t* c) {
29
+ size_t va_c = (void *)c - base;
30
+ printf("chunk %zd:\n"
31
+ " start: %zd\n"
32
+ " end : %zd\n"
33
+ " size : %zd\n"
34
+ " next : %zd\n"
35
+ " ------------------------\n"
36
+ , va_c, va_c, va_c + c->size, c->size, c->next);
37
+ }
38
+
39
+ void lmc_dump_chunk_brief(char *who, void *base, mem_chunk_descriptor_t* c) {
40
+ if (!c) { return; }
41
+ size_t va_c = (void *)c - base;
42
+ printf("[%s] chunk %zd:\n", who, va_c);
43
+ }
44
+
45
+
46
+ void lmc_dump(void *base) {
47
+ mem_chunk_descriptor_t* c = md_first_free(base);
48
+ size_t free = 0;
49
+ long chunks = 0;
50
+ while (c) {
51
+ lmc_dump_chunk(base, c);
52
+ free += c->size;
53
+ chunks++;
54
+ if (c->next == 0) { c = 0; } else { c = base + c->next; }
55
+ }
56
+ }
57
+
58
+ int is_va_valid(void *base, size_t va) {
59
+ mem_descriptor_t *md = base;
60
+ mem_chunk_descriptor_t* c = base + va;
61
+ return !(((void *)c < base ) || (base + md->total_size + sizeof(mem_descriptor_t)) < (void *)c);
62
+ }
63
+
64
+ mem_status_t lmc_status(void *base, char *where) {
65
+ mem_descriptor_t *md = base;
66
+ mem_chunk_descriptor_t* c = md_first_free(base);
67
+ mem_status_t ms;
68
+ size_t free = 0;
69
+ size_t largest_chunk = 0;
70
+ long chunks = 0;
71
+ ms.total_mem = md->total_size;
72
+ while (c) {
73
+ if (!is_va_valid(base, (void *)c - base)) {
74
+ printf("[%s] invalid pointer detected: %ld...\n", where, (void *)c - base);
75
+ lmc_dump(base);
76
+ abort();
77
+ }
78
+ free += c->size;
79
+ if (c->size > largest_chunk) { largest_chunk = c->size; }
80
+ chunks++;
81
+ if (c->next == 0) { c = 0; } else { c = base + c->next; }
82
+ }
83
+ ms.total_free_mem = free;
84
+ ms.free_mem = free > 0 ? free - sizeof(size_t) : 0;
85
+ ms.largest_chunk = largest_chunk;
86
+ ms.free_chunks = chunks;
87
+ return ms;
88
+ }
89
+
90
+ void lmc_show_status(void *base) {
91
+ mem_status_t ms = lmc_status(base, "lmc_ss");
92
+ printf("total: %zu\n", ms.total_mem);
93
+ printf("chunks: %zu, free: %zu\n", ms.free_chunks, ms.free_mem);
94
+ }
95
+
96
+ int is_lmc_already_initialized(void *base) {
97
+ mem_descriptor_t *md = base;
98
+ if (md->magic == 0xF00D) {
99
+ #ifdef LMC_DEBUG_ALLOC
100
+ printf("memory already initialized, skipping...\n");
101
+ #endif
102
+ return 1;
103
+ }
104
+ return 0;
105
+ }
106
+
107
+ void lmc_init_memory(void *ptr, size_t size) {
108
+ mem_descriptor_t *md = ptr;
109
+ size_t s = size - sizeof(mem_descriptor_t);
110
+ // size: enough space for mem_descriptor_t + mem_chunk_descriptor_t
111
+ md->first_free = sizeof(mem_descriptor_t);
112
+ md->magic = 0xF00D;
113
+ md->locked = 0;
114
+ md->total_size = s;
115
+ mem_chunk_descriptor_t *c = ptr + sizeof(mem_descriptor_t);
116
+ c->next = 0;
117
+ c->size = s;
118
+ }
119
+
120
+ size_t lmc_max(size_t a, size_t b) {
121
+ return a > b ? a : b;
122
+ }
123
+
124
+ size_t __s(char *where, mem_status_t ms, size_t mem_before, size_t expected_diff) {
125
+ size_t free = ms.total_free_mem;
126
+ printf("(%s) ", where);
127
+ if (mem_before) { printf("[%ld:%zd] ", free - mem_before, expected_diff); }
128
+ printf("mem_free: %zu, chunks: %zu\n", free, ms.free_chunks);
129
+ if (expected_diff && expected_diff != free - mem_before) {
130
+ printf("expected_diff (%zu) != diff (%ld)\n", expected_diff,
131
+ free - mem_before);
132
+ abort();
133
+ }
134
+ return free;
135
+ }
136
+
137
+ size_t lmc_valloc(void *base, size_t size) {
138
+ mem_descriptor_t *md = base;
139
+ // MOD by power of 2
140
+ size_t s = lmc_max(size + sizeof(size_t),
141
+ sizeof(mem_chunk_descriptor_t) + sizeof(size_t));
142
+ // larger than available space?
143
+ mem_chunk_descriptor_t *c = md_first_free(base);
144
+ mem_chunk_descriptor_t *p = NULL;
145
+ if (size == 0) { return 0; }
146
+ while (c && c->size <s ) {
147
+ p = c;
148
+ if (c->next == 0) {
149
+ c = 0;
150
+ break;
151
+ }
152
+ c = base + c->next;
153
+ }
154
+ if (!c) {
155
+ //fprintf(stderr, "lmc_valloc: Failed to allocate %d bytes!\n", size);
156
+ return 0;
157
+ }
158
+ size_t r = 0;
159
+ if (c->size - s < sizeof(mem_chunk_descriptor_t)) { s = c->size; }
160
+ // ----------------- -------------------
161
+ // | chunk | wanted: | |
162
+ // ----------------- -------------------
163
+ if (c->size == s) {
164
+ if (p) { p->next = c->next; }
165
+ else {md->first_free = c->next; }
166
+ r = (size_t)((void*)c - (void*)base);
167
+ } else {
168
+ // ----------------- -------------------
169
+ // | chunk | wanted: | |
170
+ // | | -------------------
171
+ // -----------------
172
+ c->size -= s;
173
+ r = (size_t)((void*)c - base) + c->size;
174
+ }
175
+ *(size_t *)(r + base) = s;
176
+ return r + sizeof(size_t);
177
+ }
178
+
179
+ // compact_chunks,
180
+ void lmc_check_coalesce(void *base, size_t va_chunk) {
181
+ mem_descriptor_t *md = base;
182
+ mem_chunk_descriptor_t *chunk = base + va_chunk;
183
+ size_t c_size = chunk->size;
184
+ size_t va_chunk_p = 0;
185
+ size_t va_c_free_chunk = 0;
186
+ mem_chunk_descriptor_t* c_free_chunk = base + va_c_free_chunk;
187
+ size_t va_previous = 0;
188
+ size_t merge1_chunk = 0;
189
+ int merge1 = 0;
190
+ while (c_free_chunk) {
191
+ va_c_free_chunk = (void *)c_free_chunk - base;
192
+ if (va_c_free_chunk != va_chunk) {
193
+ if (c_free_chunk->next == va_chunk) { va_chunk_p = va_c_free_chunk; }
194
+ else if (!merge1) {
195
+ // ----------------------
196
+ // | a_free_chunk |
197
+ // ---------------------- <---- if (...)
198
+ // | chunk |
199
+ // ----------------------
200
+ if (va_c_free_chunk + c_free_chunk->size == va_chunk) {
201
+ merge1 = 1;
202
+ merge1_chunk = va_c_free_chunk;
203
+ } else
204
+ // ----------------------
205
+ // | chunk |
206
+ // ---------------------- <---- if (...)
207
+ // | a_free_chunk |
208
+ // ----------------------
209
+ if (va_chunk + c_size == va_c_free_chunk) {
210
+ chunk->size += c_free_chunk->size;
211
+ if (chunk->next == va_c_free_chunk) { va_previous = va_chunk; }
212
+ mem_chunk_descriptor_t *p = va_previous ? base + va_previous : 0;
213
+ if (p) { p->next = c_free_chunk->next; }
214
+ break;
215
+ }
216
+ }
217
+ va_previous = va_c_free_chunk;
218
+ }
219
+ va_c_free_chunk = c_free_chunk->next;
220
+ if (va_c_free_chunk == 0) { c_free_chunk = NULL; }
221
+ else { c_free_chunk = base + va_c_free_chunk; }
222
+ }
223
+ // ----------------------
224
+ // | a_free_chunk |
225
+ // ---------------------- <---- if (...)
226
+ // | chunk |
227
+ // ----------------------
228
+ if (merge1) {
229
+ mem_chunk_descriptor_t *cd = base + merge1_chunk;
230
+ mem_chunk_descriptor_t *p = va_chunk_p ? base + va_chunk_p : 0;
231
+ mem_chunk_descriptor_t *vacd = va_chunk? base + va_chunk : 0;
232
+ if (p) { p->next = vacd->next; }
233
+ if (md->first_free == va_chunk) { md->first_free = chunk->next; }
234
+ cd->size += c_size;
235
+ }
236
+ }
237
+
238
+
239
+ void lmc_free(void *base, size_t chunk) {
240
+ #ifdef LMC_DEBUG_ALLOC
241
+ size_t mb = __s("free1", lmc_status(base, "lmc_free1"), 0, 0);
242
+ #endif
243
+ if (chunk == 0) { return; }
244
+ mem_descriptor_t *md = base;
245
+ size_t va_used_chunk = chunk - sizeof(size_t);
246
+ void *used_chunk_p = base + va_used_chunk;
247
+ mem_chunk_descriptor_t *mcd_used_chunk = used_chunk_p;
248
+ size_t uc_size = *(size_t *)used_chunk_p;
249
+ size_t va_c_free_chunk = 0;
250
+ mem_chunk_descriptor_t* c_free_chunk = base + va_c_free_chunk;
251
+ size_t va_previous = 0;
252
+ size_t va_c_free_end = 0;
253
+ if (!(chunk >= sizeof(mem_descriptor_t) + sizeof(size_t)) ||
254
+ !is_va_valid(base, chunk)) {
255
+ printf("lmc_free: Invalid pointer: %zd\n", chunk);
256
+ return;
257
+ }
258
+ #ifdef LMC_DEBUG_ALLOC
259
+ if (uc_size == 0) {
260
+ printf("SIZE is 0!\n");
261
+ lmc_dump(base);
262
+ abort();
263
+ }
264
+ memset(base + chunk, 0xF9, uc_size - sizeof(size_t));
265
+ #endif
266
+ int freed = 0;
267
+ while (c_free_chunk) {
268
+ va_c_free_chunk = (void *)c_free_chunk - base;
269
+ va_c_free_end = va_c_free_chunk + c_free_chunk->size;
270
+ // ----------------------
271
+ // | c_free_chunk |
272
+ // ---------------------- <---- if (...)
273
+ // | used_chunk |
274
+ // ----------------------
275
+ if (va_c_free_end == va_used_chunk) {
276
+ freed = 1;
277
+ c_free_chunk->size += uc_size;
278
+ lmc_check_coalesce(base, va_c_free_chunk);
279
+ break;
280
+ } else
281
+ // ----------------------
282
+ // | used_chunk |
283
+ // ---------------------- <---- if (...)
284
+ // | c_free_chunk |
285
+ // ----------------------
286
+ if (va_used_chunk + uc_size == va_c_free_chunk) {
287
+ freed = 1;
288
+ mem_chunk_descriptor_t *p = base + va_previous;
289
+ mcd_used_chunk->next = c_free_chunk->next;
290
+ mcd_used_chunk->size = uc_size + c_free_chunk->size;
291
+ p->next = va_used_chunk;
292
+ lmc_check_coalesce(base, va_used_chunk);
293
+ break;
294
+ }
295
+ if (va_used_chunk >= va_c_free_chunk && va_used_chunk <= va_c_free_end) {
296
+ fprintf(stderr, "Was pointer already freed?\n");
297
+ return;
298
+ }
299
+ va_previous = va_c_free_chunk;
300
+ va_c_free_chunk = c_free_chunk->next;
301
+ if (va_c_free_chunk == 0) { c_free_chunk = NULL; }
302
+ else { c_free_chunk = base + va_c_free_chunk; }
303
+ }
304
+ // ----------------------
305
+ // | otherwise allocated |
306
+ // ----------------------
307
+ // | used_chunk |
308
+ // ----------------------
309
+ // | otherwise allocated |
310
+ // ----------------------
311
+ if (!freed) {
312
+ mcd_used_chunk->next = md->first_free;
313
+ mcd_used_chunk->size = uc_size;
314
+ md->first_free = va_used_chunk;
315
+ }
316
+ #ifdef LMC_DEBUG_ALLOC
317
+ __s("free2", lmc_status(base, "lmc_free2"), mb, uc_size);
318
+ #endif
319
+ }
320
+
321
+ void lmc_realloc(void *base, size_t chunk) {
322
+ // check if enough reserved space, true: resize; otherwise: alloc new and
323
+ // then free
324
+ }
data/src/lmc_valloc.h ADDED
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Copyright (c) 2009, Sven C. Koehler
3
+ */
4
+
5
+ #ifndef _LMC_VALLOC_H_INCLUDED_
6
+ #define _LMC_VALLOC_H_INCLUDED_
7
+ #undef LMC_DEBUG_ALLOC
8
+ typedef struct {
9
+ size_t free_chunks;
10
+ size_t total_mem;
11
+ size_t total_free_mem;
12
+ size_t free_mem;
13
+ size_t largest_chunk;
14
+ } mem_status_t;
15
+
16
+ typedef struct {
17
+ size_t first_free;
18
+ size_t dummy2;
19
+ size_t total_size;
20
+ size_t magic;
21
+ size_t va_hash;
22
+ int locked;
23
+ } mem_descriptor_t;
24
+
25
+
26
+ size_t lmc_valloc(void *base, size_t size);
27
+ void lmc_free(void *base, size_t chunk);
28
+ mem_status_t lmc_status(void *base, char *where);
29
+ int is_lmc_already_initialized(void *base);
30
+ void lmc_init_memory(void *ptr, size_t size);
31
+ #endif
@@ -0,0 +1,130 @@
1
+ #include "localmemcache.h"
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+ #include "lmc_valloc.h"
5
+ #include "lmc_shm.h"
6
+
7
+ int lmc_set_lock_flag(void *base, lmc_error_t *e) {
8
+ mem_descriptor_t *md = base;
9
+ if (md->locked != 0) {
10
+ strncpy(e->error_str, "Failed to lock shared memory region--"
11
+ "may be corrupt.", 1023);
12
+ return 0;
13
+ } else {
14
+ md->locked = 1;
15
+ }
16
+ return 1;
17
+ }
18
+
19
+ int lmc_release_lock_flag(void *base, lmc_error_t *e) {
20
+ mem_descriptor_t *md = base;
21
+ if (md->locked != 1) {
22
+ strncpy(e->error_str, "Shared memory region appears to be unlocked already"
23
+ "--may be corrupt.", 1023);
24
+ return 0;
25
+ } else {
26
+ md->locked = 0;
27
+ }
28
+ return 1;
29
+ }
30
+
31
+ int local_memcache_clear_namespace(const char *namespace, int repair,
32
+ lmc_error_t *e) {
33
+ lmc_clean_namespace(namespace, e);
34
+ if (repair) {
35
+ lmc_lock_t *l = lmc_lock_init(namespace, 1, e);
36
+ lmc_lock_repair(l);
37
+ free(l);
38
+ }
39
+ return 1;
40
+ }
41
+
42
+ local_memcache_t *local_memcache_create(const char *namespace, size_t size,
43
+ lmc_error_t* e) {
44
+ local_memcache_t *lmc = calloc(1, sizeof(local_memcache_t));
45
+ if (!lmc || (lmc->namespace = strdup(namespace)) == NULL) return NULL;
46
+ lmc->size = size;
47
+ if ((lmc->lock = lmc_lock_init(lmc->namespace, 1, e)) == NULL) goto failed;
48
+ if (!lmc_is_lock_working(lmc->lock, e)) {
49
+ strncpy(e->error_str, "Failed to lock shared memory!", 1023);
50
+ goto failed;
51
+ }
52
+ {
53
+ if (!lmc_lock_obtain("local_memcache_create", lmc->lock, &lmc->error))
54
+ goto failed;
55
+ if ((lmc->shm = lmc_shm_create(lmc->namespace, lmc->size, 0, e)) == NULL)
56
+ goto release_and_fail;
57
+ lmc->base = lmc->shm->base;
58
+ if (is_lmc_already_initialized(lmc->base)) {
59
+ if (!lmc_set_lock_flag(lmc->base, e)) goto release_and_fail;
60
+ mem_descriptor_t *md = lmc->base;
61
+ lmc->va_hash = md->va_hash;
62
+ } else {
63
+ lmc_init_memory(lmc->base, lmc->size);
64
+ mem_descriptor_t *md = lmc->base;
65
+ if ((md->va_hash = ht_hash_create(lmc->base, e)) == 0)
66
+ goto unlock_and_fail;
67
+ lmc->va_hash = md->va_hash;
68
+ }
69
+ lmc_release_lock_flag(lmc->base, e);
70
+ lmc_lock_release("local_memcache_create", lmc->lock, e);
71
+ }
72
+ return lmc;
73
+
74
+ unlock_and_fail:
75
+ lmc_release_lock_flag(lmc->base, e);
76
+ release_and_fail:
77
+ lmc_lock_release("local_memcache_create", lmc->lock, e);
78
+ failed:
79
+ free(lmc);
80
+ return NULL;
81
+ }
82
+
83
+ int lmc_lock_shm_region(const char *who, local_memcache_t *lmc) {
84
+ if (!lmc_lock_obtain(who, lmc->lock, &lmc->error)) return 0;
85
+ if (!lmc_set_lock_flag(lmc->base, &lmc->error)) {
86
+ lmc_lock_release(who, lmc->lock, &lmc->error);
87
+ return 0;
88
+ }
89
+ return 1;
90
+ }
91
+
92
+ int lmc_unlock_shm_region(const char *who, local_memcache_t *lmc) {
93
+ int r = 1;
94
+ if (!lmc_release_lock_flag(lmc->base, &lmc->error)) r = 0;
95
+ lmc_lock_release(who, lmc->lock, &lmc->error);
96
+ return r;
97
+ }
98
+
99
+ char *local_memcache_get(local_memcache_t *lmc, const char *key) {
100
+ if (!lmc_lock_shm_region("local_memcache_get", lmc)) return 0;
101
+ char *r = ht_get(lmc->base, lmc->va_hash, key);
102
+ if (!lmc_unlock_shm_region("local_memcache_get", lmc)) return 0;
103
+ return r;
104
+ }
105
+
106
+ int local_memcache_set(local_memcache_t *lmc,
107
+ const char *key, const char* value) {
108
+ if (!lmc_lock_shm_region("local_memcache_set", lmc)) return 0;
109
+ int r = ht_set(lmc->base, lmc->va_hash, key, value, &lmc->error);
110
+ if (!lmc_unlock_shm_region("local_memcache_get", lmc)) return 0;
111
+ return r;
112
+ }
113
+
114
+ int local_memcache_delete(local_memcache_t *lmc, char *key) {
115
+ if (!lmc_lock_shm_region("local_memcache_delete", lmc)) return 0;
116
+ int r = ht_delete(lmc->base, lmc->va_hash, key);
117
+ if (!lmc_unlock_shm_region("local_memcache_delete", lmc)) return 0;
118
+ return r;
119
+ }
120
+
121
+ int local_memcache_free(local_memcache_t *lmc) {
122
+ lmc_error_t e;
123
+ if (!lmc_lock_shm_region("local_memcache_free", lmc)) return 0;
124
+ int r = ht_hash_destroy(lmc->base, lmc->va_hash);
125
+ if (!lmc_unlock_shm_region("local_memcache_free", lmc)) return 0;
126
+ lmc_shm_destroy(lmc->shm, &e);
127
+ free(lmc->namespace);
128
+ free(lmc->lock);
129
+ return r;
130
+ }
@@ -0,0 +1,33 @@
1
+ #ifndef _LOCAL_MEMCACHE_INCLUDED_
2
+ #define _LOCAL_MEMCACHE_INCLUDED_
3
+
4
+ #include <stdlib.h>
5
+ #include "lmc_hashtable.h"
6
+ #include "lmc_shm.h"
7
+ #include "lmc_lock.h"
8
+ #include "lmc_error.h"
9
+
10
+ #define LOCAL_MEMCACHE_FAILED 0
11
+ #define LOCAL_MEMCACHE_SUCCESS 1
12
+
13
+ typedef struct {
14
+ char *namespace;
15
+ size_t size;
16
+ lmc_shm_t *shm;
17
+ size_t va_hash;
18
+ lmc_lock_t *lock;
19
+ lmc_lock_t *root_lock;
20
+ void* base;
21
+ lmc_error_t error;
22
+ } local_memcache_t;
23
+
24
+ local_memcache_t *local_memcache_create(const char *namespace, size_t size,
25
+ lmc_error_t *e);
26
+ char *local_memcache_get(local_memcache_t *lmc, const char *key);
27
+ int local_memcache_set(local_memcache_t *lmc, const char *key, const char* value);
28
+ int local_memcache_delete(local_memcache_t *lmc, char *key);
29
+ int local_memcache_free(local_memcache_t *lmc);
30
+ int local_memcache_clear_namespace(const char *namespace, int repair,
31
+ lmc_error_t *e);
32
+
33
+ #endif
@@ -0,0 +1,14 @@
1
+ require 'mkmf'
2
+
3
+ dir = File.dirname(__FILE__)
4
+
5
+ $defs << "-DRUBY_VERSION_CODE=#{RUBY_VERSION.gsub(/\D/, '')}"
6
+
7
+ $srcs = ['rblocalmemcache.c']
8
+ $objs = ['rblocalmemcache.o']
9
+
10
+ $CFLAGS << " -g -I .."
11
+ $LDFLAGS << " ../liblmc.a -lpthread -lrt "
12
+
13
+ dir_config('rblocalmemcache')
14
+ create_makefile('rblocalmemcache')
@@ -0,0 +1,32 @@
1
+ require 'rblocalmemcache'
2
+
3
+ # == Overview
4
+ # TestRDocUsage: A useless file
5
+ #
6
+ # == Example
7
+ #
8
+ # Usage: ruby testRDocUsage.rb [options]
9
+ #
10
+ class LocalMemCache
11
+
12
+ # Creates a new handle for accessing a shared memory region.
13
+ #
14
+ # LocalMemCache.new :namespace=>"foo", :size_mb=> 1
15
+ #
16
+ # The namespace parameter is mandatory.
17
+ # The size_mb defaults to 1024 (1 GB).
18
+ #
19
+ def self.new(options)
20
+ o = { :size_mb => 1024 }.update(options || {})
21
+ raise "Missing mandatory option ':namespace'" if !o[:namespace]
22
+ _new(o[:namespace].gsub("/", "-"), (o[:size_mb].to_f * 1024 * 1024).to_i );
23
+ end
24
+
25
+ # Deletes the given namespaces, removing semaphores if necessary.
26
+ # Do only use if you are sure the namespace is not used anymore by other
27
+ # processes.
28
+ #
29
+ def self.clear_namespace(namespace, repair = false)
30
+ _clear_namespace(namespace, repair)
31
+ end
32
+ end
@@ -0,0 +1,119 @@
1
+ /*
2
+ * Copyright (C) 2009, Sven C. Koehler
3
+ */
4
+
5
+ #include <ruby.h>
6
+ #include "localmemcache.h"
7
+
8
+ /* :nodoc: */
9
+ long long_value(VALUE i) { return NUM2LONG(rb_Integer(i)); }
10
+ /* :nodoc: */
11
+ VALUE num2string(long i) { return rb_big2str(rb_int2big(i), 10); }
12
+ /* :nodoc: */
13
+ char *rstring_ptr(VALUE s) {
14
+ char* r = NIL_P(s) ? "nil" : RSTRING_PTR(rb_String(s));
15
+ return r ? r : "nil";
16
+ }
17
+ /* :nodoc: */
18
+ static VALUE ruby_string(char *s) { return s ? rb_str_new2(s) : Qnil; }
19
+ /* :nodoc: */
20
+ int bool_value(VALUE v) { return v == Qtrue; }
21
+
22
+ static VALUE LocalMemCacheError;
23
+
24
+ /* :nodoc: */
25
+ void raise_exception(VALUE error_klass, lmc_error_t *e) {
26
+ rb_raise(error_klass, e->error_str);
27
+ }
28
+
29
+ /* :nodoc: */
30
+ static VALUE LocalMemCache__new2(VALUE klass, VALUE namespace, VALUE size) {
31
+ lmc_error_t e;
32
+ local_memcache_t *lmc = local_memcache_create(rstring_ptr(namespace),
33
+ long_value(size), &e);
34
+ if (!lmc) { raise_exception(LocalMemCacheError, &e); }
35
+ return Data_Wrap_Struct(klass, NULL, local_memcache_free, lmc);
36
+ }
37
+
38
+ /* :nodoc: */
39
+ static VALUE LocalMemCache__clear_namespace(VALUE klass, VALUE ns, VALUE repair) {
40
+ lmc_error_t e;
41
+ if (!local_memcache_clear_namespace(rstring_ptr(ns), bool_value(repair), &e)) {
42
+ raise_exception(LocalMemCacheError, &e);
43
+ }
44
+ return Qnil;
45
+ }
46
+
47
+ /* :nodoc: */
48
+ local_memcache_t *get_LocalMemCache(VALUE obj) {
49
+ local_memcache_t *lmc;
50
+ Data_Get_Struct(obj, local_memcache_t, lmc);
51
+ return lmc;
52
+ }
53
+
54
+ /*
55
+ * call-seq:
56
+ * lmc.get(key) -> Qnil
57
+ * lmc[key] -> Qnil
58
+ *
59
+ * Retrieve value from hashtable.
60
+ */
61
+ static VALUE LocalMemCache__get(VALUE obj, VALUE key) {
62
+ return ruby_string(local_memcache_get(get_LocalMemCache(obj),
63
+ rstring_ptr(key)));
64
+ }
65
+
66
+ /*
67
+ * call-seq:
68
+ * lmc.set(key, value) -> Qnil
69
+ * lmc[key]=value -> Qnil
70
+ *
71
+ * Set value for key in hashtable.
72
+ */
73
+
74
+ static VALUE LocalMemCache__set(VALUE obj, VALUE key, VALUE value) {
75
+ local_memcache_t *lmc = get_LocalMemCache(obj);
76
+ if (!local_memcache_set(lmc, rstring_ptr(key), rstring_ptr(value))) {
77
+ raise_exception(LocalMemCacheError, &lmc->error);
78
+ }
79
+ return Qnil;
80
+ }
81
+
82
+ /*
83
+ * call-seq:
84
+ * lmc.delete(key) -> Qnil
85
+ *
86
+ * Deletes key from hashtable.
87
+ */
88
+ static VALUE LocalMemCache__delete(VALUE obj, VALUE key) {
89
+ return local_memcache_delete(get_LocalMemCache(obj),
90
+ rstring_ptr(key));
91
+ return Qnil;
92
+ }
93
+
94
+ /*
95
+ * call-seq:
96
+ * lmc.close() -> Qnil
97
+ *
98
+ * Releases hashtable.
99
+ */
100
+ static VALUE LocalMemCache__close(VALUE obj) {
101
+ local_memcache_free(get_LocalMemCache(obj));
102
+ return Qnil;
103
+ }
104
+
105
+ static VALUE LocalMemCache;
106
+
107
+ void Init_rblocalmemcache() {
108
+ LocalMemCacheError = rb_define_class("LocalMemCacheError", rb_eStandardError);
109
+ LocalMemCache = rb_define_class("LocalMemCache", rb_cObject);
110
+ rb_define_singleton_method(LocalMemCache, "_new", LocalMemCache__new2, 2);
111
+ rb_define_singleton_method(LocalMemCache, "_clear_namespace",
112
+ LocalMemCache__clear_namespace, 2);
113
+ rb_define_method(LocalMemCache, "get", LocalMemCache__get, 1);
114
+ rb_define_method(LocalMemCache, "[]", LocalMemCache__get, 1);
115
+ rb_define_method(LocalMemCache, "delete", LocalMemCache__delete, 1);
116
+ rb_define_method(LocalMemCache, "set", LocalMemCache__set, 2);
117
+ rb_define_method(LocalMemCache, "[]=", LocalMemCache__set, 2);
118
+ rb_define_method(LocalMemCache, "close", LocalMemCache__close, 0);
119
+ }
data/src/tests/alloc ADDED
@@ -0,0 +1,11 @@
1
+ #! /bin/sh
2
+ D=`dirname $0`
3
+ DIR=`cd $D; pwd`
4
+ script=$DIR/alloc.rb
5
+
6
+ if test "x$1" = "x-d"; then
7
+ irb -r $script
8
+ else
9
+ #valgrind --leak-check=full --tool=memcheck ruby $script
10
+ time ruby $script
11
+ fi