From 074340195571f292f9a487d98fbd8d426b3c585a Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 8 Aug 2024 16:25:09 +0200 Subject: [PATCH] [ADD/WIP] Most DB operations for LMDB Somewhat untested. I want to go on a test run soon. Next up: aargh... listing... The one thing LMDB may suck at. --- src/Db/LMDB.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 4 deletions(-) diff --git a/src/Db/LMDB.c b/src/Db/LMDB.c index a5750b9..1e25c30 100644 --- a/src/Db/LMDB.c +++ b/src/Db/LMDB.c @@ -68,6 +68,203 @@ LMDBKillKey(MDB_val key) Free(key.mv_data); } +static HashMap * +LMDBDecode(MDB_val val) +{ + FILE *fakefile; + Stream *fakestream; + HashMap *ret; + if (!val.mv_data || !val.mv_size) + { + return NULL; + } + + fakefile = fmemopen(val.mv_data, val.mv_size, "r"); + fakestream = StreamFile(fakefile); + ret = JsonDecode(fakestream); + StreamClose(fakestream); + + return ret; +} + +static DbRef * +LMDBLock(Db *d, Array *k) +{ + LMDB *db = (LMDB *) d; + MDB_txn *transaction; + LMDBRef *ret = NULL; + MDB_val key, empty_json; + MDB_dbi dbi; + int code; + if (!d || !k) + { + return NULL; + } + + pthread_mutex_lock(&d->lock); + key = LMDBTranslateKey(k); + + /* create a txn */ + if ((code = mdb_txn_begin(db->environ, NULL, 0, &transaction)) != 0) + { + /* Very bad! */ + Log(LOG_ERR, + "%s: could not begin transaction: %s", + __func__, mdb_strerror(code) + ); + pthread_mutex_unlock(&d->lock); + goto end; + } + /* apparently you need to give it a dbi */ + if ((code = mdb_dbi_open(transaction, "db", MDB_CREATE, &dbi)) != 0) + { + Log(LOG_ERR, + "%s: could not get transaction dbi: %s", + __func__, mdb_strerror(code) + ); + pthread_mutex_unlock(&d->lock); + goto end; + + } + + empty_json.mv_size = 0; + empty_json.mv_data = NULL; + /* get data from it */ + code = mdb_get(transaction, dbi, &key, &empty_json); + if (code == MDB_NOTFOUND) + { + Log(LOG_ERR, + "%s: mdb_get failure: %s", + __func__, mdb_strerror(code) + ); + mdb_txn_abort(transaction); + mdb_dbi_close(db->environ, dbi); + goto end; + } + else if (code != 0) + { + Log(LOG_ERR, + "%s: mdb_get failure: %s", + __func__, mdb_strerror(code) + ); + mdb_txn_abort(transaction); + mdb_dbi_close(db->environ, dbi); + goto end; + } + + ret = Malloc(sizeof(*ret)); + DbRefInit(d, (DbRef *) ret); + /* TODO: Timestamp */ + { + size_t i; + ret->base.name = ArrayCreate(); + for (i = 0; i < ArraySize(k); i++) + { + char *ent = ArrayGet(k, i); + StringArrayAppend(ret->base.name, ent); + } + } + ret->base.json = LMDBDecode(empty_json); + ret->transaction = transaction; + ret->dbi = dbi; +end: + LMDBKillKey(key); + return (DbRef *) ret; +} +static bool +LMDBExists(Db *d, Array *k) +{ + MDB_val key, empty; + LMDB *db = (LMDB *) d; + MDB_txn *transaction; + MDB_dbi dbi; + int code; + bool ret = false; + if (!d || !k) + { + return false; + } + + pthread_mutex_lock(&d->lock); + key = LMDBTranslateKey(k); + + /* create a txn */ + if ((code = mdb_txn_begin(db->environ, NULL, 0, &transaction)) != 0) + { + /* Very bad! */ + Log(LOG_ERR, + "%s: could not begin transaction: %s", + __func__, mdb_strerror(code) + ); + goto end; + } + /* apparently you need to give it a dbi */ + if ((code = mdb_dbi_open(transaction, "db", MDB_CREATE, &dbi)) != 0) + { + Log(LOG_ERR, + "%s: could not get transaction dbi: %s", + __func__, mdb_strerror(code) + ); + goto end; + + } + + ret = mdb_get(transaction, dbi, &key, &empty) == 0; + mdb_txn_abort(transaction); + mdb_dbi_close(db->environ, dbi); + +end: + LMDBKillKey(key); + pthread_mutex_unlock(&d->lock); + return ret; +} +static bool +LMDBDelete(Db *d, Array *k) +{ + MDB_val key, empty; + LMDB *db = (LMDB *) d; + MDB_txn *transaction; + MDB_dbi dbi; + int code; + bool ret = false; + if (!d || !k) + { + return false; + } + + pthread_mutex_lock(&d->lock); + key = LMDBTranslateKey(k); + + /* create a txn */ + if ((code = mdb_txn_begin(db->environ, NULL, 0, &transaction)) != 0) + { + /* Very bad! */ + Log(LOG_ERR, + "%s: could not begin transaction: %s", + __func__, mdb_strerror(code) + ); + goto end; + } + /* apparently you need to give it a dbi */ + if ((code = mdb_dbi_open(transaction, "db", MDB_CREATE, &dbi)) != 0) + { + Log(LOG_ERR, + "%s: could not get transaction dbi: %s", + __func__, mdb_strerror(code) + ); + goto end; + + } + + ret = mdb_del(transaction, dbi, &key, &empty) == 0; + mdb_txn_commit(transaction); + mdb_dbi_close(db->environ, dbi); + +end: + LMDBKillKey(key); + pthread_mutex_unlock(&d->lock); + return ret; +} static bool LMDBUnlock(Db *d, DbRef *r) @@ -256,13 +453,13 @@ DbOpenLMDB(char *dir, size_t size) DbInit((Db *) db); db->environ = env; - db->base.lockFunc = NULL; + db->base.lockFunc = LMDBLock; db->base.create = LMDBCreate; db->base.unlock = LMDBUnlock; - db->base.delete = NULL; - db->base.exists = NULL; + db->base.delete = LMDBDelete; + db->base.exists = LMDBExists; db->base.close = LMDBClose; - db->base.list = NULL; + db->base.list = NULL; /* TODO: This one is gonna be Fun. */ return (Db *) db; }