/* * Copyright (c) 2016, NORDUnet A/S. * See LICENSE for licensing information. */ #include #include #include #include #include #include #include #include #include "leveldb/c.h" #include "erlport.h" static const int keylen = 32; static void __attribute__((noreturn)) usage() { errx(1, "usage: leveldbport "); } 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: */