diff options
Diffstat (limited to 'c_src/leveldbport.c')
-rw-r--r-- | c_src/leveldbport.c | 154 |
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: */ |