diff --git a/Makefile b/Makefile index 460b16e4..91ab53c2 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ USE_AVX := yes USE_STATIC := no USE_MESHNET := no USE_UPNP := no +USE_LMDB := yes ifeq ($(WEBSOCKETS),1) NEEDED_CXXFLAGS += -DWITH_EVENTS @@ -47,6 +48,11 @@ ifeq ($(USE_MESHNET),yes) NEEDED_CXXFLAGS += -DMESHNET endif +ifeq ($(USE_LMDB),yes) + NEEDED_CXXFLAGS += -DLMDB + LDLIBS += -llmdb +endif + NEEDED_CXXFLAGS += -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD) diff --git a/libi2pd/Storage.cpp b/libi2pd/Storage.cpp index 61f52128..7fddf4fd 100644 --- a/libi2pd/Storage.cpp +++ b/libi2pd/Storage.cpp @@ -77,5 +77,158 @@ void FsIdentStorage::Iterate(const DVisitor &f) m_Storage.Iterate(fv); } +#ifdef LMDB +//MdbIdentStorage +MdbIdentStorage::~MdbIdentStorage() +{ +} + +bool MdbIdentStorage::Init() +{ + m_Path = i2p::fs::GetDataDir() + i2p::fs::dirSep + m_Name; + + if (!boost::filesystem::exists(m_Path)) + boost::filesystem::create_directory(m_Path); + + if (!mdb_env_create(&env)) + { + + int ret = mdb_env_open(env, m_Path.c_str(), MDB_NOTLS, 0664); + if (!ret) + { + return true; + } + mdb_env_close(env); + } + return false; +} + +void MdbIdentStorage::DeInit() +{ + if (m_Initialized) + DeInitWrite(); + mdb_env_close(env); +} + +bool MdbIdentStorage::BeginUpdate() //TODO: remove unneeded memory juggling +{ + return InitWrite(); +} + +bool MdbIdentStorage::EndUpdate() +{ + return DeInitWrite(); +} + +bool MdbIdentStorage::Store(const i2p::data::IdentHash &ident, const StorageRecord& record) +{ + if (!m_Initialized) + { + return false; + } + + MDB_val data; + data.mv_data = const_cast(record.data.get()); + data.mv_size = record.len; + + MDB_val key; + key.mv_data = const_cast(ident.data()); + key.mv_size = 32; + return !mdb_put(txn, dbi, &key, &data, 0); +} + +StorageRecord MdbIdentStorage::Fetch(const i2p::data::IdentHash &ident) +{ + StorageRecord result; + + MDB_txn *trn; + MDB_dbi dbh; + if (!mdb_txn_begin(env, NULL, MDB_RDONLY, &trn)) + { + if (!mdb_open(trn, NULL, 0, &dbh)) + { + MDB_val key, data; + key.mv_data = const_cast(ident.data()); + key.mv_size = 32; + if (!mdb_get(trn, dbh, &key, &data)) + { + result = StorageRecord((char*)data.mv_data, data.mv_size); + } + + mdb_txn_abort(trn); + mdb_close(env, dbh); + } + } + return result; +} + +bool MdbIdentStorage::Remove(const IdentHash &ident) +{ + if (!m_Initialized) + { + return false; + } + + MDB_val key; + key.mv_data = const_cast(ident.data()); + key.mv_size = 32; + return !mdb_del(txn, dbi, &key, NULL); +} + +void MdbIdentStorage::Iterate(const DVisitor & f) +{ + MDB_txn *trn; + MDB_dbi dbh; + MDB_val data, key; + MDB_cursor *cursor; + + if(!mdb_txn_begin(env, NULL, MDB_RDONLY, &trn)) + { + if (!mdb_open(trn, NULL, 0, &dbh)) + { + if (!mdb_cursor_open(trn, dbh, &cursor)) + { + while(!mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) + { + StorageRecord record((char*)data.mv_data, data.mv_size); + IdentHash ident((uint8_t*)key.mv_data); + f(ident, record); + } + mdb_cursor_close(cursor); + } + + mdb_txn_abort(trn); + mdb_close(env, dbh); + } else + { + mdb_txn_abort(trn); + } + } +} + +bool MdbIdentStorage::InitWrite() +{ + int ret = mdb_txn_begin(env, NULL, 0, &txn); + if (ret) + return false; + + ret = mdb_open(txn, NULL, 0, &dbi); + if (ret) + { + mdb_txn_abort(txn); + return false; + } + m_Initialized = true; + return true; +} + +bool MdbIdentStorage::DeInitWrite() { + int ret = mdb_txn_commit(txn); + mdb_close(env, dbi); + m_Initialized = false; + return !ret; +} +#endif + } //ns data } //ns i2p diff --git a/libi2pd/Storage.h b/libi2pd/Storage.h index 0fc69cc1..005fa1d8 100644 --- a/libi2pd/Storage.h +++ b/libi2pd/Storage.h @@ -5,6 +5,10 @@ #include #include +#ifdef LMDB +#include +#endif + #include "FS.h" #include "Identity.h" #include "Log.h" @@ -68,6 +72,34 @@ private: bool m_IsB32; }; +#ifdef LMDB +class MdbIdentStorage : public IdentStorage +{ +public: + MdbIdentStorage(const char *name) : m_Name(name) {} + virtual bool Init(); + virtual void DeInit(); + virtual bool BeginUpdate(); + virtual bool EndUpdate(); + virtual bool Store(const IdentHash &, const StorageRecord&); + virtual bool Remove(const IdentHash &); + StorageRecord Fetch(const IdentHash&); + virtual void Iterate(const DVisitor&); + virtual ~MdbIdentStorage(); +private: + bool InitRead(); + void DeInitRead(); + bool InitWrite(); + + bool DeInitWrite(); + bool m_Initialized = false; + std::string m_Path; + std::string m_Name; + MDB_env *env; + MDB_dbi dbi; + MDB_txn *txn; +}; +#endif } //ns data } //ns i2p