a wild random checkpoint commit appeared

This commit is contained in:
Dominik Tomičević 2015-08-30 01:12:46 +02:00
parent f31f4693ce
commit fef9953f45
80 changed files with 2716 additions and 24 deletions

View File

@ -17,6 +17,7 @@ on a 64 bit linux kernel.
* clang 3.5 or Gcc 4.8 (good c++11 support, especially lock free atomics)
* boost 1.55 (or something, probably works with almost anything)
* lexertl (2015-07-14)
* lemon (parser generator)
* catch (for compiling tests)
## build

8
cypher/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
lexertl
lemon
*.o
cypher.cpp
cypher.h
parser
cypher.out
parser

29
cypher/Makefile Normal file
View File

@ -0,0 +1,29 @@
CXX = clang++
CXXFLAGS = -std=c++11
INC = -I../
parser: parser.o cypher.o
$(CXX) parser.o cypher.o -o parser $(INC) $(CXXFLAGS)
cypher.o:
$(CXX) cypher.cpp -c -o cypher.o $(INC) $(CXXFLAGS)
parser.o: parser.cpp cypher.hpp
$(CXX) parser.cpp -c -o parser.o $(INC) $(CXXFLAGS)
cypher.cpp: lemonfiles
cypher.hpp: lemonfiles
.PHONY: lemonfiles
lemonfiles: cypher.y
lemon/lemon cypher.y -s
mv cypher.c cypher.cpp
.PHONY: clean
clean:
rm -f *.o
rm -f cypher.cpp
rm -f cypher.h
rm -f parser
rm -f cypher.out

24
cypher/ast/accessor.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef MEMGRAPH_CYPHER_AST_AST_ACCESSOR_HPP
#define MEMGRAPH_CYPHER_AST_AST_ACCESSOR_HPP
#include <memory>
#include <string>
#include "expr.hpp"
#include "identifier.hpp"
namespace ast
{
struct Accessor : public VisitableExpr<Accessor>
{
Accessor(Identifier* entity, Identifier* prop)
: entity(entity), prop(prop) {}
Identifier::uptr entity;
Identifier::uptr prop;
};
}
#endif

13
cypher/ast/ast.hpp Normal file
View File

@ -0,0 +1,13 @@
#ifndef MEMGRAPH_CYPHER_AST_AST_HPP
#define MEMGRAPH_CYPHER_AST_AST_HPP
#include "accessor.hpp"
#include "values.hpp"
#include "identifier.hpp"
#include "operators.hpp"
#include "property.hpp"
#include "relationship.hpp"
#include "node.hpp"
#include "return.hpp"
#endif

24
cypher/ast/ast_echo.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef MEMGRAPH_CYPHER_AST_PRINT_TREE_HPP
#define MEMGRAPH_CYPHER_AST_PRINT_TREE_HPP
#include <iostream>
#include "ast_visitor.hpp"
#include "values.hpp"
namespace ast
{
class AstEcho : public AstVisitor
{
public:
virtual void visit(Boolean& node)
{
std::cout << "Boolean: " << node.value << std::endl;
}
};
}
#endif

33
cypher/ast/ast_node.hpp Normal file
View File

@ -0,0 +1,33 @@
#ifndef MEMGRAPH_CYPHER_AST_AST_NODE_HPP
#define MEMGRAPH_CYPHER_AST_AST_NODE_HPP
#include <memory>
#include "utils/visitor/visitable.hpp"
#include "utils/crtp.hpp"
#include "ast_visitor.hpp"
namespace ast
{
struct AstVisitor;
struct AstVisitable : public Visitable<AstVisitor>
{
using uptr = std::unique_ptr<AstVisitable>;
};
template <class Derived>
struct AstNode : public Crtp<Derived>, public AstVisitable
{
using uptr = std::unique_ptr<Derived>;
virtual void accept(AstVisitor& visitor)
{
visitor.visit(this->derived());
}
};
}
#endif

View File

@ -0,0 +1,52 @@
#ifndef MEMGRAPH_CYPHER_AST_AST_VISITOR_HPP
#define MEMGRAPH_CYPHER_AST_AST_VISITOR_HPP
#include "utils/visitor/visitor.hpp"
namespace ast
{
struct Identifier;
// properties
struct Property;
struct PropertyList;
struct Accessor;
// values
struct Boolean;
struct Float;
struct Integer;
struct String;
// operators
struct And;
struct Or;
struct Lt;
struct Gt;
struct Ge;
struct Le;
struct Eq;
struct Ne;
struct Plus;
struct Minus;
struct Star;
struct Slash;
struct Rem;
struct RelationshipList;
struct Relationship;
struct Node;
struct LabelList;
struct ReturnList;
struct AstVisitor : Visitor<Accessor, Boolean, Float, Identifier, Integer,
String, Property, And, Or, Lt, Gt, Ge, Le, Eq, Ne, Plus, Minus, Star,
Slash, Rem, PropertyList, RelationshipList, Relationship, Node,
LabelList, ReturnList> {};
}
#endif

40
cypher/ast/expr.hpp Normal file
View File

@ -0,0 +1,40 @@
#ifndef MEMGRAPH_CYPHER_AST_EXPR_HPP
#define MEMGRAPH_CYPHER_AST_EXPR_HPP
#include "ast_node.hpp"
namespace ast
{
struct Expr : public AstVisitable {};
template <class Derived>
struct VisitableExpr : public Crtp<Derived>, public Expr
{
using uptr = std::unique_ptr<Derived>;
virtual void accept(AstVisitor& visitor)
{
visitor.visit(this->derived());
}
};
template <class T, class Derived>
struct LeafExpr : public VisitableExpr<Derived>
{
LeafExpr(T value) : value(value) {}
T value;
};
template <class Derived>
struct BinaryExpr : public VisitableExpr<Derived>
{
BinaryExpr(Expr* left, Expr* right) : left(left), right(right) {}
Expr* left;
Expr* right;
};
}
#endif

19
cypher/ast/identifier.hpp Normal file
View File

@ -0,0 +1,19 @@
#ifndef MEMGRAPH_CYPHER_AST_AST_IDENTIFIER_HPP
#define MEMGRAPH_CYPHER_AST_AST_IDENTIFIER_HPP
#include <string>
#include "ast_node.hpp"
namespace ast
{
struct Identifier : public AstNode<Identifier>
{
Identifier(std::string name) : name(name) {}
std::string name;
};
}
#endif

21
cypher/ast/list.hpp Normal file
View File

@ -0,0 +1,21 @@
#ifndef MEMGRAPH_CYPHER_AST_LIST_HPP
#define MEMGRAPH_CYPHER_AST_LIST_HPP
#include "ast_node.hpp"
namespace ast
{
template <class T, class Derived>
struct List : public AstNode<Derived>
{
List(T* value, Derived* next)
: value(value), next(next) {}
T* value;
Derived* next;
};
}
#endif

27
cypher/ast/node.hpp Normal file
View File

@ -0,0 +1,27 @@
#ifndef MEMGRAPH_CYPHER_AST_NODE_HPP
#define MEMGRAPH_CYPHER_AST_NODE_HPP
#include "list.hpp"
#include "identifier.hpp"
namespace ast
{
struct LabelList : public List<Identifier, LabelList>
{
using List::List;
};
struct Node : public AstNode<Node>
{
Node(Identifier* idn, LabelList* labels, PropertyList* props)
: idn(idn), labels(labels), props(props) {}
Identifier* idn;
LabelList* labels;
PropertyList* props;
};
}
#endif

76
cypher/ast/operators.hpp Normal file
View File

@ -0,0 +1,76 @@
#ifndef MEMGRAPH_CYPHER_AST_OPERATORS_HPP
#define MEMGRAPH_CYPHER_AST_OPERATORS_HPP
#include "expr.hpp"
namespace ast
{
struct And : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Or : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Lt : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Gt : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Ge : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Le : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Eq : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Ne : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Plus : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Minus : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Star : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Slash : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Rem : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
}
#endif

