localmemcache 0.3.0 → 0.4.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.
Files changed (65) hide show
  1. data/README +5 -2
  2. data/Rakefile +4 -0
  3. data/VERSION +1 -1
  4. data/bench/lmc_bench.rb +1 -1
  5. data/bench/tokyo_cabinet_bench +3 -0
  6. data/bench/tokyo_cabinet_bench.rb +20 -0
  7. data/site/doc/classes/LocalMemCache.html +146 -129
  8. data/site/doc/classes/LocalMemCache.src/M000001.html +1 -1
  9. data/site/doc/classes/LocalMemCache.src/M000002.html +26 -5
  10. data/site/doc/classes/LocalMemCache.src/M000003.html +16 -5
  11. data/site/doc/classes/LocalMemCache.src/M000004.html +7 -23
  12. data/site/doc/classes/LocalMemCache.src/M000005.html +7 -13
  13. data/site/doc/classes/LocalMemCache.src/M000006.html +4 -5
  14. data/site/doc/classes/LocalMemCache.src/M000007.html +6 -5
  15. data/site/doc/classes/LocalMemCache.src/M000008.html +6 -6
  16. data/site/doc/classes/LocalMemCache.src/M000009.html +1 -1
  17. data/site/doc/classes/LocalMemCache.src/M000010.html +4 -6
  18. data/site/doc/classes/LocalMemCache.src/M000011.html +4 -4
  19. data/site/doc/classes/LocalMemCache.src/M000012.html +4 -4
  20. data/site/doc/classes/LocalMemCache/ArgError.html +2 -2
  21. data/site/doc/classes/LocalMemCache/InitError.html +2 -2
  22. data/site/doc/classes/LocalMemCache/LocalMemCacheError.html +2 -2
  23. data/site/doc/classes/LocalMemCache/LockError.html +2 -2
  24. data/site/doc/classes/LocalMemCache/LockTimedOut.html +2 -2
  25. data/site/doc/classes/LocalMemCache/MemoryPoolClosed.html +2 -2
  26. data/site/doc/classes/LocalMemCache/MemoryPoolFull.html +2 -2
  27. data/site/doc/classes/LocalMemCache/OutOfMemoryError.html +2 -2
  28. data/site/doc/classes/LocalMemCache/RecoveryFailed.html +2 -2
  29. data/site/doc/classes/LocalMemCache/ShmError.html +2 -2
  30. data/site/doc/classes/LocalMemCache/ShmLockFailed.html +2 -2
  31. data/site/doc/classes/LocalMemCache/ShmUnlockFailed.html +2 -2
  32. data/site/doc/created.rid +1 -1
  33. data/site/doc/fr_class_index.html +2 -0
  34. data/site/doc/fr_file_index.html +3 -2
  35. data/site/doc/fr_method_index.html +17 -11
  36. data/site/doc/index.html +1 -1
  37. data/site/index.html +33 -17
  38. data/src/lmc_common.c +2 -1
  39. data/src/lmc_common.h +1 -1
  40. data/src/lmc_hashtable.c +62 -2
  41. data/src/lmc_hashtable.h +4 -1
  42. data/src/lmc_shm.c +1 -3
  43. data/src/lmc_shm.h +1 -3
  44. data/src/lmc_valloc.c +5 -0
  45. data/src/lmc_valloc.h +1 -0
  46. data/src/localmemcache.c +43 -8
  47. data/src/localmemcache.h +24 -6
  48. data/src/ruby-binding/localmemcache.rb +14 -29
  49. data/src/ruby-binding/rblocalmemcache.c +127 -16
  50. data/src/tests/allocfailure.rb +1 -1
  51. data/src/tests/bench.rb +1 -1
  52. data/src/tests/bench_keys.rb +1 -1
  53. data/src/tests/crash.rb +1 -1
  54. data/src/tests/lmc.rb +65 -9
  55. data/src/tests/lmctestapi.c +1 -1
  56. data/src/tests/parallelwrite.rb +1 -1
  57. data/src/tests/ttkeys +10 -0
  58. data/src/tests/ttkeys.rb +35 -0
  59. data/src/tests/ttlmc.rb +24 -6
  60. data/src/tests/ttrandom_pair +10 -0
  61. data/src/tests/ttrandom_pair.rb +23 -0
  62. metadata +8 -5
  63. data/site/doc/files/__/src/ruby-binding/extconf_rb.html +0 -108
  64. data/site/doc/files/__/src/ruby-binding/localmemcache_rb.html +0 -108
  65. data/site/doc/files/__/src/ruby-binding/rblocalmemcache_c.html +0 -101
