1
0
Fork 0
forked from blue/lmdbal

First attempt to make RAII cursors, no tests yet

This commit is contained in:
Blue 2023-10-25 19:18:23 -03:00
parent a0eebc978d
commit 96d7d9ef64
Signed by untrusted user: blue
GPG key ID: 9B203B252A63EE38
12 changed files with 374 additions and 233 deletions

View file

@ -41,6 +41,8 @@
* You are not supposed to instantiate or destory instances of this class yourself!
*/
static uint32_t idCounter = 0;
/**
* \brief Creates a cursor
*
@ -50,9 +52,74 @@ template<class K, class V>
LMDBAL::Cursor<K, V>::Cursor(Storage<K, V>* parent):
storage(parent),
cursor(nullptr),
state(closed)
state(closed),
id(++idCounter)
{
storage->cursors[id] = this;
}
/**
* \brief Creates an empty cursor.
*
* It's not usable, but can exist just to be a target of moves
*/
template<class K, class V>
LMDBAL::Cursor<K, V>::Cursor():
storage(nullptr),
cursor(nullptr),
state(closed),
id(0)
{}
/**
* \brief Moves from another cursor
*/
template<class K, class V>
LMDBAL::Cursor<K, V>::Cursor(Cursor&& other):
storage(other.storage),
cursor(other.cursor),
state(other.state),
id(other.id)
{
if (id != 0)
storage->cursors[id] = this;
other.cursor = nullptr;
other.storage = nullptr;
other.id = 0;
other.state = closed;
}
/**
* \brief A private function that turns cursor into an empty one
*
* This function is called from LMDBAL::Storage, when it gets destroyed, but still has some valid.
* Those cursors will become empty, and can't be used anymore
*/
template<class K, class V>
LMDBAL::Cursor<K, V>& LMDBAL::Cursor<K, V>::operator = (Cursor&& other) {
terminated();
if (id != 0)
storage->cursors.erase(id);
storage = other.storage;
cursor = other.cursor;
state = other.state;
id = other.id;
if (id != 0) {
other.cursor = nullptr;
other.storage = nullptr;
other.id = 0;
other.state = closed;
storage->cursors[id] = this;
}
return *this;
}
/**
* \brief Destroys a cursor
*
@ -61,13 +128,58 @@ LMDBAL::Cursor<K, V>::Cursor(Storage<K, V>* parent):
template<class K, class V>
LMDBAL::Cursor<K, V>::~Cursor () {
close();
if (id != 0)
storage->cursors.erase(id);
}
/**
* \brief Turns cursor into an empty one, releasing resources
*
* This function is called from LMDBAL::Storage, when it gets destroyed, but still has some valid.
* Those cursors will become empty, and can't be used anymore
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::drop () {
close();
if (id != 0)
storage->cursors.erase(id);
cursor = nullptr;
storage = nullptr;
id = 0;
}
/**
* \brief A private method that turns cursor into an empty one
*
* This function is called from LMDBAL::Storage, when it gets destroyed, but still has some valid.
* Those cursors will become empty, and can't be used anymore
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::dropped () {
terminated();
cursor = nullptr;
storage = nullptr;
id = 0;
}
/**
* \brief Returns true if the cursor is empty
*
* Empty cursors can't be used, they can be only targets of move operations
*/
template<class K, class V>
bool LMDBAL::Cursor<K, V>::empty () const {
return id == 0;
}
/**
* \brief A private function the storage owning this cursor will call to inform this cursor that the thansaction needs to be aborted
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::terminated () const {
void LMDBAL::Cursor<K, V>::terminated () {
close(); //for now it's the same, but if I ever going to make writable cursor - here is where it's gonna be different
}
@ -80,11 +192,15 @@ void LMDBAL::Cursor<K, V>::terminated () const {
* This function should be called when the LMDBAL::Storage is already opened and before any query with this cursor!
* It will do nothing to a cursor that was already opened (no matter what way).
*
* \exception LMDBAL::Closed thrown if you try to open the cursor on a closed database
* \exception LMDBAL::Unknown thrown if there was a problem opening the cursor by the lmdb, or to begin a transaction
* \exception LMDBAL::Closed thrown if you try to open the cursor on a closed database
* \exception LMDBAL::Unknown thrown if there was a problem opening the cursor by the lmdb, or to begin a transaction
* \exception LMDBAL::CursorEmpty thrown if the cursor was empty
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::open () const {
void LMDBAL::Cursor<K, V>::open () {
if (empty())
throw CursorEmpty(openCursorMethodName);
storage->ensureOpened(openCursorMethodName);
switch (state) {
case closed: {
@ -115,9 +231,13 @@ void LMDBAL::Cursor<K, V>::open () const {
* \exception LMDBAL::Closed thrown if you try to open the cursor on a closed database
* \exception LMDBAL::Unknown thrown if there was a problem opening the cursor by the lmdb
* \exception LMDBAL::TransactionTerminated thrown if the passed transaction not active, any action with it's inner ID is an error
* \exception LMDBAL::CursorEmpty thrown if the cursor was empty
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::open (const Transaction& transaction) const {
void LMDBAL::Cursor<K, V>::open (const Transaction& transaction) {
if (empty())
throw CursorEmpty(openCursorMethodName);
storage->ensureOpened(openCursorMethodName);
TransactionID txn = storage->extractTransactionId(transaction, openCursorMethodName);
switch (state) {
@ -146,11 +266,15 @@ void LMDBAL::Cursor<K, V>::open (const Transaction& transaction) const {
*
* This function does nothing if the cursor is closed
*
* \exception LMDBAL::Closed thrown if you try to renew the cursor on a closed database
* \exception LMDBAL::Unknown thrown if there was a problem beginning new transaction or if there was a problem renewing the cursor by lmdb
* \exception LMDBAL::Closed thrown if you try to renew the cursor on a closed database
* \exception LMDBAL::Unknown thrown if there was a problem beginning new transaction or if there was a problem renewing the cursor by lmdb
* \exception LMDBAL::CursorEmpty thrown if the cursor was empty
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::renew () const {
void LMDBAL::Cursor<K, V>::renew () {
if (empty())
throw CursorEmpty(openCursorMethodName);
storage->ensureOpened(renewCursorMethodName);
switch (state) {
case openedPrivate: {
@ -191,9 +315,13 @@ void LMDBAL::Cursor<K, V>::renew () const {
* \exception LMDBAL::Closed thrown if you try to renew the cursor on a closed database
* \exception LMDBAL::Unknown thrown if there was a problem renewing the cursor by lmdb
* \exception LMDBAL::TransactionTerminated thrown if the passed transaction not active, any action with it's inner ID is an error
* \exception LMDBAL::CursorEmpty thrown if the cursor was empty
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::renew (const Transaction& transaction) const {
void LMDBAL::Cursor<K, V>::renew (const Transaction& transaction) {
if (empty())
throw CursorEmpty(openCursorMethodName);
storage->ensureOpened(renewCursorMethodName);
TransactionID txn = storage->extractTransactionId(transaction, renewCursorMethodName);
switch (state) {
@ -226,7 +354,7 @@ void LMDBAL::Cursor<K, V>::renew (const Transaction& transaction) const {
* This function does nothing on a closed cursor.
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::close () const {
void LMDBAL::Cursor<K, V>::close () {
switch (state) {
case openedPublic: {
mdb_cursor_close(cursor);
@ -267,7 +395,7 @@ bool LMDBAL::Cursor<K, V>::opened () const {
* \exception LMDBAL::Unknown thrown if there was some unexpected problem with lmdb
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::first (K& key, V& value) const {
void LMDBAL::Cursor<K, V>::first (K& key, V& value) {
operateCursorRead(key, value, MDB_FIRST, firstMethodName, firstOperationName);
}
@ -284,7 +412,7 @@ void LMDBAL::Cursor<K, V>::first (K& key, V& value) const {
* \exception LMDBAL::Unknown thrown if there was some unexpected problem with lmdb
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::last (K& key, V& value) const {
void LMDBAL::Cursor<K, V>::last (K& key, V& value) {
operateCursorRead(key, value, MDB_LAST, lastMethodName, lastOperationName);
}
@ -307,7 +435,7 @@ void LMDBAL::Cursor<K, V>::last (K& key, V& value) const {
* \exception LMDBAL::Unknown thrown if there was some unexpected problem with lmdb
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::next (K& key, V& value) const {
void LMDBAL::Cursor<K, V>::next (K& key, V& value) {
operateCursorRead(key, value, MDB_NEXT, nextMethodName, nextOperationName);
}
@ -330,7 +458,7 @@ void LMDBAL::Cursor<K, V>::next (K& key, V& value) const {
* \exception LMDBAL::Unknown thrown if there was some unexpected problem with lmdb
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::prev (K& key, V& value) const {
void LMDBAL::Cursor<K, V>::prev (K& key, V& value) {
operateCursorRead(key, value, MDB_PREV, prevMethodName, prevOperationName);
}
@ -349,7 +477,7 @@ void LMDBAL::Cursor<K, V>::prev (K& key, V& value) const {
* \exception LMDBAL::Unknown thrown if there was some unexpected problem with lmdb
*/
template<class K, class V>
void LMDBAL::Cursor<K, V>::current (K& key, V& value) const {
void LMDBAL::Cursor<K, V>::current (K& key, V& value) const {
operateCursorRead(key, value, MDB_GET_CURRENT, currentMethodName, currentOperationName);
}
@ -365,7 +493,7 @@ void LMDBAL::Cursor<K, V>::current (K& key, V& value) const {
* \exception LMDBAL::Unknown thrown if there was some unexpected problem with lmdb
*/
template<class K, class V>
std::pair<K, V> LMDBAL::Cursor<K, V>::first () const {
std::pair<K, V> LMDBAL::Cursor<K, V>::first () {
std::pair<K, V> result;
operateCursorRead(result.first, result.second, MDB_FIRST, firstMethodName, firstOperationName);
return result;
@ -383,7 +511,7 @@ std::pair<K, V> LMDBAL::Cursor<K, V>::first () const {
* \exception LMDBAL::Unknown thrown if there was some unexpected problem with lmdb
*/
template<class K, class V>
std::pair<K, V> LMDBAL::Cursor<K, V>::last () const {
std::pair<K, V> LMDBAL::Cursor<K, V>::last () {
std::pair<K, V> result;
operateCursorRead(result.first, result.second, MDB_LAST, lastMethodName, lastOperationName);
return result;
@ -407,7 +535,7 @@ std::pair<K, V> LMDBAL::Cursor<K, V>::last () const {
* \exception LMDBAL::Unknown thrown if there was some unexpected problem with lmdb
*/
template<class K, class V>
std::pair<K, V> LMDBAL::Cursor<K, V>::next () const {
std::pair<K, V> LMDBAL::Cursor<K, V>::next () {
std::pair<K, V> result;
operateCursorRead(result.first, result.second, MDB_NEXT, nextMethodName, nextOperationName);
return result;
@ -431,7 +559,7 @@ std::pair<K, V> LMDBAL::Cursor<K, V>::next () const {
* \exception LMDBAL::Unknown thrown if there was some unexpected problem with lmdb
*/
template<class K, class V>
std::pair<K, V> LMDBAL::Cursor<K, V>::prev () const {
std::pair<K, V> LMDBAL::Cursor<K, V>::prev () {
std::pair<K, V> result;
operateCursorRead(result.first, result.second, MDB_PREV, prevMethodName, prevOperationName);
return result;