24
cypher/ast/pattern.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef MEMGRAPH_CYPHER_AST_PATTERN_HPP
#define MEMGRAPH_CYPHER_AST_PATTERN_HPP
#include "ast_node.hpp"
namespace ast
{
template <class Derived>
struct Direction : public AstNode<Derived> {};
struct DirectionLeft : public Direction<DirectionLeft> {};
struct DirectionRight : public Direction<DirectionLeft> {};
struct Unidirectional : public Direction<DirectionLeft> {};
struct Pattern : public AstNode<Pattern>
{
Node* node;
Pattern* next;
};
}
#endif

27
cypher/ast/property.hpp Normal file
View File

@ -0,0 +1,27 @@
#ifndef MEMGRAPH_CYPHER_AST_AST_PROPERTY_HPP
#define MEMGRAPH_CYPHER_AST_AST_PROPERTY_HPP
#include "list.hpp"
#include "identifier.hpp"
#include "expr.hpp"
namespace ast
{
struct Property : public AstNode<Property>
{
Property(Identifier* idn, Expr* value)
: idn(idn), value(value) {}
Identifier* idn;
Expr* value;
};
struct PropertyList : public List<Property, PropertyList>
{
using List::List;
};
}
#endif

View File

@ -0,0 +1,32 @@
#ifndef MEMGRAPH_CYPHER_AST_RELATIONSHIP_HPP
#define MEMGRAPH_CYPHER_AST_RELATIONSHIP_HPP
#include "list.hpp"
#include "identifier.hpp"
namespace ast
{
struct RelationshipList : public List<Identifier, RelationshipList>
{
using List::List;
};
struct RelationshipSpecs : public AstNode<RelationshipSpecs>
{
RelationshipSpecs(Identifier* idn, RelationshipList* types, PropertyList* props)
: idn(idn), types(types), props(props) {}
Identifier* idn;
RelationshipList* types;
PropertyList* props;
};
struct Relationship : public AstNode<Relationship>
{
Relationship()
};
}
#endif

17
cypher/ast/return.hpp Normal file
View File

@ -0,0 +1,17 @@
#ifndef MEMGRAPH_CYPHER_AST_RETURN_HPP
#define MEMGRAPH_CYPHER_AST_RETURN_HPP
#include "list.hpp"
#include "identifier.hpp"
namespace ast
{
struct ReturnList : public List<Identifier, ReturnList>
{
using List::List;
};
};
#endif

41
cypher/ast/tree.hpp Normal file
View File

@ -0,0 +1,41 @@
#ifndef MEMGRAPH_CYPHER_AST_TREE_HPP
#define MEMGRAPH_CYPHER_AST_TREE_HPP
#include <vector>
#include "ast_node.hpp"
namespace ast
{
class Ast
{
public:
Ast() {}
AstVisitable::uptr root;
void traverse(AstVisitor& visitor)
{
root->accept(visitor);
}
template <class T, typename... Args>
T* create(Args&&... args)
{
auto node = new T(std::forward<Args>(args)...);
items.push_back(std::unique_ptr<AstVisitable>(node));
return node;
}
private:
// basically a gc vector that destroys all ast nodes once this object is
// destroyed. parser generator is written in c and works only with raw
// pointers so this is what makes it leak free after the parser finishes
// parsing
std::vector<AstVisitable::uptr> items;
};
}
#endif

33
cypher/ast/values.hpp Normal file
View File

@ -0,0 +1,33 @@
#ifndef MEMGRAPH_CYPHER_AST_VALUES_HPP
#define MEMGRAPH_CYPHER_AST_VALUES_HPP
#include <string>
#include "expr.hpp"
namespace ast
{
struct Float : public LeafExpr<double, Float>
{
using LeafExpr::LeafExpr;
};
struct Integer : public LeafExpr<int, Integer>
{
using LeafExpr::LeafExpr;
};
struct Boolean : public LeafExpr<bool, Boolean>
{
using LeafExpr::LeafExpr;
};
struct String : public LeafExpr<std::string, String>
{
using LeafExpr::LeafExpr;
};
}
#endif

17
cypher/ast/visitor.cpp Normal file
View File

@ -0,0 +1,17 @@
#include <iostream>
#include "ast_visitor.hpp"
#include "ast_node.hpp"
#include "ast_echo.hpp"
#include "boolean.hpp"
int main(void)
{
Token t;
AstNode* root = new Boolean(t);
AstEcho echo;
root->accept(echo);
return 0;
}

291
cypher/cypher.y Normal file
View File

