Getting optional LMDB support into Cytoplasm #43

Merged
jordan merged 14 commits from lda/Cytoplasm:lmdbwerk into master 2024-08-23 20:19:59 +00:00
Showing only changes of commit e133eebef3 - Show all commits

View file

@ -17,6 +17,7 @@ typedef struct LMDB {
Db base; /* The base implementation required to pass */ Db base; /* The base implementation required to pass */
MDB_env *environ; MDB_env *environ;
MDB_dbi dbi;
} LMDB; } LMDB;
typedef struct LMDBRef { typedef struct LMDBRef {
DbRef base; DbRef base;
@ -140,8 +141,7 @@ LMDBLock(Db *d, DbHint hint, Array *k)
LMDB *db = (LMDB *) d; LMDB *db = (LMDB *) d;
MDB_txn *transaction; MDB_txn *transaction;
LMDBRef *ret = NULL; LMDBRef *ret = NULL;
MDB_val key, empty_json; MDB_val key, json_val;
MDB_dbi dbi;
int code, flags; int code, flags;
if (!d || !k) if (!d || !k)
{ {
@ -151,7 +151,9 @@ LMDBLock(Db *d, DbHint hint, Array *k)
pthread_mutex_lock(&d->lock); pthread_mutex_lock(&d->lock);
key = LMDBTranslateKey(k); key = LMDBTranslateKey(k);
/* create a txn */ /* Create a transaction, honoring hints. */
/* TODO: Do we want to create a "main" transaction that everyone inherits
* from? */
flags = hint == DB_HINT_READONLY ? MDB_RDONLY : 0; flags = hint == DB_HINT_READONLY ? MDB_RDONLY : 0;
if ((code = mdb_txn_begin(db->environ, NULL, flags, &transaction)) != 0) if ((code = mdb_txn_begin(db->environ, NULL, flags, &transaction)) != 0)
{ {
@ -162,25 +164,13 @@ LMDBLock(Db *d, DbHint hint, Array *k)
); );
goto end; 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;
}
empty_json.mv_size = 0; json_val.mv_size = 0;
empty_json.mv_data = NULL; json_val.mv_data = NULL;
/* get data from it */ code = mdb_get(transaction, db->dbi, &key, &json_val);
code = mdb_get(transaction, dbi, &key, &empty_json);
if (code == MDB_NOTFOUND) if (code == MDB_NOTFOUND)
{ {
/* No use logging it, as that is just locking behaviour */
mdb_txn_abort(transaction); mdb_txn_abort(transaction);
mdb_dbi_close(db->environ, dbi);
goto end; goto end;
} }
else if (code != 0) else if (code != 0)
@ -190,7 +180,6 @@ LMDBLock(Db *d, DbHint hint, Array *k)
__func__, mdb_strerror(code) __func__, mdb_strerror(code)
); );
mdb_txn_abort(transaction); mdb_txn_abort(transaction);
mdb_dbi_close(db->environ, dbi);
goto end; goto end;
} }
@ -206,19 +195,17 @@ LMDBLock(Db *d, DbHint hint, Array *k)
StringArrayAppend(ret->base.name, ent); StringArrayAppend(ret->base.name, ent);
} }
} }
ret->base.json = LMDBDecode(empty_json); ret->base.json = LMDBDecode(json_val);
ret->base.hint = hint; ret->base.hint = hint;
ret->transaction = NULL; ret->transaction = NULL;
if (hint == DB_HINT_WRITE) if (hint == DB_HINT_WRITE)
{ {
ret->transaction = transaction; ret->transaction = transaction;
ret->dbi = dbi;
} }
else else
{ {
mdb_txn_abort(transaction); mdb_txn_abort(transaction);
mdb_dbi_close(db->environ, dbi);
} }
end: end:
if (!ret || hint == DB_HINT_READONLY) if (!ret || hint == DB_HINT_READONLY)
@ -234,7 +221,6 @@ LMDBExists(Db *d, Array *k)
MDB_val key, empty; MDB_val key, empty;
LMDB *db = (LMDB *) d; LMDB *db = (LMDB *) d;
MDB_txn *transaction; MDB_txn *transaction;
MDB_dbi dbi;
int code; int code;
bool ret = false; bool ret = false;
if (!d || !k) if (!d || !k)
@ -255,21 +241,9 @@ LMDBExists(Db *d, Array *k)
); );
goto end; 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, db->dbi, &key, &empty) == 0;
ret = mdb_get(transaction, dbi, &key, &empty) == 0;
mdb_txn_abort(transaction); mdb_txn_abort(transaction);
mdb_dbi_close(db->environ, dbi);
end: end:
LMDBKillKey(key); LMDBKillKey(key);
pthread_mutex_unlock(&d->lock); pthread_mutex_unlock(&d->lock);
@ -281,7 +255,6 @@ LMDBDelete(Db *d, Array *k)
MDB_val key, empty; MDB_val key, empty;
LMDB *db = (LMDB *) d; LMDB *db = (LMDB *) d;
MDB_txn *transaction; MDB_txn *transaction;
MDB_dbi dbi;
int code; int code;
bool ret = false; bool ret = false;
if (!d || !k) if (!d || !k)
@ -302,21 +275,9 @@ LMDBDelete(Db *d, Array *k)
); );
goto end; 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, db->dbi, &key, &empty) == 0;
ret = mdb_del(transaction, dbi, &key, &empty) == 0;
mdb_txn_commit(transaction); mdb_txn_commit(transaction);
mdb_dbi_close(db->environ, dbi);
end: end:
LMDBKillKey(key); LMDBKillKey(key);
pthread_mutex_unlock(&d->lock); pthread_mutex_unlock(&d->lock);
@ -350,10 +311,9 @@ LMDBUnlock(Db *d, DbRef *r)
StreamFlush(stream); StreamFlush(stream);
StreamClose(stream); StreamClose(stream);
ret = mdb_put(ref->transaction, ref->dbi, &key, &val, 0) == 0; ret = mdb_put(ref->transaction, db->dbi, &key, &val, 0) == 0;
mdb_txn_commit(ref->transaction); mdb_txn_commit(ref->transaction);
mdb_dbi_close(db->environ, ref->dbi);
LMDBKillKey(key); LMDBKillKey(key);
} }
StringArrayFree(ref->base.name); StringArrayFree(ref->base.name);
@ -377,7 +337,6 @@ LMDBCreate(Db *d, Array *k)
MDB_txn *transaction; MDB_txn *transaction;
LMDBRef *ret = NULL; LMDBRef *ret = NULL;
MDB_val key, empty_json; MDB_val key, empty_json;
MDB_dbi dbi;
int code; int code;
if (!d || !k) if (!d || !k)
{ {
@ -397,38 +356,25 @@ LMDBCreate(Db *d, Array *k)
); );
goto end; 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;
}
empty_json.mv_size = 2; empty_json.mv_size = 2;
empty_json.mv_data = "{}"; empty_json.mv_data = "{}";
/* put data in it */ /* put data in it */
code = mdb_put(transaction, dbi, &key, &empty_json, MDB_NOOVERWRITE); code = mdb_put(transaction, db->dbi, &key, &empty_json, MDB_NOOVERWRITE);
if (code == MDB_KEYEXIST) if (code == MDB_KEYEXIST)
{ {
mdb_dbi_close(db->environ, dbi);
mdb_txn_abort(transaction); mdb_txn_abort(transaction);
goto end; goto end;
} }
else if (code == MDB_MAP_FULL) else if (code == MDB_MAP_FULL)
{ {
Log(LOG_ERR, "%s: db is full", __func__); Log(LOG_ERR, "%s: db is full", __func__);
mdb_dbi_close(db->environ, dbi);
mdb_txn_abort(transaction); mdb_txn_abort(transaction);
goto end; goto end;
} }
else if (code != 0) else if (code != 0)
{ {
Log(LOG_ERR, "%s: mdb_put failure: %s", __func__, mdb_strerror(code)); Log(LOG_ERR, "%s: mdb_put failure: %s", __func__, mdb_strerror(code));
mdb_dbi_close(db->environ, dbi);
mdb_txn_abort(transaction); mdb_txn_abort(transaction);
goto end; goto end;
} }
@ -448,7 +394,6 @@ LMDBCreate(Db *d, Array *k)
ret->base.hint = DB_HINT_WRITE; ret->base.hint = DB_HINT_WRITE;
ret->base.json = HashMapCreate(); ret->base.json = HashMapCreate();
ret->transaction = transaction; ret->transaction = transaction;
ret->dbi = dbi;
end: end:
if (!ret) if (!ret)
{ {
@ -470,7 +415,6 @@ LMDBList(Db *d, Array *k)
MDB_cursor *cursor; MDB_cursor *cursor;
MDB_cursor_op op = MDB_SET_RANGE; MDB_cursor_op op = MDB_SET_RANGE;
MDB_txn *txn; MDB_txn *txn;
MDB_dbi dbi;
int code; int code;
if (!d || !k) if (!d || !k)
@ -482,7 +426,7 @@ LMDBList(Db *d, Array *k)
/* Marked as read-only, as we just don't need to write anything /* Marked as read-only, as we just don't need to write anything
* when listing */ * when listing */
if ((code = mdb_txn_begin(db->environ, NULL, 0, &txn)) != 0) if ((code = mdb_txn_begin(db->environ, NULL, MDB_RDONLY, &txn)) != 0)
{ {
/* Very bad! */ /* Very bad! */
Log(LOG_ERR, Log(LOG_ERR,
@ -491,24 +435,13 @@ LMDBList(Db *d, Array *k)
); );
goto end; goto end;
} }
/* apparently you need to give it a dbi */ if ((code = mdb_cursor_open(txn, db->dbi, &cursor)) != 0)
if ((code = mdb_dbi_open(txn, "db", MDB_CREATE, &dbi)) != 0)
{
Log(LOG_ERR,
"%s: could not get transaction dbi: %s",
__func__, mdb_strerror(code)
);
mdb_txn_abort(txn);
goto end;
}
if ((code = mdb_cursor_open(txn, dbi, &cursor)) != 0)
{ {
Log(LOG_ERR, Log(LOG_ERR,
"%s: could not get cursor: %s", "%s: could not get cursor: %s",
__func__, mdb_strerror(code) __func__, mdb_strerror(code)
); );
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_dbi_close(db->environ, dbi);
goto end; goto end;
} }
@ -536,7 +469,6 @@ LMDBList(Db *d, Array *k)
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_dbi_close(db->environ, dbi);
end: end:
LMDBKillKey(key); LMDBKillKey(key);
@ -554,6 +486,7 @@ LMDBClose(Db *d)
return; return;
} }
mdb_dbi_close(db->environ, db->dbi);
mdb_env_close(db->environ); mdb_env_close(db->environ);
} }
@ -562,6 +495,8 @@ DbOpenLMDB(char *dir, size_t size)
{ {
/* TODO */ /* TODO */
MDB_env *env = NULL; MDB_env *env = NULL;
MDB_txn *txn;
MDB_dbi dbi;
int code; int code;
LMDB *db; LMDB *db;
if (!dir || !size) if (!dir || !size)
@ -599,10 +534,35 @@ DbOpenLMDB(char *dir, size_t size)
return NULL; return NULL;
} }
/* Initialise a DBI */
{
if ((code = mdb_txn_begin(env, NULL, 0, &txn)) != 0)
{
Log(LOG_ERR,
"%s: could not begin transaction: %s",
__func__, mdb_strerror(code)
);
mdb_env_close(env);
return NULL;
}
if ((code = mdb_dbi_open(txn, "db", MDB_CREATE, &dbi)) != 0)
{
Log(LOG_ERR,
"%s: could not get transaction dbi: %s",
__func__, mdb_strerror(code)
);
mdb_txn_abort(txn);
mdb_env_close(env);
return NULL;
}
mdb_txn_commit(txn);
}
db = Malloc(sizeof(*db)); db = Malloc(sizeof(*db));
DbInit((Db *) db); DbInit((Db *) db);
db->environ = env; db->environ = env;
db->dbi = dbi;
db->base.lockFunc = LMDBLock; db->base.lockFunc = LMDBLock;
db->base.create = LMDBCreate; db->base.create = LMDBCreate;