diff --git a/src/base.h b/src/base.h index f09330e..2b7353e 100644 --- a/src/base.h +++ b/src/base.h @@ -48,12 +48,6 @@ class Cache; typedef MDB_txn* TransactionID; /**AND value pairs allowed*/ - full /** - any configuration of duplicates goes*/ -}; - class Base { friend class iStorage; public: @@ -75,7 +69,7 @@ public: void abortTransaction(TransactionID id) const; template - LMDBAL::Storage* addStorage(const std::string& storageName, Duplicates duplicates = uniqueKey); + LMDBAL::Storage* addStorage(const std::string& storageName, bool duplicates = false); template LMDBAL::Cache* addCache(const std::string& storageName); @@ -121,7 +115,7 @@ private: * The LMDBAL::Base must be closed * * \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 * @@ -132,7 +126,7 @@ private: * \exception LMDBAL::StorageDuplicate thrown if somebody tries to add storage with repeating name */ template -LMDBAL::Storage* LMDBAL::Base::addStorage(const std::string& storageName, Duplicates duplicates) { +LMDBAL::Storage* LMDBAL::Base::addStorage(const std::string& storageName, bool duplicates) { if (opened) throw Opened(name, "add storage " + storageName); @@ -164,7 +158,7 @@ LMDBAL::Cache * LMDBAL::Base::addCache(const std::string& storageName) { if (opened) throw Opened(name, "add cache " + storageName); - Cache* cache = new Cache(this, storageName, uniqueKey); + Cache* cache = new Cache(this, storageName, false); std::pair pair = storages.insert(std::make_pair(storageName, (iStorage*)cache)); if (!pair.second) throw StorageDuplicate(name, storageName); diff --git a/src/cache.h b/src/cache.h index 7a6bef2..ff0d996 100644 --- a/src/cache.h +++ b/src/cache.h @@ -51,7 +51,7 @@ class Cache : public Storage { typedef std::map TransactionCache; protected: - Cache(Base* parent, const std::string& name, Duplicates duplicates = uniqueKey); + Cache(Base* parent, const std::string& name, bool duplicates = false); ~Cache() override; virtual void transactionStarted(TransactionID txn, bool readOnly) const override; diff --git a/src/cache.hpp b/src/cache.hpp index 5f5edb9..0f0470b 100644 --- a/src/cache.hpp +++ b/src/cache.hpp @@ -41,10 +41,10 @@ * * \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed) * \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 -LMDBAL::Cache::Cache(Base* parent, const std::string& name, Duplicates duplicates): +LMDBAL::Cache::Cache(Base* parent, const std::string& name, bool duplicates): Storage(parent, name, duplicates), mode(Mode::nothing), cache(new std::map()), diff --git a/src/storage.cpp b/src/storage.cpp index 28cd319..2f50cd4 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -33,9 +33,9 @@ * * \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed) * \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(), db(parent), name(name), diff --git a/src/storage.h b/src/storage.h index adcc0f0..46372e2 100644 --- a/src/storage.h +++ b/src/storage.h @@ -36,7 +36,7 @@ class iStorage { friend class Base; public: protected: - iStorage(Base* parent, const std::string& name, Duplicates duplicates = uniqueKey); + iStorage(Base* parent, const std::string& name, bool duplicates = false); virtual ~iStorage(); /** @@ -81,7 +81,7 @@ protected: MDB_dbi dbi; /**<\brief lmdb storage handle*/ Base* db; /**<\brief parent database pointer (borrowed)*/ 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 countMethodName = "count"; /**<\brief member function name, just for exceptions*/ @@ -99,7 +99,7 @@ protected: protected: template - int makeStorage(MDB_txn* transaction, Duplicates duplicates = uniqueKey); + int makeStorage(MDB_txn* transaction, bool duplicates = false); template static std::string toString(const T& value); @@ -112,7 +112,7 @@ class Storage : public iStorage { friend class Base; friend class Cursor; protected: - Storage(Base* parent, const std::string& name, Duplicates duplicates = uniqueKey); + Storage(Base* parent, const std::string& name, bool duplicates = false); ~Storage() override; virtual void discoveredRecord(const K& key, const V& value) const; diff --git a/src/storage.hpp b/src/storage.hpp index 3f5296f..8e63d61 100644 --- a/src/storage.hpp +++ b/src/storage.hpp @@ -43,10 +43,10 @@ * * \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed) * \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 -LMDBAL::Storage::Storage(Base* parent, const std::string& name, Duplicates duplicates): +LMDBAL::Storage::Storage(Base* parent, const std::string& name, bool duplicates): iStorage(parent, name, duplicates), keySerializer(), valueSerializer(), @@ -111,18 +111,11 @@ void LMDBAL::Storage::addRecord(const K& key, const V& value, TransactionI MDB_val lmdbKey = keySerializer.setData(key); MDB_val lmdbData = valueSerializer.setData(value); - unsigned int flags; - switch (duplicates) { - case uniqueKey: - flags = MDB_NOOVERWRITE; - break; - case uniquePair: - flags = MDB_NODUPDATA; - break; - case full: - flags = 0; - break; - } + unsigned int flags = 0; + if (duplicates) + flags |= MDB_NODUPDATA; + else + flags |= MDB_NOOVERWRITE; int rc = mdb_put(txn, dbi, &lmdbKey, &lmdbData, flags); if (rc != MDB_SUCCESS) @@ -808,7 +801,7 @@ void LMDBAL::Storage::discoveredRecord(const K& key, const V& value, Trans * \tparam K type of keys in opening storage * * \param[in] transaction - lmdb transaction to call mdb_dbi_open, 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_ -like error code * @@ -817,12 +810,12 @@ void LMDBAL::Storage::discoveredRecord(const K& key, const V& value, Trans * This infrastructure also allowes us to customize mdb_dbi_open call in the future */ template -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; if constexpr (std::is_integral::value) flags |= MDB_INTEGERKEY; - if (duplicates != uniqueKey) { + if (duplicates) { flags |= MDB_DUPSORT; if constexpr (std::is_scalar::value && std::is_scalar::value) diff --git a/test/duplicates.cpp b/test/duplicates.cpp index f25feba..b65acba 100644 --- a/test/duplicates.cpp +++ b/test/duplicates.cpp @@ -7,25 +7,25 @@ class DuplicatesTest : public ::testing::Test { protected: DuplicatesTest(): ::testing::Test(), - t1(db->getStorage("sameSizeInts")), - t2(db->getStorage("stringInt")), - t3(db->getStorage("differentSizeInts")), - t4(db->getStorage("intDouble")) {} + tu1(db->getStorage("sameSizeInts")), + tu2(db->getStorage("stringInt")), + tu3(db->getStorage("floatFloat")), + tu4(db->getStorage("intDouble")) {} ~DuplicatesTest() {} - uint32_t getT1Flags() const {return t1->flags();} - uint32_t getT2Flags() const {return t2->flags();} - uint32_t getT3Flags() const {return t3->flags();} - uint32_t getT4Flags() const {return t4->flags();} + uint32_t getTU1Flags() const {return tu1->flags();} + uint32_t getTU2Flags() const {return tu2->flags();} + uint32_t getTU3Flags() const {return tu3->flags();} + uint32_t getTU4Flags() const {return tu4->flags();} static void SetUpTestSuite() { if (db == nullptr) { db = new LMDBAL::Base("testBase"); - db->addStorage("sameSizeInts", LMDBAL::uniquePair); - db->addStorage("stringInt", LMDBAL::uniquePair); - db->addStorage("differentSizeInts", LMDBAL::uniquePair); - db->addStorage("intDouble", LMDBAL::uniquePair); + db->addStorage("sameSizeInts", true); + db->addStorage("stringInt", true); + db->addStorage("floatFloat", true); + db->addStorage("intDouble", true); db->open(); } @@ -40,51 +40,95 @@ protected: static LMDBAL::Base* db; - LMDBAL::Storage* t1; - LMDBAL::Storage* t2; - LMDBAL::Storage* t3; - LMDBAL::Storage* t4; + LMDBAL::Storage* tu1; + LMDBAL::Storage* tu2; + LMDBAL::Storage* tu3; + LMDBAL::Storage* tu4; }; LMDBAL::Base* DuplicatesTest::db = nullptr; -TEST_F(DuplicatesTest, Flags) { - uint32_t t1Flags = getT1Flags(); - uint32_t t2Flags = getT2Flags(); - uint32_t t3Flags = getT3Flags(); - uint32_t t4Flags = getT4Flags(); +TEST_F(DuplicatesTest, FlagsUnique) { + uint32_t tu1Flags = getTU1Flags(); + uint32_t tu2Flags = getTU2Flags(); + uint32_t tu3Flags = getTU3Flags(); + uint32_t tu4Flags = getTU4Flags(); - EXPECT_TRUE(t1Flags & MDB_INTEGERKEY); - EXPECT_TRUE(t1Flags & MDB_DUPSORT); - EXPECT_TRUE(t1Flags & MDB_DUPFIXED); - EXPECT_FALSE(t1Flags & MDB_INTEGERDUP); + EXPECT_TRUE(tu1Flags & MDB_INTEGERKEY); + EXPECT_TRUE(tu1Flags & MDB_DUPSORT); + EXPECT_TRUE(tu1Flags & MDB_DUPFIXED); + EXPECT_FALSE(tu1Flags & MDB_INTEGERDUP); - EXPECT_FALSE(t2Flags & MDB_INTEGERKEY); - EXPECT_TRUE(t2Flags & MDB_DUPSORT); - EXPECT_FALSE(t2Flags & MDB_DUPFIXED); - EXPECT_TRUE(t2Flags & MDB_INTEGERDUP); + EXPECT_FALSE(tu2Flags & MDB_INTEGERKEY); + EXPECT_TRUE(tu2Flags & MDB_DUPSORT); + EXPECT_FALSE(tu2Flags & MDB_DUPFIXED); + EXPECT_TRUE(tu2Flags & MDB_INTEGERDUP); - EXPECT_TRUE(t3Flags & MDB_INTEGERKEY); - EXPECT_TRUE(t3Flags & MDB_DUPSORT); - EXPECT_TRUE(t3Flags & MDB_DUPFIXED); - EXPECT_FALSE(t3Flags & MDB_INTEGERDUP); + EXPECT_FALSE(tu3Flags & MDB_INTEGERKEY); + EXPECT_TRUE(tu3Flags & MDB_DUPSORT); + EXPECT_TRUE(tu3Flags & MDB_DUPFIXED); + EXPECT_FALSE(tu3Flags & MDB_INTEGERDUP); - EXPECT_TRUE(t4Flags & MDB_INTEGERKEY); - EXPECT_TRUE(t4Flags & MDB_DUPSORT); - EXPECT_TRUE(t4Flags & MDB_DUPFIXED); - EXPECT_FALSE(t4Flags & MDB_INTEGERDUP); + EXPECT_TRUE(tu4Flags & MDB_INTEGERKEY); + EXPECT_TRUE(tu4Flags & MDB_DUPSORT); + EXPECT_TRUE(tu4Flags & MDB_DUPFIXED); + EXPECT_FALSE(tu4Flags & MDB_INTEGERDUP); } -TEST_F(DuplicatesTest, Adding) { - t1->addRecord(1, 1); - t1->addRecord(2, 2); - t1->addRecord(2, 1); - t1->addRecord(1, 2); - EXPECT_THROW(t1->addRecord(1, 1), LMDBAL::Exist); - EXPECT_THROW(t1->addRecord(1, 2), LMDBAL::Exist); - EXPECT_THROW(t1->addRecord(2, 2), LMDBAL::Exist); +TEST_F(DuplicatesTest, AddingPairUnique) { + tu1->addRecord(1, 1); + tu1->addRecord(2, 2); + tu1->addRecord(2, 1); + tu1->addRecord(1, 2); + EXPECT_THROW(tu1->addRecord(1, 1), LMDBAL::Exist); + EXPECT_THROW(tu1->addRecord(1, 2), LMDBAL::Exist); + EXPECT_THROW(tu1->addRecord(2, 2), LMDBAL::Exist); - EXPECT_EQ(t1->count(), 4); - EXPECT_EQ(t1->getRecord(1), 1); - EXPECT_EQ(t1->getRecord(2), 1); + EXPECT_EQ(tu1->count(), 4); + EXPECT_EQ(tu1->getRecord(1), 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 } diff --git a/test/serialization.cpp b/test/serialization.cpp index b413d42..9fe162e 100644 --- a/test/serialization.cpp +++ b/test/serialization.cpp @@ -4,12 +4,13 @@ #include TEST(Serialization, Double) { - double source = 5344.6542; + double source1 = 5344.6542; + double source2 = 0.4329248; LMDBAL::Serializer serializer; - LMDBAL::Serializer serializer2(source); + LMDBAL::Serializer serializer2(source1); LMDBAL::Serializer deserializer; - serializer.setData(source); + serializer.setData(source1); MDB_val data = serializer.getData(); MDB_val data2 = serializer2.getData(); @@ -19,11 +20,16 @@ TEST(Serialization, Double) { double destination; serializer.deserialize(data, destination); - EXPECT_DOUBLE_EQ(source, destination); + EXPECT_DOUBLE_EQ(source1, destination); 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) {