work in progress query_engine

This commit is contained in:
Marko Budiselic 2016-07-17 18:32:35 +01:00
parent 396f0d9c31
commit b1459a891b
16 changed files with 172 additions and 186 deletions

View File

@ -2,28 +2,41 @@
#include <string>
#include "exceptions/query_engine_exception.hpp"
#include "utils/string/join.hpp"
// TODO: all libraries have to be compiled in the server compile time
// TODO: generate copile command
// TODO:
// * all libraries have to be compiled in the server compile time
// * compile command has to be generated
#include <iostream>
class CodeCompiler
{
public:
void compile(const std::string &in_file, const std::string &out_file)
{
// generate compile command
auto compile_command =
utils::prints("clang++",
// "-std=c++1y -O2 -DNDEBUG", // compile flags
"-std=c++1y -DDEBUG", // compile flags
in_file, // input file
"-o", out_file, // ouput file
"-I./include", // include paths (TODO: parameter)
"-I./src",
"-I../../libs/fmt",
"-std=c++1y -DDEBUG", // compile flags
in_file, // input file
"-o", out_file, // ouput file
"-I./include", // include paths (TODO: parameter)
"-I./src", "-I../../libs/fmt",
"-shared -fPIC" // shared library flags
);
// synchronous call
system(compile_command.c_str());
auto compile_status = system(compile_command.c_str());
// if compilation has failed throw exception
if (compile_status == -1) {
throw QueryEngineException("Code compilation error");
}
// TODO: use logger
std::cout << fmt::format("SUCCESS: Query Code Compilation: {} -> {}",
in_file, out_file) << std::endl;
}
};

View File

@ -6,6 +6,11 @@
#include "template_engine/engine.hpp"
#include "traverser/code_traverser.hpp"
#include "utils/string/file.hpp"
#include "query_engine/exceptions/query_engine_exception.hpp"
// TODO:
// * logger
#include <iostream>
using std::string;
@ -19,10 +24,23 @@ public:
string template_path = CONFIG(config::TEMPLATE_CPU_CPP_PATH);
string template_file = utils::read_file(template_path.c_str());
// traversing
auto tree = compiler.syntax_tree(query);
// syntax tree generation
try {
tree = compiler.syntax_tree(query);
} catch (const std::exception &e) {
// TODO: extract more information
throw QueryEngineException("Syntax tree generation error");
}
code_traverser.reset();
tree.root->accept(code_traverser);
// code generation
try {
tree.root->accept(code_traverser);
} catch (const std::exception &e) {
// TODO: extract more information
throw QueryEngineException("Code generation error");
}
// save the code
string generated = template_engine.render(
@ -30,7 +48,8 @@ public:
{"stripped_hash", std::to_string(stripped_hash)},
{"query", query},
{"code", code_traverser.code}});
// TODO: ifndef
// TODO: use logger, ifndef
std::cout << generated << std::endl;
utils::write_file(generated, path);

View File

@ -1,23 +0,0 @@
#pragma once
#include <iostream>
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/traversers/jsonwriter.hpp"
using std::cout;
using std::endl;
void print_props(const Properties &properties)
{
StringBuffer buffer;
JsonWriter<StringBuffer> writer(buffer);
properties.accept(writer);
cout << buffer.str() << endl;
}
#ifdef DEBUG
#define PRINT_PROPS(_PROPS_) print_props(_PROPS_);
#else
#define PRINT_PROPS(_)
#endif

View File

@ -0,0 +1,8 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
class QueryEngineException : public BasicException
{
using BasicException::BasicException;
};

View File

