summaryrefslogtreecommitdiff
path: root/c_src/leveldbport.c
diff options
context:
space:
mode:
Diffstat (limited to 'c_src/leveldbport.c')
-rw-r--r--c_src/leveldbport.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/c_src/leveldbport.c b/c_src/leveldbport.c
new file mode 100644
index 0000000..000a804
--- /dev/null
+++ b/c_src/leveldbport.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2016, NORDUnet A/S.
+ * See LICENSE for licensing information.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <assert.h>
+#include <err.h>
+#include <sys/resource.h>
+#include "leveldb/c.h"
+#include "erlport.h"
+
+static const int keylen = 32;
+
+static void __attribute__((noreturn))
+usage()
+{
+ errx(1, "usage: leveldbport <path>");
+}
+
+static void
+getvalue(leveldb_t *db, const char *key)
+{
+ leveldb_readoptions_t *opt = leveldb_readoptions_create();
+ size_t vallen = 0;
+ char *err = NULL;
+ char *val = leveldb_get(db, opt, key, keylen, &vallen, &err);
+ leveldb_readoptions_destroy(opt);
+ if (err) {
+ fprintf(stderr, "leveldb_get: %s\n", err);
+ free(err);
+ write_reply(NULL, 0, 4);
+ return;
+ }
+ write_reply((unsigned char *) val, vallen, 4);
+ free(val);
+}
+
+static void
+addvalue(leveldb_t *db, const char *key, const char *val, size_t vallen)
+{
+ leveldb_writeoptions_t *opt = leveldb_writeoptions_create();
+ char *err = NULL;
+ leveldb_put(db, opt, key, keylen, val, vallen, &err);
+ leveldb_writeoptions_destroy(opt);
+ if (err) {
+ fprintf(stderr, "leveldb_put: %s\n", err);
+ free(err);
+ write_reply(NULL, 0, 4);
+ return;
+ }
+ unsigned char result = (unsigned char) 1;
+ write_reply(&result, 1, 4);
+}
+
+static void
+commit(leveldb_t *db)
+{
+ unsigned char result = (unsigned char) 0;
+ write_reply(&result, 1, 4);
+}
+
+static void
+portloop(leveldb_t *db)
+{
+ unsigned char buf[65536];
+ ssize_t len;
+ while ((len = read_command(buf, sizeof(buf) - 1, 4)) > 0) {
+ switch(buf[0]) {
+ case 0:
+ if (len != keylen + 1) {
+ write_reply(NULL, 0, 4);
+ } else {
+ const char *key = (char *) buf + 1;
+ getvalue(db, key);
+ }
+ break;
+ case 1:
+ if (len < keylen + 1) {
+ write_reply(NULL, 0, 4);
+ } else {
+ const char *key = (char *) buf + 1;
+ const char *val = key + keylen;
+ size_t vallen = len - 1 - keylen;
+ addvalue(db, key, val, vallen);
+ }
+ break;
+ case 2:
+ commit(db);
+ break;
+ default:
+ write_reply(NULL, 0, 4);
+ }
+ }
+}
+
+static leveldb_t*
+db_alloc(const char* name)
+{
+ leveldb_options_t *opt = leveldb_options_create();
+ leveldb_options_set_create_if_missing(opt, 1);
+ char *err = NULL;
+ leveldb_t *db = leveldb_open(opt, name, &err);
+ leveldb_options_destroy(opt);
+ if (err) {
+ fprintf(stderr, "error opening database: %s\n", err);
+ free(err);
+ return NULL;
+ }
+ return db;
+}
+
+static void
+db_free(leveldb_t *db)
+{
+ free(db);
+}
+
+int
+main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ usage();
+ }
+ const char *name = argv[1];
+
+ fprintf(stderr, "leveldbport starting with db '%s'\n", name);
+
+ leveldb_t *state = db_alloc(name);
+ if (state == NULL) {
+ write_reply(NULL, 0, 4);
+ return 1;
+ }
+
+ portloop(state);
+ db_free(state);
+
+ struct rusage rusage;
+ getrusage(RUSAGE_SELF, &rusage);
+ fprintf(stderr, "leveldbport user %ld.%d sys %ld.%d maxrss %ld M\n",
+ rusage.ru_utime.tv_sec, (int)rusage.ru_utime.tv_usec,
+ rusage.ru_stime.tv_sec, (int)rusage.ru_utime.tv_usec,
+ rusage.ru_maxrss/1024);
+
+ return 0;
+}
+
+/* Local Variables: */
+/* c-file-style: "BSD" */
+/* End: */