localmemcache 0.3.0 → 0.4.0

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