@ -1,118 +0,0 @@
#include "database/db.hpp"
#include "query_engine/query_stripper.hpp"
#include "utils/hashing/fnv.hpp"
#include "storage/model/properties/all.hpp"
#include "query_engine/query_result.hpp"
#define DEBUG
#include "query_engine/debug.hpp"
using std::cout;
using std::endl;
int main()
{
Db db;
std::vector<std::string> queries = {{
std::string("CREATE (n{id:3}) RETURN n"),
std::string("MATCH (n{id:3}) RETURN n"),
std::string("MATCH (n{id:3}) SET n.prop = \"\" RETURN n"),
std::string("MATCH (n{id:3}) DELETE n"),
std::string("MATCH (n{id:3}),(m{id:2}) CREATE (n)-[r:test]->(m) RETURN r"),
std::string("MATCH (n{id:3})-[r]->(m) RETURN count(r)")
}};
auto stripper = make_query_stripper(TK_INT, TK_FLOAT, TK_STR, TK_BOOL);
for(auto query : queries) {
auto strip = stripper.strip(query).query;
auto hash = std::to_string(fnv(strip));
cout << "QUERY: " << query <<
" STRIP: " << strip <<
" HASH: " << hash << endl;
}
auto create_node = [&db](uint64_t id) {
auto& t = db.tx_engine.begin();
auto vertex_accessor = db.graph.vertices.insert(t);
vertex_accessor.property<Int64>(
"id", Int64(id)
);
t.commit();
return vertex_accessor;
};
auto find_node = [&db](uint64_t id) {
auto& t = db.tx_engine.begin();
auto vertex_accessor = db.graph.vertices.find(t, id);
t.commit();
return vertex_accessor;
};
auto edit_node = [&db](uint64_t id, std::string prop) {
auto& t = db.tx_engine.begin();
auto vertex_accessor = db.graph.vertices.find(t, id);
if (!vertex_accessor) {
t.commit();
return vertex_accessor;
}
vertex_accessor.property<String>(
"prop", String(prop)
);
t.commit();
return vertex_accessor;
};
auto delete_node = [&db](uint64_t id) {
auto& t = db.tx_engine.begin();
auto vertex_accessor = db.graph.vertices.find(t, id);
if (!vertex_accessor)
return vertex_accessor;
vertex_accessor.remove(t);
t.commit();
return vertex_accessor;
};
auto create_edge = [&db](uint64_t id1, uint64_t id2, std::string type) {
auto& t = db.tx_engine.begin();
auto v1 = db.graph.vertices.find(t, id1);
if (!v1)
return Edge::Accessor();
auto v2 = db.graph.vertices.find(t, id2);
if (!v2)
return Edge::Accessor();
auto edge_accessor = db.graph.edges.insert(t);
v1.vlist->access(t).update()->data.out.add(edge_accessor.vlist);
v2.vlist->access(t).update()->data.in.add(edge_accessor.vlist);
edge_accessor.from(v1.vlist);
edge_accessor.to(v2.vlist);
edge_accessor.edge_type(EdgeType(type));
t.commit();
return edge_accessor;
};
auto vertex_out_degree = [&db](uint64_t id) {
auto& t = db.tx_engine.begin();
auto v = db.graph.vertices.find(t, id);
t.commit();
return v.out_degree();
};
auto created_node1 = create_node(100);
PRINT_PROPS(created_node1.properties());
auto created_node2 = create_node(200);
PRINT_PROPS(created_node2.properties());
auto found_node = find_node(0);
PRINT_PROPS(found_node.properties());
auto edited_node = edit_node(0, "test");
PRINT_PROPS(edited_node.properties());
// delete_node(0);
if (!find_node(0))
cout << "node doesn't exist" << endl;
auto edge_accessor = create_edge(0, 1, "test");
if (edge_accessor)
cout << edge_accessor.record->data.edge_type << endl;
cout << vertex_out_degree(0) << endl;
return 0;
}

View File

@ -3,9 +3,10 @@
#include <string>
#include "database/db.hpp"
#include "query_engine/debug.hpp"
#include "query_engine/util.hpp"
#include "query_program.hpp"
#include "utils/log/logger.hpp"
#include "query_engine/exceptions/query_engine_exception.hpp"
// preparations before execution
// execution
@ -16,9 +17,17 @@ class ProgramExecutor
public:
auto execute(QueryProgram &program)
{
return program.code->run(db, program.stripped.arguments);
try {
// TODO: return result of query/code exection
return program.code->run(db, program.stripped.arguments);
} catch (...) {
// TODO: return more information about the error
throw QueryEngineException("code execution error");
}
}
public:
// TODO: here shoud be one database from DBMS, not local instance of
// DB
Db db;
};

View File

@ -32,10 +32,10 @@ public:
auto load(const string &query)
{
auto stripped = stripper.strip(query);
LOG_INFO("stripped_query=" + stripped.query);
LOG_INFO("stripped_query = " + stripped.query);
auto hash_string = std::to_string(stripped.hash);
LOG_INFO("query_hash=" + hash_string);
LOG_INFO("query_hash = " + hash_string);
auto code_lib_iter = code_libs.find(stripped.hash);
@ -52,7 +52,6 @@ public:
auto path_cpp = base_path + hash_string + ".cpp";
code_generator.generate_cpp(query, stripped.hash, path_cpp);
// TODO compile generated code
auto path_so = base_path + hash_string + ".so";
code_compiler.compile(path_cpp, path_so);
@ -60,14 +59,14 @@ public:
auto code_lib = load_code_lib(path_so);
code_libs.insert({{stripped.hash, code_lib}});
// return instance of runnable code (ICodeCPU)
LOG_INFO("new code compiled and placed into cache");
// return an instance of runnable code (ICodeCPU)
return QueryProgram(code_lib->instance(), std::move(stripped));
}
private:
// TODO somehow remove int.. from here
QueryStripper<int, int, int, int> stripper;
// TODO ifdef MEMGRAPH64 problem, how to use this kind
// of ifdef functions?
// uint64_t depends on fnv function

View File

