1
0
forked from blue/lmdbal

more duplicates test, misinterpreted something about duplicates, had to fallback

This commit is contained in:
Blue 2023-08-18 10:31:30 -03:00
parent 06e1aca45a
commit 180c40370c
Signed by untrusted user: blue
GPG Key ID: 9B203B252A63EE38
8 changed files with 126 additions and 89 deletions

View File

@ -48,12 +48,6 @@ class Cache;
typedef MDB_txn* TransactionID; /**<I'm going to use transaction pointers as transaction IDs*/ typedef MDB_txn* TransactionID; /**<I'm going to use transaction pointers as transaction IDs*/
enum Duplicates { /**<Duplicates mode:*/
uniqueKey, /** - no duplicate keys allowed*/
uniquePair, /** - no duplicate key <b>AND</b> value pairs allowed*/
full /** - any configuration of duplicates goes*/
};
class Base { class Base {
friend class iStorage; friend class iStorage;
public: public:
@ -75,7 +69,7 @@ public:
void abortTransaction(TransactionID id) const; void abortTransaction(TransactionID id) const;
template <class K, class V> template <class K, class V>
LMDBAL::Storage<K, V>* addStorage(const std::string& storageName, Duplicates duplicates = uniqueKey); LMDBAL::Storage<K, V>* addStorage(const std::string& storageName, bool duplicates = false);
template <class K, class V> template <class K, class V>
LMDBAL::Cache<K, V>* addCache(const std::string& storageName); LMDBAL::Cache<K, V>* addCache(const std::string& storageName);
@ -121,7 +115,7 @@ private:
* The LMDBAL::Base must be closed * The LMDBAL::Base must be closed
* *
* \param[in] storageName - storage name * \param[in] storageName - storage name
* \param[in] duplicates - LMDBAL::Duplicates duplicates mode (uniqueKey by default) * \param[in] duplicates - true if key duplicates are allowed (false by default)
* *
* \returns storage pointer. LMDBAL::Base keeps the ownership of the added storage, you don't need to destoroy it * \returns storage pointer. LMDBAL::Base keeps the ownership of the added storage, you don't need to destoroy it
* *
@ -132,7 +126,7 @@ private:
* \exception LMDBAL::StorageDuplicate thrown if somebody tries to add storage with repeating name * \exception LMDBAL::StorageDuplicate thrown if somebody tries to add storage with repeating name
*/ */
template <class K, class V> template <class K, class V>
LMDBAL::Storage<K, V>* LMDBAL::Base::addStorage(const std::string& storageName, Duplicates duplicates) { LMDBAL::Storage<K, V>* LMDBAL::Base::addStorage(const std::string& storageName, bool duplicates) {
if (opened) if (opened)
throw Opened(name, "add storage " + storageName); throw Opened(name, "add storage " + storageName);
@ -164,7 +158,7 @@ LMDBAL::Cache<K, V> * LMDBAL::Base::addCache(const std::string& storageName) {
if (opened) if (opened)
throw Opened(name, "add cache " + storageName); throw Opened(name, "add cache " + storageName);
Cache<K, V>* cache = new Cache<K, V>(this, storageName, uniqueKey); Cache<K, V>* cache = new Cache<K, V>(this, storageName, false);
std::pair<Storages::const_iterator, bool> pair = storages.insert(std::make_pair(storageName, (iStorage*)cache)); std::pair<Storages::const_iterator, bool> pair = storages.insert(std::make_pair(storageName, (iStorage*)cache));
if (!pair.second) if (!pair.second)
throw StorageDuplicate(name, storageName); throw StorageDuplicate(name, storageName);

View File

@ -51,7 +51,7 @@ class Cache : public Storage<K, V> {
typedef std::map<TransactionID, Queue> TransactionCache; typedef std::map<TransactionID, Queue> TransactionCache;
protected: protected:
Cache(Base* parent, const std::string& name, Duplicates duplicates = uniqueKey); Cache(Base* parent, const std::string& name, bool duplicates = false);
~Cache() override; ~Cache() override;
virtual void transactionStarted(TransactionID txn, bool readOnly) const override; virtual void transactionStarted(TransactionID txn, bool readOnly) const override;

View File

@ -41,10 +41,10 @@
* *
* \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed) * \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed)
* \param[in] name - the name of the storage * \param[in] name - the name of the storage
* \param[in] duplicates - LMDBAL::Duplicates duplicates mode (uniqueKey by default) * \param[in] duplicates - true if key duplicates are allowed (false by default)
*/ */
template<class K, class V> template<class K, class V>
LMDBAL::Cache<K, V>::Cache(Base* parent, const std::string& name, Duplicates duplicates): LMDBAL::Cache<K, V>::Cache(Base* parent, const std::string& name, bool duplicates):
Storage<K, V>(parent, name, duplicates), Storage<K, V>(parent, name, duplicates),
mode(Mode::nothing), mode(Mode::nothing),
cache(new std::map<K, V>()), cache(new std::map<K, V>()),

View File

@ -33,9 +33,9 @@
* *
* \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed) * \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed)
* \param[in] name - the name of the storage * \param[in] name - the name of the storage
* \param[in] duplicates - LMDBAL::Duplicates duplicates mode (uniqueKey by default) * \param[in] duplicates - true if key duplicates are allowed (false by default)
*/ */
LMDBAL::iStorage::iStorage(Base* parent, const std::string& name, Duplicates duplicates): LMDBAL::iStorage::iStorage(Base* parent, const std::string& name, bool duplicates):
dbi(), dbi(),
db(parent), db(parent),
name(name), name(name),

View File

@ -36,7 +36,7 @@ class iStorage {
friend class Base; friend class Base;
public: public:
protected: protected:
iStorage(Base* parent, const std::string& name, Duplicates duplicates = uniqueKey); iStorage(Base* parent, const std::string& name, bool duplicates = false);
virtual ~iStorage(); virtual ~iStorage();
/** /**
@ -81,7 +81,7 @@ protected:
MDB_dbi dbi; /**<\brief lmdb storage handle*/ MDB_dbi dbi; /**<\brief lmdb storage handle*/
Base* db; /**<\brief parent database pointer (borrowed)*/ Base* db; /**<\brief parent database pointer (borrowed)*/
const std::string name; /**<\brief this storage name*/ const std::string name; /**<\brief this storage name*/
const Duplicates duplicates; /**<\brief true if storage supports duplicates*/ const bool duplicates; /**<\brief true if storage supports duplicates*/
inline static const std::string dropMethodName = "drop"; /**<\brief member function name, just for exceptions*/ inline static const std::string dropMethodName = "drop"; /**<\brief member function name, just for exceptions*/
inline static const std::string countMethodName = "count"; /**<\brief member function name, just for exceptions*/ inline static const std::string countMethodName = "count"; /**<\brief member function name, just for exceptions*/
@ -99,7 +99,7 @@ protected:
protected: protected:
template <class K, class V> template <class K, class V>
int makeStorage(MDB_txn* transaction, Duplicates duplicates = uniqueKey); int makeStorage(MDB_txn* transaction, bool duplicates = false);
template <class T> template <class T>
static std::string toString(const T& value); static std::string toString(const T& value);
@ -112,7 +112,7 @@ class Storage : public iStorage {
friend class Base; friend class Base;
friend class Cursor<K, V>; friend class Cursor<K, V>;
protected: protected:
Storage(Base* parent, const std::string& name, Duplicates duplicates = uniqueKey); Storage(Base* parent, const std::string& name, bool duplicates = false);
~Storage() override; ~Storage() override;
virtual void discoveredRecord(const K& key, const V& value) const; virtual void discoveredRecord(const K& key, const V& value) const;

View File

@ -43,10 +43,10 @@
* *
* \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed) * \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed)
* \param[in] name - the name of the storage * \param[in] name - the name of the storage
* \param[in] duplicates - LMDBAL::Duplicates duplicates mode (uniqueKey by default) * \param[in] duplicates - true if key duplicates are allowed (false by default)
*/ */
template<class K, class V> template<class K, class V>
LMDBAL::Storage<K, V>::Storage(Base* parent, const std::string& name, Duplicates duplicates): LMDBAL::Storage<K, V>::Storage(Base* parent, const std::string& name, bool duplicates):
iStorage(parent, name, duplicates), iStorage(parent, name, duplicates),
keySerializer(), keySerializer(),
valueSerializer(), valueSerializer(),
@ -111,18 +111,11 @@ void LMDBAL::Storage<K, V>::addRecord(const K& key, const V& value, TransactionI
MDB_val lmdbKey = keySerializer.setData(key); MDB_val lmdbKey = keySerializer.setData(key);
MDB_val lmdbData = valueSerializer.setData(value); MDB_val lmdbData = valueSerializer.setData(value);
unsigned int flags; unsigned int flags = 0;
switch (duplicates) { if (duplicates)
case uniqueKey: flags |= MDB_NODUPDATA;
flags = MDB_NOOVERWRITE; else
break; flags |= MDB_NOOVERWRITE;
case uniquePair:
flags = MDB_NODUPDATA;
break;
case full:
flags = 0;
break;
}
int rc = mdb_put(txn, dbi, &lmdbKey, &lmdbData, flags); int rc = mdb_put(txn, dbi, &lmdbKey, &lmdbData, flags);
if (rc != MDB_SUCCESS) if (rc != MDB_SUCCESS)
@ -808,7 +801,7 @@ void LMDBAL::Storage<K, V>::discoveredRecord(const K& key, const V& value, Trans
* \tparam K type of keys in opening storage * \tparam K type of keys in opening storage
* *
* \param[in] transaction - lmdb transaction to call <a class="el" href="http://www.lmdb.tech/doc/group__mdb.html#gac08cad5b096925642ca359a6d6f0562a">mdb_dbi_open</a>, must be a writable transaction! * \param[in] transaction - lmdb transaction to call <a class="el" href="http://www.lmdb.tech/doc/group__mdb.html#gac08cad5b096925642ca359a6d6f0562a">mdb_dbi_open</a>, must be a writable transaction!
* \param[in] duplicates - true if you wish to enable duplicates support for the storage * \param[in] duplicates - true if key duplicates are allowed (false by default)
* *
* \returns MDB_SUCCESS if everything went smooth or MDB_<error> -like error code * \returns MDB_SUCCESS if everything went smooth or MDB_<error> -like error code
* *
@ -817,12 +810,12 @@ void LMDBAL::Storage<K, V>::discoveredRecord(const K& key, const V& value, Trans
* This infrastructure also allowes us to customize mdb_dbi_open call in the future * This infrastructure also allowes us to customize mdb_dbi_open call in the future
*/ */
template<class K, class V> template<class K, class V>
inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction, Duplicates duplicates) { inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction, bool duplicates) {
unsigned int flags = MDB_CREATE; unsigned int flags = MDB_CREATE;
if constexpr (std::is_integral<K>::value) if constexpr (std::is_integral<K>::value)
flags |= MDB_INTEGERKEY; flags |= MDB_INTEGERKEY;
if (duplicates != uniqueKey) { if (duplicates) {
flags |= MDB_DUPSORT; flags |= MDB_DUPSORT;
if constexpr (std::is_scalar<K>::value && std::is_scalar<V>::value) if constexpr (std::is_scalar<K>::value && std::is_scalar<V>::value)

View File

@ -7,25 +7,25 @@ class DuplicatesTest : public ::testing::Test {
protected: protected:
DuplicatesTest(): DuplicatesTest():
::testing::Test(), ::testing::Test(),
t1(db->getStorage<int16_t, uint16_t>("sameSizeInts")), tu1(db->getStorage<int16_t, uint16_t>("sameSizeInts")),
t2(db->getStorage<std::string, int8_t>("stringInt")), tu2(db->getStorage<std::string, int8_t>("stringInt")),
t3(db->getStorage<int64_t, int8_t>("differentSizeInts")), tu3(db->getStorage<float, float>("floatFloat")),
t4(db->getStorage<uint16_t, double>("intDouble")) {} tu4(db->getStorage<uint16_t, double>("intDouble")) {}
~DuplicatesTest() {} ~DuplicatesTest() {}
uint32_t getT1Flags() const {return t1->flags();} uint32_t getTU1Flags() const {return tu1->flags();}
uint32_t getT2Flags() const {return t2->flags();} uint32_t getTU2Flags() const {return tu2->flags();}
uint32_t getT3Flags() const {return t3->flags();} uint32_t getTU3Flags() const {return tu3->flags();}
uint32_t getT4Flags() const {return t4->flags();} uint32_t getTU4Flags() const {return tu4->flags();}
static void SetUpTestSuite() { static void SetUpTestSuite() {
if (db == nullptr) { if (db == nullptr) {
db = new LMDBAL::Base("testBase"); db = new LMDBAL::Base("testBase");
db->addStorage<int16_t, uint16_t>("sameSizeInts", LMDBAL::uniquePair); db->addStorage<int16_t, uint16_t>("sameSizeInts", true);
db->addStorage<std::string, int8_t>("stringInt", LMDBAL::uniquePair); db->addStorage<std::string, int8_t>("stringInt", true);
db->addStorage<int64_t, int8_t>("differentSizeInts", LMDBAL::uniquePair); db->addStorage<float, float>("floatFloat", true);
db->addStorage<uint16_t, double>("intDouble", LMDBAL::uniquePair); db->addStorage<uint16_t, double>("intDouble", true);
db->open(); db->open();
} }
@ -40,51 +40,95 @@ protected:
static LMDBAL::Base* db; static LMDBAL::Base* db;
LMDBAL::Storage<int16_t, uint16_t>* t1; LMDBAL::Storage<int16_t, uint16_t>* tu1;
LMDBAL::Storage<std::string, int8_t>* t2; LMDBAL::Storage<std::string, int8_t>* tu2;
LMDBAL::Storage<int64_t, int8_t>* t3; LMDBAL::Storage<float, float>* tu3;
LMDBAL::Storage<uint16_t, double>* t4; LMDBAL::Storage<uint16_t, double>* tu4;
}; };
LMDBAL::Base* DuplicatesTest::db = nullptr; LMDBAL::Base* DuplicatesTest::db = nullptr;
TEST_F(DuplicatesTest, Flags) { TEST_F(DuplicatesTest, FlagsUnique) {
uint32_t t1Flags = getT1Flags(); uint32_t tu1Flags = getTU1Flags();
uint32_t t2Flags = getT2Flags(); uint32_t tu2Flags = getTU2Flags();
uint32_t t3Flags = getT3Flags(); uint32_t tu3Flags = getTU3Flags();
uint32_t t4Flags = getT4Flags(); uint32_t tu4Flags = getTU4Flags();
EXPECT_TRUE(t1Flags & MDB_INTEGERKEY); EXPECT_TRUE(tu1Flags & MDB_INTEGERKEY);
EXPECT_TRUE(t1Flags & MDB_DUPSORT); EXPECT_TRUE(tu1Flags & MDB_DUPSORT);
EXPECT_TRUE(t1Flags & MDB_DUPFIXED); EXPECT_TRUE(tu1Flags & MDB_DUPFIXED);
EXPECT_FALSE(t1Flags & MDB_INTEGERDUP); EXPECT_FALSE(tu1Flags & MDB_INTEGERDUP);
EXPECT_FALSE(t2Flags & MDB_INTEGERKEY); EXPECT_FALSE(tu2Flags & MDB_INTEGERKEY);
EXPECT_TRUE(t2Flags & MDB_DUPSORT); EXPECT_TRUE(tu2Flags & MDB_DUPSORT);
EXPECT_FALSE(t2Flags & MDB_DUPFIXED); EXPECT_FALSE(tu2Flags & MDB_DUPFIXED);
EXPECT_TRUE(t2Flags & MDB_INTEGERDUP); EXPECT_TRUE(tu2Flags & MDB_INTEGERDUP);
EXPECT_TRUE(t3Flags & MDB_INTEGERKEY); EXPECT_FALSE(tu3Flags & MDB_INTEGERKEY);
EXPECT_TRUE(t3Flags & MDB_DUPSORT); EXPECT_TRUE(tu3Flags & MDB_DUPSORT);
EXPECT_TRUE(t3Flags & MDB_DUPFIXED); EXPECT_TRUE(tu3Flags & MDB_DUPFIXED);
EXPECT_FALSE(t3Flags & MDB_INTEGERDUP); EXPECT_FALSE(tu3Flags & MDB_INTEGERDUP);
EXPECT_TRUE(t4Flags & MDB_INTEGERKEY); EXPECT_TRUE(tu4Flags & MDB_INTEGERKEY);
EXPECT_TRUE(t4Flags & MDB_DUPSORT); EXPECT_TRUE(tu4Flags & MDB_DUPSORT);
EXPECT_TRUE(t4Flags & MDB_DUPFIXED); EXPECT_TRUE(tu4Flags & MDB_DUPFIXED);
EXPECT_FALSE(t4Flags & MDB_INTEGERDUP); EXPECT_FALSE(tu4Flags & MDB_INTEGERDUP);
} }
TEST_F(DuplicatesTest, Adding) { TEST_F(DuplicatesTest, AddingPairUnique) {
t1->addRecord(1, 1); tu1->addRecord(1, 1);
t1->addRecord(2, 2); tu1->addRecord(2, 2);
t1->addRecord(2, 1); tu1->addRecord(2, 1);
t1->addRecord(1, 2); tu1->addRecord(1, 2);
EXPECT_THROW(t1->addRecord(1, 1), LMDBAL::Exist); EXPECT_THROW(tu1->addRecord(1, 1), LMDBAL::Exist);
EXPECT_THROW(t1->addRecord(1, 2), LMDBAL::Exist); EXPECT_THROW(tu1->addRecord(1, 2), LMDBAL::Exist);
EXPECT_THROW(t1->addRecord(2, 2), LMDBAL::Exist); EXPECT_THROW(tu1->addRecord(2, 2), LMDBAL::Exist);
EXPECT_EQ(t1->count(), 4); EXPECT_EQ(tu1->count(), 4);
EXPECT_EQ(t1->getRecord(1), 1); EXPECT_EQ(tu1->getRecord(1), 1);
EXPECT_EQ(t1->getRecord(2), 1); EXPECT_EQ(tu1->getRecord(2), 1);
tu2->addRecord("brass boulers", -54);
tu2->addRecord("grief ", 61);
tu2->addRecord("grief ", 19);
tu2->addRecord("grief ", 32);
tu2->addRecord("miracles of a lunch", 44);
tu2->addRecord("miracles of a lunch", 102);
tu2->addRecord("miracles of a lunch", -72);
EXPECT_THROW(tu2->addRecord("grief ", 19), LMDBAL::Exist);
EXPECT_THROW(tu2->addRecord("brass boulers", -54), LMDBAL::Exist);
EXPECT_EQ(tu2->count(), 7);
EXPECT_EQ(tu2->getRecord("grief "), 19);
EXPECT_EQ(tu2->getRecord("miracles of a lunch"), 44); //apparently ints are compared as uints
tu3->addRecord(7.2, 697);
tu3->addRecord(5119, -998.53);
tu3->addRecord(7.2001, 4);
tu3->addRecord(7.2, -113);
tu3->addRecord(7.2, -53.5478);
float tu3ds = 0.432924;
tu3->addRecord(5119, tu3ds);
EXPECT_THROW(tu3->addRecord(5119, -998.53), LMDBAL::Exist);
EXPECT_THROW(tu3->addRecord(7.2001, 4), LMDBAL::Exist);
tu3->addRecord(7.20001, 4.00000001); //not sure how exactly, but it works
EXPECT_EQ(tu3->count(), 7);
EXPECT_EQ(tu3->getRecord(7.2), -113);
float tu3dd = tu3->getRecord(5119);
EXPECT_TRUE(tu3ds == tu3dd);
EXPECT_EQ(tu3ds, tu3dd);
tu4->addRecord(327, 463.28348);
tu4->addRecord(327, 79.624923);
tu4->addRecord(172, 0.00001);
tu4->addRecord(172, 0.00000001);
EXPECT_THROW(tu4->addRecord(172, 0.00000001), LMDBAL::Exist);
EXPECT_THROW(tu4->addRecord(172, 0.00001), LMDBAL::Exist);
EXPECT_THROW(tu4->addRecord(327, 79.624923), LMDBAL::Exist);
EXPECT_EQ(tu4->count(), 4);
EXPECT_EQ(tu4->getRecord(172), 0.00000001);
EXPECT_EQ(tu4->getRecord(327), 463.28348); //since they are not int's they are compared sort of lexicographically
} }

View File

@ -4,12 +4,13 @@
#include <operators.hpp> #include <operators.hpp>
TEST(Serialization, Double) { TEST(Serialization, Double) {
double source = 5344.6542; double source1 = 5344.6542;
double source2 = 0.4329248;
LMDBAL::Serializer<double> serializer; LMDBAL::Serializer<double> serializer;
LMDBAL::Serializer<double> serializer2(source); LMDBAL::Serializer<double> serializer2(source1);
LMDBAL::Serializer<double> deserializer; LMDBAL::Serializer<double> deserializer;
serializer.setData(source); serializer.setData(source1);
MDB_val data = serializer.getData(); MDB_val data = serializer.getData();
MDB_val data2 = serializer2.getData(); MDB_val data2 = serializer2.getData();
@ -19,11 +20,16 @@ TEST(Serialization, Double) {
double destination; double destination;
serializer.deserialize(data, destination); serializer.deserialize(data, destination);
EXPECT_DOUBLE_EQ(source, destination); EXPECT_DOUBLE_EQ(source1, destination);
double dest2 = serializer.deserialize(data); double dest2 = serializer.deserialize(data);
EXPECT_DOUBLE_EQ(source, dest2); EXPECT_DOUBLE_EQ(source1, dest2);
data = serializer.setData(source2);
serializer.deserialize(data, destination);
EXPECT_DOUBLE_EQ(source2, destination);
} }
TEST(Serialization, Float) { TEST(Serialization, Float) {