@ -0,0 +1,291 @@
/*
** This file contains memgraph's grammar for Cypher. Process this file
** using the lemon parser generator to generate C code that runs
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
*/
%token_prefix TK_
%token_type {Token*}
%extra_argument {ast::Ast* ast}
%syntax_error
{
std::cout << "syntax error near '" << TOKEN->value << "'." << std::endl;
throw "";
}
%stack_overflow
{
std::cout << "parser stack overflow" << std::endl;
}
%name cypher_parser
%include
{
#include <iostream>
#include <cassert>
#include <cstdlib>
#include "token.hpp"
#include "ast/ast.hpp"
#include "ast/tree.hpp"
#define DEBUG(X) std::cout << X << std::endl
}
// define operator precedence
%left OR.
%left AND.
%right NOT.
%left IN IS_NULL IS_NOT_NULL NE EQ.
%left GT LE LT GE.
%left PLUS MINUS.
%left STAR SLASH REM.
start ::= read_query.
read_query ::= match_clause return_clause.
match_clause ::= MATCH pattern where_clause.
%type pattern {ast::Pattern*}
// pattern specification
pattern ::= node rel pattern. {
}
pattern ::= node. {
}
rel ::= MINUS rel_spec MINUS. { // unidirectional
}
rel ::= LT MINUS rel_spec MINUS { // left
}
rel(R) ::= MINUS rel_spec(S) MINUS GT { // right
R = ast->create<ast::Relationship>(
}
%type rel_spec {ast::RelationshipSpecs*}
rel_spec(R) ::= LSP rel_idn(I) rel_type(T) properties(P) RSP. {
R = ast->create<ast::RelationshipSpecs>(I, T, P);
}
rel_spec(R) ::= . {
R = nullptr;
}
%type rel_idn {ast::Identifier*}
rel_idn(R) ::= idn(I). {
R = I;
}
rel_idn(R) ::= . {
R = nullptr;
}
%type rel_type {ast::RelationshipList*}
rel_type(L) ::= COLON rel_list(R). {
L = R;
}
rel_type(L) ::= . {
L = nullptr;
}
%type rel_list {ast::RelationshipList*}
rel_list(L) ::= idn(I) PIPE rel_list(R). {
L = ast->create<ast::RelationshipList>(I, R);
}
rel_list(L) ::= idn(I). {
L = ast->create<ast::RelationshipList>(I, nullptr);
}
%type node {ast::Node*}
// node specification
node(N) ::= LP node_idn(I) label_idn(L) properties(P) RP. {
N = ast->create<ast::Node>(I, L, P);
}
node(N) ::= idn(I). {
N = ast->create<ast::Node>(I, nullptr, nullptr);
}
%type node_idn {ast::Identifier*}
// a node identifier can be ommitted
node_idn(N) ::= idn(I). {
N = I;
}
node_idn(N) ::= . {
N = nullptr;
}
%type label_idn {ast::LabelList*}
// a label can be ommited or there can be more of them
label_idn(L) ::= COLON idn(I) label_idn(N). {
L = ast->create<ast::LabelList>(I, N);
}
label_idn(L) ::= . {
L = nullptr;
}
%type where_clause {ast::Expr*}
// where clause
where_clause(W) ::= WHERE expr(E). {
W = E;
}
where_clause(W) ::= . {
W = nullptr;
}
%type return_clause {ast::ReturnList*}
// return clause
return_clause(R) ::= RETURN return_list(L). {
R = L;
}
%type return_list {ast::ReturnList*}
return_list(R) ::= idn(I) COMMA return_list(N). {
R = ast->create<ast::ReturnList>(I, N);
}
return_list(R) ::= idn(I). {
R = ast->create<ast::ReturnList>(I, nullptr);
}
%type properties {ast::PropertyList*}
// '{' <property_list> '}'
properties(P) ::= LCP property_list(L) RCP. {
P = L;
}
properties(P) ::= . {
P = nullptr;
}
%type property_list {ast::PropertyList*}
// <property> [[',' <property>]]*
property_list(L) ::= property(P) COMMA property_list(N). {
L = ast->create<ast::PropertyList>(P, N);
}
property_list(L) ::= property(P). {
L = ast->create<ast::PropertyList>(P, nullptr);
}
%type property {ast::Property*}
// IDENTIFIER ':' <expression>
property(P) ::= idn(I) COLON expr(E). {
P = ast->create<ast::Property>(I, E);
}
%type expr {ast::Expr*}
expr(E) ::= expr(L) AND expr(R). {
E = ast->create<ast::And>(L, R);
}
expr(E) ::= expr(L) OR expr(R). {
E = ast->create<ast::Or>(L, R);
}
expr(E) ::= expr(L) LT expr(R). {
E = ast->create<ast::Lt>(L, R);
}
expr(E) ::= expr(L) GT expr(R). {
E = ast->create<ast::Gt>(L, R);
}
expr(E) ::= expr(L) GE expr(R). {
E = ast->create<ast::Ge>(L, R);
}
expr(E) ::= expr(L) LE expr(R). {
E = ast->create<ast::Le>(L, R);
}
expr(E) ::= expr(L) EQ expr(R). {
E = ast->create<ast::Eq>(L, R);
}
expr(E) ::= expr(L) NE expr(R). {
E = ast->create<ast::Ne>(L, R);
}
expr(E) ::= expr(L) PLUS expr(R). {
E = ast->create<ast::Plus>(L, R);
}
expr(E) ::= expr(L) MINUS expr(R). {
E = ast->create<ast::Minus>(L, R);
}
expr(E) ::= expr(L) STAR expr(R). {
E = ast->create<ast::Star>(L, R);
}
expr(E) ::= expr(L) SLASH expr(R). {
E = ast->create<ast::Slash>(L, R);
}
expr(E) ::= expr(L) REM expr(R). {
E = ast->create<ast::Rem>(L, R);
}
expr(E) ::= idn(I) DOT idn(P). {
E = ast->create<ast::Accessor>(I, P);
}
%type idn {ast::Identifier*}
idn(I) ::= IDN(X). {
I = ast->create<ast::Identifier>(X->value);
}
expr(E) ::= INT(V). {
auto value = std::stoi(V->value);
E = ast->create<ast::Integer>(value);
}
expr(E) ::= FLOAT(V). {
auto value = std::stod(V->value);
E = ast->create<ast::Float>(value);
}
expr(E) ::= STR(V). {
auto value = V->value.substr(1, V->value.size() - 2);
E = ast->create<ast::String>(value);
}
expr(E) ::= BOOL(V). {
auto value = V->value[0] == 't' || V->value[0] == 'T' ? true : false;
E = ast->create<ast::Boolean>(value);
}

72
cypher/cypher_lexer.hpp Normal file
View File

@ -0,0 +1,72 @@
#ifndef MEMGRAPH_CYPHER_LEXER_CYPHER_LEXER_HPP
#define MEMGRAPH_CYPHER_LEXER_CYPHER_LEXER_HPP
#include "cypher.h"
#include "lexer.hpp"
class CypherLexer : public Lexer
{
public:
CypherLexer()
{
// whitespace
rule("\\s+", sm.skip());
// special characters
rule("\\.", TK_DOT);
rule(",", TK_COMMA);
rule(":", TK_COLON);
rule("\\|", TK_PIPE);
rule("\\{", TK_LCP);
rule("\\}", TK_RCP);
rule("\\(", TK_LP);
rule("\\)", TK_RP);
rule("\\[", TK_LSP);
rule("\\]", TK_RSP);
// operators
rule("\\+", TK_PLUS);
rule("-", TK_MINUS);
rule("\\*", TK_STAR);
rule("\\/", TK_SLASH);
rule("%", TK_REM);
rule(">", TK_GT);
rule("<", TK_LT);
rule(">=", TK_GE);
rule("<=", TK_LE);
rule("=", TK_EQ);
rule("<>", TK_NE);
// constants
rule("(?i:TRUE)", TK_BOOL);
rule("(?i:FALSE)", TK_BOOL);
// keywords
rule("(?i:MATCH)", TK_MATCH);
rule("(?i:WHERE)", TK_WHERE);
rule("(?i:RETURN)", TK_RETURN);
rule("(?i:AND)", TK_AND);
rule("(?i:OR)", TK_OR);
// string literal TODO single quote escape
rule("'(.*?)'", TK_STR);
// string literal TODO double quote escape
rule("\\\"(.*?)\\\"", TK_STR);
// number
rule("\\d+", TK_INT);
rule("\\d*[.]?\\d+", TK_FLOAT);
// identifier
rule("[_a-zA-Z][_a-zA-Z0-9]{0,30}", TK_IDN);
build();
}
};
#endif

56
cypher/lexer.cpp Normal file
View File

@ -0,0 +1,56 @@
#include "lexertl/generator.hpp"
#include <iostream>
#include "lexertl/lookup.hpp"
#include "cypher_lexer.hpp"
int main()
{
CypherLexer lexer;
auto tokenizer = lexer.tokenize("{name: 'Dominik', lastName: 'Tomicevic', age: 24 }");
while(true)
{
auto token = tokenizer.lookup();
if(token.id == 0)
break;
std::cout << token.id << " -> " << token.value << std::endl;
}
lexertl::rules rules;
lexertl::state_machine sm;
rules.push("\\s+", sm.skip());
rules.push("MATCH", 1);
rules.push("RETURN", 2);
rules.push("'(.*?)'", 4); // string literal TODO single quote escape
rules.push("\\\"(.*?)\\\"", 4); // string literal TODO double quote escape
rules.push("[-+]?(\\d*[.])?\\d+", 5); // number
rules.push("[_a-zA-Z][_a-zA-Z0-9]{0,30}", 3); // identifier
lexertl::generator::build(rules, sm);
std::string input("MATCH (user:User { name: 'Dominik', age: 24})-[has:HAS]->(item:Item) WHERE item.name = 'XPS 13', AND item.price = 14.99 RETURN user, has, item");
lexertl::smatch results(input.begin(), input.end());
// Read ahead
lexertl::lookup(sm, results);
while (results.id != 0)
{
std::cout << "Id: " << results.id << ", Token: '" <<
results.str () << "'\n";
lexertl::lookup(sm, results);
}
std::cout << "-1 to uint64_t = " << uint64_t(-1) << std::endl;
return 0;
}

58
cypher/lexer.hpp Normal file
View File

@ -0,0 +1,58 @@
#ifndef MEMGRAPH_CYPHER_LEXER_HPP
#define MEMGRAPH_CYPHER_LEXER_HPP
#include <cstdint>
#include "lexertl/generator.hpp"
#include "lexertl/lookup.hpp"
#include "lexical_error.hpp"
#include "token.hpp"
class Lexer
{
public:
class Tokenizer
{
public:
Tokenizer(const Lexer& lexer, const std::string& str)
: lexer(lexer), results(str.begin(), str.end()) {}
Token* lookup()
{
lexertl::lookup(lexer.sm, results);
auto token = new Token {results.id, results.str()};
if(results.id == static_cast<decltype(results.id)>(-1))
throw LexicalError(*token);
return token;
}
private:
const Lexer& lexer;
lexertl::smatch results;
};
Tokenizer tokenize(const std::string& str)
{
return Tokenizer(*this, str);
}
void build()
{
lexertl::generator::build(rules, sm);
}
void rule(const std::string& regex, uint64_t id)
{
rules.push(regex, id);
}
protected:
lexertl::rules rules;
lexertl::state_machine sm;
};
#endif

15
cypher/lexical_error.hpp Normal file
View File

@ -0,0 +1,15 @@
#ifndef MEMGRAPH_CYPHER_LEXER_LEXICAL_ERROR_HPP
#define MEMGRAPH_CYPHER_LEXER_LEXICAL_ERROR_HPP
#include <stdexcept>
#include "token.hpp"
class LexicalError : public std::runtime_error
{
public:
LexicalError(const Token& token)
: std::runtime_error("Unrecognized token '" + token.value + "'.") {}
};
#endif

55
cypher/parser.cpp Normal file
View File

@ -0,0 +1,55 @@
#include <cstdlib>
#include <vector>
#include <vector>
#include "cypher.h"
#include "token.hpp"
#include "cypher_lexer.hpp"
#include "ast/tree.hpp"
void* cypher_parserAlloc(void* (*allocProc)(size_t));
void cypher_parser(void*, int, Token*, ast::Ast* ast);
void cypher_parserFree(void*, void(*freeProc)(void*));
int main()
{
void* parser = cypher_parserAlloc(malloc);
CypherLexer lexer;
//std::string input("matcH (user:User { name: 'Dominik', age: 8 + 4})-[has:HAS|IS|CAN { duration: 'PERMANENT'}]->(item:Item)--(shop)");
std::string input("MATCH (user:User { name: 'Dominik', age: 24})-[has:HAS]->(item:Item) WHERE item.name = 'XPS 13' AND item.price = 11999.99 RETURN user, has, item");
auto tokenizer = lexer.tokenize(input);
std::vector<Token*> v;
while(true)
{
v.push_back(tokenizer.lookup());
auto token = v.back();
//std::cout << token->id << " -> " << token->value << std::endl;
auto ast = new ast::Ast();
try
{
cypher_parser(parser, token->id, token, ast);
}
catch(...)
{
std::cout << "caught exception." << std::endl;
exit(0);
}
if(token->id == 0)
break;
}
cypher_parserFree(parser, free);
return 0;
}

10
cypher/proba.cpp Normal file
View File

@ -0,0 +1,10 @@
#include <iostream>
#include "ast/float.hpp"
int main(void)
{
auto f = new Float(3);
return 0;
}

13
cypher/token.hpp Normal file
View File

@ -0,0 +1,13 @@
#ifndef MEMGRAPH_CYPHER_TOKEN_HPP
#define MEMGRAPH_CYPHER_TOKEN_HPP
#include <cstdint>
#include <string>
struct Token
{
unsigned long id;
std::string value;
};
#endif

View File

@ -26,8 +26,6 @@ public:
size_t size() const
{
return data.size();
}

View File

@ -0,0 +1,71 @@
#ifndef MEMGRAPH_DATA_STRUCTURES_QUEUE_SLQUEUE_HPP
#define MEMGRAPH_DATA_STRUCTURES_QUEUE_SLQUEUE_HPP
#include <queue>
#include "threading/sync/lockable.hpp"
#include "threading/sync/spinlock.hpp"
namespace spinlock
{
template <class T>
class Queue : Lockable<SpinLock>
{
public:
template <class... Args>
void emplace(Args&&... args)
{
auto guard = acquire();
queue.emplace(args...);
}
void push(const T& item)
{
auto guard = acquire();
queue.push(item);
}
T front()
{
auto guard = acquire();
return queue.front();
}
void pop()
{
auto guard = acquire();
queue.pop();
}
bool pop(T& item)
{
auto guard = acquire();
if(queue.empty())
return false;
item = std::move(queue.front());
queue.pop();
return true;
}
bool empty()
{
auto guard = acquire();
return queue.empty();
}
size_t size()
{
auto guard = acquire();
return queue.size();
}
private:
std::queue<T> queue;
};
}
#endif

View File

@ -3,6 +3,7 @@
#include "utils/random/xorshift.hpp"
template <class randomizer_t>
size_t new_height(int max_height)
{
// get 64 random bits (coin tosses)

View File

@ -3,10 +3,38 @@
#include <list>
template <class T,
class allocator=std::allocator<T>>
class SafeList
#include "sync/spinlock.hpp"
#include "sync/lockable.hpp"
template <class T>
class SpinLockedList : Lockable<SpinLock>
{
public:
void push_front(T item)
{
auto guard = this->acquire();
head = new Node(item, head);
}
bool remove(const T&)
{
// HM!
}
private:
struct Node : Lockable<SpinLock>
{
Node(T item, Node* next) : item(item), next(next) {}
T item;
Node* next;
};
Node* head;
// TODO add removed items to a list for garbage collection
// std::list<Node*> removed;
};
#endif

55
main.cpp Normal file
View File

@ -0,0 +1,55 @@
#include <iostream>
#include <thread>
#include "sync/spinlock.hpp"
#include "transaction/transaction_engine.hpp"
#include "memory/memory_engine.hpp"
#include "storage/storage_engine.hpp"
constexpr int K = 10000000;
constexpr int N = 64;
void insert(TransactionEngine* tx, StorageEngine* storage)
{
for(int i = 0; i < (K / N); ++i)
{
auto t = tx->begin();
Vertex* v;
storage->insert(&v, t);
tx->commit(t);
}
}
int main(void)
{
auto tx = new TransactionEngine(0);
auto mem = new MemoryEngine();
auto storage = new StorageEngine(*mem);
// auto t1 = tx->begin();
//
// Vertex* v1 = nullptr;
// storage->insert(&v1, t1);
//
// tx->commit(t1);
//
// auto t2 = tx->begin();
//
// Vertex* v2 = nullptr;
// storage->insert(&v2, t2);
//
// tx->commit(t2);
std::vector<std::thread> threads;
for(int i = 0; i < N; ++i)
threads.push_back(std::thread(insert, tx, storage));
for(auto& thread : threads)
thread.join();
return 0;
}

17
server/http/http.hpp Normal file
View File

@ -0,0 +1,17 @@
#include "httpconnection.hpp"
#include "method.hpp"
#include "httpparser.hpp"
#include "httpparsersettings.hpp"
#include "httpserver.hpp"
#include "version.hpp"
#include "ipv4.hpp"
#include "request.hpp"
#include "response.hpp"
#include "status_codes.hpp"
#include "httpconnection.inl"
#include "httpparser.inl"
#include "httpparsersettings.inl"
#include "httpserver.inl"
#include "ipv4.inl"
#include "response.inl"

View File

@ -0,0 +1,19 @@
#ifndef MEMGRAPH_SERVER_HTTP_HTTP_ERROR_HPP
#define MEMGRAPH_SERVER_HTTP_HTTP_ERROR_HPP
#include <stdexcept>
#include <string>
namespace http
{
class HttpError : public std::runtime_error
{
public:
HttpError(const std::string& message)
: std::runtime_error(message) {}
};
}
#endif

View File

@ -0,0 +1,35 @@
#ifndef MEMGRAPH_SERVER_HTTP_CONNECTION_HPP
#define MEMGRAPH_SERVER_HTTP_CONNECTION_HPP
#include "server/uv/uv.hpp"
#include "httpparser.hpp"
#include "request.hpp"
#include "response.hpp"
namespace http
{
class HttpServer;
class HttpConnection
{
public:
HttpConnection(uv::UvLoop& loop, HttpServer& server);
void close();
HttpServer& server;
uv::TcpStream client;
HttpParser parser;
Request request;
Response response;
bool keep_alive;
};
}
#endif

View File

@ -0,0 +1,27 @@
#ifndef MEMGRAPH_SERVER_HTTP_CONNECTION_INL
#define MEMGRAPH_SERVER_HTTP_CONNECTION_INL
#include <uv.h>
#include "httpconnection.hpp"
namespace http
{
HttpConnection::HttpConnection(uv::UvLoop& loop, HttpServer& server)
: server(server), client(loop), response(*this)
{
client.data(this);
parser.data(this);
}
void HttpConnection::close()
{
client.close([](uv_handle_t* client) -> void {
delete reinterpret_cast<HttpConnection*>(client->data);
});
}
}
#endif

View File

@ -0,0 +1,66 @@
#ifndef MEMGRAPH_SERVER_HTTP_HTTPPARSER_HPP
#define MEMGRAPH_SERVER_HTTP_HTTPPARSER_HPP
#include <iostream>
#include <cstdlib>
#include <http_parser.h>
namespace http
{
class HttpParserSettings;
class HttpParser
{
friend class HttpParserSettings;
public:
HttpParser();
static void init();
size_t execute(HttpParserSettings& settings,
const char* data,
size_t size);
template <typename T>
T* data();
template <typename T>
void data(T* value);
private:
http_parser parser;
std::string last_field;
static int on_message_begin(http_parser* parser);
static int on_url(http_parser* parser,
const char* at,
size_t length);
static int on_status_complete(http_parser* parser,
const char* at,
size_t length);
static int on_header_field(http_parser* parser,
const char* at,
size_t length);
static int on_header_value(http_parser* parser,
const char* at,
size_t length);
static int on_headers_complete(http_parser* parser);
static int on_body(http_parser* parser,
const char* at,
size_t length);
static int on_message_complete(http_parser* parser);
};
}
#endif

110
server/http/httpparser.inl Normal file
View File

@ -0,0 +1,110 @@
#ifndef MEMGRAPH_SERVER_HTTP_HTTPSERVER_INL
#define MEMGRAPH_SERVER_HTTP_HTTPSERVER_INL
#include "httpparser.hpp"
#include "httpserver.hpp"
#include "httpconnection.hpp"
#include "httpparsersettings.hpp"
namespace http
{
HttpParser::HttpParser()
{
http_parser_init(&parser, HTTP_REQUEST);
}
size_t HttpParser::execute(HttpParserSettings& settings,
const char* data,
size_t size)
{
return http_parser_execute(&parser, settings, data, size);
}
template <typename T>
T* HttpParser::data()
{
return reinterpret_cast<T*>(parser.data);
}
template <typename T>
void HttpParser::data(T* value)
{
parser.data = reinterpret_cast<void*>(value);
}
int HttpParser::on_message_begin(http_parser*)
{
return 0;
}
int HttpParser::on_url(http_parser* parser,
const char* at,
size_t length)
{
HttpConnection& conn = *reinterpret_cast<HttpConnection*>(parser->data);
conn.request.url = std::string(at, length);
return 0;
}
int HttpParser::on_status_complete(http_parser*, const char*, size_t)
{
return 0;
}
int HttpParser::on_header_field(http_parser* parser,
const char* at,
size_t length)
{
HttpConnection& conn = *reinterpret_cast<HttpConnection*>(parser->data);
conn.parser.last_field = std::string(at, length);
return 0;
}
int HttpParser::on_header_value(http_parser* parser,
const char* at,
size_t length)
{
HttpConnection& conn = *reinterpret_cast<HttpConnection*>(parser->data);
conn.request.headers[conn.parser.last_field] = std::string(at, length);
return 0;
}
int HttpParser::on_headers_complete(http_parser* parser)
{
HttpConnection& conn = *reinterpret_cast<HttpConnection*>(parser->data);
conn.request.version.major = parser->http_major;
conn.request.version.minor = parser->http_minor;
conn.request.method = static_cast<Method>(parser->method);
conn.keep_alive = http_should_keep_alive(parser) == true;
return 0;
}
int HttpParser::on_body(http_parser* parser, const char* at, size_t length)
{
if(length == 0)
return 0;
HttpConnection& conn = *reinterpret_cast<HttpConnection*>(parser->data);
conn.request.body.append(at, length);
return 0;
}
int HttpParser::on_message_complete(http_parser* parser)
{
HttpConnection& conn = *reinterpret_cast<HttpConnection*>(parser->data);
conn.server.respond(conn);
return 0;
}
}
#endif

View File

@ -0,0 +1,22 @@
#ifndef MEMGRAPH_SERVER_HTTP_HTTPPARSERSETTINGS_HPP
#define MEMGRAPH_SERVER_HTTP_HTTPPARSERSETTINGS_HPP
#include <http_parser.h>
namespace http
{
class HttpParserSettings
{
public:
HttpParserSettings();
operator http_parser_settings*();
private:
http_parser_settings settings;
};
}
#endif

View File

@ -0,0 +1,29 @@
#ifndef MEMGRAPH_SERVER_HTTP_HTTPPARSERSETTINGS_INL
#define MEMGRAPH_SERVER_HTTP_HTTPPARSERSETTINGS_INL
#include "httpparsersettings.hpp"
#include "httpparser.hpp"
namespace http
{
HttpParserSettings::HttpParserSettings()
{
settings.on_header_field = HttpParser::on_header_field;
settings.on_header_value = HttpParser::on_header_value;
settings.on_headers_complete = HttpParser::on_headers_complete;
settings.on_body = HttpParser::on_body;
settings.on_status = HttpParser::on_status_complete;
settings.on_message_begin = HttpParser::on_message_begin;
settings.on_message_complete = HttpParser::on_message_complete;
settings.on_url = HttpParser::on_url;
}
HttpParserSettings::operator http_parser_settings*()
{
return &settings;
}
}
#endif

View File

@ -0,0 +1,51 @@
#ifndef MEMGRAPH_SERVER_HTTP_HTTPSERVER_HPP
#define MEMGRAPH_SERVER_HTTP_HTTPSERVER_HPP
#include <iostream>
#include <uv.h>
#include "server/uv/uv.hpp"
#include "httpparsersettings.hpp"
#include "httpconnection.hpp"
#include "request.hpp"
#include "response.hpp"
#include "ipv4.hpp"
namespace http
{
typedef std::function<void(Request&, Response&)> request_cb_t;
class HttpServer
{
friend class HttpParser;
public:
HttpServer(uv::UvLoop& loop);
void listen(const Ipv4& ip, request_cb_t callback);
operator uv_tcp_t*();
operator uv_stream_t*();
private:
uv::UvLoop& loop;
uv::TcpStream stream;
HttpParserSettings settings;
request_cb_t request_cb;
static void on_connect(uv_stream_t* tcp_server, int status);
static void on_read(uv_stream_t* tcp_client,
ssize_t nread,
const uv_buf_t* buf);
static void on_alloc(uv_handle_t* tcp_client,
size_t suggested_size,
uv_buf_t* buf);
static void respond(HttpConnection& conn);
};
}
#endif

View File

@ -0,0 +1,72 @@
#ifndef UVMACHINE_HTTP_HTTPSERVER_INL
#define UVMACHINE_HTTP_HTTPSERVER_INL
#include "httpserver.hpp"
namespace http
{
HttpServer::HttpServer(uv::UvLoop& loop)
: loop(loop), stream(loop) {}
void HttpServer::listen(const Ipv4& ip, request_cb_t callback)
{
request_cb = callback;
stream.data(this);
uv_tcp_bind(stream, ip, 0);
uv_listen(stream, 128, HttpServer::on_connect);
}
HttpServer::operator uv_tcp_t*()
{
return stream;
}
HttpServer::operator uv_stream_t*()
{
return stream;
}
void HttpServer::on_connect(uv_stream_t* tcp_server, int)
{
HttpServer& server = *reinterpret_cast<HttpServer*>(tcp_server->data);
auto connection = new HttpConnection(server.loop, server);
uv_accept(server, connection->client);
uv_read_start(connection->client,
HttpServer::on_alloc,
HttpServer::on_read);
}
void HttpServer::on_alloc(uv_handle_t*, size_t suggested_size, uv_buf_t* buf)
{
buf->base = static_cast<char*>(malloc(sizeof(char) * suggested_size));
buf->len = suggested_size;
}
void HttpServer::on_read(uv_stream_t* tcp_client,
ssize_t nread,
const uv_buf_t* buf)
{
HttpConnection& conn =
*reinterpret_cast<HttpConnection*>(tcp_client->data);
if(nread >= 0)
conn.parser.execute(conn.server.settings, buf->base, nread);
else
conn.close();
delete buf->base;
}
void HttpServer::respond(HttpConnection& conn)
{
conn.server.request_cb(conn.request, conn.response);
}
}
#endif

33
server/http/ipv4.hpp Normal file
View File

@ -0,0 +1,33 @@
#ifndef MEMGRAPH_SERVER_HTTP_IPV4_HPP
#define MEMGRAPH_SERVER_HTTP_IPV4_HPP
#include <string>
#include <ostream>
#include <uv.h>
namespace http
{
class Ipv4
{
public:
Ipv4(const std::string& address, uint16_t port);
operator const sockaddr_in&() const;
operator const sockaddr*() const;
friend std::ostream& operator<< (std::ostream& stream, const Ipv4& ip) {
return stream << ip.address << ':' << ip.port;
}
protected:
sockaddr_in socket_address;
const std::string& address;
uint16_t port;
};
}
#endif

32
server/http/ipv4.inl Normal file
View File

@ -0,0 +1,32 @@
#ifndef MEMGRAPH_SERVER_HTTP_IPV4_INL
#define MEMGRAPH_SERVER_HTTP_IPV4_INL
#include "ipv4.hpp"
#include "http_error.hpp"
namespace http
{
Ipv4::Ipv4(const std::string& address, uint16_t port)
: address(address), port(port)
{
auto status = uv_ip4_addr(address.c_str(), port, &socket_address);
if(status != 0)
throw HttpError("Not a valid IP address/port (" + address + ":"
+ std::to_string(port) + ")");
}
Ipv4::operator const sockaddr_in&() const
{
return socket_address;
}
Ipv4::operator const sockaddr*() const
{
return (const struct sockaddr*)&socket_address;
}
}
#endif

20
server/http/method.hpp Normal file
View File

@ -0,0 +1,20 @@
#ifndef MEMGRAPH_SERVER_HTTP_METHOD_HPP
#define MEMGRAPH_SERVER_HTTP_METHOD_HPP
#include <http_parser.h>
namespace http
{
enum Method
{
GET = HTTP_GET,
HEAD = HTTP_HEAD,
POST = HTTP_POST,
PUT = HTTP_PUT,
DELETE = HTTP_DELETE,
};
}
#endif

25
server/http/request.hpp Normal file
View File

@ -0,0 +1,25 @@
#ifndef UVMACHINE_HTTP_REQUEST_HPP
#define UVMACHINE_HTTP_REQUEST_HPP
#include <string>
#include <map>
#include "version.hpp"
#include "method.hpp"
namespace http
{
struct Request
{
Version version;
Method method;
std::string url;
std::map<std::string, std::string> headers;
std::string body;
};
}
#endif

35
server/http/response.hpp Normal file
View File

@ -0,0 +1,35 @@
#ifndef MEMGRAPH_SERVER_HTTP_RESPONSE_HPP
#define MEMGRAPH_SERVER_HTTP_RESPONSE_HPP
#include <map>
#include "server/uv/uv.hpp"
#include "status_codes.hpp"
namespace http
{
class HttpConnection;
class Response
{
public:
Response(HttpConnection& connection);
void send(const std::string& body);
void send(Status code, const std::string& body);
Response& status(Status code);
std::map<std::string, std::string> headers;
private:
HttpConnection& connection;
uv::UvBuffer buffer;
Status code;
};
}
#endif

62
server/http/response.inl Normal file
View File

@ -0,0 +1,62 @@
#ifndef MEMGRAPH_SERVER_HTTP_RESPONSE_INL
#define MEMGRAPH_SERVER_HTTP_RESPONSE_INL
#include "response.hpp"
#include "httpconnection.hpp"
namespace http
{
Response::Response(HttpConnection& connection)
: connection(connection), buffer(65536), code(Status::Ok) {}
void Response::send(Status code, const std::string& body)
{
this->status(code).send(body);
}
void Response::send(const std::string& body)
{
uv_write_t* write_req =
static_cast<uv_write_t*>(malloc(sizeof(uv_write_t)));
write_req->data = &connection;
// set the appropriate content length
headers["Content-Length"] = std::to_string(body.size());
// set the appropriate connection type
headers["Connection"] = connection.keep_alive ? "Keep-Alive" : "Close";
buffer << "HTTP/1.1 " << to_string[code] << "\r\n";
for(auto it = headers.begin(); it != headers.end(); ++it)
buffer << it->first << ":" << it->second << "\r\n";
buffer << "\r\n" << body;
uv_write(write_req, connection.client, buffer, 1,
[](uv_write_t* write_req, int) {
HttpConnection& conn =
*reinterpret_cast<HttpConnection*>(write_req->data);
if(!conn.keep_alive)
conn.close();
conn.response.code = Status::Ok;
conn.response.buffer.clear();
conn.response.headers.clear();
std::free(write_req);
});
}
Response& Response::status(Status code)
{
this->code = code;
return *this;
}
}
#endif

View File

@ -0,0 +1,83 @@
#ifndef MEMGRAPH_SERVER_HTTP_STATUS_CODES_HPP
#define MEMGRAPH_SERVER_HTTP_STATUS_CODES_HPP
#include <map>
#include <string>
namespace http
{
#define HTTP_STATUS_CODES \
CODE(Continue, 100, CONTINUE) \
CODE(SwitchingProtocols, 101, SWITCHING PROTOCOLS) \
CODE(Processing, 102, PROCESSING) \
CODE(Ok, 200, OK) \
CODE(Created, 201, CREATED) \
CODE(Accepted, 202, ACCEPTED) \
CODE(NonAuthoritativeInformation, 203, NON AUTHORITATIVE INFORMATION) \
CODE(NoContent, 204, NO CONTENT) \
CODE(ResetContent, 205, RESET CONTENT) \
CODE(PartialContent, 206, PARTIAL CONTENT) \
CODE(MultiStatus, 207, MULTI STATUS) \
CODE(MultipleChoices, 300, MULTIPLE CHOICES) \
CODE(MovedPermanently, 301, MOVED PERMANENTLY) \
CODE(MovedTemporarily, 302, MOVED TEMPORARILY) \
CODE(SeeOther, 303, SEE OTHER) \
CODE(NotModified, 304, NOT MODIFIED) \
CODE(UseProxy, 305, USE PROXY) \
CODE(TemporaryRedirect, 307, TEMPORARY REDIRECT) \
CODE(BadRequest, 400, BAD REQUEST) \
CODE(Unauthorized, 401, UNAUTHORIZED) \
CODE(PaymentRequired, 402, PAYMENT REQUIRED) \
CODE(Forbidden, 403, FORBIDDEN) \
CODE(NotFound, 404, NOT FOUND) \
CODE(MethodNotAllowed, 405, METHOD NOT ALLOWED) \
CODE(NotAcceptable, 406, NOT ACCEPTABLE) \
CODE(ProxyAuthenticationRequired, 407, PROXY AUTHENTICATION REQUIRED) \
CODE(RequestTimeOut, 408, REQUEST TIMEOUT) \
CODE(Conflict, 409, CONFLICT) \
CODE(Gone, 410, GONE) \
CODE(LengthRequired, 411, LENGTH REQUIRED) \
CODE(PreconditionFailed, 412, PRECONDITION FAILED) \
CODE(RequestEntityTooLarge, 413, REQUEST ENTITY TOO LARGE) \
CODE(RequestUriTooLarge, 414, REQUEST URI TOO LARGE) \
CODE(UnsupportedMediaType, 415, UNSUPPORTED MEDIA TYPE) \
CODE(RequestedRangeNotSatisfiable, 416, REQUESTED RANGE NOT SATISFIABLE) \
CODE(ExpectationFailed, 417, EXPECTATION FAILED) \
CODE(ImATeapot, 418, IM A TEAPOT) \
CODE(UnprocessableEntity, 422, UNPROCESSABLE ENTITY) \
CODE(Locked, 423, LOCKED) \
CODE(FailedDependency, 424, FAILED DEPENDENCY) \
CODE(UnorderedCollection, 425, UNORDERED COLLECTION) \
CODE(UpgradeRequired, 426, UPGRADE REQUIRED) \
CODE(PreconditionRequired, 428, PRECONDITION REQUIRED) \
CODE(TooManyRequests, 429, TOO MANY REQUESTS) \
CODE(RequestHeaderFieldsTooLarge, 431, REQUEST HEADER FIELDS TOO LARGE) \
CODE(InternalServerError, 500, INTERNAL SERVER ERROR) \
CODE(NotImplemented, 501, NOT IMPLEMENTED) \
CODE(BadGateway, 502, BAD GATEWAY) \
CODE(ServiceUnavailable, 503, SERVICE UNAVAILABLE) \
CODE(GatewayTimeOut, 504, GATEWAY TIME OUT) \
CODE(HttpVersionNotSupported, 505, HTTP VERSION NOT SUPPORTED) \
CODE(VariantAlsoNegotiates, 506, VARIANT ALSO NEGOTIATES) \
CODE(InsufficientStorage, 507, INSUFFICIENT STORAGE) \
CODE(BandwidthLimitExceeded, 508, BANDWIDTH LIMIT EXCEEDED) \
CODE(NotExtended, 510, NOT EXTENDED) \
CODE(NetworkAuthenticationRequired, 511, NETWORK AUTHENTICATION REQUIRED)
enum Status
{
#define CODE(a, b, c) a = b,
HTTP_STATUS_CODES
#undef CODE
};
static std::map<Status, std::string> to_string = {
#define CODE(a, b, c) { Status::a, #b " " #c },
HTTP_STATUS_CODES
#undef CODE
};
}
#endif

15
server/http/version.hpp Normal file
View File

@ -0,0 +1,15 @@
#ifndef UVMACHINE_HTTP_HTTPVERSION_HPP
#define UVMACHINE_HTTP_HTTPVERSION_HPP
namespace http
{
struct Version
{
unsigned short major;
unsigned short minor;
};
}
#endif

19
server/test.cpp Normal file
View File

@ -0,0 +1,19 @@
#include <iostream>
#include "uvmachine.hpp"
int main(void)
{
uv::UvLoop loop;
http::HttpServer server(loop);
http::Ipv4 ip("0.0.0.0", 3400);
server.listen(ip, [](http::Request& req, http::Response& res) {
res.send(req.url);
});
loop.run(uv::UvLoop::Mode::Default);
return 0;
}

13
server/uv/core.hpp Normal file
View File

@ -0,0 +1,13 @@
#ifndef MEMGRAPH_SERVER_UV_CORE_HPP
#define MEMGRAPH_SERVER_UV_CORE_HPP
#include <uv.h>
namespace uv
{
using callback_t = void (*)(uv_handle_t *);
}
#endif

35
server/uv/tcpstream.hpp Normal file
View File

@ -0,0 +1,35 @@
#ifndef MEMGRAPH_SERVER_UV_TCPSTREAM_HPP
#define MEMGRAPH_SERVER_UV_TCPSTREAM_HPP
#include <uv.h>
#include "core.hpp"
#include "uvloop.hpp"
namespace uv
{
class TcpStream
{
public:
TcpStream(UvLoop& loop);
template <typename T>
T* data();
template <typename T>
void data(T* value);
void close(callback_t callback);
operator uv_handle_t*();
operator uv_tcp_t*();
operator uv_stream_t*();
private:
uv_tcp_t stream;
};
}
#endif

48
server/uv/tcpstream.inl Normal file
View File

@ -0,0 +1,48 @@
#ifndef MEMGRAPH_SERVER_UV_TCPSTREAM_INL
#define MEMGRAPH_SERVER_UV_TCPSTREAM_INL
#include "tcpstream.hpp"
namespace uv
{
TcpStream::TcpStream(UvLoop& loop)
{
uv_tcp_init(loop, &stream);
}
template <typename T>
T* TcpStream::data()
{
return reinterpret_cast<T*>(stream.data);
}
template <typename T>
void TcpStream::data(T* value)
{
stream.data = reinterpret_cast<void*>(value);
}
void TcpStream::close(callback_t callback)
{
uv_close(reinterpret_cast<uv_handle_t*>(&stream), callback);
}
TcpStream::operator uv_tcp_t*()
{
return &stream;
}
TcpStream::operator uv_stream_t*()
{
return reinterpret_cast<uv_stream_t*>(&stream);
}
TcpStream::operator uv_handle_t*()
{
return reinterpret_cast<uv_handle_t*>(&stream);
}
}
#endif

6
server/uv/uv.hpp Normal file
View File

@ -0,0 +1,6 @@
#include "tcpstream.hpp"
#include "uvbuffer.hpp"
#include "uvloop.hpp"
#include "tcpstream.inl"
#include "uvbuffer.inl"

19
server/uv/uv_error.hpp Normal file
View File

@ -0,0 +1,19 @@
#ifndef MEMGRAPH_SERVER_UV_UV_ERROR_HPP
#define MEMGRAPH_SERVER_UV_UV_ERROR_HPP
#include <stdexcept>
#include <string>
namespace uv
{
class UvError : public std::runtime_error
{
public:
UvError(const std::string& message)
: std::runtime_error(message) {}
};
}
#endif

38
server/uv/uvbuffer.hpp Normal file
View File

@ -0,0 +1,38 @@
#ifndef MEMGRAPH_SERVER_UV_UVBUFFER_HPP
#define MEMGRAPH_SERVER_UV_UVBUFFER_HPP
#include <string>
#include <uv.h>
namespace uv
{
class UvBuffer
{
public:
UvBuffer();
UvBuffer(size_t capacity);
UvBuffer(const std::string& data);
~UvBuffer();
size_t size() const noexcept;
size_t length() const noexcept;
void clear();
UvBuffer& append(const std::string& data);
UvBuffer& append(const char* data, size_t n);
UvBuffer& operator<<(const std::string& data);
operator uv_buf_t*();
private:
uv_buf_t buffer;
size_t capacity;
};
}
#endif

91
server/uv/uvbuffer.inl Normal file
View File

@ -0,0 +1,91 @@
#ifndef MEMGRAPH_SERVER_UV_UVBUFFER_INL
#define MEMGRAPH_SERVER_UV_UVBUFFER_INL
#include <cstdlib>
#include <cstring>
#include "uvbuffer.hpp"
namespace uv
{
UvBuffer::UvBuffer()
: capacity(0)
{
buffer.len = 0;
buffer.base = nullptr;
}
UvBuffer::UvBuffer(size_t capacity)
: capacity(capacity)
{
buffer.len = 0;
buffer.base = static_cast<char*>(malloc(capacity));
}
UvBuffer::UvBuffer(const std::string& data)
: capacity(data.size())
{
buffer.len = data.size();
buffer.base = static_cast<char*>(malloc(capacity));
std::memcpy(buffer.base, data.c_str(), buffer.len);
}
UvBuffer::~UvBuffer()
{
if(buffer.base == nullptr)
return;
free(buffer.base);
}
size_t UvBuffer::size() const noexcept
{
return buffer.len;
}
size_t UvBuffer::length() const noexcept
{
return this->size();
}
void UvBuffer::clear()
{
buffer.len = 0;
}
UvBuffer& UvBuffer::append(const std::string& data)
{
return this->append(data.c_str(), data.size());
}
UvBuffer& UvBuffer::append(const char* data, size_t n)
{
auto new_size = size() + n;
if(capacity < new_size)
{
capacity = new_size;
buffer.base = static_cast<char*>(realloc(buffer.base, new_size));
}
std::memcpy(buffer.base + size(), data, n);
buffer.len = new_size;
return *this;
}
UvBuffer& UvBuffer::operator<<(const std::string& data)
{
return this->append(data);
}
UvBuffer::operator uv_buf_t*()
{
return &buffer;
}
}
#endif

60
server/uv/uvloop.hpp Normal file
View File

@ -0,0 +1,60 @@
#ifndef MEMGRAPH_SERVER_UV_UVLOOP_HPP
#define MEMGRAPH_SERVER_UV_UVLOOP_HPP
#include <memory>
#include <uv.h>
#include "uv_error.hpp"
namespace uv
{
class UvLoop final
{
public:
enum Mode {
Default = UV_RUN_DEFAULT,
Once = UV_RUN_ONCE,
NoWait = UV_RUN_NOWAIT
};
UvLoop()
{
uv_loop = uv_default_loop();
if(uv_loop == nullptr)
throw UvError("Failed to initialize libuv event loop");
}
~UvLoop()
{
uv_loop_close(uv_loop);
}
bool run(Mode mode)
{
return uv_run(uv_loop, static_cast<uv_run_mode>(mode));
}
bool alive()
{
return uv_loop_alive(uv_loop);
}
void stop()
{
uv_stop(uv_loop);
}
operator uv_loop_t*()
{
return uv_loop;
}
private:
uv_loop_t* uv_loop;
};
}
#endif

2
server/uvmachine.hpp Normal file
View File

@ -0,0 +1,2 @@
#include "uv/uv.hpp"
#include "http/http.hpp"

View File

@ -7,11 +7,11 @@
struct Vertex;
struct
struct Edge : public Record<Edge>
{
Edge(uint64_t id) : Record<Edge>(id) {}
// pointer to the vertex this edge points to
Vertex* from;
Vertex* to;
};

View File

@ -0,0 +1,51 @@
#ifndef MEMGRAPH_STORAGE_MODEL_PROPERTIES_PROPERTIES_HPP
#define MEMGRAPH_STORAGE_MODEL_PROPERTIES_PROPERTIES_HPP
#include <map>
#include "property.hpp"
class Properties
{
using props_t = std::map<std::string, Property::sptr>;
public:
props_t::iterator find(const std::string& key)
{
return props.find(key);
}
Property* at(const std::string& key)
{
return props.at(key).get();
}
void put(const std::string& key, Property::sptr value)
{
props[key] = std::move(value);
}
void clear(const std::string& key)
{
props.erase(key);
}
void dump(std::string& buffer)
{
buffer += '{';
for(auto& kvp : props)
{
buffer += '"'; buffer += kvp.first; buffer += "\":";
kvp.second->dump(buffer); buffer += ',';
}
buffer.pop_back(); // erase last comma
buffer += '}';
}
private:
props_t props;
};
#endif

View File

@ -0,0 +1,30 @@
#ifndef MEMGRAPH_STORAGE_MODEL_PROPERTIES_PROPERTY_HPP
#define MEMGRAPH_STORAGE_MODEL_PROPERTIES_PROPERTY_HPP
#include <memory>
#include <string>
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() {}
virtual void dump(std::string& buffer) = 0;
};
template <class T>
class Value : public Property
{
public:
Value(T value) : value(value) {}
T value;
};
#endif

View File

@ -0,0 +1,17 @@
#ifndef MEMGRAPH_STORAGE_MODEL_PROPERTIES_STRING_HPP
#define MEMGRAPH_STORAGE_MODEL_PROPERTIES_STRING_HPP
#include "property.hpp"
class String : public Value<std::string>
{
public:
using Value::Value;
virtual void dump(std::string& buffer)
{
buffer += '"'; buffer += value; buffer += '"';
}
};
#endif

View File

@ -10,6 +10,8 @@
#include "storage/model/utils/mvcc.hpp"
#include "properties/properties.hpp"
template <class Derived>
class Record
: public Crtp<Derived>,
@ -17,15 +19,7 @@ class Record
Lockable<SpinLock>
{
public:
Record(uint64_t id) : id(id) {}
// 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.
uint64_t id;
private:
// TODO add real data here
Properties props;
};
#endif

19
storage/model/root.hpp Normal file
View File

@ -0,0 +1,19 @@
#ifndef MEMGRAPH_STORAGE_MODEL_ROOT_HPP
#define MEMGRAPH_STORAGE_MODEL_ROOT_HPP
#include "utils/version.hpp"
template <class T>
class Root : public Version<T>
{
public:
Root(uint64_t id, T* first)
: Version<T>(first), id(id) {}
// every record 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.
uint64_t id;
};
#endif

View File

@ -8,9 +8,7 @@
struct Vertex : public Record<Vertex>
{
Vertex(uint64_t id) : Record<Vertex>(id) {}
// adjacency list containing pointers to outgoing edges from this vertex
std::vector<Edge*> in;
std::vector<Edge*> out;
};

View File

@ -6,7 +6,6 @@
#include "transaction/transaction.hpp"
#include "storage/model/record.hpp"
#include "storage/visible.hpp"
#include "memory/memory_engine.hpp"
#include "utils/counters/atomic_counter.hpp"

109
threading/pool.hpp Normal file
View File

@ -0,0 +1,109 @@
#ifndef MEMGRAPH_THREADING_POOL_HPP
#define MEMGRAPH_THREADING_POOL_HPP
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <future>
#include "data_structures/queue/slqueue.hpp"
#include "threading/sync/lockable.hpp"
#include "worker.hpp"
#include "data_structures/queue/slqueue.hpp"
class Pool : Lockable<std::mutex>
{
using task_t = std::function<void()>;
public:
Pool(size_t n = std::thread::hardware_concurrency())
: alive(true)
{
start(n);
}
~Pool()
{
alive.store(false, std::memory_order_release);
cond.notify_all();
for(auto& worker : workers)
worker.join();
}
size_t size()
{
return workers.size();
}
template <class F, class... Args>
void execute(F&& f, Args&&... args)
{
{
auto guard = acquire();
tasks.emplace([f, args...]() { f(args...); });
}
cond.notify_one();
}
template <class F, class... Args>
auto execute_with_result(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using ret_t = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared<std::packaged_task<ret_t()>>
(std::bind(f, args...));
auto result = task->get_future();
{
auto guard = acquire();
tasks.emplace([task]() { (*task)(); });
}
cond.notify_one();
return result;
}
private:
Pool(const Pool&) = delete;
Pool(Pool&&) = delete;
std::vector<Worker<task_t>> workers;
spinlock::Queue<task_t> tasks;
std::atomic<bool> alive;
std::mutex mutex;
std::condition_variable cond;
void loop()
{
task_t task;
while(true)
{
while(tasks.pop(task))
task();
auto guard = acquire();
cond.wait(guard, [this] {
return !this->alive || !this->tasks.empty();
});
if(!alive && tasks.empty())
return;
}
}
void start(size_t n)
{
for(size_t i = 0; i < n; ++i)
workers.emplace_back([this]()->void { this->loop(); });
}
};
#endif

12
threading/task.hpp Normal file
View File

@ -0,0 +1,12 @@
#ifndef MEMGRAPH_THREADING_TASK_HPP
#define MEMGRAPH_THREADING_TASK_HPP
class Task
{
public:
private:
//std::function<
};
#endif

BIN
threading/test Executable file

Binary file not shown.

20
threading/test.cpp Normal file
View File

@ -0,0 +1,20 @@
#include <iostream>
#include "pool.hpp"
int main(void)
{
std::cout << "hardware_concurrency " << std::thread::hardware_concurrency() << std::endl;
auto size = 2048;
auto N = 1000000;
Pool pool(size);
for(int i = 0; i < N; ++i)
pool.execute([size](int) {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}, i);
return 0;
}

22
threading/worker.hpp Normal file
View File

@ -0,0 +1,22 @@
#ifndef MEMGRAPH_THREADING_WORKER_HPP
#define MEMGRAPH_THREADING_WORKER_HPP
#include <thread>
template <class F, class... Args>
class Worker
{
public:
Worker(F&& f, Args&&... args)
: thread(f, args...) {}
void join()
{
thread.join();
}
private:
std::thread thread;
};
#endif

View File

@ -5,10 +5,8 @@
// curiously recurring template pattern
template <class Derived>
class Crtp
struct Crtp
{
public:
Derived& derived()
{
return *static_cast<Derived*>(this);

View File

@ -0,0 +1,11 @@
#ifndef MEMGRAPH_UTILS_VISITOR_VISITABLE_HPP
#define MEMGRAPH_UTILS_VISITOR_VISITABLE_HPP
template <class T>
struct Visitable
{
virtual ~Visitable() {}
virtual void accept(T& visitor) = 0;
};
#endif

47
utils/visitor/visitor.hpp Normal file
View File

@ -0,0 +1,47 @@
#ifndef MEMGRAPH_UTILS_VISITOR_VISITOR_HPP
#define MEMGRAPH_UTILS_VISITOR_VISITOR_HPP
namespace detail
{
template <typename T>
struct VisitorBase {
virtual ~VisitorBase() {}
virtual void visit(T&) {}
virtual void post_visit(T&) {}
};
template<typename... T>
struct RecursiveVisitorBase;
template <typename Head, typename... Tail>
struct RecursiveVisitorBase<Head, Tail...>
: VisitorBase<Head>, RecursiveVisitorBase<Tail...>
{
using VisitorBase<Head>::visit;
using VisitorBase<Head>::post_visit;
using RecursiveVisitorBase<Tail...>::visit;
using RecursiveVisitorBase<Tail...>::post_visit;
};
template<typename T>
struct RecursiveVisitorBase<T>
: public VisitorBase<T>
{
using VisitorBase<T>::visit;
using VisitorBase<T>::post_visit;
};
}
template <typename... T>
struct Visitor
: public detail::RecursiveVisitorBase<T...>
{
using detail::RecursiveVisitorBase<T...>::visit;
using detail::RecursiveVisitorBase<T...>::post_visit;
};
#endif