started to work on duplicates support
This commit is contained in:
parent
7b26d57ab6
commit
f0727aa73d
13
CHANGELOG.md
13
CHANGELOG.md
@ -1,14 +1,22 @@
|
||||
# Changelog
|
||||
|
||||
## LMDBAL 0.5.0 (UNRELEASED, 2023)
|
||||
### New Features
|
||||
- duplicates support
|
||||
|
||||
|
||||
## LMDBAL 0.4.0 (August 13, 2023)
|
||||
### New Features
|
||||
- read only cursors
|
||||
|
||||
### Bug fixes
|
||||
- possible cache unsync
|
||||
- doxygen-awesome build bix
|
||||
|
||||
### Improvements
|
||||
- read only cursors
|
||||
- some more documentation
|
||||
- more tests
|
||||
- doxygen-awesome build bix
|
||||
|
||||
|
||||
## LMDBAL 0.3.1 (April 14, 2023)
|
||||
### Bug fixes
|
||||
@ -17,6 +25,7 @@
|
||||
### Improvements
|
||||
- exception documentation
|
||||
|
||||
|
||||
## LMDBAL 0.3.0 (April 12, 2023)
|
||||
### New features
|
||||
- transaction functions
|
||||
|
45
src/base.h
45
src/base.h
@ -69,16 +69,16 @@ public:
|
||||
void abortTransaction(TransactionID id) const;
|
||||
|
||||
template <class K, class V>
|
||||
LMDBAL::Storage<K, V>* addStorage(const std::string& name);
|
||||
LMDBAL::Storage<K, V>* addStorage(const std::string& storageName, bool duplicates = false);
|
||||
|
||||
template <class K, class V>
|
||||
LMDBAL::Cache<K, V>* addCache(const std::string& name);
|
||||
LMDBAL::Cache<K, V>* addCache(const std::string& storageName);
|
||||
|
||||
template <class K, class V>
|
||||
LMDBAL::Storage<K, V>* getStorage(const std::string& name);
|
||||
LMDBAL::Storage<K, V>* getStorage(const std::string& storageName);
|
||||
|
||||
template <class K, class V>
|
||||
LMDBAL::Cache<K, V>* getCache(const std::string& name);
|
||||
LMDBAL::Cache<K, V>* getCache(const std::string& storageName);
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, LMDBAL::iStorage*> Storages; /**<Storage and Cache pointers are saved in the std::map*/
|
||||
@ -114,7 +114,8 @@ private:
|
||||
* Defines that the database is going to have the following storage.
|
||||
* The LMDBAL::Base must be closed
|
||||
*
|
||||
* \param[in] _name - storage name
|
||||
* \param[in] storageName - storage name
|
||||
*
|
||||
* \returns storage pointer. LMDBAL::Base keeps the ownership of the added storage, you don't need to destoroy it
|
||||
*
|
||||
* \tparam K - key type of the storage
|
||||
@ -124,14 +125,14 @@ private:
|
||||
* \exception LMDBAL::StorageDuplicate thrown if somebody tries to add storage with repeating name
|
||||
*/
|
||||
template <class K, class V>
|
||||
LMDBAL::Storage<K, V>* LMDBAL::Base::addStorage(const std::string& _name) {
|
||||
LMDBAL::Storage<K, V>* LMDBAL::Base::addStorage(const std::string& storageName, bool duplicates) {
|
||||
if (opened) {
|
||||
throw Opened(name, "add storage " + _name);
|
||||
throw Opened(name, "add storage " + storageName);
|
||||
}
|
||||
Storage<K, V>* storage = new Storage<K, V>(_name, this);
|
||||
std::pair<Storages::const_iterator, bool> pair = storages.insert(std::make_pair(_name, (iStorage*)storage));
|
||||
Storage<K, V>* storage = new Storage<K, V>(this, storageName, duplicates);
|
||||
std::pair<Storages::const_iterator, bool> pair = storages.insert(std::make_pair(storageName, (iStorage*)storage));
|
||||
if (!pair.second)
|
||||
throw StorageDuplicate(name, _name);
|
||||
throw StorageDuplicate(name, storageName);
|
||||
|
||||
return storage;
|
||||
}
|
||||
@ -142,7 +143,7 @@ LMDBAL::Storage<K, V>* LMDBAL::Base::addStorage(const std::string& _name) {
|
||||
* Defines that the database is going to have the following cache.
|
||||
* The LMDBAL::Base must be closed
|
||||
*
|
||||
* \param[in] _name - cache name
|
||||
* \param[in] storageName - cache name
|
||||
* \returns cache pointer. LMDBAL::Base keeps the ownership of the added cache, you don't need to destoroy it
|
||||
*
|
||||
* \tparam K - key type of the cache
|
||||
@ -152,14 +153,14 @@ LMDBAL::Storage<K, V>* LMDBAL::Base::addStorage(const std::string& _name) {
|
||||
* \exception LMDBAL::StorageDuplicate thrown if somebody tries to add cache with repeating name
|
||||
*/
|
||||
template<class K, class V>
|
||||
LMDBAL::Cache<K, V> * LMDBAL::Base::addCache(const std::string& _name) {
|
||||
LMDBAL::Cache<K, V> * LMDBAL::Base::addCache(const std::string& storageName) {
|
||||
if (opened) {
|
||||
throw Opened(name, "add cache " + _name);
|
||||
throw Opened(name, "add cache " + storageName);
|
||||
}
|
||||
Cache<K, V>* cache = new Cache<K, V>(_name, this);
|
||||
std::pair<Storages::const_iterator, bool> pair = storages.insert(std::make_pair(_name, (iStorage*)cache));
|
||||
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));
|
||||
if (!pair.second)
|
||||
throw StorageDuplicate(name, _name);
|
||||
throw StorageDuplicate(name, storageName);
|
||||
|
||||
return cache;
|
||||
}
|
||||
@ -173,7 +174,7 @@ LMDBAL::Cache<K, V> * LMDBAL::Base::addCache(const std::string& _name) {
|
||||
* this method with template parameters <std::string, std::string>
|
||||
* on the same name of the previously added storage, or calling it on cache - the behaviour is undefined
|
||||
*
|
||||
* \param[in] _name - storage name
|
||||
* \param[in] storageName - storage name
|
||||
* \returns storage pointer. LMDBAL::Base keeps the ownership of the added storage, you don't need to destoroy it
|
||||
*
|
||||
* \tparam K - key type of the storage
|
||||
@ -182,8 +183,8 @@ LMDBAL::Cache<K, V> * LMDBAL::Base::addCache(const std::string& _name) {
|
||||
* \exception std::out_of_range thrown if storage with the given name was not found
|
||||
*/
|
||||
template <class K, class V>
|
||||
LMDBAL::Storage<K, V>* LMDBAL::Base::getStorage(const std::string& _name) {
|
||||
return static_cast<Storage<K, V>*>(storages.at(_name));
|
||||
LMDBAL::Storage<K, V>* LMDBAL::Base::getStorage(const std::string& storageName) {
|
||||
return static_cast<Storage<K, V>*>(storages.at(storageName));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,7 +196,7 @@ LMDBAL::Storage<K, V>* LMDBAL::Base::getStorage(const std::string& _name) {
|
||||
* this method with template parameters <std::string, std::string>
|
||||
* on the same name of the previously added cache, or calling it on storage - the behaviour is undefined
|
||||
*
|
||||
* \param[in] _name - cache name
|
||||
* \param[in] storageName - cache name
|
||||
* \returns cache pointer. LMDBAL::Base keeps the ownership of the added cache, you don't need to destoroy it
|
||||
*
|
||||
* \tparam K - key type of the cache
|
||||
@ -204,8 +205,8 @@ LMDBAL::Storage<K, V>* LMDBAL::Base::getStorage(const std::string& _name) {
|
||||
* \exception std::out_of_range thrown if cache with the given name was not found
|
||||
*/
|
||||
template <class K, class V>
|
||||
LMDBAL::Cache<K, V>* LMDBAL::Base::getCache(const std::string& _name) {
|
||||
return static_cast<Cache<K, V>*>(storages.at(_name));
|
||||
LMDBAL::Cache<K, V>* LMDBAL::Base::getCache(const std::string& storageName) {
|
||||
return static_cast<Cache<K, V>*>(storages.at(storageName));
|
||||
}
|
||||
|
||||
#endif //LMDBAL_BASE_H
|
||||
|
@ -51,7 +51,7 @@ class Cache : public Storage<K, V> {
|
||||
typedef std::map<TransactionID, Queue> TransactionCache;
|
||||
|
||||
protected:
|
||||
Cache(const std::string& name, Base* parent);
|
||||
Cache(Base* parent, const std::string& name, bool duplicates = false);
|
||||
~Cache() override;
|
||||
|
||||
virtual void transactionStarted(TransactionID txn, bool readOnly) const override;
|
||||
|
@ -39,12 +39,13 @@
|
||||
/**
|
||||
* \brief Creates a cache
|
||||
*
|
||||
* \param[in] _name - name of the new cache
|
||||
* \param[in] parent - parent database pointed (borrowed)
|
||||
* \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed)
|
||||
* \param[in] name - the name of the storage
|
||||
* \param[in] duplicates - true if storage supports duplicates, false otherwise (false by default)
|
||||
*/
|
||||
template<class K, class V>
|
||||
LMDBAL::Cache<K, V>::Cache(const std::string& _name, Base* parent):
|
||||
Storage<K, V>(_name, parent),
|
||||
LMDBAL::Cache<K, V>::Cache(Base* parent, const std::string& name, bool duplicates):
|
||||
Storage<K, V>(parent, name, duplicates),
|
||||
mode(Mode::nothing),
|
||||
cache(new std::map<K, V>()),
|
||||
abscent(new std::set<K>()),
|
||||
|
@ -23,11 +23,12 @@
|
||||
|
||||
/**
|
||||
* \class LMDBAL::Serializer
|
||||
* \brief A class handling serialization/deserialization
|
||||
*
|
||||
* A class that is constructed in every LMDBAL::Storage
|
||||
* to serialize or deserialize keys and values.
|
||||
*
|
||||
* It serializes to and deserializes from <a class="el" href="http://www.lmdb.tech/doc/group__mdb.html#structMDB__val">MDB_val</a>MDB_val
|
||||
* It serializes to and deserializes from <a class="el" href="http://www.lmdb.tech/doc/group__mdb.html#structMDB__val">MDB_val</a>
|
||||
*
|
||||
* \tparam K type of the keys of the storage
|
||||
* \tparam V type of the values of the storage
|
||||
|
@ -30,11 +30,16 @@
|
||||
|
||||
/**
|
||||
* \brief Constructs a storage interface
|
||||
*
|
||||
* \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed)
|
||||
* \param[in] name - the name of the storage
|
||||
* \param[in] duplicates - true if storage supports duplicates, false otherwise (false by default)
|
||||
*/
|
||||
LMDBAL::iStorage::iStorage(const std::string& p_name, Base* parent):
|
||||
LMDBAL::iStorage::iStorage(Base* parent, const std::string& name, bool duplicates):
|
||||
dbi(),
|
||||
db(parent),
|
||||
name(p_name)
|
||||
name(name),
|
||||
duplicates(duplicates)
|
||||
{}
|
||||
|
||||
/**
|
||||
|
@ -19,10 +19,14 @@
|
||||
#ifndef LMDBAL_STORAGE_H
|
||||
#define LMDBAL_STORAGE_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "base.h"
|
||||
#include "serializer.h"
|
||||
#include "cursor.h"
|
||||
|
||||
class BaseTest;
|
||||
|
||||
namespace LMDBAL {
|
||||
|
||||
typedef uint32_t SizeType;
|
||||
@ -32,7 +36,7 @@ class iStorage {
|
||||
public:
|
||||
|
||||
protected:
|
||||
iStorage(const std::string& name, Base* parent);
|
||||
iStorage(Base* parent, const std::string& name, bool duplicates = false);
|
||||
virtual ~iStorage();
|
||||
|
||||
/**
|
||||
@ -77,9 +81,11 @@ protected:
|
||||
MDB_dbi dbi; /**<\brief lmdb storage handle*/
|
||||
Base* db; /**<\brief parent database pointer (borrowed)*/
|
||||
const std::string name; /**<\brief this storage name*/
|
||||
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*/
|
||||
inline static const std::string flagsMethodName = "flags"; /**<\brief member function name, just for exceptions*/
|
||||
|
||||
inline static const std::string addRecordMethodName = "addRecord"; /**<\brief member function name, just for exceptions*/
|
||||
inline static const std::string forceRecordMethodName = "forceRecord"; /**<\brief member function name, just for exceptions*/
|
||||
@ -92,8 +98,8 @@ protected:
|
||||
inline static const std::string addRecordsMethodName = "addRecords"; /**<\brief member function name, just for exceptions*/
|
||||
|
||||
protected:
|
||||
template <class T>
|
||||
int makeStorage(MDB_txn* transaction);
|
||||
template <class K, class V>
|
||||
int makeStorage(MDB_txn* transaction, bool duplicates);
|
||||
|
||||
template <class T>
|
||||
static std::string toString(const T& value);
|
||||
@ -101,14 +107,16 @@ protected:
|
||||
|
||||
template <class K, class V>
|
||||
class Storage : public iStorage {
|
||||
friend class ::BaseTest;
|
||||
friend class Base;
|
||||
friend class Cursor<K, V>;
|
||||
protected:
|
||||
Storage(const std::string& name, Base* parent);
|
||||
Storage(Base* parent, const std::string& name, bool duplicates = false);
|
||||
~Storage() override;
|
||||
|
||||
virtual void discoveredRecord(const K& key, const V& value) const;
|
||||
virtual void discoveredRecord(const K& key, const V& value, TransactionID txn) const;
|
||||
uint32_t flags() const;
|
||||
|
||||
public:
|
||||
using iStorage::drop;
|
||||
|
118
src/storage.hpp
118
src/storage.hpp
@ -41,12 +41,13 @@
|
||||
/**
|
||||
* \brief Creates a storage
|
||||
*
|
||||
* \param[in] _name - name of the new storage
|
||||
* \param[in] parent - parent database pointed (borrowed)
|
||||
* \param[in] parent - LMDBAL::Base pointer for the owning database (borrowed)
|
||||
* \param[in] name - the name of the storage
|
||||
* \param[in] duplicates - true if storage supports duplicates, false otherwise (false by default)
|
||||
*/
|
||||
template<class K, class V>
|
||||
LMDBAL::Storage<K, V>::Storage(const std::string& _name, Base* parent):
|
||||
iStorage(_name, parent),
|
||||
LMDBAL::Storage<K, V>::Storage(Base* parent, const std::string& name, bool duplicates):
|
||||
iStorage(parent, name, duplicates),
|
||||
keySerializer(),
|
||||
valueSerializer(),
|
||||
cursors()
|
||||
@ -692,7 +693,7 @@ void LMDBAL::Storage<K, V>::removeRecord(const K& key, TransactionID txn) {
|
||||
*/
|
||||
template<class K, class V>
|
||||
int LMDBAL::Storage<K, V>::open(MDB_txn* transaction) {
|
||||
return makeStorage<K>(transaction);
|
||||
return makeStorage<K, V>(transaction, duplicates);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -719,6 +720,30 @@ LMDBAL::Cursor<K, V>* LMDBAL::Storage<K, V>::createCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reads current storage flags it was opened with
|
||||
*
|
||||
* This function exists mostly for testing purposes
|
||||
*
|
||||
* \returns Third out parameter of <a href="http://www.lmdb.tech/doc/group__internal.html#ga95ba4cb721035478a8705e57b91ae4d4">mdb_dbi_flags</a> function
|
||||
*
|
||||
* \exception LMDBAL::Closed thrown if the database was not opened
|
||||
* \exception LMDBAL::Unknown if the result of <a href="http://www.lmdb.tech/doc/group__internal.html#ga95ba4cb721035478a8705e57b91ae4d4">mdb_dbi_flags</a> was not successfull
|
||||
*/
|
||||
template<class K, class V>
|
||||
uint32_t LMDBAL::Storage<K, V>::flags() const {
|
||||
ensureOpened(flagsMethodName);
|
||||
uint32_t result;
|
||||
TransactionID txn = beginReadOnlyTransaction();
|
||||
|
||||
int res = mdb_dbi_flags(txn, dbi, &result);
|
||||
abortTransaction(txn);
|
||||
if (res != MDB_SUCCESS)
|
||||
throwUnknown(res);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Destroys cursor
|
||||
*
|
||||
@ -726,7 +751,7 @@ LMDBAL::Cursor<K, V>* LMDBAL::Storage<K, V>::createCursor() {
|
||||
*
|
||||
* \param[in] cursor a pointer to a cursor you want to destroy
|
||||
*
|
||||
* \throws LMDBAL::Unknown thrown if you try to destroy something that this storage didn't create
|
||||
* \exception LMDBAL::Unknown thrown if you try to destroy something that this storage didn't create
|
||||
*/
|
||||
template<class K, class V>
|
||||
void LMDBAL::Storage<K, V>::destroyCursor(Cursor<K, V>* cursor) {
|
||||
@ -770,79 +795,28 @@ void LMDBAL::Storage<K, V>::discoveredRecord(const K& key, const V& value, Trans
|
||||
* \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] duplicates - true if you wish to enable duplicates support for the storage
|
||||
*
|
||||
* \returns MDB_SUCCESS if everything went smooth or MDB_<error> -like error code
|
||||
*
|
||||
* This and the following collection of specializations are a way to optimise database using
|
||||
* MDB_INTEGERKEY flag, when the key is actually kind of an integer
|
||||
* This is a way to optimise database using MDB_INTEGERKEY flag,
|
||||
* when the key is actually kind of an integer
|
||||
* This infrastructure also allowes us to customize mdb_dbi_open call in the future
|
||||
*/
|
||||
template<class K>
|
||||
inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) {
|
||||
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE, &dbi);
|
||||
}
|
||||
template<class K, class V>
|
||||
inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction, bool duplicates) {
|
||||
unsigned int flags = MDB_CREATE;
|
||||
if constexpr (std::is_integral<K>::value)
|
||||
flags |= MDB_INTEGERKEY;
|
||||
|
||||
/**
|
||||
* \brief Opening database function specialization for uint64_t
|
||||
*/
|
||||
template<>
|
||||
inline int LMDBAL::iStorage::makeStorage<uint64_t>(MDB_txn* transaction) {
|
||||
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
|
||||
}
|
||||
if (duplicates) {
|
||||
flags |= MDB_DUPSORT;
|
||||
|
||||
/**
|
||||
* \brief Opening database function specialization for uint32_t
|
||||
*/
|
||||
template<>
|
||||
inline int LMDBAL::iStorage::makeStorage<uint32_t>(MDB_txn* transaction) {
|
||||
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
|
||||
}
|
||||
if constexpr (std::is_integral<V>::value)
|
||||
flags |= MDB_INTEGERDUP | MDB_DUPFIXED;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Opening database function specialization for uint16_t
|
||||
*/
|
||||
template<>
|
||||
inline int LMDBAL::iStorage::makeStorage<uint16_t>(MDB_txn* transaction) {
|
||||
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Opening database function specialization for uint8_t
|
||||
*/
|
||||
template<>
|
||||
inline int LMDBAL::iStorage::makeStorage<uint8_t>(MDB_txn* transaction) {
|
||||
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Opening database function specialization for int64_t
|
||||
*/
|
||||
template<>
|
||||
inline int LMDBAL::iStorage::makeStorage<int64_t>(MDB_txn* transaction) {
|
||||
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Opening database function specialization for int32_t
|
||||
*/
|
||||
template<>
|
||||
inline int LMDBAL::iStorage::makeStorage<int32_t>(MDB_txn* transaction) {
|
||||
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Opening database function specialization for int16_t
|
||||
*/
|
||||
template<>
|
||||
inline int LMDBAL::iStorage::makeStorage<int16_t>(MDB_txn* transaction) {
|
||||
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Opening database function specialization for int8_t
|
||||
*/
|
||||
template<>
|
||||
inline int LMDBAL::iStorage::makeStorage<int8_t>(MDB_txn* transaction) {
|
||||
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
|
||||
return mdb_dbi_open(transaction, name.c_str(), flags, &dbi);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,10 @@ protected:
|
||||
|
||||
~BaseTest() {}
|
||||
|
||||
uint32_t getT1Flags() const {return t1->flags();}
|
||||
uint32_t getT2Flags() const {return t2->flags();}
|
||||
uint32_t getC1Flags() const {return c1->flags();}
|
||||
|
||||
static void SetUpTestSuite() {
|
||||
if (db == nullptr) {
|
||||
db = new LMDBAL::Base("testBase");
|
||||
@ -56,6 +60,27 @@ TEST_F(BaseTest, OpeningClosingDatabase) {
|
||||
EXPECT_EQ(db->ready(), true);
|
||||
}
|
||||
|
||||
TEST_F(BaseTest, Flags) {
|
||||
uint32_t t1Flags = getT1Flags();
|
||||
uint32_t t2Flags = getT2Flags();
|
||||
uint32_t c1Flags = getC1Flags();
|
||||
|
||||
EXPECT_TRUE(t1Flags & MDB_INTEGERKEY);
|
||||
EXPECT_FALSE(t1Flags & MDB_DUPSORT);
|
||||
EXPECT_FALSE(t1Flags & MDB_DUPFIXED);
|
||||
EXPECT_FALSE(t1Flags & MDB_INTEGERDUP);
|
||||
|
||||
EXPECT_FALSE(t2Flags & MDB_INTEGERKEY);
|
||||
EXPECT_FALSE(t2Flags & MDB_DUPSORT);
|
||||
EXPECT_FALSE(t2Flags & MDB_DUPFIXED);
|
||||
EXPECT_FALSE(t2Flags & MDB_INTEGERDUP);
|
||||
|
||||
EXPECT_TRUE(c1Flags & MDB_INTEGERKEY);
|
||||
EXPECT_FALSE(c1Flags & MDB_DUPSORT);
|
||||
EXPECT_FALSE(c1Flags & MDB_DUPFIXED);
|
||||
EXPECT_FALSE(c1Flags & MDB_INTEGERDUP);
|
||||
}
|
||||
|
||||
TEST_F(BaseTest, AddingIntegerKey) {
|
||||
EXPECT_EQ(db->ready(), true);
|
||||
t1->addRecord(1, 2);
|
||||
|
Loading…
Reference in New Issue
Block a user