author | Alberto Bertogli
<albertito@gmail.com> 2007-03-28 01:47:43 UTC |
committer | Alberto Bertogli
<albertito@gmail.com> 2007-03-28 01:47:43 UTC |
parent | 8568296068ced9ff713fd60f93be0cffa2f27bf9 |
d/nmdb.d | +177 | -0 |
d/nmdb_ll.d | +52 | -0 |
d/sizeof.c | +17 | -0 |
d/test1c.d | +44 | -0 |
d/testt.d | +21 | -0 |
diff --git a/d/nmdb.d b/d/nmdb.d new file mode 100644 index 0000000..f69344f --- /dev/null +++ b/d/nmdb.d @@ -0,0 +1,177 @@ + +module nmdb; + +import nmdb_ll; + + +/* Exception to raise when a key can't be found. It'd be better to use the + * same D arrays use (ArrayBoundsException) but it's designed for compiler + * use, and the lack of a standard exception hierarchy sucks. */ +class KeyNotFound : Exception { + this(char[] s) { + super(s); + } +} + + +/* Operation modes */ +enum { + MODE_NORMAL = 1, + MODE_CACHE = 2, + MODE_SYNC = 3, +} + + +class DB +{ + private nmdb_t *db; + int mode = MODE_NORMAL; + + + this(int port = 10) + { + db = nmdb_init(port); + } + + ~this() + { + nmdb_free(db); + } + + + private char[] do_get(char[] key, int mode) + { + long size; + ubyte* k = cast(ubyte *) key.ptr; + auto v = new char[256]; + + if (mode == MODE_NORMAL || mode == MODE_SYNC) { + size = nmdb_get(db, k, key.length, + cast(ubyte *) v, v.sizeof); + } else if (mode == MODE_CACHE) { + size = nmdb_cache_get(db, k, key.length, + cast(ubyte *) v, v.sizeof); + } else { + throw new Exception("Invalid mode"); + } + + if (size == 0) { + throw new KeyNotFound("Key not found: " ~ key); + } else if (size < 0) { + throw new Exception("Can't get value"); + } + + return v[0 .. cast(ulong) size]; + } + + private void do_set(char[] key, char[] val, int mode) + { + ubyte* k = cast(ubyte *) key.ptr; + ubyte* v = cast(ubyte *) val.ptr; + int res = 0; + + if (mode == MODE_NORMAL) { + res = nmdb_set(db, k, key.length, v, val.length); + } else if (mode == MODE_SYNC) { + res = nmdb_set_sync(db, k, key.length, + v, val.length); + } else if (mode == MODE_CACHE) { + res = nmdb_cache_set(db, k, key.length, + v, val.length); + } else { + throw new Exception("Invalid mode"); + } + + if (res != 1) { + throw new Exception("Can't set value"); + } + } + + private int do_del(char[] key, int mode) + { + ubyte* k = cast(ubyte *) key.ptr; + int res = 0; + + if (mode == MODE_NORMAL) { + res = nmdb_del(db, k, key.length); + } else if (mode == MODE_SYNC) { + res = nmdb_del_sync(db, k, key.length); + } else if (mode == MODE_CACHE) { + res = nmdb_cache_del(db, k, key.length); + } else { + throw new Exception("Invalid mode"); + } + return res; + } + + + char[] get(char[] key) + { + return do_get(key, mode); + } + + char[] get_normal(char[] key) + { + return do_get(key, MODE_NORMAL); + } + + char[] cache_get(char[] key) + { + return do_get(key, MODE_CACHE); + } + + + void set(char[] key, char[] val) + { + return do_set(key, val, mode); + } + + void set_normal(char[] key, char[] val) + { + return do_set(key, val, MODE_NORMAL); + } + + void set_sync(char[] key, char[] val) + { + return do_set(key, val, MODE_SYNC); + } + + void cache_set(char[] key, char[] val) + { + return do_set(key, val, MODE_CACHE); + } + + + int remove(char[] key) + { + return do_del(key, mode); + } + + int remove_normal(char[] key) + { + return do_del(key, MODE_NORMAL); + } + + int remove_sync(char[] key) + { + return do_del(key, MODE_SYNC); + } + + int cache_remove(char[] key) + { + return do_del(key, MODE_CACHE); + } + + + char[] opIndex(char[] key) + { + return get(key); + } + + void opIndexAssign(char[] val, char[] key) + { + return set(key, val); + } + +} + diff --git a/d/nmdb_ll.d b/d/nmdb_ll.d new file mode 100644 index 0000000..8750eea --- /dev/null +++ b/d/nmdb_ll.d @@ -0,0 +1,52 @@ + +module nmdb_ll; + + +/* We need to define the nmdb_t type used by the C API. + * + * One possiblity is to import the C struct here (alignment and stuff is + * supposed to be the same), but since it includes some OS structures like + * sockaddr_tipc, it means several lines of code and it's difficult to + * maintain. Because to us it's an opaque type, we define it to be an ubyte + * array of the same length as C's struct nmdb_t. That way we retain ABI + * compatibility but minimize the clutter. + * + * To port this to another architecture, just compile and run the "sizeof.c" + * program. It should output some lines like "sizeof(struct nmdb_t) = 16". + * Then use that information to define the aliases for your platform. + * + * Should nmdb_t change, the numbers must be updated to reflect the new sizes. + */ + +version (X86_64) { + /* The following has been generated on a Pentium D running Gentoo in + * 64 bit mode. It should be the same on all Linux amd64 boxes. */ + alias ubyte[16] nmdb_t; + alias ulong size_t; + alias long ssize_t; +} + + +/* nmdb structures and prototypes, these shouldn't need any changes + * unless libnmdb/nmdb.h is updated */ + +extern (C) nmdb_t *nmdb_init(int port); +extern (C) int nmdb_add_server(nmdb_t *db, int port); +extern (C) int nmdb_free(nmdb_t *db); + +extern (C) ssize_t nmdb_get(nmdb_t *db, ubyte *key, size_t ksize, + ubyte *val, size_t vsize); +extern (C) ssize_t nmdb_cache_get(nmdb_t *db, ubyte *key, size_t ksize, + ubyte *val, size_t vsize); + +extern (C) int nmdb_set(nmdb_t *db, ubyte *key, size_t ksize, + ubyte *val, size_t vsize); +extern (C) int nmdb_set_sync(nmdb_t *db, ubyte *key, size_t ksize, + ubyte *val, size_t vsize); +extern (C) int nmdb_cache_set(nmdb_t *db, ubyte *key, size_t ksize, + ubyte *val, size_t vsize); + +extern (C) int nmdb_del(nmdb_t *db, ubyte *key, size_t ksize); +extern (C) int nmdb_del_sync(nmdb_t *db, ubyte *key, size_t ksize); +extern (C) int nmdb_cache_del(nmdb_t *db, ubyte *key, size_t ksize); + diff --git a/d/sizeof.c b/d/sizeof.c new file mode 100644 index 0000000..93d053a --- /dev/null +++ b/d/sizeof.c @@ -0,0 +1,17 @@ + +/* sizeof.c + * Used to find out the size of some intresting structures and data types, to + * help defining D's bindings. + */ + +#include <stdio.h> +#include <nmdb.h> + +int main() +{ + printf("sizeof(struct nmdb_t) = %lu\n", sizeof(struct nmdb_t)); + printf("sizeof(size_t) = %lu\n", sizeof(size_t)); + printf("sizeof(ssize_t) = %lu\n", sizeof(ssize_t)); + return 0; +} + diff --git a/d/test1c.d b/d/test1c.d new file mode 100644 index 0000000..1bbffc9 --- /dev/null +++ b/d/test1c.d @@ -0,0 +1,44 @@ + +import nmdb; +import std.stdio; +import std.stream; +import std.string; +import std.perf; + + +int main(char [][] argv) +{ + if (argv.length != 2) { + writefln("Usage: test1d TIMES"); + return 1; + } + + auto times = atoi(argv[1]); + char[] val; + + nmdb.DB db = new nmdb.DB(10); + db.mode = nmdb.MODE_CACHE; + + auto counter = new PerformanceCounter; + + counter.start(); + for (int i = 0; i < times; i++) + db["1"] = "D"; + counter.stop(); + writefln("d set: ", counter.microseconds()); + + counter.start(); + for (int i = 0; i < times; i++) + val = db["1"]; + counter.stop(); + writefln("d get: ", counter.microseconds()); + + counter.start(); + for (int i = 0; i < times; i++) + db.remove("1"); + counter.stop(); + writefln("d del: ", counter.microseconds()); + + return 0; +} + diff --git a/d/testt.d b/d/testt.d new file mode 100644 index 0000000..78e080a --- /dev/null +++ b/d/testt.d @@ -0,0 +1,21 @@ + +import nmdb; +import std.stdio; +import std.stream; + + +int main() +{ + char[] val1; + + nmdb.DB db = new nmdb.DB(); + + db.mode = MODE_CACHE; + db["1"] = "D"; + val1 = db["1"]; + + writefln(val1); + + return 0; +} +