localmemcache 0.0.1 → 0.2.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.
data/src/lmc_valloc.h CHANGED
@@ -11,7 +11,13 @@ typedef struct {
11
11
  size_t total_free_mem;
12
12
  size_t free_mem;
13
13
  size_t largest_chunk;
14
- } mem_status_t;
14
+ } lmc_mem_status_t;
15
+
16
+ typedef struct {
17
+ int op_id;
18
+ size_t p1;
19
+ size_t p2;
20
+ } lmc_log_descriptor_t;
15
21
 
16
22
  typedef struct {
17
23
  size_t first_free;
@@ -20,12 +26,26 @@ typedef struct {
20
26
  size_t magic;
21
27
  size_t va_hash;
22
28
  int locked;
23
- } mem_descriptor_t;
29
+ lmc_log_descriptor_t log;
30
+ } lmc_mem_descriptor_t;
31
+
32
+ typedef struct {
33
+ size_t next;
34
+ size_t size;
35
+ } lmc_mem_chunk_descriptor_t;
24
36
 
25
37
 
26
38
  size_t lmc_valloc(void *base, size_t size);
27
39
  void lmc_free(void *base, size_t chunk);
28
- mem_status_t lmc_status(void *base, char *where);
40
+ lmc_mem_status_t lmc_status(void *base, char *where);
29
41
  int is_lmc_already_initialized(void *base);
30
42
  void lmc_init_memory(void *ptr, size_t size);
43
+
44
+ int lmc_um_mark_allocated(void *base, char *bf, size_t va);
45
+ char *lmc_um_new_mem_usage_bitmap(void *base);
46
+ int lmc_um_find_leaks(void *base, char *bf);
47
+
48
+ lmc_log_descriptor_t *lmc_log_op(void *base, int opid);
49
+ void lmc_log_finish(void *base);
50
+
31
51
  #endif
data/src/localmemcache.c CHANGED
@@ -1,3 +1,7 @@
1
+ /*
2
+ * Copyright (c) 2009, Sven C. Koehler
3
+ */
4
+
1
5
  #include "localmemcache.h"
2
6
  #include <stdio.h>
3
7
  #include <string.h>
@@ -5,10 +9,10 @@
5
9
  #include "lmc_shm.h"
6
10
 
