/* * LMDB Abstraction Layer. * Copyright (C) 2023 Yury Gubich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "transaction.h" #include "cursorcommon.h" /** * \class LMDBAL::Transaction * \brief Public read only transaction * * This class provides read only transactions you can use * to speed to your queries keeping them thread safe. * LMDBAL::Transaction is NOT COPYABLE but MOVABLE. * Transaction can be in one of two states: active or terminated. * The way to receive an active LMDBAL::Transaction is to call LMDBAL::Base::beginReadOnlyTransaction. * * Active transactions become terminated upon the call of LMDBAL::Transaction::terminate. * Active transactions automaticaly terminate themselves upon destruction. * * You CAN NOT use inactive transactions for any query. */ /** * \brief Constructs inactive transaction */ LMDBAL::Transaction::Transaction(): txn(nullptr), active(false), parent(nullptr), cursors() {} /** * \brief Constructs an active transaction */ LMDBAL::Transaction::Transaction(TransactionID txn, const Base* parent) : txn(txn), active(true), parent(parent), cursors() { parent->transactions[txn] = this; } /** * \brief Moves transaction to a new object */ LMDBAL::Transaction::Transaction(Transaction&& other): txn(other.txn), active(other.active), parent(other.parent), cursors(other.cursors) { if (active) { parent->transactions[txn] = this; other.reset(); } } /** * \brief Destroys transaction */ LMDBAL::Transaction::~Transaction() { terminate(); } /** * \brief Move-assigns transaction to the new object */ LMDBAL::Transaction& LMDBAL::Transaction::operator=(Transaction&& other) { if (this == &other) return *this; terminate(); txn = other.txn; active = other.active; parent = other.parent; cursors = other.cursors; if (active) { parent->transactions[txn] = this; other.reset(); } return *this; } /** * \brief Terminates transaction if it was active * * Transaction becomes terminated after calling this method */ void LMDBAL::Transaction::terminate() { if (active) { closeCursors(); parent->abortTransaction(txn); parent->transactions.erase(txn); reset(); } } /** * \brief Resets inner transaction properties to inactive state */ void LMDBAL::Transaction::reset() { active = false; txn = nullptr; parent = nullptr; cursors.clear(); } /** * \brief Closes attached curors; */ void LMDBAL::Transaction::closeCursors () { for (const std::pair& pair : cursors) pair.second->terminated(); } /** * \brief Returns transaction states * * \returns true if the transaction is active, false otherwise */ bool LMDBAL::Transaction::isActive() const { return active; //todo may be it's better if I query it from DB? } /** * \class LMDBAL::WriteTransaction * \brief Public writable transaction * * This class provides writable transactions you can use * to speed to your queries and modifications keeping them thread safe. * LMDBAL::WriteTransaction is NOT COPYABLE but MOVABLE. * Transaction can be in one of two states: active or terminated. * The way to receive an active LMDBAL::WriteTransaction is to call LMDBAL::Base::beginTransaction. * You can use LMDBAL::WriteTransaction for everything instead of LMDBAL::Transaction * * Active transactions become terminated upon the call of * LMDBAL::WriteTransaction::abort or LMDBAL::WriteTransaction::commit. * Calling LMDBAL::Transaction::terminate on LMDBAL::WriteTransaction * is exactly the same as calling LMDBAL::WriteTransaction::abort. * * Active transactions automaticaly terminate themselves upon destruction. * For LMDBAL::WriteTransaction default behaviour upon destruction is to abort. * * You CAN NOT use inactive transactions for any query. */ /** * \brief Constructs active write transaction */ LMDBAL::WriteTransaction::WriteTransaction(TransactionID txn, Base* parent): Transaction(txn, parent) {} /** * \brief Constructs inactive write transaction */ LMDBAL::WriteTransaction::WriteTransaction(): Transaction() {} /** * \brief Moves transaction to the new object */ LMDBAL::WriteTransaction::WriteTransaction(WriteTransaction&& other): Transaction(std::move(other)) {} LMDBAL::WriteTransaction& LMDBAL::WriteTransaction::operator=(WriteTransaction&& other) { Transaction::operator=(std::move(other)); return *this; } /** * \brief Aborts transaction cancelling all changes * * Transaction becomes terminated after calling this method */ void LMDBAL::WriteTransaction::abort() { terminate(); } /** * \brief Commits transaction submitting all changes * * Transaction becomes terminated after calling this method */ void LMDBAL::WriteTransaction::commit() { if (active) { closeCursors(); const_cast(parent)->commitTransaction(txn); parent->transactions.erase(txn); reset(); } }