localmemcache 0.4.3 → 0.4.4

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.3
1
+ 0.4.4
@@ -1,14 +1,96 @@
1
1
  <html>
2
2
  <head>
3
3
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4
- <title>Localmemcache</title>
5
- <link type="text/css" rel="stylesheet" href="style.css" media="screen"/>
4
+ <title>Localmemcache: mmap -> lmc_valloc -> hashtable. BAM database</title>
5
+ <script type="text/javascript">
6
+ // <![CDATA[
7
+ function show_complete_history() {
8
+ var e = document.getElementById('old-news')
9
+ e.style.display = e.style.display == "none" ? "block" : "none";
10
+ return false;
11
+ }
12
+ // ]]
13
+ </script>
14
+
15
+ <style type="text/css">
16
+ body {
17
+ background: #FFF;
18
+ color: #333;
19
+ font-family: "Helvetica Neue", Helvetica, "Trebuchet MS", "Lucida Grande", Verdana, sans-serif;
20
+ margin: 0;
21
+ font-size: 17pt;
22
+ line-height: 1.3em;
23
+ }
24
+
25
+ h1, h2, h3, h4 {
26
+ color: #0;
27
+ padding: 0;
28
+ margin: 1em 0;
29
+ }
30
+
31
+ #opener-background {
32
+ background-color: #333;
33
+ padding-bottom: 10px;
34
+ }
35
+
36
+ #opener {
37
+ width: 1024px;
38
+ }
39
+
40
+ #opener, #opener * {
41
+ font: 40pt/44pt "Helvetica Neue", Helvetica, Arial, sans-serif;
42
+ font-weight: bold;
43
+ letter-spacing: -0.75pt;
44
+ margin: auto ;
45
+ color: #aaa;
46
+ background-color: #333;
47
+ }
48
+
49
+ #opener em {
50
+ color: #fff;
51
+ }
52
+
53
+ #content em {
54
+ color: #aaa;
55
+ font: 50pt/40pt "Helvetica Neue", Helvetica, Arial, sans-serif;
56
+ letter-spacing: -0.75pt;
57
+ font-weight: bold;
58
+ }
59
+
60
+ #opener #title {
61
+ line-height: 1.9em;
62
+ }
63
+
64
+ pre, code {
65
+ font-family: Courier;
66
+ font-size: 17pt;
67
+ overflow: auto;
68
+ }
69
+
70
+ a { color: #0088FF; text-decoration: none }
71
+ a:hover { color: #fff; background-color: #0088FF }
72
+
73
+ #content {
74
+ margin: 0 auto ;
75
+ width: 1024px;
76
+ }
77
+
78
+ ol, ul { padding-left: 0; }
79
+
80
+ </style>
6
81
  </head>
7
- <body>
82
+ <body>
83
+ <div id="opener-background">
84
+ <div id="opener">
85
+ <div id="title">How would one design a database today?</div>
86
+ <table cellspacing=0 cellpadding=0 width="100%">
87
+ <tr><td><em>then</em></td><td>memory scarce, open, read, write</td></tr>
88
+ <tr><td><em>today</em></td><td>64bit, mmap, sparse files</td></tr>
89
+ </table>
90
+ </div>
91
+ </div>
8
92
 
9
93
  <div id="content">
10
- <h1>A persistent key-value database based on mmap()'ed shared memory</h1>
11
-
12
94
  <p><b>Localmemcache</b> is a library for <b>C</b> and <b>Ruby</b> that aims
13
95
  to provide
14
96
  an interface similar to memcached but for accessing local data instead of
@@ -17,6 +99,17 @@ speed</b>.
17
99
  Since version 0.3.0 it supports <b>persistence</b>, also making it <b>a fast
18
100
  alternative to GDBM, Berkeley DB, and Tokyo Cabinet</b>.
19
101
 
102
+ <h2>Version 0.4.4: Bugfixes for OS X and Autorepair</h2>
103
+
104
+ Version 0.4.4 brings fixes for coredumps on OS X and bugs in the
105
+ autorepair (now also better covered by tests). <br>
106
+ New methods: <b>shm_status</b>, <b>has_key?</b><br>
107
+ (Thanks to <b>Max Sch&ouml;fmann</b> and <b>Florian D&uuml;tsch</b> for feedback/bug reports.)
108
+ <p>
109
+
110
+ <a href="#" onclick="return show_complete_history()" />Previous Releases</a>
111
+ <div id='old-news' style='display:none'>
112
+
20
113
  <h2>Version 0.4.3: Improving Iteration and bugfixes (2009-10-02)</h2>
21
114
 
22
115
  Fixes by <b>Paul Mineiro</b> (thanks!):
@@ -26,26 +119,13 @@ faster</b>.</li>
26
119
  <li><b>fix for leak</b> in local_memcache_free()</li>
27
120
  <li><b>C API</b>: Some C API functions were not yet covered by tests. This
28
121
  has been fixed.</li>
29
- <p>
30
122
 
31
123
  Other fixes:
32
124
  <li><b>autorepair</b> fixed: Autorepair of namespaces did sometimes wrongly
33
125
  report corrupt namespaces.
34
126
  <li><b>:min_alloc_size</b> now also works on Ruby 1.9.</li>
35
127
 
36
-
37
- <script type="text/javascript">
38
- // <![CDATA[
39
- function show_complete_history() {
40
- var e = document.getElementById('old-news')
41
- e.style.display = e.style.display == "none" ? "block" : "none";
42
- return false;
43
- }
44
- // ]]
45
- </script>
46
-
47
- <a href="#" onclick="show_complete_history()" />Previous Releases</a>
48
- <div id='old-news' style='display:none'><h2>Version 0.4.2: Improving Append Performance (2009-08-10)</h2>
128
+ <h2>Version 0.4.2: Improving Append Performance (2009-08-10)</h2>
49
129
 
50
130
  In 0.4.2 the <b>:min_alloc_size</b> parameter was introduced to help with use
51
131
  cases that intend to use a hash table with growing values. This is
@@ -54,24 +134,15 @@ with a large list of unusable free blocks. By setting the
54
134
  <b>:min_alloc_size</b> parameter you help the allocator to plan better
55
135
  ahead. (<a href="http://localmemcache.rubyforge.org/doc/classes/LocalMemCache.html#M000001">more</a>)
56
136
 
57
- </div>
58
-
59
- <h2>Key features as of 0.4.0 (2009-05-16)</h2>
137
+ <h2>Key features as of 0.4.4 (2009-11-10)</h2>
60
138
  <li><a href="#performance">blazingly fast</a></li>
61
139
  <li>a very simple API</li>
62
140
  <li>persistent</li>
63
141
  <li>parallel writes are supported by default</li>
64
142
  <li>uses transactions internally to avoid data corruption</li>
65
- <li>lightweight: the core library is just about <b>1400</b> lines of <b>C</b> code</li>
143
+ <li>lightweight: the core library is just about <b>1500</b> lines of <b>C</b> code</li>
66
144
 
67
- <h2>Requirements</h2>
68
- <li>a &gt;=64bit Unix (32bit is possible but you'll run out of virtual address space quickly)</li>
69
- <li>a file system that offers <a href="http://en.wikipedia.org/wiki/Sparse_file">sparse files</a></li>
70
- Note for <b>OS X</b>: <b>OS X</b> disqualifies as <b>HFS+</b> doesn't
71
- have sparse files and <b>sem_timedwait</b>() and <b>sem_getvalue</b>() aren't
72
- supported as well.<br>
73
- Note for <b>FreeBSD</b>: It has been reported that localmemcache
74
- sometimes hangs there, it is not yet clear what the problem is.
145
+ </div>
75
146
 
76
147
  <h2>Install</h2>
77
148
 
@@ -83,6 +154,16 @@ sometimes hangs there, it is not yet clear what the problem is.
83
154
 
84
155
  If you just want to use the <b>C API</b>, download the .tar.gz from <a href="http://rubyforge.org/frs/?group_id=7925">here</a>.
85
156
 
157
+ <h2>Requirements</h2>
158
+ <li>a &gt;=64bit Unix (32bit is possible but you'll run out of virtual address space quickly)</li>
159
+ <li>a file system that offers <a href="http://en.wikipedia.org/wiki/Sparse_file">sparse files</a></li>
160
+ Note for <b>OS X</b>: <b>OS X</b> disqualifies as <b>HFS+</b> doesn't
161
+ have sparse files and <b>sem_timedwait</b>() and <b>sem_getvalue</b>() aren't
162
+ supported as well.<br>
163
+ Note for <b>FreeBSD</b>: It has been reported that localmemcache
164
+ sometimes hangs there, it is not yet clear what the problem is.
165
+
166
+
86
167
  <h2>Using</h2>
87
168
  <b>API</b>:&nbsp;<a href="http://github.com/sck/localmemcache/blob/d72a5bd825b0fb573f1048ea9cae92d8c143525c/src/localmemcache.h">C</a>|<a href="http://localmemcache.rubyforge.org/doc/">Ruby</a><br>
88
169
  <p><pre><code>require 'localmemcache'
@@ -130,6 +211,16 @@ data on disk is about <b>10</b>% slower than keeping them in memory in a
130
211
  Ruby hash of strings. It's about <b>40</b>% faster than <b>Tokyo Cabinet</b>
131
212
  (which offers features similar to <b>LocalMemCache</b>).
132
213
 
214
+ <h2>Who uses Localmemcache?</h2>
215
+
216
+ <a href="http://www.personifi.com">Personifi</a> use localmemcache to
217
+ serve billions of hits each month. Armin Roehrl: "we use
218
+ localmemcache because it solves one problem very well and we love it!"
219
+
220
+ <h2>Slides for my talk at the <a href="http://www.munich-on-rails.com/">Ruby on Rails Group Munich</a></h2>
221
+
222
+ Now available on github&nbsp;&nbsp;&lt;&nbsp;<a href="http://cloud.github.com/downloads/sck/localmemcache/localmemcache.pdf">pdf</a>&nbsp;|&nbsp;<a href="http://cloud.github.com/downloads/sck/localmemcache/localmemcache.key">key</a>&nbsp;&gt;&nbsp;(German)
223
+
133
224
  <h2>Source code</h2>
134
225
 
135
226
  <p>The source code is hosted on <a href="http://github.com/sck/localmemcache/tree/master">github</a>. It
@@ -140,18 +231,13 @@ can be retrieved by executing</p>
140
231
 
141
232
  <h2>Caveats</h2>
142
233
 
143
- <li>Localmemcache's .lmc files are not binary compatible, they are essentially
234
+ <li>Localmemcache's .lmc files are not binary compatible across different
235
+ CPU architectures, they are essentially
144
236
  memory mapped c structs</li>
145
237
  <li>Because of the convenient auto repair feature after a lock timeout,
146
238
  localmemcache is allergic to SIGSTOP (If you manage to SIGSTOP a process
147
239
  while localmemcache is currently possessing a lock, that is)</li>
148
240
 
149
- <h2>Who uses Localmemcache?</h2>
150
-
151
- <a href="http://www.personifi.com">Personifi</a> use localmemcache to
152
- serve billions of hits each month. Armin Roehrl: "we use
153
- localmemcache because it solves one problem very well and we love it!"
154
-
155
241
  <h2>Tips for backups</h2>
156
242
 
157
243
  Note that you cannot copy localmemcache's .lmc files while other
@@ -43,9 +43,10 @@ size_t lmc_test_valloc_fail(const char *file, int line, const char *function,
43
43
  }
44
44
 
45
45
  void lmc_clean_string(char *result, const char *source) {
46
- size_t n = strlen(source);
47
- if (n > 256) { n = 256; }
48
- const char *s = source;
46
+ size_t nn = strlen(source);
47
+ size_t n = nn;
48
+ if (n > 20) { n = 20; }
49
+ const char *s = source + nn - n;
49
50
  char *d = result;
50
51
  char ch;
51
52
  for (; n--; d++, s++) {
@@ -39,7 +39,6 @@ void lmc_dump_chunk_brief(char *who, void *base, lmc_mem_chunk_descriptor_t* c)
39
39
  printf("[%s] chunk %zd:\n", who, va_c);
40
40
  }
41
41
 
42
-
43
42
  void lmc_dump(void *base) {
44
43
  lmc_mem_chunk_descriptor_t* c = md_first_free(base);
45
44
  size_t free = 0;
@@ -85,6 +84,11 @@ int lmc_is_va_valid(void *base, size_t va) {
85
84
  (base + md->total_size + sizeof(lmc_mem_descriptor_t)) < (void *)c);
86
85
  }
87
86
 
87
+ size_t lmc_total_shm_size(void *base) {
88
+ lmc_mem_descriptor_t *md = base;
89
+ return md->total_size + sizeof(lmc_mem_descriptor_t);
90
+ }
91
+
88
92
  lmc_mem_status_t lmc_status(void *base, char *where) {
89
93
  lmc_mem_descriptor_t *md = base;
90
94
  lmc_mem_chunk_descriptor_t* c = md_first_free(base);
@@ -93,6 +97,7 @@ lmc_mem_status_t lmc_status(void *base, char *where) {
93
97
  size_t largest_chunk = 0;
94
98
  long chunks = 0;
95
99
  ms.total_mem = md->total_size;
100
+ ms.total_shm_size = lmc_total_shm_size(base);
96
101
  while (c) {
97
102
  if (!lmc_is_va_valid(base, (void *)c - base)) {
98
103
  printf("[localmemcache] [%s] invalid pointer detected: %zd...\n", where,
@@ -379,11 +384,12 @@ int lmc_um_find_leaks(void *base, char *bf) {
379
384
  size_t gap_count = 0;
380
385
  size_t space = 0;
381
386
  memset(&m, 0xFF, sizeof(m));
382
- for (i = 0; i < md->total_size; ++i) {
387
+ size_t tts = lmc_total_shm_size(md);
388
+ for (i = 0; i < tts; ++i) {
383
389
  if (!gap) {
384
390
  size_t *b = (void *)bf + i / 8;
385
- size_t ee = md->total_size - sizeof(size_t) * 8;
386
- while (*b == m && i < ee) {
391
+ size_t ee = tts - sizeof(size_t) * 8;
392
+ while (i < ee && *b == m) {
387
393
  i += sizeof(size_t) * 8; b++;
388
394
  }
389
395
  }
@@ -417,10 +423,11 @@ int lmc_um_check_unmarked(void *base, char *bf, size_t va, size_t size) {
417
423
  for (i = va; i < va + size; ++i) {
418
424
  size_t *b = (void *)bf + i / 8;
419
425
  size_t ee = end - sizeof(size_t) * 8;
420
- while (*b == n && i < ee) {
426
+ while (i < ee && *b == n) {
421
427
  i += sizeof(size_t) * 8; b++;
422
428
  }
423
429
  if (lmc_um_getbit(bf, i) != 0) {
430
+ printf("i: %zd marked!\n", i);
424
431
  return 0;
425
432
  }
426
433
  }
@@ -464,7 +471,7 @@ int lmc_um_mark_allocated(void *base, char *bf, size_t va) {
464
471
 
465
472
  char *lmc_um_new_mem_usage_bitmap(void *base) {
466
473
  lmc_mem_descriptor_t *md = base;
467
- size_t ts = ((md->total_size + 7) / 8);
474
+ size_t ts = ((lmc_total_shm_size(md) + 7) / 8);
468
475
  char *bf = calloc(1, ts);
469
476
  size_t va = md->first_free;
470
477
  if (!lmc_um_mark(base, bf, 0, sizeof(lmc_mem_descriptor_t))) goto failed;
@@ -9,6 +9,7 @@ typedef struct {
9
9
  size_t free_chunks;
10
10
  size_t total_mem;
11
11
  size_t total_free_mem;
12
+ size_t total_shm_size;
12
13
  size_t free_mem;
13
14
  size_t largest_chunk;
14
15
  } lmc_mem_status_t;
@@ -155,6 +155,7 @@ local_memcache_t *local_memcache_create(const char *namespace,
155
155
  char clean_ns[1024];
156
156
  double s = size_mb == 0.0 ? 1024.0 : size_mb;
157
157
  size_t si = s * 1024 * 1024;
158
+ if (si < 1024 * 1024) { si = 1024 * 1024; }
158
159
  //printf("size: %f, s: %f, si: %zd\n", size_mb, s, si);
159
160
  if (!lmc_namespace_or_filename((char *)clean_ns, namespace, filename, e))
160
161
  return 0;
@@ -53,13 +53,17 @@ class LocalMemCache
53
53
  o = { :size_mb => 0 }.update(options || {})
54
54
  _new(o);
55
55
  end
56
+ def has_key?(k) !get(k).nil? end
56
57
 
57
58
  # <code>SharedObjectStorage</code> inherits from class LocalMemCache but
58
59
  # stores Ruby objects as values instead of just strings (It still uses
59
60
  # strings for the keys, though).
60
61
  class SharedObjectStorage < LocalMemCache
62
+ alias __super_get get
61
63
  def []=(key,val) super(key, Marshal.dump(val)) end
62
64
  def [](key) v = super(key); v.nil? ? nil : Marshal.load(v) end
65
+ alias set []=
66
+ alias get []
63
67
  def each_pair(&block)
64
68
  super {|k, mv| block.call(k, Marshal.load(mv)) }
65
69
  end
@@ -67,6 +71,6 @@ class LocalMemCache
67
71
  rp = super
68
72
  rp.nil? ? nil : [rp.first, Marshal.load(rp.last)]
69
73
  end
74
+ def has_key?(k) !__super_get(k).nil? end
70
75
  end
71
-
72
76
  end
@@ -34,6 +34,24 @@ long long_value(VALUE i) { return NIL_P(i) ? 0 : NUM2LONG(rb_Integer(i)); }
34
34
  double double_value(VALUE i) { return NUM2DBL(i); }
35
35
  /* :nodoc: */
36
36
  VALUE num2string(long i) { return rb_big2str(rb_int2big(i), 10); }
37
+
38
+ typedef struct {
39
+ char *cstr;
40
+ size_t len;
41
+ } lmc_rb_str_d_t;
42
+
43
+ /* :nodoc: */
44
+ void rstring_acquire(VALUE s, lmc_rb_str_d_t *d) {
45
+ if (NIL_P(s)) {
46
+ d->cstr = "nil";
47
+ d->len = 0;
48
+ return;
49
+ }
50
+ VALUE v = TYPE(s) == T_STRING ? s : rb_funcall(s, rb_intern("to_s"), 0);
51
+ d->cstr = RSTRING_PTR(v);
52
+ d->len = RSTRING_LEN(v);
53
+ }
54
+
37
55
  /* :nodoc: */
38
56
  char *rstring_ptr(VALUE s) {
39
57
  char* r = NIL_P(s) ? "nil" : RSTRING_PTR(rb_String(s));
@@ -218,8 +236,10 @@ static VALUE LocalMemCache__disable_test_crash(VALUE klass) {
218
236
  */
219
237
  static VALUE LocalMemCache__get(VALUE obj, VALUE key) {
220
238
  size_t l;
239
+ lmc_rb_str_d_t k;
240
+ rstring_acquire(key, &k);
221
241
  const char* r = __local_memcache_get(get_LocalMemCache(obj),
222
- rstring_ptr(key), rstring_length(key), &l);
242
+ k.cstr, k.len, &l);
223
243
  VALUE rr = lmc_ruby_string2(r, l);
224
244
  lmc_unlock_shm_region("local_memcache_get", get_LocalMemCache(obj));
225
245
  return rr;
@@ -256,8 +276,10 @@ static VALUE LocalMemCache__random_pair(VALUE obj) {
256
276
  */
257
277
  static VALUE LocalMemCache__set(VALUE obj, VALUE key, VALUE value) {
258
278
  local_memcache_t *lmc = get_LocalMemCache(obj);
259
- if (!local_memcache_set(lmc, rstring_ptr(key), rstring_length(key),
260
- rstring_ptr(value), rstring_length(value))) {
279
+ lmc_rb_str_d_t k, v;
280
+ rstring_acquire(key, &k);
281
+ rstring_acquire(value, &v);
282
+ if (!local_memcache_set(lmc, k.cstr, k.len, v.cstr, v.len)) {
261
283
  rb_lmc_raise_exception(&lmc->error);
262
284
  }
263
285
  return Qnil;
@@ -283,8 +305,9 @@ static VALUE LocalMemCache__clear(VALUE obj) {
283
305
  * Deletes key from hashtable. The key is converted to string.
284
306
  */
285
307
  static VALUE LocalMemCache__delete(VALUE obj, VALUE key) {
286
- return local_memcache_delete(get_LocalMemCache(obj),
287
- rstring_ptr(key), rstring_length(key));
308
+ lmc_rb_str_d_t k;
309
+ rstring_acquire(key, &k);
310
+ return local_memcache_delete(get_LocalMemCache(obj), k.cstr, k.len);
288
311
  return Qnil;
289
312
  }
290
313
 
@@ -414,6 +437,36 @@ static VALUE LocalMemCache__size(VALUE obj) {
414
437
  return rb_int2big(ht->size);
415
438
  }
416
439
 
440
+ /*
441
+ * call-seq:
442
+ * lmc.shm_status -> hash
443
+ *
444
+ * Some status information on the shared memory:
445
+ *
446
+ * :total_bytes # the total size of the shm in bytes
447
+ * :used_bytes # how many bytes are used in this shm
448
+ * # For exmpty namespaces this will reflect the amount
449
+ * # of memory used for the hash buckets and some other
450
+ * # administrative data structures.
451
+ * :free_bytes # how many bytes are free
452
+ */
453
+ static VALUE LocalMemCache__shm_status(VALUE obj) {
454
+ VALUE hash = rb_hash_new();
455
+
456
+ local_memcache_t *lmc = get_LocalMemCache(obj);
457
+ if (!lmc_lock_shm_region("shm_status", lmc)) return Qnil;
458
+ lmc_mem_status_t ms = lmc_status(lmc->base, "shm_status");
459
+ if (!lmc_unlock_shm_region("shm_status", lmc)) return Qnil;
460
+
461
+ rb_hash_aset(hash, ID2SYM(rb_intern("free_bytes")),
462
+ rb_int2big(ms.total_free_mem));
463
+ rb_hash_aset(hash, ID2SYM(rb_intern("total_bytes")),
464
+ rb_int2big(ms.total_shm_size));
465
+ rb_hash_aset(hash, ID2SYM(rb_intern("used_bytes")), rb_int2big(
466
+ ms.total_shm_size - ms.total_free_mem));
467
+ return hash;
468
+ }
469
+
417
470
  /*
418
471
  * internal, do not use
419
472
  */
@@ -500,6 +553,7 @@ void Init_rblocalmemcache() {
500
553
  0);
501
554
  rb_define_method(LocalMemCache, "close", LocalMemCache__close, 0);
502
555
  rb_define_method(LocalMemCache, "size", LocalMemCache__size, 0);
556
+ rb_define_method(LocalMemCache, "shm_status", LocalMemCache__shm_status, 0);
503
557
  rb_define_method(LocalMemCache, "check_consistency",
504
558
  LocalMemCache__check_consistency, 0);
505
559
 
@@ -7,7 +7,7 @@ require 'localmemcache'
7
7
  Bacon.summary_on_exit
8
8
 
9
9
  LocalMemCache.drop :namespace => "speed-comparison", :force => true
10
- $lm2 = LocalMemCache.new :namespace=>"speed-comparison"
10
+ $lm2 = LocalMemCache.new :namespace=>"speed-comparison", :size_mb => 200
11
11
 
12
12
  def compare_speed(n)
13
13
 
@@ -0,0 +1,6 @@
1
+ #! /bin/sh
2
+ D=`dirname $0`
3
+ DIR=`cd $D; pwd`
4
+ script=$DIR/console.rb
5
+
6
+ irb -r $script
@@ -0,0 +1,4 @@
1
+ $DIR=File.dirname(__FILE__)
2
+ ['.', '..', '../ruby-binding/'].each {|p| $:.unshift File.join($DIR, p) }
3
+
4
+ require 'localmemcache'
@@ -10,7 +10,7 @@ $pids = []
10
10
  lm = LocalMemCache.new :namespace=>"crash-t"
11
11
  puts "pid: #{$$}"
12
12
  c = 0;
13
- 40000000.times {
13
+ 40_000_000.times {
14
14
  c += 1
15
15
  r = rand(10000).to_s
16
16
  lm.set(r, r)
@@ -22,7 +22,7 @@ def compare_speed(n)
22
22
 
23
23
  puts "rhash: filling dict"
24
24
  $hh = {}
25
- measure_time(1) { n.times {|i| $hh[i] = i } }
25
+ measure_time(1) { n.times {|i| $hh[i.to_s] = i.to_s } }
26
26
  puts "rhash: iterating"
27
27
  c = 0
28
28
  measure_time(1) {
@@ -7,7 +7,7 @@ require 'localmemcache'
7
7
  Bacon.summary_on_exit
8
8
 
9
9
  LocalMemCache.drop :namespace => "test", :force => true
10
- $lm = LocalMemCache.new :namespace=>"test", :size_mb => 20
10
+ $lm = LocalMemCache.new :namespace=>"test", :size_mb => 2
11
11
 
12
12
  LocalMemCache.drop :namespace => "test-small", :force => true
13
13
  $lms = LocalMemCache.new :namespace=>"test-small", :size_mb => 1;
@@ -20,6 +20,14 @@ describe 'LocalMemCache' do
20
20
  $lm.get("foo").should.equal "1"
21
21
  end
22
22
 
23
+ it 'should support has_key?' do
24
+ $lm.has_key?("foo").should.be.true
25
+ $lm.has_key?("non-existant").should.be.false
26
+ $lm[:bar] = nil
27
+ $lm.has_key?(:bar).should.be.true
28
+ $lm.delete(:bar)
29
+ end
30
+
23
31
  it 'should support the [] and []= operators' do
24
32
  $lm["boo"] = "2"
25
33
  $lm["boo"].should.equal "2"
@@ -48,12 +56,12 @@ describe 'LocalMemCache' do
48
56
 
49
57
  it 'should support random_pair' do
50
58
  $lm.random_pair.size.should.equal 2
51
- LocalMemCache.drop :namespace => :empty, :force => true
52
- ll = LocalMemCache.new :namespace => :empty
59
+ LocalMemCache.drop :namespace => :empty, :force => true, :size_mb => 2
60
+ ll = LocalMemCache.new :namespace => :empty, :size_mb => 2
53
61
  ll.random_pair.should.be.nil
54
62
  end
55
63
 
56
- it 'should allow be consistent' do
64
+ it 'should be consistent' do
57
65
  $lm.check_consistency.should.be.true
58
66
  end
59
67
 
@@ -75,6 +83,12 @@ describe 'LocalMemCache' do
75
83
  should.raise(LocalMemCache::MemoryPoolFull) { $lms["two"] = "b" * 8000000; }
76
84
  end
77
85
 
86
+ it 'should set a minimum size' do
87
+ LocalMemCache.drop :namespace => :toosmall, :force => true
88
+ ll = LocalMemCache.new :namespace => :toosmall, :size_mb => 0.1
89
+ ll.shm_status[:total_bytes].should.equal 1024*1024
90
+ end
91
+
78
92
 
79
93
  it 'should support clearing of the hashtable' do
80
94
  ($lms.size > 0).should.be.true
@@ -98,13 +112,10 @@ describe 'LocalMemCache' do
98
112
  ll.size.should.equal 0
99
113
  end
100
114
 
101
-
102
-
103
115
  it 'should support checking of namespaces' do
104
116
  LocalMemCache.check :namespace => "test"
105
117
  end
106
118
 
107
-
108
119
  it 'should support dropping of namespaces' do
109
120
  LocalMemCache.drop :namespace => "test"
110
121
  end
@@ -123,13 +134,14 @@ end
123
134
 
124
135
  LocalMemCache.drop :namespace => "test-shared-os", :force => true
125
136
  $lmsh = LocalMemCache::SharedObjectStorage.new :namespace=>"test-shared-os",
126
- :size_mb => 20
137
+ :size_mb => 2
127
138
 
128
139
  describe 'LocalMemCache::SharedObjectStorage' do
129
140
  it 'should allow to set and query for ruby objects' do
130
141
  $lmsh["non-existant"].should.be.nil
131
- $lmsh["array"] = [:foo, :boo]
142
+ $lmsh.set("array", [:foo, :boo])
132
143
  $lmsh["array"].should.be.kind_of? Array
144
+ $lmsh.get("array").should.be.kind_of? Array
133
145
  end
134
146
 
135
147
  it 'support iteration' do
@@ -139,5 +151,12 @@ describe 'LocalMemCache::SharedObjectStorage' do
139
151
  it 'support random_pair' do
140
152
  $lmsh.random_pair.last.should.be.kind_of? Array
141
153
  end
142
- end
143
154
 
155
+ it 'should support has_key?' do
156
+ $lmsh[:foo] = 1
157
+ $lmsh.has_key?(:foo).should.be.true
158
+ $lmsh.has_key?(:non_existant).should.be.false
159
+ $lmsh[:bar] = nil
160
+ $lmsh.has_key?(:bar).should.be.true
161
+ end
162
+ end
@@ -15,6 +15,8 @@ echo "bench-append"
15
15
 
16
16
  echo "ttlmc"
17
17
  ./ttlmc
18
+ echo "ttlmc-consistency"
19
+ ./ttlmc-consistency
18
20
  echo "ttrandom_pair"
19
21
  ./ttrandom_pair
20
22
  echo "ttalloc"
@@ -0,0 +1,11 @@
1
+ #! /bin/sh
2
+ D=`dirname $0`
3
+ DIR=`cd $D; pwd`
4
+ script=$DIR/ttlmc-consistency.rb
5
+
6
+ if test "x$1" = "x-d"; then
7
+ irb -r $script
8
+ else
9
+ time ruby $script
10
+ #valgrind --leak-check=full --tool=memcheck ruby $script
11
+ fi
@@ -0,0 +1,57 @@
1
+ $DIR=File.dirname(__FILE__)
2
+ ['.', '../', '../ruby-binding/'].each {|p| $:.unshift File.join($DIR, p) }
3
+
4
+ require 'torture'
5
+ require 'localmemcache'
6
+
7
+ LocalMemCache.drop :namespace => "torture", :force => true
8
+ $h = LocalMemCache.new :namespace=>'torture', :size_mb => 200
9
+
10
+
11
+ puts "STARTED: #{$$}"
12
+
13
+ class LocalMemCache
14
+ def __set(k, v)
15
+ set(k, v)
16
+ if get(k) != v.to_s
17
+ puts "Set FAILED!"
18
+ end
19
+ raise "Consistency failed" if !check_consistency
20
+ end
21
+ def __delete(k)
22
+ delete(k)
23
+ raise "Consistency failed" if !check_consistency
24
+ end
25
+
26
+ def __clear
27
+ clear if rand * 100 > 99
28
+ end
29
+
30
+ def __each_pair
31
+ each_pair { } if rand * 100 > 99
32
+ end
33
+
34
+ def __keys
35
+ keys if rand * 100 > 99
36
+ end
37
+
38
+ end
39
+
40
+
41
+ class TortureTesting
42
+ def self.rand_index
43
+ rand(9999)
44
+ end
45
+ end
46
+
47
+ TortureTesting.no_progress
48
+
49
+ TortureTesting.run(2_000,
50
+ [$h, :get, [:rand_index]],
51
+ [$h, :__set, [:rand_index, :any]],
52
+ [$h, :__delete, [:rand_index]],
53
+ [$h, :__clear],
54
+ [$h, :__keys],
55
+ [$h, :random_pair],
56
+ [$h, :__each_pair]
57
+ ) {|e| raise e }
@@ -7,15 +7,15 @@ require 'localmemcache'
7
7
  LocalMemCache.drop :namespace => "torture", :force => true
8
8
  $h = LocalMemCache.new :namespace=>'torture', :size_mb => 200
9
9
 
10
+
10
11
  puts "STARTED: #{$$}"
11
12
 
12
13
  class LocalMemCache
13
14
  def __set(k, v)
14
15
  set(k, v)
15
- #if get(k) != v.to_s
16
- # puts "Set FAILED!"
17
- # raise "set failed"
18
- #end
16
+ if get(k) != v.to_s
17
+ puts "Set FAILED!"
18
+ end
19
19
  end
20
20
  def __delete(k)
21
21
  delete(k)
@@ -52,4 +52,4 @@ TortureTesting.run(200_000,
52
52
  [$h, :__keys],
53
53
  [$h, :random_pair],
54
54
  [$h, :__each_pair]
55
- )
55
+ ) {|e| raise e }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: localmemcache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sven C. Koehler
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-02 00:00:00 +00:00
12
+ date: 2009-11-10 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -100,7 +100,6 @@ files:
100
100
  - site/doc/index.html
101
101
  - site/doc/rdoc-style.css
102
102
  - site/index.html
103
- - site/style.css
104
103
  - src/Makefile.in
105
104
  - src/lmc_common.c
106
105
  - src/lmc_common.h
@@ -133,6 +132,8 @@ files:
133
132
  - src/tests/bench_keys.rb
134
133
  - src/tests/capi.c
135
134
  - src/tests/capi.sh
135
+ - src/tests/console
136
+ - src/tests/console.rb
136
137
  - src/tests/crash
137
138
  - src/tests/crash-small
138
139
  - src/tests/crash-small.rb
@@ -156,6 +157,8 @@ files:
156
157
  - src/tests/ttkeys
157
158
  - src/tests/ttkeys.rb
158
159
  - src/tests/ttlmc
160
+ - src/tests/ttlmc-consistency
161
+ - src/tests/ttlmc-consistency.rb
159
162
  - src/tests/ttlmc.rb
160
163
  - src/tests/ttrandom_pair
161
164
  - src/tests/ttrandom_pair.rb
@@ -1,37 +0,0 @@
1
- body {
2
- background: #FFF;
3
- color: #333;
4
- font-family: "Helvetica Neue", Helvetica, "Trebuchet MS", "Lucida Grande", Verdana, sans-serif;
5
- line-height: 15pt;
6
- margin: 0;
7
- font-size: 12pt;
8
- line-height: 1.6em;
9
- }
10
-
11
- h1, h2, h3, h4 {
12
- color: #0;
13
- padding: 0;
14
- margin: 1em 0;
15
- }
16
-
17
- pre, code {
18
- font-family: Courier;
19
- font-size: 11pt;
20
- overflow: auto;
21
- }
22
-
23
- a { color: #0088FF; text-decoration: none }
24
- a:hover { color: #fff; background-color: #0088FF }
25
-
26
- #content {
27
- margin: 1em auto ;
28
- max-width: 35em;
29
- }
30
-
31
- ol, ul { padding-left: 0; }
32
-
33
- #content p {
34
- }
35
- #about {
36
- list-style:none;
37
- }