@@ -55,8 +55,8 @@
55
55
  <tr class="top-aligned-row">
56
56
  <td><strong>In:</strong></td>
57
57
  <td>
58
- <a href="../../files/__/src/ruby-binding/localmemcache_rb.html">
59
- ../src/ruby-binding/localmemcache.rb
58
+ <a href="../../files/localmemcache_rb.html">
59
+ localmemcache.rb
60
60
  </a>
61
61
  <br />
62
62
  </td>
@@ -1 +1 @@
1
- Fri, 17 Apr 2009 00:10:05 +0000
1
+ Wed, 06 May 2009 09:55:58 +0000
@@ -22,6 +22,7 @@
22
22
  <div id="index-entries">
23
23
  <a href="classes/LocalMemCache.html">LocalMemCache</a><br />
24
24
  <a href="classes/LocalMemCache/ArgError.html">LocalMemCache::ArgError</a><br />
25
+ <a href="classes/LocalMemCache/DBVersionNotSupported.html">LocalMemCache::DBVersionNotSupported</a><br />
25
26
  <a href="classes/LocalMemCache/InitError.html">LocalMemCache::InitError</a><br />
26
27
  <a href="classes/LocalMemCache/LocalMemCacheError.html">LocalMemCache::LocalMemCacheError</a><br />
27
28
  <a href="classes/LocalMemCache/LockError.html">LocalMemCache::LockError</a><br />
@@ -30,6 +31,7 @@
30
31
  <a href="classes/LocalMemCache/MemoryPoolFull.html">LocalMemCache::MemoryPoolFull</a><br />
31
32
  <a href="classes/LocalMemCache/OutOfMemoryError.html">LocalMemCache::OutOfMemoryError</a><br />
32
33
  <a href="classes/LocalMemCache/RecoveryFailed.html">LocalMemCache::RecoveryFailed</a><br />
34
+ <a href="classes/LocalMemCache/SharedObjectStorage.html">LocalMemCache::SharedObjectStorage</a><br />
33
35
  <a href="classes/LocalMemCache/ShmError.html">LocalMemCache::ShmError</a><br />
34
36
  <a href="classes/LocalMemCache/ShmLockFailed.html">LocalMemCache::ShmLockFailed</a><br />
35
37
  <a href="classes/LocalMemCache/ShmUnlockFailed.html">LocalMemCache::ShmUnlockFailed</a><br />
@@ -20,8 +20,9 @@
20
20
  <div id="index">
21
21
  <h1 class="section-bar">Files</h1>
22
22
  <div id="index-entries">
23
- <a href="files/__/src/ruby-binding/localmemcache_rb.html">../src/ruby-binding/localmemcache.rb</a><br />
24
- <a href="files/__/src/ruby-binding/rblocalmemcache_c.html">../src/ruby-binding/rblocalmemcache.c</a><br />
23
+ <a href="files/extconf_rb.html">extconf.rb</a><br />
24
+ <a href="files/localmemcache_rb.html">localmemcache.rb</a><br />
25
+ <a href="files/rblocalmemcache_c.html">rblocalmemcache.c</a><br />
25
26
  </div>
26
27
  </div>
27
28
  </body>
@@ -20,18 +20,24 @@
20
20
  <div id="index">
21
21
  <h1 class="section-bar">Methods</h1>
22
22
  <div id="index-entries">
