diff --git a/data_structures/skiplist/skiplist.hpp b/data_structures/skiplist/skiplist.hpp index 2446ab00f..6dce15f12 100644 --- a/data_structures/skiplist/skiplist.hpp +++ b/data_structures/skiplist/skiplist.hpp @@ -402,6 +402,11 @@ public: return Accessor(this); } + Accessor access() const + { + return Accessor(this); + } + private: using guard_t = std::unique_lock; diff --git a/data_structures/skiplist/skiplistset.hpp b/data_structures/skiplist/skiplistset.hpp index abf3f298d..bf77607d5 100644 --- a/data_structures/skiplist/skiplistset.hpp +++ b/data_structures/skiplist/skiplistset.hpp @@ -224,6 +224,11 @@ public: return Accessor(std::move(data.access())); } + Accessor access() const + { + return Accessor(std::move(data.access())); + } + private: SkipList data; }; diff --git a/mvcc/version_list.hpp b/mvcc/version_list.hpp index 8971aa757..b6f44dd0d 100644 --- a/mvcc/version_list.hpp +++ b/mvcc/version_list.hpp @@ -5,7 +5,7 @@ #include "memory/lazy_gc.hpp" #include "mvcc/serialization_error.hpp" -#include "database/locking/record_lock.hpp" +#include "storage/locking/record_lock.hpp" namespace mvcc { @@ -22,16 +22,16 @@ public: { friend class VersionList; - Accessor(tx::Transaction& transaction, VersionList& record) - : transaction(transaction), record(record) + Accessor(tx::Transaction& transaction, VersionList& vlist) + : transaction(transaction), vlist(vlist) { - record.add_ref(); + vlist.add_ref(); } public: ~Accessor() { - record.release_ref(); + vlist.release_ref(); } Accessor(const Accessor&) = default; @@ -42,27 +42,42 @@ public: T* insert() { - return record.insert(transaction); + return vlist.insert(transaction); } const T* find() const { - return record.find(transaction); + return vlist.find(transaction); } T* update() { - return record.update(transaction); + return vlist.update(transaction); + } + + T* update(T* record) + { + return vlist.update(record, transaction); } 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: tx::Transaction& transaction; - VersionList& record; + VersionList& vlist; }; VersionList() = default; @@ -117,6 +132,9 @@ public: private: std::atomic head {nullptr}; RecordLock lock; + + Id id; + //static Recycler recycler; T* find(const tx::Transaction& t) @@ -139,9 +157,10 @@ private: return r; } - T* insert(tx::Transaction& t) + T* insert(tx::Transaction& t, const Id& id) { assert(head == nullptr); + this->id = id; // create a first version of the record // TODO replace 'new' with something better @@ -158,12 +177,20 @@ private: T* update(tx::Transaction& t) { assert(head != nullptr); - auto record = lock_and_validate(t); + auto record = find(t); // check if we found any visible records if(!record) 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(); updated->data = record->data; @@ -179,15 +206,23 @@ private: bool remove(tx::Transaction& t) { assert(head != nullptr); - auto record = lock_and_validate(t); + auto record = find(t); if(!record) 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 == find(t)); @@ -198,27 +233,12 @@ private: // if the record hasn't been deleted yet or the deleting transaction // has aborted, it's ok to modify it if(!record->tx.exp() || record->hints.load().exp.is_aborted()) - return record; + return; // if it committed, then we have a serialization conflict assert(record->hints.load().exp.is_committed()); 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; -using EdgeRecord = mvcc::VersionList; diff --git a/storage/cursor.hpp b/storage/cursor.hpp new file mode 100644 index 000000000..6960e9357 --- /dev/null +++ b/storage/cursor.hpp @@ -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 RecordCursor : public Crtp +{ +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 + void property(const std::string& key, Args&&... args) + { + record->props.template set(key, std::forward(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 Vertex::Cursor + : public RecordCursor> +{ +public: + +}; diff --git a/storage/indexes/index.hpp b/storage/indexes/index.hpp new file mode 100644 index 000000000..14189637f --- /dev/null +++ b/storage/indexes/index.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "data_structures/skiplist/skiplist.hpp" +#include "keys/unique_key.hpp" + +#include "storage/cursor.hpp" + +template +class Index +{ + using skiplist_t = SkipList; + 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; +}; diff --git a/storage/indexes/index_key.hpp b/storage/indexes/index_key.hpp new file mode 100644 index 000000000..6bb7689ec --- /dev/null +++ b/storage/indexes/index_key.hpp @@ -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 UniqueIndexKey +{ +public: + namespace + +private: + Property& key; +}; + +template +class IndexKey +{ +public: + +}; diff --git a/storage/indexes/keys/non_unique_key.hpp b/storage/indexes/keys/non_unique_key.hpp new file mode 100644 index 000000000..dd64b0264 --- /dev/null +++ b/storage/indexes/keys/non_unique_key.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "unique_key.hpp" + +template +class NonUniqueKey +{ +public: + NonUniqueKey(const K& key, const T&) + { + + } + +private: + intptr_t x; +}; diff --git a/storage/indexes/keys/unique_key.hpp b/storage/indexes/keys/unique_key.hpp new file mode 100644 index 000000000..2917b195d --- /dev/null +++ b/storage/indexes/keys/unique_key.hpp @@ -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 UniqueKey : public TotalOrdering> +{ +public: + using type = UniqueKey; + 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 +using UniqueKeyAsc = UniqueKey>; + +template +using UniqueKeyDesc = UniqueKey>; + diff --git a/storage/indexes/sort_order.hpp b/storage/indexes/sort_order.hpp new file mode 100644 index 000000000..c30ee02eb --- /dev/null +++ b/storage/indexes/sort_order.hpp @@ -0,0 +1,19 @@ +#pragma once + +template +class Ascending +{ + constexpr bool operator()(const T& lhs, const T& rhs) const + { + return lhs < rhs; + } +}; + +template +class Descending +{ + constexpr bool operator()(const T& lhs, const T& rhs) const + { + return lhs > rhs; + } +}; diff --git a/storage/label_store.hpp b/storage/label_store.hpp new file mode 100644 index 000000000..f40e37a8b --- /dev/null +++ b/storage/label_store.hpp @@ -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