diff --git a/test/transactionengine.cpp b/test/transactionengine.cpp new file mode 100644 index 000000000..0a6d20991 --- /dev/null +++ b/test/transactionengine.cpp @@ -0,0 +1,53 @@ +#include +#include +#include + +#include "catch.hpp" + +#include "transaction/transactionengine.hpp" +#include "sync/spinlock.hpp" + +TEST_CASE("(try to) test correctness of the transaction life cycle") +{ + constexpr int THREADS = 16; + constexpr int TRANSACTIONS = 10; + + TransactionEngine engine(0); + std::vector sums; + + sums.resize(THREADS); + + auto f = [&engine, &sums](int idx, int n) + { + uint64_t sum = 0; + + for(int i = 0; i < n; ++i) + { + auto t = engine.begin(); + sum += t.id; + engine.commit(t); + } + + sums[idx] = sum; + }; + + std::vector threads; + + for(int i = 0; i < THREADS; ++i) + threads.push_back(std::thread(f, i, TRANSACTIONS)); + + for(auto& thread : threads) + thread.join(); + + uint64_t sum_computed = 0; + + for(int i = 0; i < THREADS; ++i) + sum_computed += sums[i]; + + uint64_t sum_actual = 0; + + for(uint64_t i = 0; i <= THREADS * TRANSACTIONS; ++i) + sum_actual += i; + + REQUIRE(sum_computed == sum_actual); +} diff --git a/transaction/transaction.hpp b/transaction/transaction.hpp new file mode 100644 index 000000000..d13c9c9b2 --- /dev/null +++ b/transaction/transaction.hpp @@ -0,0 +1,26 @@ +#ifndef MEMGRAPH_TRANSACTION_TRANSACTION_HPP +#define MEMGRAPH_TRANSACTION_TRANSACTION_HPP + +#include +#include + +template +struct Transaction +{ + Transaction(id_t id, std::vector active) + : id(id), active(std::move(active)) {} + + // index of this transaction + id_t id; + + // the ids of the currently active transactions used by the mvcc + // implementation for snapshot isolation + std::vector active; + + bool operator<(const Transaction& rhs) + { + return id < rhs.id; + } +}; + +#endif diff --git a/transaction/transaction_log.hpp b/transaction/transaction_log.hpp new file mode 100644 index 000000000..d599cb48a --- /dev/null +++ b/transaction/transaction_log.hpp @@ -0,0 +1,5 @@ +#ifndef MEMGRAPH_TRANSACTION_TRANSACTION_LOG_HPP +#define MEMGRAPH_TRANSACTION_TRANSACTION_LOG_HPP + + +#endif diff --git a/transaction/transactionengine.hpp b/transaction/transactionengine.hpp new file mode 100644 index 000000000..8389ccd4a --- /dev/null +++ b/transaction/transactionengine.hpp @@ -0,0 +1,88 @@ +#ifndef MEMGRAPH_TRANSACTION_TRANSACTIONENGINE_HPP +#define MEMGRAPH_TRANSACTION_TRANSACTIONENGINE_HPP + +#include +#include +#include +#include +#include +#include + +#include "transaction.hpp" + +template +class TransactionEngine +{ + using trans_t = Transaction; + +public: + TransactionEngine(id_t n) : counter(n) {} + + Transaction begin() + { + auto guard = acquire(); + + auto id = ++counter; + auto t = Transaction(id, active); + + active.push_back(id); + + return t; + } + + void commit(const Transaction& t) + { + auto guard = acquire(); + + finalize_transaction(t); + } + + void rollback(const Transaction& t) + { + auto guard = acquire(); + // what to do here? + + finalize_transaction(t); + } + + // id of the last finished transaction + id_t epochs_passed() + { + auto guard = acquire(); + return active.front() - 1; + } + + // total number of transactions started from the beginning of time + id_t count() + { + auto guard = acquire(); + return counter; + } + + // the number of currently active transactions + size_t size() + { + auto guard = acquire(); + return active.size(); + } + +private: + void finalize_transaction(const Transaction& t) + { + // remove transaction from the active transactions list + auto last = std::remove(active.begin(), active.end(), t.id); + active.erase(last, active.end()); + } + + std::unique_lock acquire() + { + return std::unique_lock(lock); + } + + id_t counter; + lock_t lock; + + std::vector active; +}; + +#endif