refactored storage engine
This commit is contained in:
parent
47bd3b372b
commit
379bfb14c4
@ -28,10 +28,7 @@ public:
|
|||||||
|
|
||||||
void unlock()
|
void unlock()
|
||||||
{
|
{
|
||||||
// INVALID flag is far more readable, but _ /
|
owner = INVALID;
|
||||||
// for some reason it gives linker errors o.O
|
|
||||||
// owner = INVALID; (_)
|
|
||||||
owner = Id(); // ^ ^
|
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,3 +36,7 @@ private:
|
|||||||
Futex mutex;
|
Futex mutex;
|
||||||
Id owner;
|
Id owner;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr struct timespec RecordLock::timeout;
|
||||||
|
constexpr Id RecordLock::INVALID;
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ int main(void)
|
|||||||
auto a1 = vertex.access(t1);
|
auto a1 = vertex.access(t1);
|
||||||
auto v1 = a1.insert();
|
auto v1 = a1.insert();
|
||||||
|
|
||||||
v1->data.props.emplace<String>("name", "buda");
|
v1->data.props.set<String>("name", "buda");
|
||||||
v1->data.props.emplace<Int32>("age", 23);
|
v1->data.props.set<Int32>("age", 23);
|
||||||
|
|
||||||
cout << vertex;
|
cout << vertex;
|
||||||
|
|
||||||
@ -25,9 +25,19 @@ int main(void)
|
|||||||
|
|
||||||
auto& t2 = engine.begin();
|
auto& t2 = engine.begin();
|
||||||
auto a2 = vertex.access(t2);
|
auto a2 = vertex.access(t2);
|
||||||
a2.remove();
|
auto v2 = a2.update();
|
||||||
|
|
||||||
/* v2->data.props.emplace<Int32>("age", 24); */
|
v2->data.props.set<Int32>("age", 24);
|
||||||
|
|
||||||
|
cout << vertex;
|
||||||
|
|
||||||
|
t2.abort();
|
||||||
|
|
||||||
|
auto& t3 = engine.begin();
|
||||||
|
auto a3 = vertex.access(t3);
|
||||||
|
auto v3 = a3.update();
|
||||||
|
|
||||||
|
v3->data.props.set<Int32>("age", 25);
|
||||||
|
|
||||||
cout << vertex;
|
cout << vertex;
|
||||||
|
|
||||||
|
@ -19,9 +19,7 @@ namespace mvcc
|
|||||||
template <class T>
|
template <class T>
|
||||||
class Record : public Version<T>
|
class Record : public Version<T>
|
||||||
{
|
{
|
||||||
friend class VersionList<T>;
|
public:
|
||||||
|
|
||||||
private:
|
|
||||||
// tx.cre is the id of the transaction that created the record
|
// tx.cre is the id of the transaction that created the record
|
||||||
// and tx.exp is the id of the transaction that deleted the record
|
// and tx.exp is the id of the transaction that deleted the record
|
||||||
// these values are used to determine the visibility of the record
|
// these values are used to determine the visibility of the record
|
||||||
|
@ -13,13 +13,24 @@ namespace mvcc
|
|||||||
template <class T>
|
template <class T>
|
||||||
class VersionList : LazyGC<VersionList<T>>
|
class VersionList : LazyGC<VersionList<T>>
|
||||||
{
|
{
|
||||||
|
friend class Accessor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Accessor
|
class Accessor
|
||||||
{
|
{
|
||||||
friend class VersionList<T>;
|
friend class VersionList<T>;
|
||||||
|
|
||||||
Accessor(tx::Transaction& transaction, VersionList<T>& record)
|
Accessor(tx::Transaction& transaction, VersionList<T>& record)
|
||||||
: transaction(transaction), record(record) {}
|
: transaction(transaction), record(record)
|
||||||
|
{
|
||||||
|
record.add_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Accessor()
|
||||||
|
{
|
||||||
|
record.release_ref();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Accessor(const Accessor&) = default;
|
Accessor(const Accessor&) = default;
|
||||||
Accessor(Accessor&&) = default;
|
Accessor(Accessor&&) = default;
|
||||||
@ -79,7 +90,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<T*> head;
|
std::atomic<T*> head {nullptr};
|
||||||
RecordLock lock;
|
RecordLock lock;
|
||||||
//static Recycler recycler;
|
//static Recycler recycler;
|
||||||
|
|
||||||
@ -106,6 +117,7 @@ private:
|
|||||||
T* insert(tx::Transaction& t)
|
T* insert(tx::Transaction& t)
|
||||||
{
|
{
|
||||||
assert(head == nullptr);
|
assert(head == nullptr);
|
||||||
|
|
||||||
// create a first version of the record
|
// create a first version of the record
|
||||||
// TODO replace 'new' with something better
|
// TODO replace 'new' with something better
|
||||||
auto v1 = new T();
|
auto v1 = new T();
|
||||||
@ -160,11 +172,11 @@ private:
|
|||||||
|
|
||||||
// if the record hasn't been deleted yet or the deleting transaction
|
// if the record hasn't been deleted yet or the deleting transaction
|
||||||
// has aborted, it's ok to modify it
|
// has aborted, it's ok to modify it
|
||||||
if(!record->tx.exp() || record->hints.load().max.is_aborted())
|
if(!record->tx.exp() || record->hints.load().exp.is_aborted())
|
||||||
return record;
|
return record;
|
||||||
|
|
||||||
// if it committed, then we have a serialization conflict
|
// if it committed, then we have a serialization conflict
|
||||||
assert(record->hints.load().max.is_committed());
|
assert(record->hints.load().exp.is_committed());
|
||||||
throw SerializationError();
|
throw SerializationError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,12 +21,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class... Args>
|
template <class T, class... Args>
|
||||||
void emplace(const std::string& key, Args&&... args)
|
void set(const std::string& key, Args&&... args)
|
||||||
{
|
{
|
||||||
auto value = std::make_shared<T>(std::forward<Args>(args)...);
|
auto value = std::make_shared<T>(std::forward<Args>(args)...);
|
||||||
|
|
||||||
// try to emplace the item
|
// try to emplace the item
|
||||||
auto result = props.emplace(std::make_pair(key, std::move(value)));
|
auto result = props.emplace(std::make_pair(key, value));
|
||||||
|
|
||||||
// return if we succedded
|
// return if we succedded
|
||||||
if(result.second)
|
if(result.second)
|
||||||
@ -36,7 +36,7 @@ public:
|
|||||||
result.first->second = std::move(value);
|
result.first->second = std::move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void put(const std::string& key, Property::sptr value)
|
void set(const std::string& key, Property::sptr value)
|
||||||
{
|
{
|
||||||
props[key] = std::move(value);
|
props[key] = std::move(value);
|
||||||
}
|
}
|
||||||
|
@ -1,110 +0,0 @@
|
|||||||
#ifndef MEMGRAPH_STORAGE_STORAGE_ENGINE_HPP
|
|
||||||
#define MEMGRAPH_STORAGE_STORAGE_ENGINE_HPP
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#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 <class T>
|
|
||||||
bool insert(T** record, const Transaction& t)
|
|
||||||
{
|
|
||||||
auto n = next<T>();
|
|
||||||
*record = memory.create<T>(n);
|
|
||||||
|
|
||||||
// set creating transaction
|
|
||||||
(*record)->tx.min(t.id);
|
|
||||||
|
|
||||||
// set creating command of this transaction
|
|
||||||
(*record)->cmd.min(t.cid);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
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<T>();
|
|
||||||
**updated = *record; // copy the data in the current node TODO memset?
|
|
||||||
|
|
||||||
record->newer(*updated);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
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<class T>
|
|
||||||
uint64_t next();
|
|
||||||
|
|
||||||
AtomicCounter<uint64_t> vertex_counter;
|
|
||||||
AtomicCounter<uint64_t> edge_counter;
|
|
||||||
|
|
||||||
MemoryEngine& memory;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template<>
|
|
||||||
uint64_t StorageEngine::next<Vertex>()
|
|
||||||
{
|
|
||||||
return vertex_counter.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
uint64_t StorageEngine::next<Edge>()
|
|
||||||
{
|
|
||||||
return edge_counter.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -30,8 +30,8 @@ inline std::ostream& operator<<(std::ostream& stream, const Vertex& record)
|
|||||||
writer.finish();
|
writer.finish();
|
||||||
|
|
||||||
return stream << "Vertex"
|
return stream << "Vertex"
|
||||||
<< "(xmin = " << record.tx.cre()
|
<< "(cre = " << record.tx.cre()
|
||||||
<< ", xmax = " << record.tx.exp()
|
<< ", exp = " << record.tx.exp()
|
||||||
<< "): " << buffer.str();
|
<< "): " << buffer.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
storage/vertex_store.hpp
Normal file
2
storage/vertex_store.hpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#pragma once
|
||||||
|
|
Loading…
Reference in New Issue
Block a user