dncurrency/nano/secure/transaction.hpp
Piotr Wójcik 6882f656e7
Make nano::async::task::join safe to call from multiple threads (#4892)
* Make `nano::async::task::join` safe to call from multiple threads

* Test `nano::async::task::join ()`
2025-04-21 13:06:36 +02:00

175 lines
3.8 KiB
C++

#pragma once
#include <nano/store/transaction.hpp>
#include <nano/store/write_queue.hpp>
#include <future>
#include <utility>
namespace nano::secure
{
class transaction
{
public:
transaction () = default;
virtual ~transaction () = default;
// Deleting copy and assignment operations
transaction (const transaction &) = delete;
transaction & operator= (const transaction &) = delete;
// Default move operations
transaction (transaction &&) noexcept = default;
transaction & operator= (transaction &&) noexcept = default;
// Pure virtual function to get a const reference to the base store transaction
virtual const nano::store::transaction & base_txn () const = 0;
// Conversion operator to const nano::store::transaction&
virtual operator const nano::store::transaction & () const = 0;
// Certain transactions may need to be refreshed if they are held for a long time
virtual bool refresh_if_needed (std::chrono::milliseconds max_age = std::chrono::milliseconds{ 500 }) = 0;
};
class write_transaction final : public transaction
{
nano::store::write_guard guard; // Guard should be released after the transaction
nano::store::write_transaction txn;
std::chrono::steady_clock::time_point start;
// Future to signal transaction got committed
std::promise<void> promise;
std::shared_future<void> future{ promise.get_future () };
public:
write_transaction (nano::store::write_transaction && txn_a, nano::store::write_guard && guard_a) noexcept :
guard{ std::move (guard_a) },
txn{ std::move (txn_a) },
start{ std::chrono::steady_clock::now () }
{
debug_assert (active ());
}
~write_transaction () override
{
if (active ())
{
commit ();
}
}
write_transaction (write_transaction && other) = default;
// Override to return a reference to the encapsulated write_transaction
const nano::store::transaction & base_txn () const override
{
return txn;
}
void commit ()
{
txn.commit ();
guard.release ();
promise.set_value ();
}
void renew ()
{
guard.renew ();
txn.renew ();
start = std::chrono::steady_clock::now ();
promise = {};
future = { promise.get_future () };
}
void refresh ()
{
commit ();
renew ();
}
bool refresh_if_needed (std::chrono::milliseconds max_age = std::chrono::milliseconds{ 500 }) override
{
auto now = std::chrono::steady_clock::now ();
if (now - start > max_age)
{
refresh ();
return true;
}
return false;
}
auto timestamp () const
{
return txn.timestamp ();
}
bool active () const
{
return guard.is_owned ();
}
std::shared_future<void> get_future () const
{
return future; // Give a copy of the shared future
}
// Conversion operator to const nano::store::transaction&
operator const nano::store::transaction & () const override
{
return txn;
}
// Additional conversion operator specific to nano::store::write_transaction
operator const nano::store::write_transaction & () const
{
return txn;
}
};
class read_transaction final : public transaction
{
nano::store::read_transaction txn;
public:
explicit read_transaction (nano::store::read_transaction && t) noexcept :
txn{ std::move (t) }
{
}
// Override to return a reference to the encapsulated read_transaction
const nano::store::transaction & base_txn () const override
{
return txn;
}
void refresh ()
{
txn.refresh ();
}
bool refresh_if_needed (std::chrono::milliseconds max_age = std::chrono::milliseconds{ 500 }) override
{
return txn.refresh_if_needed (max_age);
}
auto timestamp () const
{
return txn.timestamp ();
}
// Conversion operator to const nano::store::transaction&
operator const nano::store::transaction & () const override
{
return txn;
}
// Additional conversion operator specific to nano::store::read_transaction
operator const nano::store::read_transaction & () const
{
return txn;
}
};
}