record accessor, indexes and cursors
This commit is contained in:
parent
c495872b22
commit
b93bab375e
@ -402,6 +402,11 @@ public:
|
|||||||
return Accessor(this);
|
return Accessor(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Accessor access() const
|
||||||
|
{
|
||||||
|
return Accessor(this);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using guard_t = std::unique_lock<lock_t>;
|
using guard_t = std::unique_lock<lock_t>;
|
||||||
|
|
||||||
|
@ -224,6 +224,11 @@ public:
|
|||||||
return Accessor(std::move(data.access()));
|
return Accessor(std::move(data.access()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Accessor access() const
|
||||||
|
{
|
||||||
|
return Accessor(std::move(data.access()));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkipList<Key, T> data;
|
SkipList<Key, T> data;
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "memory/lazy_gc.hpp"
|
#include "memory/lazy_gc.hpp"
|
||||||
#include "mvcc/serialization_error.hpp"
|
#include "mvcc/serialization_error.hpp"
|
||||||
#include "database/locking/record_lock.hpp"
|
#include "storage/locking/record_lock.hpp"
|
||||||
|
|
||||||
namespace mvcc
|
namespace mvcc
|
||||||
{
|
{
|
||||||
@ -22,16 +22,16 @@ public:
|
|||||||
{
|
{
|
||||||
friend class VersionList<T>;
|
friend class VersionList<T>;
|
||||||
|
|
||||||
Accessor(tx::Transaction& transaction, VersionList<T>& record)
|
Accessor(tx::Transaction& transaction, VersionList<T>& vlist)
|
||||||
: transaction(transaction), record(record)
|
: transaction(transaction), vlist(vlist)
|
||||||
{
|
{
|
||||||
record.add_ref();
|
vlist.add_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Accessor()
|
~Accessor()
|
||||||
{
|
{
|
||||||
record.release_ref();
|
vlist.release_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
Accessor(const Accessor&) = default;
|
Accessor(const Accessor&) = default;
|
||||||
@ -42,27 +42,42 @@ public:
|
|||||||
|
|
||||||
T* insert()
|
T* insert()
|
||||||
{
|
{
|
||||||
return record.insert(transaction);
|
return vlist.insert(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
const T* find() const
|
const T* find() const
|
||||||
{
|
{
|
||||||
return record.find(transaction);
|
return vlist.find(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
T* update()
|
T* update()
|
||||||
{
|
{
|
||||||
return record.update(transaction);
|
return vlist.update(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
T* update(T* record)
|
||||||
|
{
|
||||||
|
return vlist.update(record, transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool remove()
|
bool remove()
|
||||||
{
|
{
|
||||||
return record.remove(transaction);
|
return vlist.remove(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove(T* record)
|
||||||
|
{
|
||||||
|
return vlist.remove(record, transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Id& id() const
|
||||||
|
{
|
||||||
|
return vlist.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tx::Transaction& transaction;
|
tx::Transaction& transaction;
|
||||||
VersionList<T>& record;
|
VersionList<T>& vlist;
|
||||||
};
|
};
|
||||||
|
|
||||||
VersionList() = default;
|
VersionList() = default;
|
||||||
@ -117,6 +132,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::atomic<T*> head {nullptr};
|
std::atomic<T*> head {nullptr};
|
||||||
RecordLock lock;
|
RecordLock lock;
|
||||||
|
|
||||||
|
Id id;
|
||||||
|
|
||||||
//static Recycler recycler;
|
//static Recycler recycler;
|
||||||
|
|
||||||
T* find(const tx::Transaction& t)
|
T* find(const tx::Transaction& t)
|
||||||
@ -139,9 +157,10 @@ private:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
T* insert(tx::Transaction& t)
|
T* insert(tx::Transaction& t, const Id& id)
|
||||||
{
|
{
|
||||||
assert(head == nullptr);
|
assert(head == nullptr);
|
||||||
|
this->id = id;
|
||||||
|
|
||||||
// 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
|
||||||
@ -158,12 +177,20 @@ private:
|
|||||||
T* update(tx::Transaction& t)
|
T* update(tx::Transaction& t)
|
||||||
{
|
{
|
||||||
assert(head != nullptr);
|
assert(head != nullptr);
|
||||||
auto record = lock_and_validate(t);
|
auto record = find(t);
|
||||||
|
|
||||||
// check if we found any visible records
|
// check if we found any visible records
|
||||||
if(!record)
|
if(!record)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
return update(record, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
T* update(T* record, tx::Transaction& t)
|
||||||
|
{
|
||||||
|
assert(record != nullptr);
|
||||||
|
lock_and_validate(record, t);
|
||||||
|
|
||||||
auto updated = new T();
|
auto updated = new T();
|
||||||
updated->data = record->data;
|
updated->data = record->data;
|
||||||
|
|
||||||
@ -179,15 +206,23 @@ private:
|
|||||||
bool remove(tx::Transaction& t)
|
bool remove(tx::Transaction& t)
|
||||||
{
|
{
|
||||||
assert(head != nullptr);
|
assert(head != nullptr);
|
||||||
auto record = lock_and_validate(t);
|
auto record = find(t);
|
||||||
|
|
||||||
if(!record)
|
if(!record)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return record->mark_deleted(t), true;
|
lock_and_validate(record, t);
|
||||||
|
return remove(record, t), true;
|
||||||
}
|
}
|
||||||
|
|
||||||
T* lock_and_validate(T* record, tx::Transaction& t)
|
void remove(T* record, tx::Transaction& t)
|
||||||
|
{
|
||||||
|
assert(record != nullptr);
|
||||||
|
lock_and_validate(record, t);
|
||||||
|
record->mark_deleted(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock_and_validate(T* record, tx::Transaction& t)
|
||||||
{
|
{
|
||||||
assert(record != nullptr);
|
assert(record != nullptr);
|
||||||
assert(record == find(t));
|
assert(record == find(t));
|
||||||
@ -198,27 +233,12 @@ 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().exp.is_aborted())
|
if(!record->tx.exp() || record->hints.load().exp.is_aborted())
|
||||||
return record;
|
return;
|
||||||
|
|
||||||
// if it committed, then we have a serialization conflict
|
// if it committed, then we have a serialization conflict
|
||||||
assert(record->hints.load().exp.is_committed());
|
assert(record->hints.load().exp.is_committed());
|
||||||
throw SerializationError();
|
throw SerializationError();
|
||||||
}
|
}
|
||||||
|
|
||||||
T* lock_and_validate(tx::Transaction& t)
|
|
||||||
{
|
|
||||||
// find the visible record version to delete
|
|
||||||
auto record = find(t);
|
|
||||||
return record == nullptr ? nullptr : lock_and_validate(record, t);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// these are convenient typedefs to use in other contexes to make the code a
|
|
||||||
// bit clearer
|
|
||||||
class Vertex;
|
|
||||||
class Edge;
|
|
||||||
|
|
||||||
using VertexRecord = mvcc::VersionList<Vertex>;
|
|
||||||
using EdgeRecord = mvcc::VersionList<Edge>;
|
|
||||||
|
99
storage/cursor.hpp
Normal file
99
storage/cursor.hpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "transactions/transaction.hpp"
|
||||||
|
#include "mvcc/version_list.hpp"
|
||||||
|
#include "storage/model/properties/property.hpp"
|
||||||
|
|
||||||
|
#include "storage/vertex.hpp"
|
||||||
|
|
||||||
|
template <class T, class Accessor, class It, class Derived>
|
||||||
|
class RecordCursor : public Crtp<Derived>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RecordCursor(Accessor&& accessor, It item, tx::Transaction& t)
|
||||||
|
: accessor(accessor), item(item), t(t)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// |------------------------- data operations -------------------------|
|
||||||
|
|
||||||
|
const Property* property(const std::string& key) const
|
||||||
|
{
|
||||||
|
return record->props.at(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class V, class... Args>
|
||||||
|
void property(const std::string& key, Args&&... args)
|
||||||
|
{
|
||||||
|
record->props.template set<V>(key, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// |------------------------ record operations ------------------------|
|
||||||
|
|
||||||
|
Derived& update()
|
||||||
|
{
|
||||||
|
record = item->update(t);
|
||||||
|
return this->derived();
|
||||||
|
}
|
||||||
|
|
||||||
|
Derived& remove()
|
||||||
|
{
|
||||||
|
item->remove(t);
|
||||||
|
return this->derived();
|
||||||
|
}
|
||||||
|
|
||||||
|
// |-------------------------- iterator impl --------------------------|
|
||||||
|
|
||||||
|
Derived& operator++()
|
||||||
|
{
|
||||||
|
++item;
|
||||||
|
}
|
||||||
|
|
||||||
|
Derived& operator++(int)
|
||||||
|
{
|
||||||
|
return operator++();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator==(const Derived& a, const Derived& b)
|
||||||
|
{
|
||||||
|
return a.record == b.record;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator!=(const Derived& a, const Derived& b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& operator*() const
|
||||||
|
{
|
||||||
|
assert(record != nullptr);
|
||||||
|
return *record;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* operator->() const
|
||||||
|
{
|
||||||
|
assert(record != nullptr);
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator const T&() const
|
||||||
|
{
|
||||||
|
return *record;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Accessor accessor;
|
||||||
|
tx::Transaction& t;
|
||||||
|
It item;
|
||||||
|
|
||||||
|
T* record;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class It, class Accessor>
|
||||||
|
class Vertex::Cursor
|
||||||
|
: public RecordCursor<Vertex, Accessor, It, Cursor<It, Accessor>>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
};
|
25
storage/indexes/index.hpp
Normal file
25
storage/indexes/index.hpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "data_structures/skiplist/skiplist.hpp"
|
||||||
|
#include "keys/unique_key.hpp"
|
||||||
|
|
||||||
|
#include "storage/cursor.hpp"
|
||||||
|
|
||||||
|
template <class Key, class Cursor, class Item, class SortOrder>
|
||||||
|
class Index
|
||||||
|
{
|
||||||
|
using skiplist_t = SkipList<Key, Item*>;
|
||||||
|
using iterator_t = typename skiplist_t::Iterator;
|
||||||
|
using accessor_t = typename skiplist_t::Accessor;
|
||||||
|
using K = typename Key::key_t;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Cursor insert(const K& key, Item* item, tx::Transaction& t)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
skiplist_t skiplist;
|
||||||
|
};
|
24
storage/indexes/index_key.hpp
Normal file
24
storage/indexes/index_key.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils/total_ordering.hpp"
|
||||||
|
|
||||||
|
#include "ordering.hpp"
|
||||||
|
#include "storage/model/properties/properties.hpp"
|
||||||
|
#include "storage/model/properties/property.hpp"
|
||||||
|
|
||||||
|
template <class Ordering>
|
||||||
|
class UniqueIndexKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
namespace
|
||||||
|
|
||||||
|
private:
|
||||||
|
Property& key;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Orderingt>
|
||||||
|
class IndexKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
};
|
16
storage/indexes/keys/non_unique_key.hpp
Normal file
16
storage/indexes/keys/non_unique_key.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "unique_key.hpp"
|
||||||
|
|
||||||
|
template <class K, class T, class SortOrder>
|
||||||
|
class NonUniqueKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NonUniqueKey(const K& key, const T&)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
intptr_t x;
|
||||||
|
};
|
40
storage/indexes/keys/unique_key.hpp
Normal file
40
storage/indexes/keys/unique_key.hpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils/total_ordering.hpp"
|
||||||
|
|
||||||
|
#include "storage/indexes/sort_order.hpp"
|
||||||
|
#include "storage/model/properties/properties.hpp"
|
||||||
|
#include "storage/model/properties/property.hpp"
|
||||||
|
|
||||||
|
template <class K, class SortOrder>
|
||||||
|
class UniqueKey : public TotalOrdering<UniqueKey<K, SortOrder>>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using type = UniqueKey<K, SortOrder>;
|
||||||
|
using key_t = K;
|
||||||
|
|
||||||
|
UniqueKey(const K& key) : key(key) {}
|
||||||
|
|
||||||
|
friend constexpr bool operator<(const type& lhs, const type& rhs)
|
||||||
|
{
|
||||||
|
return sort_order(lhs.key, rhs.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator==(const type& lhs, const type& rhs)
|
||||||
|
{
|
||||||
|
return lhs.key == rhs.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator const K&() const { return key; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr SortOrder sort_order = SortOrder();
|
||||||
|
const K& key;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
using UniqueKeyAsc = UniqueKey<K, Ascending<K>>;
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
using UniqueKeyDesc = UniqueKey<K, Descending<K>>;
|
||||||
|
|
19
storage/indexes/sort_order.hpp
Normal file
19
storage/indexes/sort_order.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class Ascending
|
||||||
|
{
|
||||||
|
constexpr bool operator()(const T& lhs, const T& rhs) const
|
||||||
|
{
|
||||||
|
return lhs < rhs;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class Descending
|
||||||
|
{
|
||||||
|
constexpr bool operator()(const T& lhs, const T& rhs) const
|
||||||
|
{
|
||||||
|
return lhs > rhs;
|
||||||
|
}
|
||||||
|
};
|
24
storage/label_store.hpp
Normal file
24
storage/label_store.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "model/label.hpp"
|
||||||
|
#include "data_structures/skiplist/skiplistset.hpp"
|
||||||
|
|
||||||
|
class LabelStore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
const Label& find_or_create(const std::string& name)
|
||||||
|
{
|
||||||
|
auto accessor = labels.access();
|
||||||
|
return accessor.insert(Label(name)).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const std::string& name) const
|
||||||
|
{
|
||||||
|
auto accessor = labels.access();
|
||||||
|
return accessor.find(Label(name)) != accessor.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SkipListSet<Label> labels;
|
||||||
|
};
|
@ -7,29 +7,32 @@
|
|||||||
class Label : public TotalOrdering<Label>
|
class Label : public TotalOrdering<Label>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Label(const std::string& id) : id(id) {}
|
Label(const std::string& name) : name(name) {}
|
||||||
Label(std::string&& id) : id(std::move(id)) {}
|
Label(std::string&& name) : name(std::move(name)) {}
|
||||||
|
|
||||||
|
Label(const Label&) = default;
|
||||||
|
Label(Label&&) = default;
|
||||||
|
|
||||||
friend bool operator<(const Label& lhs, const Label& rhs)
|
friend bool operator<(const Label& lhs, const Label& rhs)
|
||||||
{
|
{
|
||||||
return lhs.id < rhs.id;
|
return lhs.name < rhs.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(const Label& lhs, const Label& rhs)
|
friend bool operator==(const Label& lhs, const Label& rhs)
|
||||||
{
|
{
|
||||||
return lhs.id == rhs.id;
|
return lhs.name == rhs.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& stream, const Label& label)
|
friend std::ostream& operator<<(std::ostream& stream, const Label& label)
|
||||||
{
|
{
|
||||||
return stream << label.id;
|
return stream << label.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator const std::string&() const
|
operator const std::string&() const
|
||||||
{
|
{
|
||||||
return id;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string id;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
@ -14,11 +14,6 @@ public:
|
|||||||
auto end() const { return labels.end(); }
|
auto end() const { return labels.end(); }
|
||||||
auto cend() const { return labels.end(); }
|
auto cend() const { return labels.end(); }
|
||||||
|
|
||||||
bool add(Label&& label)
|
|
||||||
{
|
|
||||||
return labels.insert(std::move(label)).second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool add(const Label& label)
|
bool add(const Label& label)
|
||||||
{
|
{
|
||||||
return labels.insert(label).second;
|
return labels.insert(label).second;
|
||||||
@ -50,5 +45,5 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<Label> labels;
|
std::set<const Label&> labels;
|
||||||
};
|
};
|
||||||
|
@ -9,12 +9,7 @@ class Properties
|
|||||||
using props_t = std::map<std::string, Property::sptr>;
|
using props_t = std::map<std::string, Property::sptr>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
props_t::iterator find(const std::string& key)
|
const Property* at(const std::string& key) const
|
||||||
{
|
|
||||||
return props.find(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
Property* at(const std::string& key)
|
|
||||||
{
|
{
|
||||||
auto it = props.find(key);
|
auto it = props.find(key);
|
||||||
return it == props.end() ? nullptr : it->second.get();
|
return it == props.end() ? nullptr : it->second.get();
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
#include <mutex>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include "utils/crtp.hpp"
|
|
||||||
|
|
||||||
#include "threading/sync/spinlock.hpp"
|
|
||||||
|
|
||||||
#include "mvcc/mvcc.hpp"
|
|
||||||
|
|
||||||
#include "properties/properties.hpp"
|
|
||||||
|
|
||||||
template <class Derived>
|
|
||||||
class Record : public Crtp<Derived>, public mvcc::Mvcc<Derived>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// a record contains a key value map containing data
|
|
||||||
Properties properties;
|
|
||||||
|
|
||||||
// each record can have one or more distinct labels.
|
|
||||||
// std::set<uint16_t> labels;
|
|
||||||
};
|
|
61
storage/record_accessor.hpp
Normal file
61
storage/record_accessor.hpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "transactions/transaction.hpp"
|
||||||
|
#include "mvcc/version_list.hpp"
|
||||||
|
#include "storage/model/properties/property.hpp"
|
||||||
|
|
||||||
|
template <class T, class Store, class Derived>
|
||||||
|
class RecordAccessor
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
using vlist_t = mvcc::VersionList<T>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RecordAccessor() = default;
|
||||||
|
|
||||||
|
RecordAccessor(T* record, vlist_t* vlist, Store* store)
|
||||||
|
: record(record), vlist(vlist), store(store) {}
|
||||||
|
|
||||||
|
const Id& id() const
|
||||||
|
{
|
||||||
|
auto accessor = vlist->access();
|
||||||
|
return accessor.id();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return record == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Derived update(tx::Transaction& t) const
|
||||||
|
{
|
||||||
|
assert(!empty());
|
||||||
|
|
||||||
|
auto accessor = vlist->access();
|
||||||
|
return Derived(accessor->update(t), vlist, store);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove(tx::Transaction& t) const
|
||||||
|
{
|
||||||
|
assert(!empty());
|
||||||
|
|
||||||
|
auto accessor = vlist->access();
|
||||||
|
return accessor->remove(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Property* property(const std::string& key) const
|
||||||
|
{
|
||||||
|
return record->props.at(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class V, class... Args>
|
||||||
|
void property(const std::string& key, Args&&... args)
|
||||||
|
{
|
||||||
|
record->props.template set<V>(key, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
T* const record {nullptr};
|
||||||
|
vlist_t* const vlist {nullptr};
|
||||||
|
Store* const store {nullptr};
|
||||||
|
};
|
@ -7,6 +7,8 @@
|
|||||||
class Vertex : public mvcc::Record<Vertex>
|
class Vertex : public mvcc::Record<Vertex>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
class Accessor;
|
||||||
|
|
||||||
Vertex() = default;
|
Vertex() = default;
|
||||||
Vertex(const VertexModel& data) : data(data) {}
|
Vertex(const VertexModel& data) : data(data) {}
|
||||||
Vertex(VertexModel&& data) : data(std::move(data)) {}
|
Vertex(VertexModel&& data) : data(std::move(data)) {}
|
||||||
|
11
storage/vertex_accessor.hpp
Normal file
11
storage/vertex_accessor.hpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "record_accessor.hpp"
|
||||||
|
#include "vertex.hpp"
|
||||||
|
#include "vertices.hpp"
|
||||||
|
|
||||||
|
class Vertex::Accessor : public RecordAccessor<Vertex, Vertices, Accessor>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using RecordAccessor::RecordAccessor;
|
||||||
|
};
|
@ -26,60 +26,9 @@ public:
|
|||||||
return vertex;
|
return vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexProxy insert(tx::Transaction& transaction)
|
|
||||||
{
|
|
||||||
// get next vertex id
|
|
||||||
auto next = counter.next(std::memory_order_acquire);
|
|
||||||
|
|
||||||
// create new vertex record
|
|
||||||
VertexRecord vertex_record;
|
|
||||||
|
|
||||||
// insert the new vertex record into the vertex store
|
|
||||||
auto vertices_accessor = vertices.access();
|
|
||||||
auto result = vertices_accessor.insert_unique(next, std::move(vertex_record));
|
|
||||||
|
|
||||||
// create new vertex
|
|
||||||
auto inserted_vertex_record = result.first;
|
|
||||||
auto vertex_accessor = inserted_vertex_record->second.access(transaction);
|
|
||||||
auto vertex = vertex_accessor.insert();
|
|
||||||
|
|
||||||
VertexProxy vertex_proxy(next, vertex, this, &inserted_vertex_record->second);
|
|
||||||
return vertex_proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vertex* update(tx::Transaction& transaction, const Id& id)
|
|
||||||
{
|
|
||||||
// find vertex record
|
|
||||||
auto vertices_accessor = vertices.access();
|
|
||||||
auto vertex_record = vertices_accessor.find(id);
|
|
||||||
|
|
||||||
if (vertex_record == vertices_accessor.end())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
// get vertex that is going to be updated
|
|
||||||
auto vertex_accessor = vertex_record->second.access(transaction);
|
|
||||||
auto vertex = vertex_accessor.update();
|
|
||||||
|
|
||||||
return vertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool remove(tx::Transaction& transaction, const Id& id)
|
|
||||||
{
|
|
||||||
// find vertex record
|
|
||||||
auto vertices_accessor = vertices.access();
|
|
||||||
auto vertex_record = vertices_accessor.find(id);
|
|
||||||
|
|
||||||
if (vertex_record == vertices_accessor.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// mark vertex record via the vertex accessor as deleted
|
|
||||||
// return boolean result true if vertex could be removed
|
|
||||||
// or false if vertex couldn't be removed
|
|
||||||
auto vertex_accessor = vertex_record->second.access(transaction);
|
|
||||||
return vertex_accessor.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkipList<uint64_t, VertexRecord> vertices;
|
Indexes indexes;
|
||||||
|
|
||||||
|
SkipList<uint64_t, VersionList<Vertex>> vertices;
|
||||||
AtomicCounter<uint64_t> counter;
|
AtomicCounter<uint64_t> counter;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user