From 31c2097798f8446f97e7525e38bed60b92e6858a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Tomic=CC=8Cevic=CC=81?= <dominik.tomicevic@gmail.com> Date: Sat, 4 Jul 2015 11:39:16 +0200 Subject: [PATCH] starting to add support for mvcc --- storage/edge.hpp | 16 ++++++ storage/graph.hpp | 13 +++++ storage/json/all.hpp | 14 +++++ storage/json/array.hpp | 84 +++++++++++++++++++++++++++++ storage/json/bool.hpp | 33 ++++++++++++ storage/json/integral.hpp | 33 ++++++++++++ storage/json/json.hpp | 47 ++++++++++++++++ storage/json/null.hpp | 30 +++++++++++ storage/json/object.hpp | 106 +++++++++++++++++++++++++++++++++++++ storage/json/primitive.hpp | 29 ++++++++++ storage/json/real.hpp | 33 ++++++++++++ storage/json/string.hpp | 34 ++++++++++++ storage/record.hpp | 58 ++++++++++++++++++++ storage/vertex.hpp | 14 +++++ 14 files changed, 544 insertions(+) create mode 100644 storage/edge.hpp create mode 100644 storage/graph.hpp create mode 100644 storage/json/all.hpp create mode 100644 storage/json/array.hpp create mode 100644 storage/json/bool.hpp create mode 100644 storage/json/integral.hpp create mode 100644 storage/json/json.hpp create mode 100644 storage/json/null.hpp create mode 100644 storage/json/object.hpp create mode 100644 storage/json/primitive.hpp create mode 100644 storage/json/real.hpp create mode 100644 storage/json/string.hpp create mode 100644 storage/record.hpp create mode 100644 storage/vertex.hpp diff --git a/storage/edge.hpp b/storage/edge.hpp new file mode 100644 index 000000000..fcd65c66e --- /dev/null +++ b/storage/edge.hpp @@ -0,0 +1,16 @@ +#ifndef MEMGRAPH_DATA_MODEL_EDGE_HPP +#define MEMGRAPH_DATA_MODEL_EDGE_HPP + +#include "json/all.hpp" +#include "record.hpp" + +struct Node; + +struct Edge : Record +{ + Node* to; + + std::string data; +}; + +#endif diff --git a/storage/graph.hpp b/storage/graph.hpp new file mode 100644 index 000000000..b74f73ed9 --- /dev/null +++ b/storage/graph.hpp @@ -0,0 +1,13 @@ +#ifndef MEMGRAPH_DATA_MODEL_GRAPH_HPP +#define MEMGRAPH_DATA_MODEL_GRAPH_HPP + +#include <vector> + +#include "node.hpp" +#include "edge.hpp" + +struct Graph +{ +} + +#endif diff --git a/storage/json/all.hpp b/storage/json/all.hpp new file mode 100644 index 000000000..d6bf229a4 --- /dev/null +++ b/storage/json/all.hpp @@ -0,0 +1,14 @@ +#ifndef MEMGRAPH_DATA_MODEL_JSON_ALL_HPP +#define MEMGRAPH_DATA_MODEL_JSON_ALL_HPP + +#include "array.hpp" +#include "bool.hpp" +#include "integral.hpp" +#include "json.hpp" +#include "null.hpp" +#include "object.hpp" +#include "primitive.hpp" +#include "real.hpp" +#include "string.hpp" + +#endif diff --git a/storage/json/array.hpp b/storage/json/array.hpp new file mode 100644 index 000000000..0ec2187f5 --- /dev/null +++ b/storage/json/array.hpp @@ -0,0 +1,84 @@ +#ifndef MEMGRAPH_DATA_MODEL_JSON_ARRAY_HPP +#define MEMGRAPH_DATA_MODEL_JSON_ARRAY_HPP + +#include <cassert> +#include <memory> +#include <vector> + +#include "utilities/string/intercalate.hpp" + +#include "json.hpp" + +namespace json +{ + +class Array final : public Json +{ +public: + Array() {} + + template <typename It> + Array(It first, It last) + : elements(first, last) {} + + Array(std::initializer_list<spJson> elements) + : elements(elements) {} + + virtual bool is_array() const; + + size_t size() const; + + Array& push(const std::shared_ptr<Json>& element); + + const spJson& operator[](size_t i) const; + spJson operator[](size_t i); + + virtual operator std::string() const; + +private: + std::vector<spJson> elements; +}; + +bool Array::is_array() const +{ + return true; +} + +size_t Array::size() const +{ + return elements.size(); +} + +Array& Array::push(const spJson& element) +{ + assert(element); + + elements.push_back(element); + return *this; +} + +const spJson& Array::operator[](size_t i) const +{ + return elements[i]; +} + +spJson Array::operator[](size_t i) +{ + return elements[i]; +} + +Array::operator std::string() const +{ + std::vector<std::string> xs; + + std::transform(elements.begin(), elements.end(), std::back_inserter(xs), + [](const spJson& element) { + return static_cast<std::string>(*element); + }); + + return "[" + utils::intercalate(xs.begin(), xs.end(), ",") + "]"; +} + +} + +#endif diff --git a/storage/json/bool.hpp b/storage/json/bool.hpp new file mode 100644 index 000000000..545386062 --- /dev/null +++ b/storage/json/bool.hpp @@ -0,0 +1,33 @@ +#ifndef MEMGRAPH_DATA_MODEL_JSON_BOOL_HPP +#define MEMGRAPH_DATA_MODEL_JSON_BOOL_HPP + +#include "primitive.hpp" + +namespace json { + +class Bool final : public Primitive<bool> +{ +public: + Bool() {} + + Bool(bool value) + : Primitive<bool>(value) {} + + virtual bool is_boolean() const; + + virtual operator std::string() const; +}; + +bool Bool::is_boolean() const +{ + return true; +} + +Bool::operator std::string() const +{ + return value == true ? "true" : "false"; +} + +} + +#endif diff --git a/storage/json/integral.hpp b/storage/json/integral.hpp new file mode 100644 index 000000000..2467f8742 --- /dev/null +++ b/storage/json/integral.hpp @@ -0,0 +1,33 @@ +#ifndef MEMGRAPH_DATA_MODEL_JSON_INTEGRAL_HPP +#define MEMGRAPH_DATA_MODEL_JSON_INTEGRAL_HPP + +#include "primitive.hpp" + +namespace json { + +class Integral final : public Primitive<int64_t> +{ +public: + Integral() {} + + Integral(int64_t value) + : Primitive<int64_t>(value) {} + + virtual bool is_integral() const; + + virtual operator std::string() const; +}; + +bool Integral::is_integral() const +{ + return true; +} + +Integral::operator std::string() const +{ + return std::to_string(value); +} + +} + +#endif diff --git a/storage/json/json.hpp b/storage/json/json.hpp new file mode 100644 index 000000000..dc9784108 --- /dev/null +++ b/storage/json/json.hpp @@ -0,0 +1,47 @@ +#ifndef MEMGRAPH_DATA_MODEL_JSON_JSON_HPP +#define MEMGRAPH_DATA_MODEL_JSON_JSON_HPP + +#include <initializer_list> +#include <string> +#include <memory> + +namespace json { + +class Json; + +typedef std::shared_ptr<Json> spJson; + +class Json +{ +public: + Json() {} + virtual ~Json() {} + + virtual bool is_object() const { return false; } + virtual bool is_array() const { return false; } + virtual bool is_real() const { return false; } + virtual bool is_integral() const { return false; } + virtual bool is_boolean() const { return false; } + virtual bool is_null() const { return false; } + + template <typename T> T& as(); + template <typename T> const T& as() const; + + virtual operator std::string() const = 0; +}; + +template <typename T> +T& Json::as() +{ + return *dynamic_cast<T*>(this); +} + +template <typename T> +const T& Json::as() const +{ + return *dynamic_cast<T*>(this); +} + +} + +#endif diff --git a/storage/json/null.hpp b/storage/json/null.hpp new file mode 100644 index 000000000..3a50bf867 --- /dev/null +++ b/storage/json/null.hpp @@ -0,0 +1,30 @@ +#ifndef MEMGRAPH_DATA_MODEL_JSON_NULL_HPP +#define MEMGRAPH_DATA_MODEL_JSON_NULL_HPP + +#include "json.hpp" + +namespace json { + +class Null final : public Json +{ +public: + Null() {} + + virtual bool is_null() const; + + virtual operator std::string() const; +}; + +bool Null::is_null() const +{ + return true; +} + +Null::operator std::string() const +{ + return "null"; +} + +} + +#endif diff --git a/storage/json/object.hpp b/storage/json/object.hpp new file mode 100644 index 000000000..ee7b13ce1 --- /dev/null +++ b/storage/json/object.hpp @@ -0,0 +1,106 @@ +#ifndef MEMGRAPH_DATA_MODEL_JSON_OBJECT_HPP +#define MEMGRAPH_DATA_MODEL_JSON_OBJECT_HPP + +#include <iostream> + +#include <functional> +#include <sstream> +#include <cassert> +#include <vector> +#include <map> + +#include "utilities/string/intercalate.hpp" + +#include "json.hpp" + +namespace json { + +typedef std::pair<const std::string, spJson> const_kv_pair_t; +typedef std::pair<std::string, spJson> kv_pair_t; + +class Object; + +typedef std::shared_ptr<Object> spObject; + +class Object : public Json +{ +public: + Object() {} + + Object(std::initializer_list<const_kv_pair_t> elements) + : props(elements) {} + + virtual bool is_object() const; + + const spJson& at(const std::string& key) const; + spJson at(const std::string& key); + + const spJson& operator[](const std::string& key) const; + spJson operator[](const std::string& key); + + Object& put(const std::string& key, spJson value); + + Object& operator<<(const kv_pair_t& kv_pair); + + virtual operator std::string() const; + +protected: + std::map<std::string, spJson> props; +}; + +bool Object::is_object() const +{ + return true; +} + +const spJson& Object::at(const std::string& key) const +{ + return props.at(key); +} + +spJson Object::at(const std::string& key) +{ + return props.at(key); +} + +const spJson& Object::operator[](const std::string& key) const +{ + return this->at(key); +} + +spJson Object::operator[](const std::string& key) +{ + return this->at(key); +} + +Object& Object::put(const std::string& key, spJson value) +{ + assert(value); + + props[key] = value; + return *this; +} + +Object& Object::operator<<(const kv_pair_t& kv_pair) +{ + return this->put(std::get<0>(kv_pair), std::get<1>(kv_pair)); +} + +Object::operator std::string() const +{ + if(props.empty()) + return "{}"; + + std::vector<std::string> xs; + + std::transform(props.begin(), props.end(), std::back_inserter(xs), + [](const kv_pair_t& kvp) { + return "\"" + kvp.first + "\":" + static_cast<std::string>(*kvp.second); + }); + + return "{" + utils::intercalate(xs.begin(), xs.end(), ",") + "}"; +} + +} + +#endif diff --git a/storage/json/primitive.hpp b/storage/json/primitive.hpp new file mode 100644 index 000000000..cf4a9451b --- /dev/null +++ b/storage/json/primitive.hpp @@ -0,0 +1,29 @@ +#ifndef MEMGRAPH_DATA_MODEL_JSON_PRIMITIVE_HPP +#define MEMGRAPH_DATA_MODEL_JSON_PRIMITIVE_HPP + +#include "json.hpp" + +namespace json { + +template <class T> +class Primitive : public Json +{ +public: + Primitive() {} + + Primitive(const T& value) + : value(value) {} + + T get() const { return value; } + void set(T value) { this->value = value; } + + operator T() const { return this->get(); } + +protected: + T value; +}; + + +} + +#endif diff --git a/storage/json/real.hpp b/storage/json/real.hpp new file mode 100644 index 000000000..214b2ba63 --- /dev/null +++ b/storage/json/real.hpp @@ -0,0 +1,33 @@ +#ifndef MEMGRAPH_DATA_MODEL_JSON_REAL_HPP +#define MEMGRAPH_DATA_MODEL_JSON_REAL_HPP + +#include "primitive.hpp" + +namespace json { + +class Real final : public Primitive<float> +{ +public: + Real() {} + + Real(float value) + : Primitive<float>(value) {} + + virtual bool is_real() const; + + virtual operator std::string() const; +}; + +bool Real::is_real() const +{ + return true; +} + +Real::operator std::string() const +{ + return std::to_string(value); +} + +} + +#endif diff --git a/storage/json/string.hpp b/storage/json/string.hpp new file mode 100644 index 000000000..842a7399b --- /dev/null +++ b/storage/json/string.hpp @@ -0,0 +1,34 @@ +#ifndef MEMGRAPH_DATA_MODEL_JSON_STRING_HPP +#define MEMGRAPH_DATA_MODEL_JSON_STRING_HPP + +#include "primitive.hpp" + +namespace json +{ + +class String final : public Primitive<std::string> +{ +public: + String() {} + + String(const std::string& value) + : Primitive<std::string>(value) {} + + virtual bool is_string() const; + + virtual operator std::string() const; +}; + +bool String::is_string() const +{ + return true; +} + +String::operator std::string() const +{ + return "\"" + value + "\""; +} + +} + +#endif diff --git a/storage/record.hpp b/storage/record.hpp new file mode 100644 index 000000000..fce83b192 --- /dev/null +++ b/storage/record.hpp @@ -0,0 +1,58 @@ +#ifndef MEMGRAPH_STORAGE_RECORD_HPP +#define MEMGRAPH_STORAGE_RECORD_HPP + +#include <mutex> +#include <list> + +#include "sync/spinlock.hpp" + +template <class lock_type = SpinLock> +class Record +{ + // every node has a unique id. 2^64 = 1.8 x 10^19. that should be enough + // for a looong time :) but keep in mind that some vacuuming would be nice + // to reuse indices for deleted nodes. also, vacuuming would enable the + // use of uint32_t which could be more memory conserving + uint64_t id; + + // acquire an exclusive guard on this node, use for concurrent access + std::unique_lock<lock_type> guard() + { + return std::unique_lock<lock_type>(lock); + } + + uint64_t xmin() + { + return xmin_.load(std::memory_order_acquire); + } + + uint64_t xmin_inc() + { + return xmin_.fetch_add(1, std::memory_order_relaxed); + } + + uint64_t xmax() + { + return xmax_.load(std::memory_order_release); + } + + uint64_t xmax_inc() + { + return xmax_.fetch_add(1, std::memory_order_relaxed); + } + + Record* newer() + { + return versions.load(std::memory_order_consume); + } + +private: + // used by MVCC to keep track of what's visible to transactions + std::atomic<uint64_t> xmin_, xmax_; + + std::atomic<Record*> versions; + + lock_type lock; +}; + +#endif diff --git a/storage/vertex.hpp b/storage/vertex.hpp new file mode 100644 index 000000000..3c35e21d9 --- /dev/null +++ b/storage/vertex.hpp @@ -0,0 +1,14 @@ +#ifndef MEMGRAPH_STORAGE_VERTEX_HPP +#define MEMGRAPH_STORAGE_VERTEX_HPP + +#include "record.hpp" +#include "edge.hpp" + +struct Vertex : Record +{ + std::list<Edge*> out; + + std::string name; +}; + +#endif