localmemcache 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
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
- }