2016-11-17 20:07:59 +00:00
|
|
|
/***
|
|
|
|
* Here are the wrappers for the lightning database
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
2016-11-30 16:46:41 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
2016-11-17 20:07:59 +00:00
|
|
|
|
|
|
|
#include "lmdb.h"
|
|
|
|
#include "ipfs/repo/fsrepo/lmdb_datastore.h"
|
|
|
|
|
2016-12-05 22:23:58 +00:00
|
|
|
int repo_fsrepo_lmdb_get_block(const struct Cid* cid, struct Block** block, const struct Datastore* datastore) {
|
|
|
|
int retVal;
|
|
|
|
MDB_txn* mdb_txn;
|
|
|
|
MDB_dbi mdb_dbi;
|
|
|
|
struct MDB_val db_key;
|
|
|
|
struct MDB_val db_value;
|
|
|
|
|
|
|
|
MDB_env* mdb_env = (MDB_env*)datastore->handle;
|
|
|
|
if (mdb_env == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// open transaction
|
|
|
|
retVal = mdb_txn_begin(mdb_env, NULL, 0, &mdb_txn);
|
|
|
|
if (retVal != 0)
|
|
|
|
return 0;
|
|
|
|
retVal = mdb_dbi_open(mdb_txn, NULL, MDB_DUPSORT, &mdb_dbi);
|
|
|
|
if (retVal != 0) {
|
|
|
|
mdb_txn_commit(mdb_txn);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// prepare data
|
|
|
|
db_key.mv_size = cid->hash_length;
|
|
|
|
db_key.mv_data = cid->hash;
|
|
|
|
|
|
|
|
retVal = mdb_get(mdb_txn, mdb_dbi, &db_key, &db_value);
|
|
|
|
if (retVal != 0) {
|
|
|
|
mdb_dbi_close(mdb_env, mdb_dbi);
|
|
|
|
mdb_txn_commit(mdb_txn);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now copy the data
|
|
|
|
retVal = ipfs_blocks_block_new(db_value.mv_data, db_value.mv_size, block);
|
|
|
|
if (retVal == 0) {
|
|
|
|
mdb_dbi_close(mdb_env, mdb_dbi);
|
|
|
|
mdb_txn_commit(mdb_txn);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clean up
|
|
|
|
mdb_dbi_close(mdb_env, mdb_dbi);
|
|
|
|
mdb_txn_commit(mdb_txn);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* retrieve a record from the database and put in a pre-sized buffer
|
|
|
|
* @param key the key to look for
|
|
|
|
* @param key_size the length of the key
|
|
|
|
* @param data the data that is retrieved
|
|
|
|
* @param max_data_size the length of the data buffer
|
|
|
|
* @param data_size the length of the data that was found in the database
|
|
|
|
* @param datastore where to look for the data
|
|
|
|
* @returns true(1) on success
|
|
|
|
*/
|
|
|
|
int repo_fsrepo_lmdb_get(const char* key, size_t key_size, unsigned char* data, size_t max_data_size, size_t* data_size, const struct Datastore* datastore) {
|
|
|
|
int retVal;
|
|
|
|
MDB_txn* mdb_txn;
|
|
|
|
MDB_dbi mdb_dbi;
|
|
|
|
struct MDB_val db_key;
|
|
|
|
struct MDB_val db_value;
|
|
|
|
|
|
|
|
MDB_env* mdb_env = (MDB_env*)datastore->handle;
|
|
|
|
if (mdb_env == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// open transaction
|
|
|
|
retVal = mdb_txn_begin(mdb_env, NULL, 0, &mdb_txn);
|
|
|
|
if (retVal != 0)
|
|
|
|
return 0;
|
|
|
|
retVal = mdb_dbi_open(mdb_txn, NULL, MDB_DUPSORT, &mdb_dbi);
|
|
|
|
if (retVal != 0) {
|
|
|
|
mdb_txn_commit(mdb_txn);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// prepare data
|
|
|
|
db_key.mv_size = key_size;
|
|
|
|
db_key.mv_data = (char*)key;
|
|
|
|
|
|
|
|
retVal = mdb_get(mdb_txn, mdb_dbi, &db_key, &db_value);
|
|
|
|
if (retVal != 0) {
|
|
|
|
mdb_dbi_close(mdb_env, mdb_dbi);
|
|
|
|
mdb_txn_commit(mdb_txn);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now copy the data
|
|
|
|
if (db_value.mv_size > max_data_size) {
|
|
|
|
mdb_dbi_close(mdb_env, mdb_dbi);
|
|
|
|
mdb_txn_commit(mdb_txn);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set return values
|
|
|
|
memcpy(data, db_value.mv_data, db_value.mv_size);
|
|
|
|
(*data_size) = db_value.mv_size;
|
|
|
|
|
|
|
|
// clean up
|
|
|
|
mdb_dbi_close(mdb_env, mdb_dbi);
|
|
|
|
mdb_txn_commit(mdb_txn);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-11-30 16:46:41 +00:00
|
|
|
/**
|
2016-12-05 22:23:58 +00:00
|
|
|
* Write data to the datastore with the specified key
|
2016-11-30 16:46:41 +00:00
|
|
|
* @param key the key
|
2016-12-05 22:23:58 +00:00
|
|
|
* @param key_size the length of the key
|
|
|
|
* @param data the data to be written
|
|
|
|
* @param data_size the length of the data to be written
|
|
|
|
* @param datastore the datastore to write to
|
2016-11-30 16:46:41 +00:00
|
|
|
* @returns true(1) on success
|
|
|
|
*/
|
2016-12-05 22:23:58 +00:00
|
|
|
int repo_fsrepo_lmdb_put(unsigned const char* key, size_t key_size, unsigned char* data, size_t data_size, const struct Datastore* datastore) {
|
2016-11-30 16:46:41 +00:00
|
|
|
int retVal;
|
|
|
|
MDB_txn* mdb_txn;
|
|
|
|
MDB_dbi mdb_dbi;
|
|
|
|
struct MDB_val db_key;
|
|
|
|
struct MDB_val db_value;
|
|
|
|
|
|
|
|
MDB_env* mdb_env = (MDB_env*)datastore->handle;
|
|
|
|
if (mdb_env == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// open transaction
|
|
|
|
retVal = mdb_txn_begin(mdb_env, NULL, 0, &mdb_txn);
|
|
|
|
if (retVal != 0)
|
|
|
|
return 0;
|
2016-12-05 19:34:10 +00:00
|
|
|
retVal = mdb_dbi_open(mdb_txn, NULL, MDB_DUPSORT, &mdb_dbi);
|
2016-11-30 16:46:41 +00:00
|
|
|
if (retVal != 0)
|
|
|
|
return 0;
|
|
|
|
|
2016-12-05 19:34:10 +00:00
|
|
|
// prepare data
|
2016-12-01 18:08:30 +00:00
|
|
|
db_key.mv_size = key_size;
|
2016-11-30 16:46:41 +00:00
|
|
|
db_key.mv_data = (char*)key;
|
2016-12-05 19:34:10 +00:00
|
|
|
|
|
|
|
// write
|
2016-12-05 11:54:21 +00:00
|
|
|
db_value.mv_size = data_size;
|
|
|
|
db_value.mv_data = data;
|
2016-12-05 19:34:10 +00:00
|
|
|
retVal = mdb_put(mdb_txn, mdb_dbi, &db_key, &db_value, MDB_NODUPDATA | MDB_NOOVERWRITE);
|
|
|
|
if (retVal == 0) // the normal case
|
|
|
|
retVal = 1;
|
|
|
|
else {
|
|
|
|
if (retVal == MDB_KEYEXIST) // We tried to add a key that already exists. Skip.
|
|
|
|
retVal = 1;
|
|
|
|
else
|
|
|
|
retVal = 0;
|
|
|
|
}
|
2016-11-30 16:46:41 +00:00
|
|
|
|
|
|
|
// cleanup
|
|
|
|
mdb_dbi_close(mdb_env, mdb_dbi);
|
|
|
|
mdb_txn_commit(mdb_txn);
|
2016-12-05 19:34:10 +00:00
|
|
|
return retVal;
|
2016-11-30 16:46:41 +00:00
|
|
|
}
|
|
|
|
|
2016-12-05 22:23:58 +00:00
|
|
|
/**
|
|
|
|
* Write a block to the datastore with the specified key
|
|
|
|
* @param block the block to be written
|
|
|
|
* @param datastore the datastore to write to
|
|
|
|
* @returns true(1) on success
|
|
|
|
*/
|
|
|
|
int repo_fsrepo_lmdb_put_block(const struct Block* block, const struct Datastore* datastore) {
|
|
|
|
return repo_fsrepo_lmdb_put(block->cid->hash, block->cid->hash_length, block->data, block->data_length, datastore);
|
|
|
|
}
|
2016-11-30 16:46:41 +00:00
|
|
|
|
2016-11-17 20:07:59 +00:00
|
|
|
/**
|
|
|
|
* Open an lmdb database with the given parameters.
|
|
|
|
* Note: for now, the parameters are not used
|
|
|
|
* @param argc number of parameters in the following array
|
|
|
|
* @param argv an array of parameters
|
|
|
|
*/
|
|
|
|
int repo_fsrepro_lmdb_open(int argc, char** argv, struct Datastore* datastore) {
|
|
|
|
// create environment
|
|
|
|
struct MDB_env* mdb_env;
|
|
|
|
int retVal = mdb_env_create(&mdb_env);
|
|
|
|
if (retVal < 0) {
|
|
|
|
mdb_env_close(mdb_env);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// open the environment
|
2016-11-30 16:46:41 +00:00
|
|
|
retVal = mdb_env_open(mdb_env, datastore->path, 0, S_IRWXU);
|
2016-11-17 20:07:59 +00:00
|
|
|
if (retVal < 0) {
|
|
|
|
mdb_env_close(mdb_env);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
datastore->handle = (void*)mdb_env;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* Close an LMDB database
|
|
|
|
* NOTE: for now, argc and argv are not used
|
|
|
|
* @param argc number of parameters in the argv array
|
|
|
|
* @param argv parameters to be passed in
|
|
|
|
* @param datastore the datastore struct that contains information about the opened database
|
|
|
|
*/
|
2016-12-01 18:08:30 +00:00
|
|
|
int repo_fsrepo_lmdb_close(struct Datastore* datastore) {
|
2016-11-17 20:07:59 +00:00
|
|
|
struct MDB_env* mdb_env = (struct MDB_env*)datastore->handle;
|
|
|
|
mdb_env_close(mdb_env);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* Places the LMDB methods into the datastore's function pointers
|
|
|
|
* @param datastore the datastore to fill
|
|
|
|
* @returns true(1) on success;
|
|
|
|
*/
|
|
|
|
int repo_fsrepo_lmdb_cast(struct Datastore* datastore) {
|
|
|
|
datastore->datastore_open = &repo_fsrepro_lmdb_open;
|
|
|
|
datastore->datastore_close = &repo_fsrepo_lmdb_close;
|
2016-11-30 16:46:41 +00:00
|
|
|
datastore->datastore_put = &repo_fsrepo_lmdb_put;
|
2016-12-05 22:23:58 +00:00
|
|
|
datastore->datastore_put_block = &repo_fsrepo_lmdb_put_block;
|
|
|
|
datastore->datastore_get = &repo_fsrepo_lmdb_get;
|
|
|
|
datastore->datastore_get_block = &repo_fsrepo_lmdb_get_block;
|
2016-11-17 20:07:59 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-11-30 16:46:41 +00:00
|
|
|
/***
|
|
|
|
* Creates the directory
|
|
|
|
* @param datastore contains the path that needs to be created
|
|
|
|
* @returns true(1) on success
|
|
|
|
*/
|
|
|
|
int repo_fsrepo_lmdb_create_directory(struct Datastore* datastore) {
|
|
|
|
return mkdir(datastore->path, S_IRWXU) == 0;
|
|
|
|
}
|
|
|
|
|