localmemcache 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/COPYING +21 -0
- data/LICENSE +3 -0
- data/Makefile.in +18 -0
- data/README +83 -0
- data/Rakefile +78 -0
- data/VERSION +1 -0
- data/aclocal.m4 +3 -0
- data/configure +5254 -0
- data/configure.in +42 -0
- data/site/index.html +70 -0
- data/site/style.css +37 -0
- data/src/Makefile.in +53 -0
- data/src/lmc_config.h.in +4 -0
- data/src/lmc_error.c +18 -0
- data/src/lmc_error.h +19 -0
- data/src/lmc_hashtable.c +104 -0
- data/src/lmc_hashtable.h +33 -0
- data/src/lmc_lock.c +65 -0
- data/src/lmc_lock.h +22 -0
- data/src/lmc_shm.c +92 -0
- data/src/lmc_shm.h +22 -0
- data/src/lmc_valloc.c +324 -0
- data/src/lmc_valloc.h +31 -0
- data/src/localmemcache.c +130 -0
- data/src/localmemcache.h +33 -0
- data/src/ruby-binding/extconf.rb +14 -0
- data/src/ruby-binding/localmemcache.rb +32 -0
- data/src/ruby-binding/rblocalmemcache.c +119 -0
- data/src/tests/alloc +11 -0
- data/src/tests/alloc.rb +61 -0
- data/src/tests/bacon.rb +301 -0
- data/src/tests/bench +11 -0
- data/src/tests/bench.rb +46 -0
- data/src/tests/extconf.rb +14 -0
- data/src/tests/lmc +11 -0
- data/src/tests/lmc.rb +85 -0
- data/src/tests/lmctestapi.c +162 -0
- data/src/tests/runtest.sh +9 -0
- data/src/tests/shm +11 -0
- data/src/tests/shm.rb +20 -0
- data/src/tests/torture.rb +56 -0
- data/src/tests/ttalloc +11 -0
- data/src/tests/ttalloc.rb +47 -0
- data/src/tests/ttlmc +11 -0
- data/src/tests/ttlmc.rb +21 -0
- metadata +99 -0
data/configure.in
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
AC_INIT(${srcdir}/src/lmc_config.h.in)
|
2
|
+
AC_CONFIG_HEADER(${srcdir}/src/lmc_config.h)
|
3
|
+
AC_PROG_CC
|
4
|
+
AC_SUBST(CC)
|
5
|
+
AC_PROG_RANLIB
|
6
|
+
AC_SUBST(RANLIB)
|
7
|
+
|
8
|
+
AC_MSG_CHECKING([version])
|
9
|
+
VERSION=`cat ${srcdir}/VERSION`
|
10
|
+
AC_SUBST(VERSION)
|
11
|
+
AC_MSG_RESULT([$VERSION])
|
12
|
+
|
13
|
+
AC_MSG_CHECKING([installation directory prefix])
|
14
|
+
|
15
|
+
if test "$prefix" = "NONE"; then
|
16
|
+
if test "x$PREFIX" != "x" ; then
|
17
|
+
prefix=$PREFIX
|
18
|
+
else
|
19
|
+
prefix=/usr/local
|
20
|
+
fi
|
21
|
+
fi
|
22
|
+
AC_PREFIX_DEFAULT($prefix)
|
23
|
+
PREFIX=$ac_default_prefix
|
24
|
+
PREFIX=$prefix
|
25
|
+
exec_prefix=$PREFIX
|
26
|
+
AC_SUBST(PREFIX)
|
27
|
+
AC_MSG_RESULT([$PREFIX])
|
28
|
+
|
29
|
+
AC_MSG_CHECKING([if inside RubyGems])
|
30
|
+
env > /tmp/lmc.env
|
31
|
+
AC_MSG_RESULT([$PREFIX])
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
#--------------------------------------------------------------------
|
36
|
+
# Propagate prefix argument as installation directory.
|
37
|
+
#--------------------------------------------------------------------
|
38
|
+
AC_SUBST(PREFIX)
|
39
|
+
|
40
|
+
|
41
|
+
AC_OUTPUT(src/Makefile)
|
42
|
+
AC_OUTPUT(Makefile)
|
data/site/index.html
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
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"/>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
|
9
|
+
<div id="content">
|
10
|
+
<h1>Efficiently sharing a hashtable between processes on a local Unix machine.</h1>
|
11
|
+
|
12
|
+
<p><b>Localmemcache</b> aims to be faster than using <a href="http://www.danga.com/memcached/">memcached</a> locally by using shared memory and providing a similar interface for Ruby and C.
|
13
|
+
|
14
|
+
<h2>Install</h2>
|
15
|
+
|
16
|
+
<p>The Ruby binding is available as a Ruby Gem. It can be installed by executing</p>
|
17
|
+
|
18
|
+
<pre><code>gem install localmemcache
|
19
|
+
</code></pre>
|
20
|
+
|
21
|
+
<h2>Using</h2>
|
22
|
+
<p><pre><code>require 'localmemcache'
|
23
|
+
$lm = LocalMemCache.new :namespace => :viewcounters
|
24
|
+
$lm[:foo] = 1
|
25
|
+
$lm[:foo]
|
26
|
+
$lm.delete(:foo)
|
27
|
+
</code></pre>
|
28
|
+
</p>
|
29
|
+
<a href="http://github.com/sck/localmemcache/tree/master">Read more</a>.
|
30
|
+
|
31
|
+
<h2>Performance</h2>
|
32
|
+
|
33
|
+
<p>Here's a quick speed comparison, made on an
|
34
|
+
<b>Intel(R) Xeon(R) CPU E5205 @ 1.86GHz</b>:</p>
|
35
|
+
Benchmark pseudo code:
|
36
|
+
<pre><code>2_000_000.times {
|
37
|
+
index = rand(10000).to_s
|
38
|
+
$hash.set(index, index)
|
39
|
+
$hash.get(index)
|
40
|
+
}
|
41
|
+
</code></pre>
|
42
|
+
|
43
|
+
<pre>
|
44
|
+
MemCache: <b>253,326.122</b> ms
|
45
|
+
LocalMemCache: <b>6,055.552</b> ms
|
46
|
+
Ruby's Hash: <b>4,963.313</b> ms
|
47
|
+
</pre>
|
48
|
+
|
49
|
+
<b>Localmemcache</b> is about <b>40</b> times faster than using memcached
|
50
|
+
locally, and about <b>20%</b> slower than Ruby's hash.
|
51
|
+
|
52
|
+
<h2>Source code</h2>
|
53
|
+
|
54
|
+
<p>The source code is hosted on <a href="http://github.com/sck/localmemcache/tree/master">github</a>. It
|
55
|
+
can be retrieved by executing</p>
|
56
|
+
|
57
|
+
<pre><code>git clone git://github.com/sck/localmemcache.git
|
58
|
+
</code></pre>
|
59
|
+
|
60
|
+
<h2>License</h2>
|
61
|
+
|
62
|
+
<p>Copyright (c) 2009 Sven C. Koehler (schween at s n a f u dot de)<br>
|
63
|
+
Localmemcache is freely distributable under the terms of an
|
64
|
+
<a href="http://github.com/sck/localmemcache/blob/af51a7d10e7162551e0cb1cf1b1635c1c76fe8d2/COPYING">MIT-style license</a>.
|
65
|
+
</p>
|
66
|
+
|
67
|
+
</div>
|
68
|
+
|
69
|
+
</body>
|
70
|
+
</html>
|
data/site/style.css
ADDED
@@ -0,0 +1,37 @@
|
|
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
|
+
}
|
data/src/Makefile.in
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
CC=@CC@
|
2
|
+
VERSION=@VERSION@
|
3
|
+
TARGET=liblmc.a
|
4
|
+
CFLAGS=-Wall -Wunused -fPIC -O2
|
5
|
+
RUBY_LIB=rblocalmemcache.so
|
6
|
+
LDFLAGS=
|
7
|
+
AR=ar
|
8
|
+
RANLIB=@RANLIB@
|
9
|
+
PREFIX=@PREFIX@
|
10
|
+
LIBS=
|
11
|
+
OFILES= \
|
12
|
+
lmc_valloc.o \
|
13
|
+
lmc_error.o \
|
14
|
+
lmc_hashtable.o \
|
15
|
+
lmc_shm.o \
|
16
|
+
lmc_lock.o \
|
17
|
+
localmemcache.o
|
18
|
+
|
19
|
+
compile: $(TARGET)
|
20
|
+
|
21
|
+
ruby-binding: $(RUBY_LIB)
|
22
|
+
|
23
|
+
$(RUBY_LIB): $(TARGET)
|
24
|
+
cd ruby-binding; ruby extconf.rb
|
25
|
+
-$(MAKE) -C ruby-binding
|
26
|
+
cd tests; ruby extconf.rb
|
27
|
+
-$(MAKE) -C tests
|
28
|
+
|
29
|
+
$(TARGET): $(OFILES)
|
30
|
+
$(AR) r $@ $(OFILES)
|
31
|
+
$(RANLIB) $@
|
32
|
+
|
33
|
+
%.o: %.c
|
34
|
+
$(CC) $(CFLAGS) -c -o $@ $<
|
35
|
+
|
36
|
+
test: $(TARGET)
|
37
|
+
./tests/runtest.sh
|
38
|
+
|
39
|
+
install: $(TARGET)
|
40
|
+
@echo "INSTALLING localmemcache to ${PREFIX}"
|
41
|
+
install -d -m755 ${PREFIX}/lib
|
42
|
+
install -d -m755 ${PREFIX}/include
|
43
|
+
install -m644 ${TARGET} ${PREFIX}/lib
|
44
|
+
@echo INSTALLING headers to ${PREFIX}/include
|
45
|
+
install -m644 lmc_config.h lmc_error.h lmc_hashtable.h lmc_lock.h \
|
46
|
+
lmc_shm.h lmc_valloc.h ${PREFIX}/include
|
47
|
+
|
48
|
+
clean:
|
49
|
+
rm -f *.log *.so *.a *.o tests/core tests/vgcore* \
|
50
|
+
tests/*.so tests/*.o ruby-binding/*.o ruby-binding/*.so
|
51
|
+
|
52
|
+
distclean: clean
|
53
|
+
rm -f lmc_config.h tests/Makefile ruby-binding/Makefile
|
data/src/lmc_config.h.in
ADDED
data/src/lmc_error.c
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#include "lmc_error.h"
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <errno.h>
|
5
|
+
#include <string.h>
|
6
|
+
|
7
|
+
int lmc_handle_error(int check, const char *ctx, lmc_error_t *e) {
|
8
|
+
if (!check) { return LMC_OK; }
|
9
|
+
return lmc_handle_error_with_err_string(ctx, strerror(errno), e);
|
10
|
+
}
|
11
|
+
|
12
|
+
int lmc_handle_error_with_err_string(const char *ctx,
|
13
|
+
const char *error_msg, lmc_error_t *e) {
|
14
|
+
if (!e) { return LMC_OK; }
|
15
|
+
snprintf((char *)&e->error_str, 1023, "%s: %s", ctx, error_msg);
|
16
|
+
e->error_number = errno;
|
17
|
+
return LMC_ERROR;
|
18
|
+
}
|
data/src/lmc_error.h
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2009, Sven C. Koehler
|
3
|
+
*/
|
4
|
+
|
5
|
+
#ifndef _LMC_ERROR_H_
|
6
|
+
#define _LMC_ERROR_H_
|
7
|
+
|
8
|
+
#define LMC_OK 1
|
9
|
+
#define LMC_ERROR 0
|
10
|
+
|
11
|
+
typedef struct {
|
12
|
+
char error_str[1024];
|
13
|
+
int error_number;
|
14
|
+
} lmc_error_t;
|
15
|
+
|
16
|
+
int lmc_handle_error(int check, const char *ctx, lmc_error_t* e);
|
17
|
+
int lmc_handle_error_with_err_string(const char *ctx, const char* error_msg,
|
18
|
+
lmc_error_t* e);
|
19
|
+
#endif
|
data/src/lmc_hashtable.c
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2009, Sven C. Koehler
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include <stdio.h>
|
6
|
+
#include <stdlib.h>
|
7
|
+
#include <string.h>
|
8
|
+
|
9
|
+
#include "lmc_hashtable.h"
|
10
|
+
#include "lmc_valloc.h"
|
11
|
+
|
12
|
+
size_t ht_strdup(void *base, const char *s) {
|
13
|
+
size_t va_s = lmc_valloc(base, strlen(s) + 1);
|
14
|
+
if (!va_s) { return 0; }
|
15
|
+
//memcpy(base + va_s, s, strlen(s) + 1);
|
16
|
+
strcpy(base + va_s, s);
|
17
|
+
return va_s;
|
18
|
+
}
|
19
|
+
|
20
|
+
unsigned long ht_hash_key(const char *s) {
|
21
|
+
unsigned long v;
|
22
|
+
for (v = 0; *s != '\0'; s++) { v = *s + 31 * v; }
|
23
|
+
return v % HT_BUCKETS;
|
24
|
+
}
|
25
|
+
|
26
|
+
ht_hash_entry_t null_node = { 0, 0, 0 };
|
27
|
+
|
28
|
+
va_ht_hash_t ht_hash_create(void *base, lmc_error_t *e) {
|
29
|
+
va_ht_hash_t va_ht = lmc_valloc(base, sizeof(ht_hash_t));
|
30
|
+
if (!va_ht) {
|
31
|
+
lmc_handle_error_with_err_string("ht_hash_create", "memory pool full", e);
|
32
|
+
return 0;
|
33
|
+
}
|
34
|
+
memset(base + va_ht, 0, sizeof(ht_hash_t));
|
35
|
+
return va_ht;
|
36
|
+
}
|
37
|
+
|
38
|
+
int ht_hash_destroy(void *base, va_ht_hash_t ht) {
|
39
|
+
// ignore: Hashes are only deleted by deleting the namespace region
|
40
|
+
return 1;
|
41
|
+
}
|
42
|
+
|
43
|
+
ht_hash_entry_t *ht_lookup(void *base, va_ht_hash_t va_ht, const char *key) {
|
44
|
+
va_ht_hash_entry_t va_hr;
|
45
|
+
ht_hash_entry_t *hr ;
|
46
|
+
ht_hash_t *ht = base + va_ht;
|
47
|
+
for (va_hr = ht->va_buckets[ht_hash_key(key)];
|
48
|
+
va_hr != 0 && hr != NULL; va_hr = hr->va_next) {
|
49
|
+
hr = va_hr ? base + va_hr : 0;
|
50
|
+
if (hr && (strcmp(key, base + hr->va_key) == 0)) { return hr; }
|
51
|
+
}
|
52
|
+
return &null_node;
|
53
|
+
}
|
54
|
+
|
55
|
+
char *ht_get(void *base, va_ht_hash_t va_ht, const char *key) {
|
56
|
+
size_t va = ht_lookup(base, va_ht, key)->va_value;
|
57
|
+
char *r = va ? base + va : 0;
|
58
|
+
return r;
|
59
|
+
}
|
60
|
+
|
61
|
+
int ht_set(void *base, va_ht_hash_t va_ht, const char *key,
|
62
|
+
const char *value, lmc_error_t *e) {
|
63
|
+
ht_hash_t *ht = base + va_ht;
|
64
|
+
ht_hash_entry_t *hr = ht_lookup(base, va_ht, key);
|
65
|
+
unsigned v;
|
66
|
+
if (hr->va_key == 0) {
|
67
|
+
va_ht_hash_entry_t va = lmc_valloc(base, sizeof(ht_hash_entry_t));
|
68
|
+
hr = va ? base + va : 0;
|
69
|
+
if (hr == NULL || (hr->va_key = ht_strdup(base, key)) == 0) {
|
70
|
+
lmc_handle_error_with_err_string("ht_set", "memory pool full", e);
|
71
|
+
return 0;
|
72
|
+
}
|
73
|
+
v = ht_hash_key(key);
|
74
|
+
hr->va_next = ht->va_buckets[v];
|
75
|
+
ht->va_buckets[v] = va;
|
76
|
+
} else {
|
77
|
+
lmc_free(base, hr->va_value);
|
78
|
+
}
|
79
|
+
if ((hr->va_value = ht_strdup(base, value)) == 0) {
|
80
|
+
lmc_handle_error_with_err_string("ht_set", "memory pool full", e);
|
81
|
+
return 0;
|
82
|
+
}
|
83
|
+
return 1;
|
84
|
+
}
|
85
|
+
|
86
|
+
int ht_delete(void *base, va_ht_hash_t va_ht, const char *key) {
|
87
|
+
va_ht_hash_entry_t va_hr;
|
88
|
+
ht_hash_entry_t *hr;
|
89
|
+
ht_hash_entry_t *p = NULL;
|
90
|
+
ht_hash_t *ht = base + va_ht;
|
91
|
+
unsigned long k = ht_hash_key(key);
|
92
|
+
for (va_hr = ht->va_buckets[k]; va_hr != 0 && hr != NULL;
|
93
|
+
va_hr = hr->va_next) {
|
94
|
+
hr = va_hr ? base + va_hr : 0;
|
95
|
+
if (hr && (strcmp(key, base + hr->va_key) == 0)) {
|
96
|
+
// remove previous entry
|
97
|
+
if (p) { p->va_next = hr->va_next; }
|
98
|
+
else { ht->va_buckets[k] = 0; }
|
99
|
+
return 1;
|
100
|
+
}
|
101
|
+
p = base + hr->va_key;
|
102
|
+
}
|
103
|
+
return 0;
|
104
|
+
}
|
data/src/lmc_hashtable.h
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2009, Sven C. Koehler
|
3
|
+
*/
|
4
|
+
|
5
|
+
#ifndef _LMC_HASHTABLE_H_INCLUDED_
|
6
|
+
#define _LMC_HASHTABLE_H_INCLUDED_
|
7
|
+
#include "lmc_error.h"
|
8
|
+
|
9
|
+
typedef size_t va_string_t;
|
10
|
+
typedef size_t va_ht_hash_entry_t;
|
11
|
+
|
12
|
+
typedef struct {
|
13
|
+
va_ht_hash_entry_t va_next;
|
14
|
+
va_string_t va_key;
|
15
|
+
va_string_t va_value;
|
16
|
+
} ht_hash_entry_t;
|
17
|
+
|
18
|
+
#define HT_BUCKETS 499
|
19
|
+
|
20
|
+
typedef size_t va_ht_hash_t;
|
21
|
+
typedef struct {
|
22
|
+
va_ht_hash_entry_t va_buckets[HT_BUCKETS];
|
23
|
+
} ht_hash_t;
|
24
|
+
|
25
|
+
|
26
|
+
va_ht_hash_t ht_hash_create(void *base, lmc_error_t *e);
|
27
|
+
int ht_set(void *base, va_ht_hash_t va_ht, const char *key, const char *value,
|
28
|
+
lmc_error_t* e);
|
29
|
+
ht_hash_entry_t *ht_lookup(void *base, va_ht_hash_t va_ht, const char *key);
|
30
|
+
char *ht_get(void *base, va_ht_hash_t ht, const char *key);
|
31
|
+
int ht_delete(void *base, va_ht_hash_t va_ht, const char *key);
|
32
|
+
int ht_hash_destroy(void *base, va_ht_hash_t ht);
|
33
|
+
#endif
|
data/src/lmc_lock.c
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <fcntl.h>
|
4
|
+
#include <sys/stat.h>
|
5
|
+
#include <errno.h>
|
6
|
+
#include <string.h>
|
7
|
+
#include <time.h>
|
8
|
+
#include "lmc_lock.h"
|
9
|
+
|
10
|
+
int c_l(lmc_lock_t *l, lmc_error_t *e) {
|
11
|
+
if (!l) { strncpy(e->error_str, "Semaphore not initialized", 1023); }
|
12
|
+
return l != NULL;
|
13
|
+
}
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
lmc_lock_t *lmc_lock_init(const char *namespace, int init, lmc_error_t *e) {
|
18
|
+
lmc_lock_t *l = malloc(sizeof(lmc_lock_t));
|
19
|
+
if (!l) return NULL;
|
20
|
+
strncpy((char *)&l->namespace, namespace, 1023);
|
21
|
+
|
22
|
+
lmc_handle_error((l->sem = sem_open(l->namespace, O_CREAT, 0600, init)) == NULL,
|
23
|
+
"sem_open", e);
|
24
|
+
if (!l->sem) { free(l); return NULL; }
|
25
|
+
return l;
|
26
|
+
}
|
27
|
+
|
28
|
+
int lmc_is_locked(lmc_lock_t* l, lmc_error_t *e) {
|
29
|
+
if (!c_l(l, e)) { return 0; }
|
30
|
+
if (sem_trywait(l->sem) == -1) {
|
31
|
+
return 1;
|
32
|
+
} else {
|
33
|
+
sem_post(l->sem);
|
34
|
+
return 0;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
int lmc_is_lock_working(lmc_lock_t* l, lmc_error_t *e) {
|
39
|
+
if (!c_l(l, e)) { return 0; }
|
40
|
+
struct timespec ts;
|
41
|
+
clock_gettime(CLOCK_REALTIME, &ts);
|
42
|
+
ts.tv_sec += 2;
|
43
|
+
if (sem_timedwait(l->sem, &ts) == -1) {
|
44
|
+
return 0;
|
45
|
+
} else {
|
46
|
+
sem_post(l->sem);
|
47
|
+
return 1;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
void lmc_lock_repair(lmc_lock_t *l) {
|
52
|
+
int v;
|
53
|
+
sem_getvalue(l->sem, &v);
|
54
|
+
if (v == 0) { sem_post(l->sem); }
|
55
|
+
sem_getvalue(l->sem, &v);
|
56
|
+
printf("value after repair: %d\n", v);
|
57
|
+
}
|
58
|
+
|
59
|
+
int lmc_lock_obtain(const char *where, lmc_lock_t* l, lmc_error_t *e) {
|
60
|
+
return c_l(l,e) && lmc_handle_error(sem_wait(l->sem) == -1, "sem_wait", e);
|
61
|
+
}
|
62
|
+
|
63
|
+
int lmc_lock_release(const char *where, lmc_lock_t* l, lmc_error_t *e) {
|
64
|
+
return c_l(l, e) && lmc_handle_error(sem_post(l->sem) == -1, "sem_post", e);
|
65
|
+
}
|
data/src/lmc_lock.h
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2009, Sven C. Koehler
|
3
|
+
*/
|
4
|
+
|
5
|
+
#ifndef _LMC_LOCK_H_
|
6
|
+
#define _LMC_LOCK_H_
|
7
|
+
#include <semaphore.h>
|
8
|
+
#include "lmc_error.h"
|
9
|
+
|
10
|
+
typedef struct {
|
11
|
+
sem_t *sem;
|
12
|
+
char namespace[1024];
|
13
|
+
} lmc_lock_t;
|
14
|
+
|
15
|
+
lmc_lock_t *lmc_lock_init(const char *namespace, int init, lmc_error_t *e);
|
16
|
+
int lmc_lock_obtain(const char *where, lmc_lock_t* l, lmc_error_t *e);
|
17
|
+
int lmc_lock_release(const char *where, lmc_lock_t* l, lmc_error_t *e);
|
18
|
+
|
19
|
+
int lmc_is_locked(lmc_lock_t* l, lmc_error_t *e);
|
20
|
+
int lmc_is_lock_working(lmc_lock_t* l, lmc_error_t *e);
|
21
|
+
void lmc_lock_repair(lmc_lock_t *l);
|
22
|
+
#endif
|
data/src/lmc_shm.c
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2009, Sven C. Koehler
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include <stdio.h>
|
6
|
+
#include <stdlib.h>
|
7
|
+
#include <sys/types.h>
|
8
|
+
#include <sys/stat.h>
|
9
|
+
#include <string.h>
|
10
|
+
#include <unistd.h>
|
11
|
+
#include <fcntl.h>
|
12
|
+
#include <sys/mman.h>
|
13
|
+
|
14
|
+
#include "lmc_shm.h"
|
15
|
+
|
16
|
+
#define LMC_SHM_ROOT_PATH "/var/tmp/localmemcache"
|
17
|
+
|
18
|
+
int lmc_does_file_exist(const char *fn) {
|
19
|
+
struct stat st;
|
20
|
+
return stat(fn, &st) != -1;
|
21
|
+
}
|
22
|
+
|
23
|
+
void lmc_shm_ensure_root_path() {
|
24
|
+
if (!lmc_does_file_exist(LMC_SHM_ROOT_PATH)) {
|
25
|
+
mkdir(LMC_SHM_ROOT_PATH, 01777);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
void lmc_file_path_for_namespace(char *result, const char *ns) {
|
30
|
+
snprintf(result, 1023, "%s/%s.lmc", LMC_SHM_ROOT_PATH, ns);
|
31
|
+
}
|
32
|
+
|
33
|
+
int lmc_does_namespace_exist(const char *ns) {
|
34
|
+
char fn[1024];
|
35
|
+
lmc_file_path_for_namespace((char *)&fn, ns);
|
36
|
+
return lmc_does_file_exist(fn);
|
37
|
+
}
|
38
|
+
|
39
|
+
int lmc_clean_namespace(const char *ns, lmc_error_t *e) {
|
40
|
+
lmc_shm_ensure_root_path();
|
41
|
+
char fn[1024];
|
42
|
+
lmc_file_path_for_namespace((char *)&fn, ns);
|
43
|
+
if (lmc_does_namespace_exist(ns)) {
|
44
|
+
if (!lmc_handle_error(unlink(fn) == -1, "unlink", e)) { return 0; }
|
45
|
+
}
|
46
|
+
return 1;
|
47
|
+
}
|
48
|
+
|
49
|
+
void lmc_shm_ensure_namespace_file(const char *ns) {
|
50
|
+
lmc_shm_ensure_root_path();
|
51
|
+
char fn[1024];
|
52
|
+
lmc_file_path_for_namespace((char *)&fn, ns);
|
53
|
+
if (!lmc_does_namespace_exist(ns)) { close(open(fn, O_CREAT, 0777)); }
|
54
|
+
}
|
55
|
+
|
56
|
+
lmc_shm_t *lmc_shm_create(const char* namespace, size_t size, int use_persistence,
|
57
|
+
lmc_error_t *e) {
|
58
|
+
lmc_shm_t *mc = calloc(1, sizeof(lmc_shm_t));
|
59
|
+
if (!mc) {
|
60
|
+
lmc_handle_error_with_err_string("lmc_shm_create", "Out of memory", e);
|
61
|
+
return NULL;
|
62
|
+
}
|
63
|
+
strncpy((char *)&mc->namespace, namespace, 1023);
|
64
|
+
mc->use_persistence = 0;
|
65
|
+
mc->size = size;
|
66
|
+
|
67
|
+
lmc_shm_ensure_namespace_file(mc->namespace);
|
68
|
+
char fn[1024];
|
69
|
+
lmc_file_path_for_namespace((char *)&fn, mc->namespace);
|
70
|
+
if (!lmc_handle_error((mc->fd = open(fn, O_RDWR, (mode_t)0777)) == -1,
|
71
|
+
"open", e)) goto open_failed;
|
72
|
+
if (!lmc_handle_error(lseek(mc->fd, mc->size - 1, SEEK_SET) == -1, "lseek", e))
|
73
|
+
goto failed;
|
74
|
+
if (!lmc_handle_error(write(mc->fd, "", 1) != 1, "write", e)) goto failed;
|
75
|
+
mc->base = mmap(0, mc->size, PROT_READ | PROT_WRITE, MAP_SHARED, mc->fd,
|
76
|
+
(off_t)0);
|
77
|
+
if (!lmc_handle_error(mc->base == MAP_FAILED, "mmap", e)) goto failed;
|
78
|
+
return mc;
|
79
|
+
|
80
|
+
failed:
|
81
|
+
close(mc->fd);
|
82
|
+
open_failed:
|
83
|
+
free(mc);
|
84
|
+
return NULL;
|
85
|
+
}
|
86
|
+
|
87
|
+
int lmc_shm_destroy(lmc_shm_t *mc, lmc_error_t *e) {
|
88
|
+
int r = lmc_handle_error(munmap(mc->base, mc->size) == -1, "munmap", e);
|
89
|
+
close(mc->fd);
|
90
|
+
free(mc);
|
91
|
+
return r;
|
92
|
+
}
|
data/src/lmc_shm.h
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2009, Sven C. Koehler
|
3
|
+
*/
|
4
|
+
|
5
|
+
#ifndef _LMC_SHM_H_INCLUDED_
|
6
|
+
#define _LMC_SHM_H_INCLUDED_
|
7
|
+
#include "lmc_error.h"
|
8
|
+
|
9
|
+
typedef struct {
|
10
|
+
int fd;
|
11
|
+
void *base;
|
12
|
+
size_t size;
|
13
|
+
int use_persistence;
|
14
|
+
char namespace[1024];
|
15
|
+
} lmc_shm_t;
|
16
|
+
|
17
|
+
lmc_shm_t *lmc_shm_create(const char *namespace, size_t size, int use_persistence,
|
18
|
+
lmc_error_t *e);
|
19
|
+
int lmc_shm_destroy(lmc_shm_t *mc, lmc_error_t *e);
|
20
|
+
int lmc_does_namespace_exist(const char *ns);
|
21
|
+
int lmc_clean_namespace(const char *ns, lmc_error_t *e);
|
22
|
+
#endif
|