23
- <a href="classes/LocalMemCache.html#M000007">[] (LocalMemCache)</a><br />
24
- <a href="classes/LocalMemCache.html#M000010">[]= (LocalMemCache)</a><br />
25
- <a href="classes/LocalMemCache.html#M000005">check (LocalMemCache)</a><br />
26
- <a href="classes/LocalMemCache.html#M000003">check_namespace (LocalMemCache)</a><br />
27
- <a href="classes/LocalMemCache.html#M000004">clear (LocalMemCache)</a><br />
28
- <a href="classes/LocalMemCache.html#M000002">clear_namespace (LocalMemCache)</a><br />
29
- <a href="classes/LocalMemCache.html#M000012">close (LocalMemCache)</a><br />
30
- <a href="classes/LocalMemCache.html#M000008">delete (LocalMemCache)</a><br />
31
- <a href="classes/LocalMemCache.html#M000006">get (LocalMemCache)</a><br />
32
- <a href="classes/LocalMemCache.html#M000011">keys (LocalMemCache)</a><br />
23
+ <a href="classes/LocalMemCache/SharedObjectStorage.html#M000016">[] (LocalMemCache::SharedObjectStorage)</a><br />
24
+ <a href="classes/LocalMemCache.html#M000005">[] (LocalMemCache)</a><br />
25
+ <a href="classes/LocalMemCache.html#M000009">[]= (LocalMemCache)</a><br />
26
+ <a href="classes/LocalMemCache/SharedObjectStorage.html#M000015">[]= (LocalMemCache::SharedObjectStorage)</a><br />
27
+ <a href="classes/LocalMemCache.html#M000003">check (LocalMemCache)</a><br />
28
+ <a href="classes/LocalMemCache.html#M000008">clear (LocalMemCache)</a><br />
29
+ <a href="classes/LocalMemCache.html#M000013">close (LocalMemCache)</a><br />
30
+ <a href="classes/LocalMemCache.html#M000006">delete (LocalMemCache)</a><br />
31
+ <a href="classes/LocalMemCache.html#M000002">drop (LocalMemCache)</a><br />
32
+ <a href="classes/LocalMemCache.html#M000011">each_pair (LocalMemCache)</a><br />
33
+ <a href="classes/LocalMemCache/SharedObjectStorage.html#M000017">each_pair (LocalMemCache::SharedObjectStorage)</a><br />
34
+ <a href="classes/LocalMemCache.html#M000004">get (LocalMemCache)</a><br />
35
+ <a href="classes/LocalMemCache.html#M000010">keys (LocalMemCache)</a><br />
33
36
  <a href="classes/LocalMemCache.html#M000001">new (LocalMemCache)</a><br />
34
- <a href="classes/LocalMemCache.html#M000009">set (LocalMemCache)</a><br />
37
+ <a href="classes/LocalMemCache.html#M000012">random_pair (LocalMemCache)</a><br />
38
+ <a href="classes/LocalMemCache/SharedObjectStorage.html#M000018">random_pair (LocalMemCache::SharedObjectStorage)</a><br />
39
+ <a href="classes/LocalMemCache.html#M000007">set (LocalMemCache)</a><br />
40
+ <a href="classes/LocalMemCache.html#M000014">size (LocalMemCache)</a><br />
35
41
  </div>
36
42
  </div>
37
43
  </body>
@@ -19,6 +19,6 @@
19
19
  <frame src="fr_class_index.html" name="Classes" />
20
20
  <frame src="fr_method_index.html" name="Methods" />
21
21
  </frameset>
22
- <frame src="files/__/src/ruby-binding/localmemcache_rb.html" name="docwin" />
22
+ <frame src="files/localmemcache_rb.html" name="docwin" />
23
23
  </frameset>
24
24
  </html>
@@ -9,25 +9,28 @@
9
9
  <div id="content">
10
10
  <h1>A persistent key-value database based on mmap()'ed shared memory</h1>
11
11
 
12
- <p><b>Localmemcache</b> is a library for C and ruby that aims to provide
12
+ <p><b>Localmemcache</b> is a library for <b>C</b> and <b>Ruby</b> that aims
13
+ to provide
13
14
  an interface similar to memcached but for accessing local data instead of
14
- remote data. It's based on <b>mmap()</b>'ed shared memory for maximum speed.
15
- Since version 0.3.0 it supports persistence, also making it a fast
16
- alternative to GDBM and Berkeley DB.
15
+ remote data. It's based on <b>mmap()</b>'ed shared memory for <b>maximum
16
+ speed</b>.
17
+ Since version 0.3.0 it supports <b>persistence</b>, also making it <b>a fast
18
+ alternative to GDBM and Berkeley DB</b>.
17
19
 
