From 768ad5e4518b5d953dd01bf088e76b323102a700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Tomic=CC=8Cevic=CC=81?= <dominik.tomicevic@gmail.com> Date: Sun, 11 Oct 2015 20:59:27 +0200 Subject: [PATCH] connected the first working version of memgraph --- .gitignore | 1 + Makefile | 4 +- api/link_resources.py | 43 ++-- api/resources/animal.hpp | 24 --- api/resources/include.hpp | 20 +- api/resources/include.hpp.template | 28 ++- api/resources/node.hpp | 76 +++++-- api/restful/resource.hpp | 190 ++++-------------- api/restful/restful_resource.hpp | 156 ++++++++++++++ database/db.hpp | 13 +- io/uv/blockbuffer.hpp | 128 ++++++++++++ io/uv/uv.hpp | 1 + io/uv/uvloop.hpp | 2 + memgraph | Bin 137904 -> 0 bytes memgraph.cpp | 29 ++- speedy/http/httpconnection.hpp | 2 - speedy/http/httpserver.inl | 1 - speedy/http/response.hpp | 4 +- speedy/http/response.inl | 7 +- speedy/r3.hpp | 46 ++--- speedy/request.hpp | 4 + speedy/speedy.hpp | 42 +++- storage/model/properties/property.hpp | 16 +- threading/pool.hpp | 10 +- threading/task.hpp | 83 ++++++++ .../{transaction_engine.hpp => engine.hpp} | 10 +- utils/ioc/container.hpp | 14 +- utils/placeholder.hpp | 45 +++++ 28 files changed, 695 insertions(+), 304 deletions(-) delete mode 100644 api/resources/animal.hpp create mode 100644 api/restful/restful_resource.hpp create mode 100644 io/uv/blockbuffer.hpp delete mode 100755 memgraph create mode 100644 threading/task.hpp rename transactions/{transaction_engine.hpp => engine.hpp} (91%) create mode 100644 utils/placeholder.hpp diff --git a/.gitignore b/.gitignore index 125348867..81a453937 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ *.swo *.out *.dSYM/ +memgraph diff --git a/Makefile b/Makefile index 7ee745dd7..fe33c9735 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CXX=clang++ -CFLAGS=-std=c++1y -Wall -O2 -LDFLAGS=-luv -lhttp_parser speedy/r3/.libs/libr3.a -L/usr/local/lib -lpcre +CFLAGS=-std=c++1y -O2 -Wall -Wno-unknown-pragmas +LDFLAGS=-luv -lhttp_parser speedy/r3/.libs/libr3.a -L/usr/local/lib -lpcre -pthread INC=-I./ SOURCES=$(wildcard *.cpp) diff --git a/api/link_resources.py b/api/link_resources.py index c3b8eb7de..5ef3886f5 100644 --- a/api/link_resources.py +++ b/api/link_resources.py @@ -1,6 +1,7 @@ # this script generates the include.hpp file for restful resources import re import os +from itertools import chain print "generating include.hpp file" @@ -16,27 +17,38 @@ if os.path.isfile(include_path): class Resource(object): """ represents a restful resource class for speedy """ - def __init__(self, filename): + def __init__(self, filename, class_name, url): self.filename = filename - self.class_name = None + self.class_name = class_name + self.url = url - with open(os.path.join(resource_path, filename)) as f: - class_name = re.compile('\s*class\s*(\w+)\s*\:') - for line in f: - result = re.search(class_name, line) +def scan_resources(filename): - if result is None: - continue + with open(os.path.join(resource_path, filename)) as f: + url_regex = re.compile('#pragma\s+url\s+([^\s]+)\s+') + class_name_regex = re.compile('\s*class\s*(\w+)\s*\:') - self.class_name = result.group(1) + lines = f.readlines() + pairs = zip(lines, lines[1:]) - break + for first, second in pairs: + url = re.search(url_regex, first) + + if url is None: + continue + + class_name = re.search(class_name_regex, second) + + if class_name is None: + continue + + yield Resource(filename, class_name.group(1), url.group(1)) def load_resources(): - resources = [Resource(f) for f in os.listdir(resource_path) - if f.endswith('.hpp')] + resources = chain(*[scan_resources(f) for f in os.listdir(resource_path) + if f.endswith('.hpp')]) return [r for r in resources if r.class_name is not None] @@ -48,9 +60,10 @@ def write_includes(file, resources): def write_inits(file, resources): - for class_name in [resource.class_name for resource in resources]: - print 'writing init for', class_name - file.write(' insert<{}>(app);\n'.format(class_name)) + for class_name, url in [(r.class_name, r.url) for r in resources]: + print('writing init for {} -> {}'.format(class_name, url)) + file.write(' insert<{}>(container, "{}");\n' + .format(class_name, url)) def make_include_file(): diff --git a/api/resources/animal.hpp b/api/resources/animal.hpp deleted file mode 100644 index 05003318c..000000000 --- a/api/resources/animal.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MEMGRAPH_ANIMAL_HPP -#define MEMGRAPH_ANIMAL_HPP - -#include "speedy/speedy.hpp" -#include "api/restful/resource.hpp" - -/* class Ani mal : public Resource<Animal, GET, POST> */ -/* { */ -/* public: */ -/* Animal(sp::Speedy& app) */ -/* : Resource(app, "/animal/{id:\\d+}/{name:\\w+}/commit") {} */ - -/* void get(sp::Request& req, sp::Response& res) */ -/* { */ -/* return res.send("Ok, here is a Dog"); */ -/* } */ - -/* void post(sp::Request& req, sp::Response& res) */ -/* { */ -/* return res.send("Oh, you gave me an animal?"); */ -/* } */ -/* }; */ - -#endif diff --git a/api/resources/include.hpp b/api/resources/include.hpp index 21b94a257..4fbc0825a 100644 --- a/api/resources/include.hpp +++ b/api/resources/include.hpp @@ -4,6 +4,8 @@ * This file is autogenerated by the python script link_resources.py * * YOU SHOULD NOT EDIT THIS FILE MANUALLY! + * + * well, only if you're editing the template file, that's ok :) */ #ifndef MEMGRAPH_API_RESOURCES_INCLUDE_HPP @@ -12,22 +14,28 @@ #include <list> #include <memory> +#include "utils/ioc/container.hpp" #include "api/restful/resource.hpp" + +#include "transactions/engine.hpp" +#include "threading/task.hpp" #include "speedy/speedy.hpp" #include "node.hpp" - -static std::list<std::unique_ptr<RestfulResource>> resources; +#include "node.hpp" template <class T> -void insert(sp::Speedy& app) +void insert(ioc::Container& container, const std::string& path) { - resources.push_back(std::unique_ptr<RestfulResource>(new T(app))); + auto app = container.resolve<sp::Speedy>(); + auto resource = container.singleton<T, Task, Db>(); + resource->link(*app, path); } -void init(sp::Speedy& app) +void init(ioc::Container& container) { - insert<Node>(app); + insert<Nodes>(container, "/node"); + insert<Node>(container, "/node/{id:\\d+}"); } #endif diff --git a/api/resources/include.hpp.template b/api/resources/include.hpp.template index 5204150db..c400bf923 100644 --- a/api/resources/include.hpp.template +++ b/api/resources/include.hpp.template @@ -4,6 +4,8 @@ * This file is autogenerated by the python script link_resources.py * * YOU SHOULD NOT EDIT THIS FILE MANUALLY! + * + * well, only if you're editing the template file, that's ok :) */ #ifndef MEMGRAPH_API_RESOURCES_INCLUDE_HPP @@ -12,21 +14,37 @@ #include <list> #include <memory> +#include "utils/ioc/container.hpp" #include "api/restful/resource.hpp" + +#include "transactions/engine.hpp" +#include "threading/task.hpp" #include "speedy/speedy.hpp" +// for each file in this folder a script will generate an include directive if +// this file contains any resources +// e.g. +// #include "node.hpp" +// #include "relationship.hpp" <INCLUDE> -static std::list<std::unique_ptr<RestfulResource>> resources; - template <class T> -void insert(sp::Speedy& app) +void insert(ioc::Container& container, const std::string& path) { - resources.push_back(std::unique_ptr<RestfulResource>(new T(app))); + auto app = container.resolve<sp::Speedy>(); + auto resource = container.singleton<T, Task, Db>(); + resource->link(*app, path); } -void init(sp::Speedy& app) +void init(ioc::Container& container) { + // for each resource in a file included above, the script will generate a + // linkage command call to the function above + // e.g. + // insert<CLASS>(PATH); + // + // insert<Nodes>("/node"); + // insert<Node>("/node/{id:\\d+}"); <INIT> } diff --git a/api/resources/node.hpp b/api/resources/node.hpp index 7fee61680..1ee8afe28 100644 --- a/api/resources/node.hpp +++ b/api/resources/node.hpp @@ -1,31 +1,83 @@ #ifndef MEMGRAPH_API_RESOURCES_NODE_HPP #define MEMGRAPH_API_RESOURCES_NODE_HPP -#include "api/restful/resource.hpp" +#include <random> -class Node : public Resource<Node, GET, POST> +#include "api/restful/resource.hpp" +#include "debug/log.hpp" + +#pragma url /node +class Nodes : public Resource<Nodes, POST> { public: - Node(sp::Speedy& app) : Resource(app, "/node") {} - - void get(sp::Request& req, sp::Response& res) - { - return res.send("Ok, here is a Dog"); - } + using Resource::Resource; void post(sp::Request& req, sp::Response& res) { - return res.send("Ok, here is a Dog"); + task->run([this, &req]() { + // start a new transaction and obtain a reference to it + auto t = db->tx_engine.begin(); + + // insert a new vertex in the graph + auto atom = db->graph.vertices.insert(t); + + // a new version was created and we got an atom along with the + // first version. obtain a pointer to the first version + // + // nullptr + // ^ + // | + // [Vertex v1] + // ^ + // | + // [Atom id=k] k {1, 2, ...} + // + auto node = atom->first(); + + // TODO read the JSON body and store the properties in the + // first version + // + // for(key, value in body) + // node->properties[key] = value; + + // commit the transaction + db->tx_engine.commit(t); + + // return the node we created so we can send it as a response body + return node; + }, + [&req, &res](Vertex* node) { + // make a string buffer + std::string buffer; + + // dump properties in this buffer + node->properties.dump(buffer); + + // respond to the use with the buffer + return res.send(buffer); + }); } - +}; + +#pragma url /node/{id:\\d+} +class Node : public Resource<Node, GET, PUT, DELETE> +{ +public: + using Resource::Resource; + + void get(sp::Request& req, sp::Response& res) + { + return res.send(req.url); + } + void put(sp::Request& req, sp::Response& res) { - return res.send("Ok, here is a Dog"); + return res.send(req.url); } void del(sp::Request& req, sp::Response& res) { - return res.send("Ok, here is a Dog"); + return res.send(req.url); } }; diff --git a/api/restful/resource.hpp b/api/restful/resource.hpp index 37ce2bf07..ce9145247 100644 --- a/api/restful/resource.hpp +++ b/api/restful/resource.hpp @@ -1,157 +1,53 @@ -#ifndef MEMGRAPH_API_RESOURCE_HPP -#define MEMGRAPH_API_RESOURCE_HPP +#ifndef MEMGRAPH_API_RESTFUL_RESOURCE_HPP +#define MEMGRAPH_API_RESTFUL_RESOURCE_HPP -#include <memory> +#include "api/restful/restful_resource.hpp" + +#include "database/db.hpp" +#include "threading/task.hpp" #include "speedy/speedy.hpp" -#include "utils/crtp.hpp" -/** @brief GET handler method for the resource - * Contains the code for registering GET handler for a URL to Speedy - */ -struct GET -{ - /** @brief Links ::get handler to speedy for a given path - * - * @tparam T Class type containing the required handler - * @param app Instance of speedy to register the method to - * @param path URL of the resource being registered - * @param resource Object containing ::get http::request_cb_t handler - */ - template <class T> - void link(sp::Speedy& app, const std::string& path, T& resource) - { - using namespace std::placeholders; - app.get(path, std::bind(&T::get, resource, _1, _2)); - } -}; -/** @brief POST handler method for the resource - * Contains the code for registering POST handler for a URL to Speedy - */ -struct POST -{ - /** @brief Links ::post handler to speedy for a given path - * - * @tparam T Class type containing the required handler - * @param app Instance of speedy to register the method to - * @param path URL of the resource being registered - * @param resource Object containing ::post http::request_cb_t handler - */ - template <class T> - void link(sp::Speedy& app, const std::string& path, T& resource) - { - using namespace std::placeholders; - app.post(path, std::bind(&T::post, resource, _1, _2)); - } -}; - -struct PUT -{ - template <class T> - void link(sp::Speedy& app, const std::string& path, T& resource) - { - using namespace std::placeholders; - app.put(path, std::bind(&T::put, resource, _1, _2)); - } -}; - -struct DELETE -{ - template <class T> - void link(sp::Speedy& app, const std::string& path, T& resource) - { - using namespace std::placeholders; - app.del(path, std::bind(&T::del, resource, _1, _2)); - } -}; - -namespace detail -{ - -/** @brief Registers a method for a path to speedy - * - * @tparam T Derived class containing the handler of the method - * @tparam M A method to register - */ -template <class T, class M> -struct Method : public M -{ - /** Registers a route handler for the resource - * - * Registers a method handler for M on the given URL - * - * @param app instance of speedy to register the method to - * @param path URL of the resource being registered - */ - Method(sp::Speedy& app, const std::string& path) - { - M::link(app, path, static_cast<T&>(*this)); - } -}; - -/** @brief Generates the Method<T, M> inheritance for each M in Ms - * - * Implemented inheriting recursively using variadic templates - * - * @tparam T Derived class containing handlers for each method M in Ms - * @tparam Ms... Methods to register - */ template <class T, class... Ms> -struct Methods; - -/** @brief specialization of the struct Methods<T, Ms...> - * - * Unrolls one method M and generates a handler for this method by inheriting - * from Method<T, M> and generates the rest of the handlers recursively by - * inheriting from Methods<T, Ms...> and unrolling one M each time. - * - * @tparam T Derived class containing handlers for each method M in Ms - * @tparam M Unrolled method M for which to generate a handler - * @tparam Ms... The rest of the methods - */ -template <class T, class M, class... Ms> -struct Methods<T, M, Ms...> : public Method<T, M>, public Methods<T, Ms...> -{ - Methods(sp::Speedy& app, const std::string& path) - : Method<T, M>(app, path), Methods<T, Ms...>(app, path) {} -}; - -/** @brief specialization of the struct Methods<T, Ms...> - * - * Specializes the recursion termination case containing only one method M - * - * @tparam T Derived class containing handlers for method M - * @tparam M Unrolled method M for which to generate a handler - */ -template <class T, class M> -struct Methods<T, M> : public Method<T, M> -{ - using Method<T, M>::Method; -}; - -} - -struct RestfulResource {}; - -/** @brief Represents a restful resource - * - * Automatically registers get, put, post, del... methods inside the derived - * class T. Methods are given as a template parameter to the class. Valid - * template parameters are classes which implement a function - * - * void link(sp::Speedy&, const std::string&, T& resource) - * - * which registers a method you want to use with speedy - * - * @tparam T Derived class (CRTP) - * @tparam Ms... HTTP methods to register for this resource (GET, POST...) - */ -template <class T, class... Ms> -class Resource : public detail::Methods<T, Ms...>, public RestfulResource +class Resource { public: - Resource(sp::Speedy& app, const std::string& path) - : detail::Methods<T, Ms...>(app, path) {} + /** @brief Resource constructor + * + * List ALL the dependencies here so that ioc can resolve them and store + * them to protected members so that derived resources can access them + * + * @param task shared_ptr to the task dispatching library + * @param db shared_ptr to the database instance + */ + Resource(Task::sptr task, Db::sptr db) + : task(task), db(db) {} + + /** @brief Link all resources to an instance of speedy + * + * link_resources.py generates an include.hpp file which includes and + * instantinates all available resources. The include.hpp file also calls + * this method to link the resources to speedy for a given path + */ + void link(sp::Speedy& app, const std::string& path) + { + // make sure this is called once even if someone actually calls this + // function multiple times + std::call_once(once_flag, [this, &app, &path]() { + Restful<T, Ms...>(static_cast<T&>(*this), app, path); + }); + } + +protected: + // all resources have pointers to these instances add everything else + // neccessary here as a shared_ptr and also include it in the constructor + // and modify the include.hpp.template to include the new dependencies for + // resource linking + Task::sptr task; + Db::sptr db; + +private: + std::once_flag once_flag; }; #endif diff --git a/api/restful/restful_resource.hpp b/api/restful/restful_resource.hpp new file mode 100644 index 000000000..470c55cc9 --- /dev/null +++ b/api/restful/restful_resource.hpp @@ -0,0 +1,156 @@ +#ifndef MEMGRAPH_API_RESTFUL_RESTFUL_RESOURCE_HPP +#define MEMGRAPH_API_RESTFUL_RESTFUL_RESOURCE_HPP + +#include <memory> +#include "speedy/speedy.hpp" +#include "utils/crtp.hpp" + +/** @brief GET handler method for the resource + * Contains the code for registering GET handler for a URL to Speedy + */ +struct GET +{ + /** @brief Links ::get handler to speedy for a given path + * + * @tparam T Class type containing the required handler + * @param app Instance of speedy to register the method to + * @param path URL of the resource being registered + * @param resource Object containing ::get http::request_cb_t handler + */ + template <class T> + void link(sp::Speedy& app, const std::string& path, T& resource) + { + using namespace std::placeholders; + app.get(path, std::bind(&T::get, std::ref(resource), _1, _2)); + } +}; + +/** @brief POST handler method for the resource + * Contains the code for registering POST handler for a URL to Speedy + */ +struct POST +{ + /** @brief Links ::post handler to speedy for a given path + * + * @tparam T Class type containing the required handler + * @param app Instance of speedy to register the method to + * @param path URL of the resource being registered + * @param resource Object containing ::post http::request_cb_t handler + */ + template <class T> + void link(sp::Speedy& app, const std::string& path, T& resource) + { + using namespace std::placeholders; + app.post(path, std::bind(&T::post, std::ref(resource), _1, _2)); + } +}; + +struct PUT +{ + template <class T> + void link(sp::Speedy& app, const std::string& path, T& resource) + { + using namespace std::placeholders; + app.put(path, std::bind(&T::put, std::ref(resource), _1, _2)); + } +}; + +struct DELETE +{ + template <class T> + void link(sp::Speedy& app, const std::string& path, T& resource) + { + using namespace std::placeholders; + app.del(path, std::bind(&T::del, std::ref(resource), _1, _2)); + } +}; + +namespace detail +{ + +/** @brief Registers a method for a path to speedy + * + * @tparam T Derived class containing the handler of the method + * @tparam M A method to register + */ +template <class T, class M> +struct Method : public M +{ + /** Registers a route handler for the resource + * + * Registers a method handler for M on the given URL + * + * @param app instance of speedy to register the method to + * @param path URL of the resource being registered + */ + Method(T& resource, sp::Speedy& app, const std::string& path) + { + M::link(app, path, resource); + } +}; + +/** @brief Generates the Method<T, M> inheritance for each M in Ms + * + * Implemented inheriting recursively using variadic templates + * + * @tparam T Derived class containing handlers for each method M in Ms + * @tparam Ms... Methods to register + */ +template <class T, class... Ms> +struct Methods; + +/** @brief specialization of the struct Methods<T, Ms...> + * + * Unrolls one method M and generates a handler for this method by inheriting + * from Method<T, M> and generates the rest of the handlers recursively by + * inheriting from Methods<T, Ms...> and unrolling one M each time. + * + * @tparam T Derived class containing handlers for each method M in Ms + * @tparam M Unrolled method M for which to generate a handler + * @tparam Ms... The rest of the methods + */ +template <class T, class M, class... Ms> +struct Methods<T, M, Ms...> : public Method<T, M>, public Methods<T, Ms...> +{ + Methods(T& resource, sp::Speedy& app, const std::string& path) + : Method<T, M>(resource, app, path), + Methods<T, Ms...>(resource, app, path) {} +}; + +/** @brief specialization of the struct Methods<T, Ms...> + * + * Specializes the recursion termination case containing only one method M + * + * @tparam T Derived class containing handlers for method M + * @tparam M Unrolled method M for which to generate a handler + */ +template <class T, class M> +struct Methods<T, M> : public Method<T, M> +{ + using Method<T, M>::Method; +}; + +} + +/** @brief Represents a restful resource + * + * Automatically registers get, put, post, del... methods inside the derived + * class T. Methods are given as a template parameter to the class. Valid + * template parameters are classes which implement a function + * + * void link(sp::Speedy&, const std::string&, T& resource) + * + * which registers a method you want to use with speedy + * + * @tparam T Derived class (CRTP) + * @tparam Ms... HTTP methods to register for this resource (GET, POST...) + */ +template <class T, class... Ms> +class Restful : public detail::Methods<T, Ms...> +{ +public: + Restful(T& resource, sp::Speedy& app, const std::string& path) + : detail::Methods<T, Ms...>(resource, app, path) {} +}; + +#endif diff --git a/database/db.hpp b/database/db.hpp index 4796b9eb5..aa4a4db91 100644 --- a/database/db.hpp +++ b/database/db.hpp @@ -1,20 +1,17 @@ #ifndef MEMGRAPH_DATABASE_DB_HPP #define MEMGRAPH_DATABASE_DB_HPP -#include "transactions/transaction_engine.hpp" +#include "storage/graph.hpp" +#include "transactions/engine.hpp" #include "transactions/commit_log.hpp" class Db { public: - static Db& get() - { - static Db db; - return db; - } + using sptr = std::shared_ptr<Db>; - tx::CommitLog commit_log; - tx::TransactionEngine transaction_engine; + Graph graph; + tx::Engine tx_engine; }; #endif diff --git a/io/uv/blockbuffer.hpp b/io/uv/blockbuffer.hpp new file mode 100644 index 000000000..ae22895f5 --- /dev/null +++ b/io/uv/blockbuffer.hpp @@ -0,0 +1,128 @@ +#ifndef MEMGRAPH_IO_UV_BLOCKBUFFER_HPP +#define MEMGRAPH_IO_UV_BLOCKBUFFER_HPP + +#include <cstring> +#include <uv.h> + +#include "utils/memory/block_allocator.hpp" + +namespace uv +{ + +template <size_t block_size> +class BlockBuffer +{ + static BlockAllocator<block_size> allocator; + + struct Block : public uv_buf_t + { + Block() + { + // acquire a new block of memory for this buffer + base = static_cast<char*>(allocator.acquire()); + len = 0; + } + + ~Block() + { + // release the block of memory previously acquired + allocator.release(base); + } + + size_t append(const char* data, size_t size) + { + // compute the remaining capacity for this block + auto capacity = block_size - len; + + // if the capacity is smaller than the requested size, copy only + // up to the remaining capacity + if(size > capacity) + size = capacity; + + std::memcpy(base + len, data, size); + len += size; + + // return how much we've copied + return size; + } + }; + +public: + BlockBuffer() + { + // create the first buffer + buffers.emplace_back(); + } + + ~BlockBuffer() + { + buffers.clear(); + } + + BlockBuffer(BlockBuffer&) = delete; + BlockBuffer(BlockBuffer&&) = delete; + + size_t count() const + { + return buffers.size(); + } + + void clear() + { + // pop all buffers except for the first one since we need to allocate + // it again anyway so why not keep it in the first place + while(count() > 1) + buffers.pop_back(); + + // pretend we just allocated our first buffer and set it's length to 0 + buffers.back().len = 0; + } + + BlockBuffer& operator<<(const std::string& data) + { + append(data); + return *this; + } + + void append(const std::string& data) + { + append(data.c_str(), data.size()); + } + + void append(const char* data, size_t size) + { + while(true) + { + // try to copy as much data as possible + auto copied = buffers.back().append(data, size); + + // if we managed to copy everything, we're done + if(copied == size) + break; + + // move the pointer past the copied part + data += copied; + + // reduce the total size by the number of copied items + size -= copied; + + // since we ran out of space, construct a new buffer + buffers.emplace_back(); + } + } + + operator uv_buf_t*() + { + return buffers.data(); + } + +private: + std::vector<Block> buffers; +}; + +template <size_t block_size> +BlockAllocator<block_size> BlockBuffer<block_size>::allocator; + +} + +#endif diff --git a/io/uv/uv.hpp b/io/uv/uv.hpp index b771aed53..ea3941e4a 100644 --- a/io/uv/uv.hpp +++ b/io/uv/uv.hpp @@ -1,6 +1,7 @@ #include "tcpstream.hpp" #include "uvbuffer.hpp" #include "uvloop.hpp" +#include "blockbuffer.hpp" #include "tcpstream.inl" #include "uvbuffer.inl" diff --git a/io/uv/uvloop.hpp b/io/uv/uvloop.hpp index cb2d8ae90..4ad881ff2 100644 --- a/io/uv/uvloop.hpp +++ b/io/uv/uvloop.hpp @@ -12,6 +12,8 @@ namespace uv class UvLoop final { public: + using sptr = std::shared_ptr<UvLoop>; + enum Mode { Default = UV_RUN_DEFAULT, Once = UV_RUN_ONCE, diff --git a/memgraph b/memgraph deleted file mode 100755 index b791f189d8d49852941d7ef18421925057de4678..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137904 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 diff --git a/memgraph.cpp b/memgraph.cpp index a737ed089..2d4255777 100644 --- a/memgraph.cpp +++ b/memgraph.cpp @@ -1,22 +1,35 @@ #include <iostream> #include <vector> +#include "debug/log.hpp" +#include "utils/ioc/container.hpp" + +#include "database/db.hpp" + #include "speedy/speedy.hpp" #include "api/resources/include.hpp" -#include "utils/auto_scope.hpp" +#include "threading/pool.hpp" +#include "threading/task.hpp" -int main(int argc, char** argv) +int main() { - uv::UvLoop loop; - sp::Speedy app(loop); + ioc::Container container; - init(app); + container.singleton<Db>(); - http::Ipv4 ip("0.0.0.0", 3400); - app.listen(ip); + auto loop = container.singleton<uv::UvLoop>(); + auto app = container.singleton<sp::Speedy, uv::UvLoop>("/db/data"); - loop.run(uv::UvLoop::Mode::Default); + container.singleton<Pool>(4); + container.singleton<Task, uv::UvLoop, Pool>(); + + init(container); + + http::Ipv4 ip("0.0.0.0", 7474); + app->listen(ip); + + loop->run(uv::UvLoop::Mode::Default); return 0; } diff --git a/speedy/http/httpconnection.hpp b/speedy/http/httpconnection.hpp index 7561a3b56..dcc3afbcb 100644 --- a/speedy/http/httpconnection.hpp +++ b/speedy/http/httpconnection.hpp @@ -7,8 +7,6 @@ #include "request.hpp" #include "response.hpp" -#include "utils/memory/block_allocator.hpp" - namespace http { diff --git a/speedy/http/httpserver.inl b/speedy/http/httpserver.inl index 224aaffa9..ea4df5f0d 100644 --- a/speedy/http/httpserver.inl +++ b/speedy/http/httpserver.inl @@ -66,7 +66,6 @@ void HttpServer<Req, Res>:: conn.close(); buffer_allocator.release(buf->base); - //delete buf->base; } template <class Req, class Res> diff --git a/speedy/http/response.hpp b/speedy/http/response.hpp index 886915da4..2fd233d77 100644 --- a/speedy/http/response.hpp +++ b/speedy/http/response.hpp @@ -9,6 +9,8 @@ namespace http { +static constexpr size_t buffer_size = 65536; + template <class Req, class Res> class HttpConnection; @@ -30,7 +32,7 @@ public: private: connection_t& connection; - uv::UvBuffer buffer; + uv::BlockBuffer<buffer_size> buffer; }; } diff --git a/speedy/http/response.inl b/speedy/http/response.inl index dd2ed0c7c..e7e541ae7 100644 --- a/speedy/http/response.inl +++ b/speedy/http/response.inl @@ -9,14 +9,11 @@ namespace http { -constexpr size_t buffer_size = 65536; - static BlockAllocator<sizeof(uv_write_t)> write_req_allocator; template <class Req, class Res> Response<Req, Res>::Response(connection_t& connection) - : status(Status::Ok), connection(connection), - buffer(buffer_size) {} + : status(Status::Ok), connection(connection), buffer() {} template <class Req, class Res> void Response<Req, Res>::send(Status status, const std::string& body) @@ -45,7 +42,7 @@ void Response<Req, Res>::send(const std::string& body) buffer << "\r\n" << body; - uv_write(write_req, connection.client, buffer, 1, + uv_write(write_req, connection.client, buffer, buffer.count(), [](uv_write_t* write_req, int) { connection_t& conn = *reinterpret_cast<connection_t*>(write_req->data); diff --git a/speedy/r3.hpp b/speedy/r3.hpp index 939dd009c..a93d47f19 100644 --- a/speedy/r3.hpp +++ b/speedy/r3.hpp @@ -47,17 +47,18 @@ public: } } -private: - class MatchEntry +public: + class Route { public: - MatchEntry(Method method, const std::string& path) + Route(r3::node* node, Method method, const std::string& path) { entry = r3::match_entry_createl(path.c_str(), path.size()); entry->request_method = method; + route = r3::r3_tree_match_route(node, entry); } - ~MatchEntry() + ~Route() { r3::match_entry_free(entry); } @@ -67,22 +68,17 @@ private: return entry; } - private: - r3::match_entry* entry; - r3::route* route; - }; - -public: - class Route - { - public: - Route(r3::route* route) : route(route) {} - bool exists() const { return route != nullptr; } + void populate(sp::Request& req) + { + for(int i = 0; i < entry->vars->len; ++i) + req.params.emplace_back(entry->vars->tokens[i]); + } + void operator()(sp::Request& req, sp::Response& res) { assert(route != nullptr); @@ -92,6 +88,7 @@ public: } private: + r3::match_entry* entry; r3::route* route; }; @@ -124,24 +121,7 @@ public: Route match(Method method, const std::string& path) { - auto entry_m = MatchEntry(method, path); - return Route(r3::r3_tree_match_route(root, entry_m)); - -/* if(!route.exists()) */ -/* return route; */ - -/* r3::match_entry* entry = entry_m; */ - -/* std::cout << "Eetry Matched!" << std::endl */ -/* << "path = " << std::string(entry->path, entry->path_len) << std::endl */ -/* << "host = " << std::string(entry->host, entry->host_len) << std::endl */ -/* << "remote_addr = " << std::string(entry->remote_addr, entry->remote_addr_len) << std::endl */ -/* << "tokens_len = " << entry->vars->len << std::endl; */ - -/* for(int i = 0; i < entry->vars->len; ++i) */ -/* std::cout << "token " << i << " = " << std::string(entry->vars->tokens[i]) << std::endl; */ - - //return route; + return Route(root, method, path); } void compile() diff --git a/speedy/request.hpp b/speedy/request.hpp index 35d5341aa..11e417351 100644 --- a/speedy/request.hpp +++ b/speedy/request.hpp @@ -1,6 +1,8 @@ #ifndef MEMGRAPH_SPEEDY_REQUEST_HPP #define MEMGRAPH_SPEEDY_REQUEST_HPP +#include <vector> + #include "http/request.hpp" namespace sp @@ -10,6 +12,8 @@ class Request : public http::Request { public: using http::Request::Request; + + std::vector<std::string> params; }; } diff --git a/speedy/speedy.hpp b/speedy/speedy.hpp index 7e7497fa2..13bce33a2 100644 --- a/speedy/speedy.hpp +++ b/speedy/speedy.hpp @@ -23,33 +23,36 @@ namespace sp class Speedy { public: + using sptr = std::shared_ptr<Speedy>; + using server_t = http::HttpServer<Request, Response>; using request_cb_t = server_t::request_cb_t; - Speedy(uv::UvLoop& loop, size_t capacity = 100) - : server(loop), router(capacity) {} + Speedy(uv::UvLoop::sptr loop, const std::string& prefix = "", + size_t capacity = 100) + : server(*loop), prefix(std::move(prefix)), router(capacity) {} Speedy(Speedy&) = delete; Speedy(Speedy&&) = delete; void get(const std::string& path, server_t::request_cb_t cb) { - router.insert(R3::Method::GET, path, cb); + router.insert(R3::Method::GET, join(prefix, path), cb); } void post(const std::string& path, server_t::request_cb_t cb) { - router.insert(R3::Method::POST, path, cb); + router.insert(R3::Method::POST, join(prefix, path), cb); } void put(const std::string& path, server_t::request_cb_t cb) { - router.insert(R3::Method::PUT, path, cb); + router.insert(R3::Method::PUT, join(prefix, path), cb); } void del(const std::string& path, server_t::request_cb_t cb) { - router.insert(R3::Method::DELETE, path, cb); + router.insert(R3::Method::DELETE, join(prefix, path), cb); } void listen(const http::Ipv4& ip) @@ -57,20 +60,43 @@ public: router.compile(); server.listen(ip, [this](Request& req, Response& res) { - return res.send("Hello World"); - auto route = router.match(R3::to_r3_method(req.method), req.url); if(!route.exists()) return res.send(http::Status::NotFound, "Resource not found"); + route.populate(req); route(req, res); }); } private: server_t server; + std::string prefix; R3 router; + + std::string join(const std::string& prefix, const std::string& path) + { + // check if prefix has a trailing / + if(prefix.back() == '/') + { + // prefix has a / on the end so remove the / from the path + // if it has it too. e.g /db/data/ + /node = /db/data/node + if(path.front() == '/') + return prefix + path.substr(1); + + // there is only one / so it's ok to concat them + return prefix + path; + } + + // the prefix doesn't have a slash + if(path.front() == '/') + // the path has though, so it's ok to concat them + return prefix + path; + + // neither the prefix or the path have a / so we need to add it + return prefix + '/' + path; + } }; } diff --git a/storage/model/properties/property.hpp b/storage/model/properties/property.hpp index 1da19b419..61174225a 100644 --- a/storage/model/properties/property.hpp +++ b/storage/model/properties/property.hpp @@ -10,15 +10,17 @@ namespace model class Property { public: - // shared_ptr is being used because of MVCC - when you clone a record, you - // clone it's properties. when a single property is updated, a lot of - // memory is being wasted. this way it is shared until you need to change - // something and shared ptr ensures it's being properly tracked and - // cleaned up after no one is using it - using sptr = std::shared_ptr<Property>; - virtual ~Property() {} + template <class T, class... Args> + static Property::sptr make(Args&&... args) + { + return std::shared_ptr<Property>(new T(std::forward<Args>(args)...)); + } + + Property() = default; + virtual ~Property() = default; + virtual void dump(std::string& buffer) = 0; template <class T> diff --git a/threading/pool.hpp b/threading/pool.hpp index 846a3f81d..f8d0b5cd5 100644 --- a/threading/pool.hpp +++ b/threading/pool.hpp @@ -13,6 +13,8 @@ class Pool : Lockable<std::mutex> { using task_t = std::function<void()>; public: + using sptr = std::shared_ptr<Pool>; + Pool(size_t n = std::thread::hardware_concurrency()) : alive(true) { threads.reserve(n); @@ -33,15 +35,11 @@ public: thread.join(); } - template <class F, class... Args> - void run(F&& f, Args&&... args) + void run(task_t f) { { auto lock = acquire_unique(); - - tasks.emplace([&f, &args...]() { - f(std::forward<Args>(args)...); - }); + tasks.push(f); } cond.notify_one(); diff --git a/threading/task.hpp b/threading/task.hpp new file mode 100644 index 000000000..5ef9382bc --- /dev/null +++ b/threading/task.hpp @@ -0,0 +1,83 @@ +#ifndef MEMGRAPH_THREADING_TASK_HPP +#define MEMGRAPH_THREADING_TASK_HPP + +#include <iostream> + +#include "pool.hpp" +#include "io/uv/uvloop.hpp" +#include "utils/placeholder.hpp" + +class Task +{ + template <class T> + using work_t = std::function<T(void)>; + + template <class T> + using after_work_t = std::function<void(T)>; + + template <class T> + struct Work + { + + Work(uv::UvLoop& loop, work_t<T> work, after_work_t<T> after_work) + : work(std::move(work)), after_work(std::move(after_work)) + { + uv_async_init(loop, &this->async, async_cb); + } + + void operator()() + { + result.set(std::move(work())); + + async.data = static_cast<void*>(this); + uv_async_send(&this->async); + } + + work_t<T> work; + after_work_t<T> after_work; + + Placeholder<T> result; + + uv_async_t async; + + private: + static void async_cb(uv_async_t* handle) + { + auto work = static_cast<Work<T>*>(handle->data); + + work->after_work(std::move(work->result.get())); + + auto async_as_handle = reinterpret_cast<uv_handle_t*>(handle); + + uv_close(async_as_handle, [](uv_handle_t* handle) { + auto work = static_cast<Work<T>*>(handle->data); + delete work; + }); + } + }; + +public: + using sptr = std::shared_ptr<Task>; + + Task(uv::UvLoop::sptr loop, Pool::sptr pool) : loop(loop), pool(pool) {} + + Task(Task&) = delete; + Task(Task&&) = delete; + + template <class F1, class F2> + void run(F1&& work, F2&& after_work) + { + using T = decltype(work()); + + auto w = new Work<T>(*loop, std::forward<F1>(work), + std::forward<F2>(after_work)); + + pool->run([w]() { w->operator()(); }); + } + +private: + uv::UvLoop::sptr loop; + Pool::sptr pool; +}; + +#endif diff --git a/transactions/transaction_engine.hpp b/transactions/engine.hpp similarity index 91% rename from transactions/transaction_engine.hpp rename to transactions/engine.hpp index 27a4d7504..a7929bc29 100644 --- a/transactions/transaction_engine.hpp +++ b/transactions/engine.hpp @@ -1,5 +1,5 @@ -#ifndef MEMGRAPH_MVCC_TRANSACTIONENGINE_HPP -#define MEMGRAPH_MVCC_TRANSACTIONENGINE_HPP +#ifndef MEMGRAPH_TRANSACTIONS_ENGINE_HPP +#define MEMGRAPH_TRANSACTIONS_ENGINE_HPP #include <atomic> #include <vector> @@ -22,10 +22,12 @@ public: using std::runtime_error::runtime_error; }; -class TransactionEngine : Lockable<SpinLock> +class Engine : Lockable<SpinLock> { public: - TransactionEngine() : counter(0) {} + using sptr = std::shared_ptr<Engine>; + + Engine() : counter(0) {} const Transaction& begin() { diff --git a/utils/ioc/container.hpp b/utils/ioc/container.hpp index 9d00df900..05f9fc98c 100644 --- a/utils/ioc/container.hpp +++ b/utils/ioc/container.hpp @@ -69,23 +69,17 @@ public: return item->get(); } - template <class T, class... Args> - std::shared_ptr<T> singleton() + template <class T, class... Deps, class... Args> + std::shared_ptr<T> singleton(Args&&... args) { - auto item = std::make_shared<T>(resolve<Args>()...); + auto item = std::make_shared<T>(resolve<Deps>()..., args...); items.emplace(key<T>(), Holdable::uptr(new Instance<T>(item))); return item; } - template <class T> - void singleton(std::shared_ptr<T>&& item) - { - items.emplace(key<T>(), Holdable::uptr(new Instance<T>(item))); - } - template <class T> void factory(typename Creator<T>::func&& f) - { + { items[key<T>()] = std::move(Holdable::uptr( new Creator<T>(std::forward<typename Creator<T>::func>(f)) )); diff --git a/utils/placeholder.hpp b/utils/placeholder.hpp new file mode 100644 index 000000000..f5f5c1c6d --- /dev/null +++ b/utils/placeholder.hpp @@ -0,0 +1,45 @@ +#ifndef MEMGRAPH_UTILS_PLACEHOLDER_HPP +#define MEMGRAPH_UTILS_PLACEHOLDER_HPP + +#include <utility> +#include <ext/aligned_buffer.h> + +template <class T> +class Placeholder +{ +public: + Placeholder() = default; + + Placeholder(Placeholder&) = delete; + Placeholder(Placeholder&&) = delete; + + ~Placeholder() + { + if(initialized) + get().~T(); + }; + + T& get() noexcept + { + assert(initialized); + return *data._M_ptr(); + } + + void set(const T& item) + { + new (data._M_addr()) T(item); + initialized = true; + } + + void set(T&& item) + { + new (data._M_addr()) T(std::move(item)); + initialized = true; + } + +private: + __gnu_cxx::__aligned_buffer<T> data; + bool initialized = false; +}; + +#endif