#ifndef MEMGRAPH_STORAGE_STORAGE_ENGINE_HPP #define MEMGRAPH_STORAGE_STORAGE_ENGINE_HPP #include #include #include "transaction/transaction.hpp" #include "storage/model/record.hpp" #include "memory/memory_engine.hpp" #include "utils/counters/atomic_counter.hpp" #include "storage/model/root.hpp" class StorageEngine { public: StorageEngine(MemoryEngine& memory) : vertex_counter(0), edge_counter(0), memory(memory) {} template bool insert(T** record, const Transaction& t) { auto n = next(); *record = memory.create(n); // set creating transaction (*record)->tx.min(t.id); // set creating command of this transaction (*record)->cmd.min(t.cid); return true; } template bool update(T* record, T** updated, const Transaction& t) { // put a lock on the node to prevent other writers from modifying it auto guard = record->guard(); // find the record visible version of the record about to be updated record = record->latest(t); if(record == nullptr) return false; // another transaction just deleted it! *updated = memory.allocate(); **updated = *record; // copy the data in the current node TODO memset? record->newer(*updated); return true; } template bool remove(T& record, const Transaction& t) { // put a lock on the node to prevent other writers from modifying it auto guard = record->guard(); auto latest = record.latest(t); if(record == nullptr) return false; // only mark the record as deleted if it isn't already deleted // this prevents phantom reappearance of the deleted nodes // // T1 |---------- DELETE N --------| COMMIT // T2 |----- DELETE N ---------------------------------| COMMIT // T3 |-- SELECT N --| // // if xmax was overwritten by T2, T3 would see that T1 was still // running and determined that the record hasn't been deleted yet // even though T1 already committed before T3 even started! if(record->xmax()) return false; // another transaction deleted it! record->xmax(t.id); return true; } private: template uint64_t next(); AtomicCounter vertex_counter; AtomicCounter edge_counter; MemoryEngine& memory; }; template<> uint64_t StorageEngine::next() { return vertex_counter.next(); } template<> uint64_t StorageEngine::next() { return edge_counter.next(); } #endif