7
11
  int lmc_set_lock_flag(void *base, lmc_error_t *e) {
8
- mem_descriptor_t *md = base;
12
+ lmc_mem_descriptor_t *md = base;
9
13
  if (md->locked != 0) {
10
- strncpy(e->error_str, "Failed to lock shared memory region--"
11
- "may be corrupt.", 1023);
14
+ lmc_handle_error_with_err_string("lmc_set_lock_flag",
15
+ "Failed to lock shared memory--may be corrupt!", "ShmLockFailed", e);
12
16
  return 0;
13
17
  } else {
14
18
  md->locked = 1;
@@ -17,10 +21,11 @@ int lmc_set_lock_flag(void *base, lmc_error_t *e) {
17
21
  }
18
22
 
19
23
  int lmc_release_lock_flag(void *base, lmc_error_t *e) {
20
- mem_descriptor_t *md = base;
24
+ lmc_mem_descriptor_t *md = base;
21
25
  if (md->locked != 1) {
22
- strncpy(e->error_str, "Shared memory region appears to be unlocked already"
23
- "--may be corrupt.", 1023);
26
+ lmc_handle_error_with_err_string("lmc_release_lock_flag",
27
+ "Shared memory appears to be unlocked already--may be corrupt!",
28
+ "ShmUnlockFailed", e);
24
29
  return 0;
25
30
  } else {
26
31
  md->locked = 0;
@@ -28,46 +33,93 @@ int lmc_release_lock_flag(void *base, lmc_error_t *e) {
28
33
  return 1;
29
34
  }
30
35
 
36
+ void lmc_clean_namespace_string(char *result, const char* original) {
37
+ size_t n = strlen(original);
38
+ if (n > 256) { n = 256; }
39
+ const char *s = original;
40
+ char *d = result;
41
+ char ch;
42
+ for (; n--; d++, s++) {
43
+ ch = *s;
44
+ if ((ch >= 'a' && ch <= 'z') ||
45
+ (ch >= 'A' && ch <= 'Z')) {
46
+ *d = ch;
47
+ } else {
48
+ *d = '-';
49
+ }
50
+ }
51
+ *d = 0x0;
52
+ }
53
+
31
54
  int local_memcache_clear_namespace(const char *namespace, int repair,
32
55
  lmc_error_t *e) {
33
- lmc_clean_namespace(namespace, e);
56
+ char clean_ns[1024];
57
+ lmc_clean_namespace_string((char *)clean_ns, namespace);
58
+ lmc_clean_namespace((char *)clean_ns, e);
34
59
  if (repair) {
35
- lmc_lock_t *l = lmc_lock_init(namespace, 1, e);
60
+ lmc_lock_t *l = lmc_lock_init((char *)clean_ns, 1, e);
36
61
  lmc_lock_repair(l);
37
62
  free(l);
63
+ char check_lock_name[1024];
64
+ snprintf((char *)&check_lock_name, 1023, "%s-check", (char *)clean_ns);
65
+ lmc_lock_t *check_l;
66
+ check_l = lmc_lock_init(check_lock_name, 1, e);
67
+ lmc_lock_repair(check_l);
68
+ free(check_l);
38
69
  }
39
70
  return 1;
40
71
  }
41
72
 
42
- local_memcache_t *local_memcache_create(const char *namespace, size_t size,
43
- lmc_error_t* e) {
73
+ local_memcache_t *__local_memcache_create(const char *namespace, size_t size,
74
+ int force, int *ok, lmc_error_t* e) {
75
+ int d;
76
+ if (!ok) { ok = &d; }
77
+ *ok = 1;
44
78
  local_memcache_t *lmc = calloc(1, sizeof(local_memcache_t));
45
79
  if (!lmc || (lmc->namespace = strdup(namespace)) == NULL) return NULL;
46
80
  lmc->size = size;
47
81
  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);
82
+ int retry_counter = 0;
83
+ retry:
84
+ if (retry_counter++ > 10) {
85
+ lmc_handle_error_with_err_string("local_memcache_create",
86
+ "Too many retries: Failed to repair shared memory!",
87
+ "ShmLockFailed", e);
50
88
  goto failed;
51
89
  }
90
+ if (!lmc_is_lock_working(lmc->lock, e)) {
91
+ if (!force) {
92
+ if (local_memcache_check_namespace(namespace, e)) goto retry;
93
+ lmc_handle_error_with_err_string("local_memcache_create",
94
+ "Failed to repair shared memory!", "ShmLockFailed", e);
95
+ goto failed;
96
+ }
97
+ *ok = 0;
98
+ }
52
99
  {
53
- if (!lmc_lock_obtain("local_memcache_create", lmc->lock, &lmc->error))
100
+ if (*ok && !lmc_lock_obtain("local_memcache_create", lmc->lock, &lmc->error))
54
101
  goto failed;
55
102
  if ((lmc->shm = lmc_shm_create(lmc->namespace, lmc->size, 0, e)) == NULL)
56
103
  goto release_and_fail;
57
104
  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;
105
+ if (!*ok || is_lmc_already_initialized(lmc->base)) {
106
+ if (*ok && !lmc_set_lock_flag(lmc->base, e)) {
107
+ if (!force) goto release_and_fail;
108
+ *ok = 0;
109
+ }
110
+ lmc_mem_descriptor_t *md = lmc->base;
61
111
  lmc->va_hash = md->va_hash;
62
112
  } else {
63
113
  lmc_init_memory(lmc->base, lmc->size);
64
- mem_descriptor_t *md = lmc->base;
114
+ lmc_mem_descriptor_t *md = lmc->base;
65
115
  if ((md->va_hash = ht_hash_create(lmc->base, e)) == 0)
66
116
  goto unlock_and_fail;
67
117
  lmc->va_hash = md->va_hash;
68
118
  }
69
- lmc_release_lock_flag(lmc->base, e);
70
- lmc_lock_release("local_memcache_create", lmc->lock, e);
119
+ if (*ok) {
120
+ lmc_release_lock_flag(lmc->base, e);
121
+ lmc_lock_release("local_memcache_create", lmc->lock, e);
122
+ }
71
123
  }
72
124
  return lmc;
73
125
 
@@ -76,12 +128,106 @@ unlock_and_fail:
76
128
  release_and_fail:
77
129
  lmc_lock_release("local_memcache_create", lmc->lock, e);
78
130
  failed:
131
+ *ok = 0;
79
132
  free(lmc);
80
133
  return NULL;
81
134
  }
82
135
 
136
+ local_memcache_t *local_memcache_create(const char *namespace, double size_mb,
137
+ lmc_error_t* e) {
138
+ char clean_ns[1024];
139
+ double s = size_mb == 0.0 ? 1024.0 : size_mb;
140
+ size_t si = s * 1024 * 1024;
141
+ //printf("size: %f, s: %f, si: %zd\n", size_mb, s, si);
142
+ lmc_clean_namespace_string((char *)clean_ns, namespace);
143
+ return __local_memcache_create((char *)clean_ns, si, 0, 0, e);
144
+ }
145
+
146
+ int local_memcache_check_namespace(const char *namespace, lmc_error_t *e) {
147
+ char clean_ns[1024];
148
+ lmc_clean_namespace_string((char *)clean_ns, namespace);
149
+ char check_lock_name[1024];
150
+ snprintf((char *)check_lock_name, 1023, "%s-check", (char *)clean_ns);
151
+
152
+ if (!lmc_does_namespace_exist((char *)clean_ns)) {
153
+ lmc_clear_namespace_lock(check_lock_name);
154
+ lmc_clear_namespace_lock(namespace);
155
+ printf("namespace '%s' does not exist!\n", (char *)clean_ns);
156
+ return 1;
157
+ }
158
+
159
+ lmc_lock_t *check_l;
160
+ if ((check_l = lmc_lock_init(check_lock_name, 1, e)) == NULL) {
161
+ lmc_handle_error_with_err_string("lmc_lock_init",
162
+ "Unable to initialize lock for checking namespace", "LockError", e);
163
+ return 0;
164
+ }
165
+ if (!lmc_lock_obtain_mandatory("local_memcache_check_namespace",
166
+ check_l, e)) goto check_lock_failed;
167
+ lmc_mem_descriptor_t *md = 0;
168
+ size_t ns_size = lmc_namespace_size((char *)clean_ns);
169
+ int ok;
170
+ local_memcache_t *lmc = __local_memcache_create((char *)clean_ns, ns_size,
171
+ 1, &ok, e);
172
+ if (!lmc) {
173
+ printf("WOAH: lmc == 0!\n");
174
+ goto failed;
175
+ }
176
+ md = lmc->base;
177
+ if (!ok) {
178
+ printf("[lmc] Auto repairing namespace '%s'\n", namespace);
179
+ if (!md->locked) goto release;
180
+ if (md->log.op_id == 0) goto unlock_and_release;
181
+ if (ht_redo(lmc->base, md->va_hash, &md->log, e)) goto unlock_and_release;
182
+ goto failed;
183
+ }
184
+ goto release_but_no_lock_correction;
185
+
186
+ unlock_and_release:
187
+ if (md) {
188
+ if (!ht_check_memory(lmc->base, md->va_hash)) goto failed;
189
+ md->locked = 0;
190
+ }
191
+ release:
192
+ {
193
+ int v;
194
+ sem_getvalue(lmc->lock->sem, &v);
195
+ if (v == 0) {
196
+ lmc_lock_release("local_memcache_create", lmc->lock, e);
197
+ }
198
+ }
199
+ release_but_no_lock_correction:
200
+ local_memcache_free(lmc, e);
201
+ lmc_lock_release("local_memcache_check_namespace", check_l, e);
202
+ free(check_l);
203
+ return 1;
204
+ failed:
205
+ lmc_handle_error_with_err_string("local_memcache_check_namespace",
206
+ "Unable to recover namespace", "RecoveryFailed", e);
207
+ local_memcache_free(lmc, e);
208
+ lmc_lock_release("local_memcache_check_namespace", check_l, e);
209
+ check_lock_failed:
210
+ free(check_l);
211
+ printf("[lmc] Failed to repair namespace '%s'\n", namespace);
212
+ return 0;
213
+ }
214
+
215
+
83
216
  int lmc_lock_shm_region(const char *who, local_memcache_t *lmc) {
84
- if (!lmc_lock_obtain(who, lmc->lock, &lmc->error)) return 0;
217
+ int r;
218
+ int retry_counter = 0;
219
+ retry:
220
+ if (retry_counter++ > 10) {
221
+ printf("[lmc] Too many retries: Cannot repair namespace '%s'\n",
222
+ lmc->namespace);
223
+ return 0;
224
+ }
225
+ r = lmc_lock_obtain(who, lmc->lock, &lmc->error);
226
+ if (!r && (strcmp(lmc->error.error_type, "LockTimedOut") == 0)) {
227
+ if (local_memcache_check_namespace(lmc->namespace, &lmc->error)) goto retry;
228
+ printf("[lmc] Cannot repair namespace '%s'\n", lmc->namespace);
229
+ }
230
+ if (!r) return 0;
85
231
  if (!lmc_set_lock_flag(lmc->base, &lmc->error)) {
86
232
  lmc_lock_release(who, lmc->lock, &lmc->error);
87
233
  return 0;
@@ -96,35 +242,51 @@ int lmc_unlock_shm_region(const char *who, local_memcache_t *lmc) {
96
242
  return r;
97
243
  }
98
244
 
99
- char *local_memcache_get(local_memcache_t *lmc, const char *key) {
245
+ const char *__local_memcache_get(local_memcache_t *lmc,
246
+ const char *key, size_t n_key, size_t *n_value) {
100
247
  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;
248
+ const char *r = ht_get(lmc->base, lmc->va_hash, key, n_key, n_value);
103
249
  return r;
104
250
  }
105
251
 
252
+ char *local_memcache_get_new(local_memcache_t *lmc,
253
+ const char *key, size_t n_key, size_t *n_value) {
254
+ const char *r = __local_memcache_get(lmc, key, n_key, n_value);
255
+ char *new_s = malloc(*n_value);
256
+ memcpy(new_s, r, *n_value);
257
+ if (!lmc_unlock_shm_region("local_memcache_get_new", lmc)) return 0;
258
+ return new_s;
259
+ }
260
+
106
261
  int local_memcache_set(local_memcache_t *lmc,
107
- const char *key, const char* value) {
262
+ const char *key, size_t n_key, const char* value, size_t n_value) {
108
263
  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;
264
+ int r = ht_set(lmc->base, lmc->va_hash, key, n_key, value, n_value,
265
+ &lmc->error);
266
+ if (!lmc_unlock_shm_region("local_memcache_set", lmc)) return 0;
111
267
  return r;
112
268
  }
113
269
 
114
- int local_memcache_delete(local_memcache_t *lmc, char *key) {
270
+ int local_memcache_delete(local_memcache_t *lmc, char *key, size_t n_key) {
115
271
  if (!lmc_lock_shm_region("local_memcache_delete", lmc)) return 0;
116
- int r = ht_delete(lmc->base, lmc->va_hash, key);
272
+ int r = ht_delete(lmc->base, lmc->va_hash, key, n_key);
117
273
  if (!lmc_unlock_shm_region("local_memcache_delete", lmc)) return 0;
118
274
  return r;
119
275
  }
120
276
 
121
- int local_memcache_free(local_memcache_t *lmc) {
122
- lmc_error_t e;
277
+ int local_memcache_free(local_memcache_t *lmc, lmc_error_t *e) {
123
278
  if (!lmc_lock_shm_region("local_memcache_free", lmc)) return 0;
124
279
  int r = ht_hash_destroy(lmc->base, lmc->va_hash);
125
280
  if (!lmc_unlock_shm_region("local_memcache_free", lmc)) return 0;
126
- lmc_shm_destroy(lmc->shm, &e);
281
+ lmc_shm_destroy(lmc->shm, e);
127
282
  free(lmc->namespace);
128
283
  free(lmc->lock);
129
284
  return r;
130
285
  }
286
+
287
+ int local_memcache_iterate(local_memcache_t *lmc, void *ctx, ITERATOR_P(iter)) {
288
+ if (!lmc_lock_shm_region("local_memcache_iterate", lmc)) return 0;
289
+ int r = ht_hash_iterate(lmc->base, lmc->va_hash, ctx, iter);
290
+ if (!lmc_unlock_shm_region("local_memcache_iterate", lmc)) return 0;
291
+ return r;
292
+ }
data/src/localmemcache.h CHANGED
@@ -1,3 +1,7 @@
1
+ /*
2
+ * Copyright (c) 2009, Sven C. Koehler
3
+ */
4
+
1
5
  #ifndef _LOCAL_MEMCACHE_INCLUDED_
2
6
  #define _LOCAL_MEMCACHE_INCLUDED_
3
7
 
@@ -6,6 +10,7 @@
6
10
  #include "lmc_shm.h"
7
11
  #include "lmc_lock.h"
8
12
  #include "lmc_error.h"
13
+ #include "lmc_common.h"
9
14
 
10
15
  #define LOCAL_MEMCACHE_FAILED 0
11
16
  #define LOCAL_MEMCACHE_SUCCESS 1
@@ -21,13 +26,20 @@ typedef struct {
21
26
  lmc_error_t error;
22
27
  } local_memcache_t;
23
28
 
24
- local_memcache_t *local_memcache_create(const char *namespace, size_t size,
29
+ local_memcache_t *local_memcache_create(const char *namespace, double size_mb,
25
30
  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);
31
+ char *local_memcache_get_new(local_memcache_t *lmc, const char *key,
32
+ size_t n_key, size_t *n_value);
33
+ int local_memcache_set(local_memcache_t *lmc, const char *key, size_t n_key,
34
+ const char* value, size_t n_value);
35
+ int local_memcache_delete(local_memcache_t *lmc, char *key, size_t n_key);
36
+ int local_memcache_free(local_memcache_t *lmc, lmc_error_t *e);
37
+ int local_memcache_iterate(local_memcache_t *lmc, void *ctx, ITERATOR_P(iter));
30
38
  int local_memcache_clear_namespace(const char *namespace, int repair,
31
39
  lmc_error_t *e);
40
+ int local_memcache_check_namespace(const char *namespace, lmc_error_t *e);
41
+
42
+ const char *__local_memcache_get(local_memcache_t *lmc,
43
+ const char *key, size_t n_key, size_t *n_value);
32
44
 
33
45
  #endif
@@ -9,6 +9,16 @@ require 'rblocalmemcache'
9
9
  #
10
10
  class LocalMemCache
11
11
 
12
+ class LocalMemCacheError < StandardError; end
13
+ class ShmError < LocalMemCacheError; end
14
+ class MemoryPoolFull < LocalMemCacheError; end
15
+ class LockError < LocalMemCacheError; end
16
+ class LockTimedOut < LocalMemCacheError; end
17
+ class OutOfMemoryError < LocalMemCacheError; end
18
+ class RecoveryFailed < LocalMemCacheError; end
19
+ class ShmLockFailed < LocalMemCacheError; end
20
+ class ShmUnlockFailed < LocalMemCacheError; end
21
+
12
22
  # Creates a new handle for accessing a shared memory region.
13
23
  #
14
24
  # LocalMemCache.new :namespace=>"foo", :size_mb=> 1
@@ -17,9 +27,9 @@ class LocalMemCache
17
27
  # The size_mb defaults to 1024 (1 GB).
18
28
  #
19
29
  def self.new(options)
20
- o = { :size_mb => 1024 }.update(options || {})
30
+ o = { :size_mb => 0 }.update(options || {})
21
31
  raise "Missing mandatory option ':namespace'" if !o[:namespace]
22
- _new(o[:namespace].gsub("/", "-"), (o[:size_mb].to_f * 1024 * 1024).to_i );
32
+ _new(o[:namespace].to_s, o[:size_mb].to_f);
23
33
  end
24
34
 
25
35
  # Deletes the given namespaces, removing semaphores if necessary.
@@ -27,6 +37,6 @@ class LocalMemCache
27
37
  # processes.
28
38
  #
29
39
  def self.clear_namespace(namespace, repair = false)
30
- _clear_namespace(namespace, repair)
40
+ _clear_namespace(namespace.to_s, repair)
31
41
  end
32
42
  end
@@ -8,42 +8,83 @@
8
8
  /* :nodoc: */
9
9
  long long_value(VALUE i) { return NUM2LONG(rb_Integer(i)); }
10
10
  /* :nodoc: */
11
+ double double_value(VALUE i) { return NUM2DBL(i); }
12
+ /* :nodoc: */
11
13
  VALUE num2string(long i) { return rb_big2str(rb_int2big(i), 10); }
12
14
  /* :nodoc: */
13
15
  char *rstring_ptr(VALUE s) {
14
16
  char* r = NIL_P(s) ? "nil" : RSTRING_PTR(rb_String(s));
15
17
  return r ? r : "nil";
16
18
  }
19
+
20
+ size_t rstring_length(VALUE s) {
21
+ size_t r = NIL_P(s) ? 0 : RSTRING_LEN(rb_String(s));
22
+ return r;
23
+ }
17
24
  /* :nodoc: */
18
- static VALUE ruby_string(char *s) { return s ? rb_str_new2(s) : Qnil; }
25
+ static VALUE ruby_string(const char *s) { return s ? rb_str_new2(s) : Qnil; }
19
26
  /* :nodoc: */
20
27
  int bool_value(VALUE v) { return v == Qtrue; }
21
28
 
22
- static VALUE LocalMemCacheError;
29
+ static VALUE lmc_ruby_string2(const char *s, size_t l) {
30
+ return s ? rb_str_new(s, l) : Qnil;
31
+ }
32
+
33
+ static VALUE lmc_ruby_string(const char *s) {
34
+ return lmc_ruby_string2(s + sizeof(size_t), *(size_t *) s);
35
+ }
36
+
37
+
38
+ static VALUE LocalMemCache;
23
39
 
24
40
  /* :nodoc: */
25
- void raise_exception(VALUE error_klass, lmc_error_t *e) {
26
- rb_raise(error_klass, e->error_str);
41
+ void raise_exception(lmc_error_t *e) {
42
+ VALUE eid = rb_intern(e->error_type);
43
+ VALUE k = rb_const_get(LocalMemCache, eid);
44
+ rb_raise(k, e->error_str);
27
45
  }
28
46
 
29
47
  /* :nodoc: */
30
- static VALUE LocalMemCache__new2(VALUE klass, VALUE namespace, VALUE size) {
48
+ static VALUE LocalMemCache__new2(VALUE klass, VALUE namespace, VALUE size_mb) {
31
49
  lmc_error_t e;
32
50
  local_memcache_t *lmc = local_memcache_create(rstring_ptr(namespace),
33
- long_value(size), &e);
34
- if (!lmc) { raise_exception(LocalMemCacheError, &e); }
51
+ double_value(size_mb), &e);
52
+ if (!lmc) { raise_exception(&e); }
35
53
  return Data_Wrap_Struct(klass, NULL, local_memcache_free, lmc);
36
54
  }
37
55
 
38
56
  /* :nodoc: */
39
- static VALUE LocalMemCache__clear_namespace(VALUE klass, VALUE ns, VALUE repair) {
57
+ static VALUE LocalMemCache__clear_namespace(VALUE klass, VALUE ns,
58
+ VALUE repair) {
40
59
  lmc_error_t e;
41
60
  if (!local_memcache_clear_namespace(rstring_ptr(ns), bool_value(repair), &e)) {
42
- raise_exception(LocalMemCacheError, &e);
61
+ raise_exception(&e);
43
62
  }
44
63
  return Qnil;
45
64
  }
46
65
 
66
+ /* :nodoc: */
67
+ static VALUE LocalMemCache__check_namespace(VALUE klass, VALUE ns) {
68
+ lmc_error_t e;
69
+ if (!local_memcache_check_namespace(rstring_ptr(ns), &e)) {
70
+ raise_exception(&e);
71
+ }
72
+ return Qnil;
73
+ }
74
+
75
+ /* :nodoc: */
76
+ static VALUE LocalMemCache__enable_test_crash(VALUE klass) {
77
+ srand(getpid());
78
+ lmc_test_crash_enabled = 1;
79
+ return Qnil;
80
+ }
81
+
82
+ /* :nodoc: */
83
+ static VALUE LocalMemCache__disable_test_crash(VALUE klass) {
84
+ lmc_test_crash_enabled = 0;
85
+ return Qnil;
86
+ }
87
+
47
88
  /* :nodoc: */
48
89
  local_memcache_t *get_LocalMemCache(VALUE obj) {
49
90
  local_memcache_t *lmc;
@@ -59,8 +100,12 @@ local_memcache_t *get_LocalMemCache(VALUE obj) {
59
100
  * Retrieve value from hashtable.
60
101
  */
61
102
  static VALUE LocalMemCache__get(VALUE obj, VALUE key) {
62
- return ruby_string(local_memcache_get(get_LocalMemCache(obj),
63
- rstring_ptr(key)));
103
+ size_t l;
104
+ const char* r = __local_memcache_get(get_LocalMemCache(obj),
105
+ rstring_ptr(key), rstring_length(key), &l);
106
+ VALUE rr = lmc_ruby_string2(r, l);
107
+ lmc_unlock_shm_region("local_memcache_get", get_LocalMemCache(obj));
108
+ return rr;
64
109
  }
65
110
 
66
111
  /*
@@ -73,8 +118,9 @@ static VALUE LocalMemCache__get(VALUE obj, VALUE key) {
73
118
 
74
119
  static VALUE LocalMemCache__set(VALUE obj, VALUE key, VALUE value) {
75
120
  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);
121
+ if (!local_memcache_set(lmc, rstring_ptr(key), rstring_length(key),
122
+ rstring_ptr(value), rstring_length(value))) {
123
+ raise_exception(&lmc->error);
78
124
  }
79
125
  return Qnil;
80
126
  }
@@ -87,7 +133,7 @@ static VALUE LocalMemCache__set(VALUE obj, VALUE key, VALUE value) {
87
133
  */
88
134
  static VALUE LocalMemCache__delete(VALUE obj, VALUE key) {
89
135
  return local_memcache_delete(get_LocalMemCache(obj),
90
- rstring_ptr(key));
136
+ rstring_ptr(key), rstring_length(key));
91
137
  return Qnil;
92
138
  }
93
139
 
@@ -98,22 +144,66 @@ static VALUE LocalMemCache__delete(VALUE obj, VALUE key) {
98
144
  * Releases hashtable.
99
145
  */
100
146
  static VALUE LocalMemCache__close(VALUE obj) {
101
- local_memcache_free(get_LocalMemCache(obj));
147
+ lmc_error_t e;
148
+ if (!local_memcache_free(get_LocalMemCache(obj), &e)) raise_exception(&e);
102
149
  return Qnil;
103
150
  }
104
151
 
105
- static VALUE LocalMemCache;
152
+ typedef struct {
153
+ VALUE ary;
154
+ } lmc_ruby_iter_collect_keys;
155
+
156
+ int lmc_ruby_iter(void *ctx, const char* key, const char* value) {
157
+ lmc_ruby_iter_collect_keys *data = ctx;
158
+ rb_ary_push(data->ary, lmc_ruby_string(key));
159
+ return 1;
160
+ }
161
+
162
+ static VALUE __LocalMemCache__keys(VALUE d) {
163
+ VALUE obj = rb_ary_entry(d, 0);
164
+ VALUE r = rb_ary_entry(d, 1);
165
+ lmc_ruby_iter_collect_keys data;
166
+ data.ary = r;
167
+ int success = local_memcache_iterate(get_LocalMemCache(obj),
168
+ (void *) &data, lmc_ruby_iter);
169
+ if (!success) { return Qnil; }
170
+ }
171
+
172
+ /*
173
+ * call-seq:
174
+ * lmc.keys() -> array or nil
175
+ *
176
+ * Returns a list of keys.
177
+ */
178
+ static VALUE LocalMemCache__keys(VALUE obj) {
179
+ VALUE d = rb_ary_new();
180
+ rb_ary_push(d, obj);
181
+ rb_ary_push(d, rb_ary_new());
182
+ int error = 0;
183
+ rb_protect(__LocalMemCache__keys, d, &error);
184
+ if (error) {
185
+ lmc_unlock_shm_region("local_memcache_iterate", get_LocalMemCache(obj));
186
+ rb_exc_raise(ruby_errinfo);
187
+ }
188
+ return rb_ary_entry(d, 1);
189
+ }
106
190
 
107
191
  void Init_rblocalmemcache() {
108
- LocalMemCacheError = rb_define_class("LocalMemCacheError", rb_eStandardError);
109
192
  LocalMemCache = rb_define_class("LocalMemCache", rb_cObject);
110
193
  rb_define_singleton_method(LocalMemCache, "_new", LocalMemCache__new2, 2);
111
194
  rb_define_singleton_method(LocalMemCache, "_clear_namespace",
112
195
  LocalMemCache__clear_namespace, 2);
196
+ rb_define_singleton_method(LocalMemCache, "check_namespace",
197
+ LocalMemCache__check_namespace, 1);
198
+ rb_define_singleton_method(LocalMemCache, "disable_test_crash",
199
+ LocalMemCache__disable_test_crash, 0);
200
+ rb_define_singleton_method(LocalMemCache, "enable_test_crash",
201
+ LocalMemCache__enable_test_crash, 0);
113
202
  rb_define_method(LocalMemCache, "get", LocalMemCache__get, 1);
114
203
  rb_define_method(LocalMemCache, "[]", LocalMemCache__get, 1);
115
204
  rb_define_method(LocalMemCache, "delete", LocalMemCache__delete, 1);
116
205
  rb_define_method(LocalMemCache, "set", LocalMemCache__set, 2);
117
206
  rb_define_method(LocalMemCache, "[]=", LocalMemCache__set, 2);
207
+ rb_define_method(LocalMemCache, "keys", LocalMemCache__keys, 0);
118
208
  rb_define_method(LocalMemCache, "close", LocalMemCache__close, 0);
119
209
  }
data/src/tests/alloc CHANGED
File without changes
@@ -0,0 +1,15 @@
1
+ #! /bin/sh
2
+ D=`dirname $0`
3
+ DIR=`cd $D; pwd`
4
+ script=$DIR/allocfailure.rb
5
+
6
+ export CFLAGS=-DDO_TEST_ALLOC_FAILURE
7
+ make -C .. clean && make -C .. && make -C ../ruby-binding &&
8
+ ruby extconf.rb && make clean && make
9
+
10
+ if test "x$1" = "x-d"; then
11
+ irb -r $script
12
+ else
13
+ #valgrind --leak-check=full --tool=memcheck ruby $script
14
+ ruby $script
15
+ fi
@@ -0,0 +1,20 @@
1
+ $DIR=File.dirname(__FILE__)
2
+ ['.', '..', '../ruby-binding/'].each {|p| $:.unshift File.join($DIR, p) }
3
+
4
+ require 'localmemcache'
5
+
6
+ LocalMemCache.clear_namespace("alloc-failure-test", true);
7
+
8
+
9
+ LocalMemCache.enable_test_crash
10
+ $lm2 = LocalMemCache.new :namespace=>"alloc-failure-test"
11
+ 2000000.times {
12
+ begin
13
+ r = rand(10000).to_s
14
+ $lm2.set(r, r)
15
+ $lm2.get(r)
16
+ rescue Exception => e
17
+ puts "e: #{e.to_s}"
18
+ end
19
+ }
20
+
data/src/tests/bench CHANGED
File without changes