@ -14,6 +14,7 @@ class QueryEngine
public:
auto execute(const std::string &query)
{
// TODO: error handling
auto program = program_loader.load(query);
auto result = program_executor.execute(program);
return result;

View File

@ -9,10 +9,14 @@
#include "read_traverser.hpp"
#include "update_traverser.hpp"
#include "delete_traverser.hpp"
#include "read_write_traverser.hpp"
class CodeTraverser : public Traverser, public Code
{
public:
// TODO: remove code duplication
void visit(ast::WriteQuery& write_query) override
{
auto write_traverser = WriteTraverser();
@ -40,4 +44,11 @@ public:
delete_query.accept(delete_traverser);
code = delete_traverser.code;
}
void visit(ast::ReadWriteQuery& read_write_query) override
{
auto read_write_traverser = ReadWriteTraverser();
read_write_query.accept(read_write_traverser);
code = read_write_traverser.code;
}
};

View File

@ -5,4 +5,14 @@
class DeleteTraverser : public Traverser, public Code
{
void visit(ast::Match& match) override
{
code += LINE(fmt::format(code::todo, "MATCH"));
}
void visit(ast::Delete& delete_clause) override
{
code += LINE(fmt::format(code::todo, "DELETE"));
code += LINE(code::return_empty_result);
}
};

View File

@ -23,11 +23,9 @@ private:
std::map<std::string, uint32_t> property_indices;
public:
std::string code;
void update_entities(const std::string &name)
{
std::cout << name << std::endl;
std::cout << name << std::endl;
if (entities.find(name) == entities.end()) {
csm.init_cost(name);
property_indices[name] = index++;
@ -49,7 +47,7 @@ public:
auto name = identifier->name;
update_entities(name);
if (node.labels != nullptr && node.labels->value != nullptr)
if (node.labels != nullptr && node.labels->value != nullptr)
csm.search_cost(name, search_label_index, label_cost);
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "code.hpp"
#include "cypher/visitor/traverser.hpp"
class ReadWriteTraverser : public Traverser, public Code
{
void visit(ast::Match& match) override
{
code += LINE(fmt::format(code::todo, "MATCH"));
Traverser::visit(match);
}
void visit(ast::Where& where) override
{
code += LINE(fmt::format(code::todo, "WHERE"));
Traverser::visit(where);
}
void visit(ast::Create& create) override
{
code += LINE(fmt::format(code::todo, "CREATE"));
Traverser::visit(create);
}
void visit(ast::Return& ast_return) override
{
code += LINE(fmt::format(code::todo, "RETURN"));
code += LINE(code::return_empty_result);
}
};

View File

@ -7,13 +7,17 @@ class UpdateTraverser : public Traverser, public Code
{
void visit(ast::Match& match) override
{
code += LINE(fmt::format(code::todo, "MATCH"));
}
void visit(ast::Set& set) override
{
code += LINE(fmt::format(code::todo, "SET"));
}
void visit(ast::Return& ret) override
{
code += LINE(fmt::format(code::todo, "RETURN"));
code += LINE(code::return_empty_result);
}
};

View File

@ -1,5 +1,26 @@
#pragma once
#include <iostream>
#include <string>
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/traversers/jsonwriter.hpp"
using std::cout;
using std::endl;
std::string LINE(std::string line) { return "\t" + line + "\n"; }
void print_props(const Properties &properties)
{
StringBuffer buffer;
JsonWriter<StringBuffer> writer(buffer);
properties.accept(writer);
cout << buffer.str() << endl;
}
#ifdef DEBUG
#define PRINT_PROPS(_PROPS_) print_props(_PROPS_);
#else
#define PRINT_PROPS(_)
#endif

View File

@ -11,34 +11,22 @@
using std::cout;
using std::endl;
// * INPUT ARGUMENTS *
// -q -> query
// -v -> visitor
// -f -> file
//
int main(int argc, char *argv[])
{
std::set_terminate(&terminate_handler);
// arguments parsing
// // arguments parsing
auto arguments = all_arguments(argc, argv);
// query extraction
// // query extraction
auto cypher_query = extract_query(arguments);
cout << "QUERY: " << cypher_query << endl;
// traversers
auto traverser = get_argument(arguments, "-t", "code");
auto print_traverser = Traverser::sptr(new PrintVisitor(cout));
std::map<std::string, Traverser::sptr> traversers = {
{"print", print_traverser}
};
auto print_visitor = new PrintVisitor(cout);
cypher::Compiler compiler;
auto tree = compiler.syntax_tree(cypher_query);
auto t = traversers[traverser];
tree.root->accept(*t);
tree.root->accept(*print_visitor);
cout << endl;
return 0;
}

View File

@ -6,6 +6,7 @@
#include "cypher/common.hpp"
#include "query_engine/query_engine.hpp"
#include "utils/time/timer.hpp"
#include "utils/terminate_handler.hpp"
using std::cout;
using std::endl;
@ -13,15 +14,29 @@ using std::cin;
int main(void)
{
std::set_terminate(&terminate_handler);
QueryEngine engine;
std::string command;
cout << "-- Memgraph query engine --" << endl;
do {
while (true) {
// read command
cout << "> ";
std::string command;
std::getline(cin, command);
engine.execute(command);
} while (command != "quit");
if (command == "quit")
break;
// execute command
try {
engine.execute(command);
} catch (const std::exception& e) {
cout << e.what() << endl;
} catch (const QueryEngineException& e) {
cout << e.what() << endl;
}
}
return 0;
}