Getting optional LMDB support into Cytoplasm #43
1 changed files with 201 additions and 4 deletions
205
src/Db/LMDB.c
205
src/Db/LMDB.c
|
@ -68,6 +68,203 @@ LMDBKillKey(MDB_val key)
|
||||||
|
|
||||||
Free(key.mv_data);
|
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
|
static bool
|
||||||
LMDBUnlock(Db *d, DbRef *r)
|
LMDBUnlock(Db *d, DbRef *r)
|
||||||
|
@ -256,13 +453,13 @@ DbOpenLMDB(char *dir, size_t size)
|
||||||
DbInit((Db *) db);
|
DbInit((Db *) db);
|
||||||
db->environ = env;
|
db->environ = env;
|
||||||
|
|
||||||
db->base.lockFunc = NULL;
|
db->base.lockFunc = LMDBLock;
|
||||||
db->base.create = LMDBCreate;
|
db->base.create = LMDBCreate;
|
||||||
db->base.unlock = LMDBUnlock;
|
db->base.unlock = LMDBUnlock;
|
||||||
db->base.delete = NULL;
|
db->base.delete = LMDBDelete;
|
||||||
db->base.exists = NULL;
|
db->base.exists = LMDBExists;
|
||||||
db->base.close = LMDBClose;
|
db->base.close = LMDBClose;
|
||||||
db->base.list = NULL;
|
db->base.list = NULL; /* TODO: This one is gonna be Fun. */
|
||||||
|
|
||||||
return (Db *) db;
|
return (Db *) db;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue