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 +1 -1
- data/site/index.html +124 -38
- data/src/lmc_common.c +4 -3
- data/src/lmc_valloc.c +13 -6
- data/src/lmc_valloc.h +1 -0
- data/src/localmemcache.c +1 -0
- data/src/ruby-binding/localmemcache.rb +5 -1
- data/src/ruby-binding/rblocalmemcache.c +59 -5
- data/src/tests/bench.rb +1 -1
- data/src/tests/console +6 -0
- data/src/tests/console.rb +4 -0
- data/src/tests/crash.rb +1 -1
- data/src/tests/iter.rb +1 -1
- data/src/tests/lmc.rb +29 -10
- data/src/tests/run-all-tests +2 -0
- data/src/tests/ttlmc-consistency +11 -0
- data/src/tests/ttlmc-consistency.rb +57 -0
- data/src/tests/ttlmc.rb +5 -5
- metadata +6 -3
- data/site/style.css +0 -37
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.4
|
data/site/index.html
CHANGED
@@ -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
|
-
|
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
|
-
|
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öfmann</b> and <b>Florian Dü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
|
-
</
|
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>
|
143
|
+
<li>lightweight: the core library is just about <b>1500</b> lines of <b>C</b> code</li>
|
66
144
|
|
67
|
-
|
68
|
-
<li>a >=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 >=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>: <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 < <a href="http://cloud.github.com/downloads/sck/localmemcache/localmemcache.pdf">pdf</a> | <a href="http://cloud.github.com/downloads/sck/localmemcache/localmemcache.key">key</a> > (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
|
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
|
data/src/lmc_common.c
CHANGED
@@ -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
|
47
|
-
|
48
|
-
|
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++) {
|
data/src/lmc_valloc.c
CHANGED
@@ -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
|
-
|
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 =
|
386
|
-
while (
|
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 (
|
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
|
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;
|
data/src/lmc_valloc.h
CHANGED
data/src/localmemcache.c
CHANGED
@@ -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
|
-
|
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
|
-
|
260
|
-
|
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
|
-
|
287
|
-
|
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
|
|
data/src/tests/bench.rb
CHANGED
@@ -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
|
|
data/src/tests/console
ADDED
data/src/tests/crash.rb
CHANGED
data/src/tests/iter.rb
CHANGED
data/src/tests/lmc.rb
CHANGED
@@ -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 =>
|
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
|
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 =>
|
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
|
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
|
data/src/tests/run-all-tests
CHANGED
@@ -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 }
|
data/src/tests/ttlmc.rb
CHANGED
@@ -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
|
-
|
16
|
-
|
17
|
-
|
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.
|
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
|
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
|
data/site/style.css
DELETED
@@ -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
|
-
}
|