18
- <h2>Key features as of 0.3.0 (2009-04-17)</h2>
20
+ <h2>Key features as of 0.4.0 (2009-05-16)</h2>
19
21
  <li><a href="#performance">blazingly fast</a></li>
22
+ <li>a very simple API</li>
20
23
  <li>persistent</li>
21
24
  <li>parallel writes are supported by default</li>
22
25
  <li>uses transactions internally to avoid data corruption</li>
23
26
  <li>lightweight: the core library is just about <b>1400</b> lines of <b>C</b> code</li>
24
27
 
25
28
  <h2>Requirements</h2>
26
- <li>a &gt;=64bit Unix</li>
29
+ <li>a &gt;=64bit Unix (32bit is possible but you'll run out of virtual address space quickly)</li>
27
30
  <li>a file system that offers <a href="http://en.wikipedia.org/wiki/Sparse_file">sparse files</a></li>
28
31
  Note for <b>OS X</b>: <b>OS X</b> disqualifies as <b>HFS+</b> doesn't
29
32
  have sparse files and <b>sem_timedwait</b>() and <b>sem_getvalue</b>() aren't
30
- supported as well.
33
+ supported as well.<br>
31
34
  Note for <b>FreeBSD</b>: It has been reported that Localmemcache
32
35
  sometimes hangs there, it is not yet clear what the problem is.
33
36
 
@@ -42,15 +45,19 @@ sometimes hangs there, it is not yet clear what the problem is.
42
45
  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>.
43
46
 
44
47
  <h2>Using</h2>
45
- <b>API</b>:&nbsp;<a href="http://github.com/sck/localmemcache/blob/e980ba949034a349dbf0e6f8f9ef77bbe3e3e314/src/localmemcache.h">C</a>|<a href="http://localmemcache.rubyforge.org/doc/">Ruby</a><br>
48
+ <b>API</b>:&nbsp;<a href="http://github.com/sck/localmemcache/blob/591d943507236035e99471f372dc2826271610c9/src/localmemcache.h">C</a>|<a href="http://localmemcache.rubyforge.org/doc/">Ruby</a><br>
46
49
  <p><pre><code>require 'localmemcache'
47
50
  # 1. the memcached way
48
51
  # $lm = LocalMemCache.new :namespace => :viewcounters
49
52
  # 2. the GDBM way
50
- $lm = LocalMemCache.new :filename => "./viewcounters.lmc"
53
+ #$lm = LocalMemCache.new :filename => "./viewcounters.lmc"
54
+ # 3. Using LocalMemCache::SharedObjectStorage
55
+ $lm = LocalMemCache::SharedObjectStorage.new :filename =>
56
+ "./viewcounters.lmc"
51
57
  $lm[:foo] = 1
52
58
  $lm[:foo]
53
59
  $lm.delete(:foo)
60
+
54
61
  </code></pre>
55
62
  (C version of this example: <a href="http://github.com/sck/localmemcache/blob/e980ba949034a349dbf0e6f8f9ef77bbe3e3e314/example/hello.c">hello.c</a>)
56
63
  </p>
@@ -69,22 +76,20 @@ Ruby benchmark pseudo code:
69
76
  </code></pre>
70
77
 
71
78
  <pre>
72
- Tokyo Tyrant: <b>298,226.197</b> ms
73
79
  MemCache: <b>253,326.122</b> ms
74
80
  GDBM: <b>24,226.116</b> ms
75
- Localmemcache 0.2.2: <b>5,799.225</b> ms
76
- Localmemcache 0.3.0: <b>5,300.055</b> ms
81
+ Tokyo Cabinet: <b>9,092.707</b> ms
82
+ Localmemcache 0.4.0: <b>5,310.055</b> ms
77
83
  Ruby Hash of Strings: <b>4,963.313</b> ms
78
84
  </pre>
79
- (<a href="http://github.com/sck/localmemcache/tree/e980ba949034a349dbf0e6f8f9ef77bbe3e3e314/bench">Code of the benchmarks used</a>)
85
+ (<a href="http://github.com/sck/localmemcache/tree/7e5a9549a3b8c32662aaebaec3642253ce0ea8b0/bench">Code of the benchmarks used</a>)
80
86
 
81
87
  <p>
82
88
 
83
- So, on my machine, using <b>Localmemcache</b> 0.3.0 to store key-value
89
+ So, on my machine, using <b>Localmemcache</b> 0.4.0 to store key-value
84
90
  data on disk is about <b>10</b>% slower than keeping them in memory in a
85
- Ruby hash of strings. Also keep in mind that of the above mentioned
86
- software components <b>Tokyo Tyrant</b> is the only one that offers
87
- persistence and parallel writes like <b>Localmemcache</b> does.
91
+ Ruby hash of strings. It's about 70% faster than <b>Tokyo Cabinet</b>
92
+ (which offers features similar to <b>LocalMemCache</b>).
88
93
 
89
94
  <h2>Source code</h2>
90
95
 
@@ -115,4 +120,15 @@ Localmemcache is freely distributable under the terms of an
115
120
  </div>
116
121
 
117
122
  </body>
123
+ <script type="text/javascript">
124
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl."
125
+ : "http://www.");
126
+ document.write(unescape("%3Cscript src='" + gaJsHost +
127
+ "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
128
+ </script>
129
+ <script type="text/javascript">
130
+ try {
131
+ var pageTracker = _gat._getTracker("UA-657352-3");
132
+ pageTracker._trackPageview();
133
+ } catch(err) {}</script>
118
134
  </html>
@@ -51,7 +51,8 @@ void lmc_clean_string(char *result, const char *source) {
51
51
  for (; n--; d++, s++) {
52
52
  ch = *s;
53
53
  if ((ch >= 'a' && ch <= 'z') ||
54
- (ch >= 'A' && ch <= 'Z')) {
54
+ (ch >= 'A' && ch <= 'Z') ||
55
+ (ch >= '0' && ch <= '9')) {
55
56
  *d = ch;
56
57
  } else {
57
58
  *d = '-';
@@ -5,7 +5,7 @@
5
5
  #ifndef _LMC_COMMON_H_INCLUDED_
6
6
  #define _LMC_COMMON_H_INCLUDED_
7
7
 
8
- #define LMC_DB_VERSION 0
8
+ #define LMC_DB_VERSION 1
9
9
 
10
10
  extern int lmc_test_crash_enabled;
11
11
  #ifdef DO_TEST_CRASH
@@ -131,6 +131,7 @@ int ht_set(void *base, va_ht_hash_t va_ht, const char *key,
131
131
  hr->va_next = ht->va_buckets[v];
132
132
  ht->va_buckets[v] = va;
133
133
  hr->va_value = l->va_value;
134
+ ht->size += 1;
134
135
  lmc_log_finish(base);
135
136
  } else {
136
137
  LMC_TEST_CRASH
@@ -174,6 +175,7 @@ int ht_delete(void *base, va_ht_hash_t va_ht, const char *key, size_t n_key) {
174
175
  lmc_free(base, hr->va_key);
175
176
  lmc_free(base, hr->va_value);
176
177
  lmc_free(base, va_hr);
178
+ ht->size -= 1;
177
179
  return 1;
178
180
 
179
181
  next:
@@ -183,21 +185,79 @@ int ht_delete(void *base, va_ht_hash_t va_ht, const char *key, size_t n_key) {
183
185
  }
184
186
 
185
187
  int ht_hash_iterate(void *base, va_ht_hash_t va_ht, void *ctx,
186
- LMC_ITERATOR_P(iter)) {
188
+ size_t *ofs, LMC_ITERATOR_P(iter)) {
187
189
  va_ht_hash_entry_t va_hr;
188
190
  ht_hash_entry_t *hr = &lmc_null_node;
189
191
  ht_hash_t *ht = base + va_ht;
190
192
  size_t k;
193
+ size_t item_c = 0;
194
+ size_t slice_counter = 0;
191
195
  for (k = 0; k < LMC_HT_BUCKETS; k++) {
192
196
  for (va_hr = ht->va_buckets[k]; va_hr != 0 && hr != NULL;
193
197
  va_hr = hr->va_next) {
194
198
  hr = va_hr ? base + va_hr : 0;
195
- iter(ctx, base + hr->va_key, base + hr->va_value);
199
+ if (*ofs < ++item_c) {
200
+ iter(ctx, base + hr->va_key, base + hr->va_value);
201
+ if (++slice_counter > 999) {
202
+ *ofs = item_c;
203
+ return 2;
204
+ }
205
+ }
196
206
  }
197
207
  }
198
208
  return 1;
199
209
  }
200
210
 
211
+ int ht_random_pair(void *base, va_ht_hash_t va_ht, char **r_key,
212
+ size_t *n_key, char **r_value, size_t *n_value) {
213
+ va_ht_hash_entry_t va_hr;
214
+ ht_hash_t *ht = base + va_ht;
215
+ ht_hash_entry_t *hr = &lmc_null_node;
216
+ size_t k;
217
+ int rk = -1;
218
+ int filled_buckets = 0;
219
+ for (k = 0; k < LMC_HT_BUCKETS; k++) {
220
+ if (ht->va_buckets[k]) { filled_buckets++; }
221
+ }
222
+ if (filled_buckets == 0) { *r_key = 0x0; r_value = 0x0; return 0; }
223
+ int bnr = rand() % filled_buckets;
224
+ for (k = 0; k < LMC_HT_BUCKETS; k++) {
225
+ if (ht->va_buckets[k] && bnr-- < 1) {
226
+ rk = k;
227
+ break;
228
+ }
229
+ }
230
+ if (rk == -1) {
231
+ printf("WHOA: Bucket not found!\n");
232
+ abort();
233
+ }
234
+ int pair_counter = 0;
235
+ hr = &lmc_null_node;
236
+ for (va_hr = ht->va_buckets[rk]; va_hr != 0 && hr != NULL;
237
+ va_hr = hr->va_next) {
238
+ hr = va_hr ? base + va_hr : 0;
239
+ pair_counter++;
240
+ }
241
+ int random_pair = rand() % pair_counter;
242
+ hr = &lmc_null_node;
243
+ for (va_hr = ht->va_buckets[rk]; va_hr != 0 && hr != NULL;
244
+ va_hr = hr->va_next) {
245
+ hr = va_hr ? base + va_hr : 0;
246
+ if (random_pair-- < 1) {
247
+ char *k = base + hr->va_key;
248
+ char *v = base + hr->va_value;
249
+ *r_key = lmc_string_data(k);
250
+ *n_key = lmc_string_len(k);
251
+ *r_value = lmc_string_data(v);
252
+ *n_value = lmc_string_len(v);
253
+ return 1;
254
+ }
255
+ }
256
+ printf("whoa no random entry found!\n");
257
+ abort();
258
+ return 0;
259
+ }
260
+
201
261
  int ht_check_memory(void *base, va_ht_hash_t va_ht) {
202
262
  char *bf = lmc_um_new_mem_usage_bitmap(base);
203
263
  if (!bf) return 0;
@@ -22,6 +22,7 @@ typedef struct {
22
22
 
23
23
  typedef size_t va_ht_hash_t;
24
24
  typedef struct {
25
+ size_t size;
25
26
  va_ht_hash_entry_t va_buckets[LMC_HT_BUCKETS];
26
27
  } ht_hash_t;
27
28
 
@@ -34,8 +35,10 @@ const char *ht_get(void *base, va_ht_hash_t va_ht, const char *key, size_t n_key
34
35
  size_t *n_value);
35
36
  int ht_delete(void *base, va_ht_hash_t va_ht, const char *key, size_t n_key);
36
37
  int ht_hash_destroy(void *base, va_ht_hash_t ht);
37
- int ht_hash_iterate(void *base, va_ht_hash_t ht, void *ctx,
38
+ int ht_hash_iterate(void *base, va_ht_hash_t ht, void *ctx, size_t *ofs,
38
39
  LMC_ITERATOR_P(iter));
40
+ int ht_random_pair(void *base, va_ht_hash_t va_ht, char **r_key,
41
+ size_t *n_key, char **r_value, size_t *n_value);
39
42
 
40
43
  int ht_check_memory(void *base, va_ht_hash_t va_ht);
41
44
  int ht_redo(void *base, va_ht_hash_t va_ht, lmc_log_descriptor_t *l,
@@ -73,15 +73,13 @@ void lmc_shm_ensure_namespace_file(const char *ns) {
73
73
  if (!lmc_does_namespace_exist(ns)) { close(open(fn, O_CREAT, 0777)); }
74
74
  }
75
75
 
76
- lmc_shm_t *lmc_shm_create(const char* namespace, size_t size, int use_persistence,
77
- lmc_error_t *e) {
76
+ lmc_shm_t *lmc_shm_create(const char* namespace, size_t size, lmc_error_t *e) {
78
77
  lmc_shm_t *mc = calloc(1, sizeof(lmc_shm_t));
79
78
  if (!mc) {
80
79
  STD_OUT_OF_MEMORY_ERROR("lmc_shm_create");
81
80
  return NULL;
82
81
  }
83
82
  snprintf((char *)&mc->namespace, 1023, "%s", namespace);
84
- mc->use_persistence = 0;
85
83
  mc->size = size;
86
84
 
87
85
  lmc_shm_ensure_namespace_file(mc->namespace);
@@ -10,12 +10,10 @@ typedef struct {
10
10
  int fd;
11
11
  void *base;
12
12
  size_t size;
13
- int use_persistence;
14
13
  char namespace[1024];
15
14
  } lmc_shm_t;
16
15
 
17
- lmc_shm_t *lmc_shm_create(const char *namespace, size_t size, int use_persistence,
18
- lmc_error_t *e);
16
+ lmc_shm_t *lmc_shm_create(const char *namespace, size_t size, lmc_error_t *e);
19
17
  int lmc_shm_destroy(lmc_shm_t *mc, lmc_error_t *e);
20
18
  int lmc_does_namespace_exist(const char *ns);
21
19
  int lmc_namespace_size(const char *ns);
@@ -116,6 +116,11 @@ void lmc_init_memory(void *ptr, size_t size) {
116
116
  c->size = s;
117
117
  }
118
118
 
119
+ size_t lmc_get_db_version(void *ptr) {
120
+ lmc_mem_descriptor_t *md = ptr;
121
+ return md->version;
122
+ }
123
+
119
124
  size_t lmc_max(size_t a, size_t b) {
120
125
  return a > b ? a : b;
121
126
  }
@@ -41,6 +41,7 @@ void lmc_free(void *base, size_t chunk);
41
41
  lmc_mem_status_t lmc_status(void *base, char *where);
42
42
  int is_lmc_already_initialized(void *base);
43
43
  void lmc_init_memory(void *ptr, size_t size);
44
+ size_t lmc_get_db_version(void *ptr);
44
45
 
45
46
  int lmc_um_mark_allocated(void *base, char *bf, size_t va);
46
47
  char *lmc_um_new_mem_usage_bitmap(void *base);
@@ -55,13 +55,13 @@ int lmc_namespace_or_filename(char *result, const char* ons, const char *ofn,
55
55
  return 0;
56
56
  }
57
57
 
58
- int local_memcache_clear_namespace(const char *namespace, const char *filename,
59
- int repair, lmc_error_t *e) {
58
+ int local_memcache_drop_namespace(const char *namespace, const char *filename,
59
+ int force, lmc_error_t *e) {
60
60
  char clean_ns[1024];
61
61
  if (!lmc_namespace_or_filename((char *)clean_ns, namespace, filename, e))
62
62
  return 1;
63
63
  lmc_clean_namespace((char *)clean_ns, e);
64
- if (repair) {
64
+ if (force) {
65
65
  lmc_lock_t *l = lmc_lock_init((char *)clean_ns, 1, e);
66
66
  lmc_lock_repair(l);
67
67
  free(l);
@@ -106,7 +106,7 @@ retry:
106
106
  {
107
107
  if (*ok && !lmc_lock_obtain("local_memcache_create", lmc->lock, &lmc->error))
108
108
  goto failed;
109
- if ((lmc->shm = lmc_shm_create(lmc->namespace, lmc->size, 0, e)) == NULL)
109
+ if ((lmc->shm = lmc_shm_create(lmc->namespace, lmc->size, e)) == NULL)
110
110
  goto release_and_fail;
111
111
  lmc->base = lmc->shm->base;
112
112
  if (!*ok || is_lmc_already_initialized(lmc->base)) {
@@ -114,6 +114,11 @@ retry:
114
114
  if (!force) goto release_and_fail;
115
115
  *ok = 0;
116
116
  }
117
+ if (lmc_get_db_version(lmc->base) != LMC_DB_VERSION) {
118
+ lmc_handle_error_with_err_string("local_memcache_create",
119
+ "DB version is incompatible", "DBVersionNotSupported", e);
120
+ goto unlock_and_fail;
121
+ }
117
122
  lmc_mem_descriptor_t *md = lmc->base;
118
123
  lmc->va_hash = md->va_hash;
119
124
  } else {
@@ -230,8 +235,6 @@ int local_memcache_check_namespace(const char *namespace, const char *filename,
230
235
  return __local_memcache_check_namespace(clean_ns, e);
231
236
  }
232
237
 
233
-
234
-
235
238
  int lmc_lock_shm_region(const char *who, local_memcache_t *lmc) {
236
239
  int r;
237
240
  int retry_counter = 0;
@@ -279,6 +282,27 @@ char *local_memcache_get_new(local_memcache_t *lmc,
279
282
  return new_s;
280
283
  }
281
284
 
285
+ int __local_memcache_random_pair(local_memcache_t *lmc,
286
+ char **r_key, size_t *n_key, char **r_value, size_t *n_value) {
287
+ if (!lmc_lock_shm_region("local_memcache_random_pair", lmc)) return 0;
288
+ return ht_random_pair(lmc->base, lmc->va_hash, r_key, n_key, r_value,
289
+ n_value);
290
+ }
291
+
292
+ int local_memcache_random_pair_new(local_memcache_t *lmc,
293
+ char **r_key, size_t *n_key, char **r_value, size_t *n_value) {
294
+ char *k;
295
+ char *v;
296
+ if (__local_memcache_random_pair(lmc, &k, n_key, &v, n_value)) {
297
+ char *new_k = malloc(*n_key);
298
+ memcpy(new_k, k, *n_key);
299
+ char *new_v = malloc(*n_value);
300
+ memcpy(new_v, v, *n_value);
301
+ }
302
+ if (!lmc_unlock_shm_region("local_memcache_random_pair", lmc)) return 0;
303
+ return 1;
304
+ }
305
+
282
306
  int local_memcache_set(local_memcache_t *lmc,
283
307
  const char *key, size_t n_key, const char* value, size_t n_value) {
284
308
  if (!lmc_lock_shm_region("local_memcache_set", lmc)) return 0;
@@ -288,6 +312,17 @@ int local_memcache_set(local_memcache_t *lmc,
288
312
  return r;
289
313
  }
290
314
 
315
+ int local_memcache_clear(local_memcache_t *lmc) {
316
+ if (!lmc_lock_shm_region("local_memcache_clear", lmc)) return 0;
317
+ lmc_init_memory(lmc->base, lmc->size);
318
+ lmc_mem_descriptor_t *md = lmc->base;
319
+ int r = 1;
320
+ if ((md->va_hash = ht_hash_create(lmc->base, &lmc->error)) == 0) { r = 0; }
321
+ else { lmc->va_hash = md->va_hash; }
322
+ if (!lmc_unlock_shm_region("local_memcache_clear", lmc)) return 0;
323
+ return r;
324
+ }
325
+
291
326
  int local_memcache_delete(local_memcache_t *lmc, char *key, size_t n_key) {
292
327
  if (!lmc_lock_shm_region("local_memcache_delete", lmc)) return 0;
293
328
  int r = ht_delete(lmc->base, lmc->va_hash, key, n_key);
@@ -306,9 +341,9 @@ int local_memcache_free(local_memcache_t *lmc, lmc_error_t *e) {
306
341
  }
307
342
 
308
343
  int local_memcache_iterate(local_memcache_t *lmc, void *ctx,
309
- LMC_ITERATOR_P(iter)) {
344
+ size_t *ofs, LMC_ITERATOR_P(iter)) {
310
345
  if (!lmc_lock_shm_region("local_memcache_iterate", lmc)) return 0;
311
- int r = ht_hash_iterate(lmc->base, lmc->va_hash, ctx, iter);
346
+ int r = ht_hash_iterate(lmc->base, lmc->va_hash, ctx, ofs, iter);
312
347
  if (!lmc_unlock_shm_region("local_memcache_iterate", lmc)) return 0;
313
348
  return r;
314
349
  }