query engine better version

This commit is contained in:
Marko Budiselic 2016-07-17 01:22:43 +01:00
parent 8a3aee1ba6
commit 396f0d9c31
10 changed files with 287 additions and 45 deletions

View File

@ -30,6 +30,9 @@ public:
{"stripped_hash", std::to_string(stripped_hash)},
{"query", query},
{"code", code_traverser.code}});
// TODO: ifndef
std::cout << generated << std::endl;
utils::write_file(generated, path);
}

View File

@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -61,6 +61,7 @@ public:
code_libs.insert({{stripped.hash, code_lib}});
// return instance of runnable code (ICodeCPU)
LOG_INFO("new code compiled and placed into cache");
return QueryProgram(code_lib->instance(), std::move(stripped));
}

View File

@ -0,0 +1,124 @@
#pragma once
#include <algorithm>
#include <limits>
#include <map>
// TODO: remove
#include "utils/underlying_cast.hpp"
#include <iostream>
// entities are nodes or relationship
namespace entity_search
{
// returns maximum value for given template argument (for give type)
template <typename T>
constexpr T max()
{
return std::numeric_limits<uint64_t>::max();
}
using cost_t = uint64_t;
// TODO: rething
// at least load hard coded values from somewhere
constexpr cost_t internal_id_cost = 10;
constexpr cost_t property_cost = 100;
constexpr cost_t label_cost = 1000;
constexpr cost_t max_cost = max<cost_t>();
template <typename T>
class SearchCost
{
public:
enum class SearchPlace : int
{
internal_id,
label_index,
property_index,
main_storage
};
using costs_t = std::map<SearchPlace, T>;
using cost_pair_t = std::pair<SearchPlace, T>;
SearchCost()
{
costs[SearchPlace::internal_id] = max<T>();
costs[SearchPlace::label_index] = max<T>();
costs[SearchPlace::property_index] = max<T>();
costs[SearchPlace::main_storage] = max<T>();
}
SearchCost(const SearchCost &other) = default;
SearchCost(SearchCost &&other) : costs(std::move(other.costs)) {}
void set(SearchPlace place, T cost) { costs[place] = cost; }
T get(SearchPlace place) const { return costs.at(place); }
SearchPlace min() const
{
auto min_pair = std::min_element(
costs.begin(), costs.end(),
[](const cost_pair_t &l, const cost_pair_t &r) -> bool {
return l.second < r.second;
});
if (min_pair->second == max_cost) return SearchPlace::main_storage;
return min_pair->first;
}
private:
costs_t costs;
};
using search_cost_t = SearchCost<cost_t>;
constexpr auto search_internal_id = search_cost_t::SearchPlace::internal_id;
constexpr auto search_label_index = search_cost_t::SearchPlace::label_index;
constexpr auto search_property_index =
search_cost_t::SearchPlace::property_index;
constexpr auto search_main_storage = search_cost_t::SearchPlace::main_storage;
}
class CypherStateMachine
{
public:
void init_cost(const std::string &entity)
{
entity_search::search_cost_t search_cost;
_search_costs.emplace(entity, search_cost);
}
void search_cost(const std::string &entity,
entity_search::search_cost_t::SearchPlace search_place,
entity_search::cost_t cost)
{
if (_search_costs.find(entity) != _search_costs.end()) {
entity_search::search_cost_t search_cost;
_search_costs.emplace(entity, std::move(search_cost));
}
_search_costs[entity].set(search_place, cost);
}
entity_search::cost_t
search_cost(const std::string &entity,
entity_search::search_cost_t::SearchPlace search_place) const
{
return _search_costs.at(entity).get(search_place);
}
entity_search::search_cost_t::SearchPlace
min(const std::string &entity) const
{
return _search_costs.at(entity).min();
}
private:
std::map<std::string, entity_search::search_cost_t> _search_costs;
};

View File

@ -2,9 +2,54 @@
#include <string>
#include "query_engine/util.hpp"
struct Code
{
void reset() { code = ""; }
std::string code;
};
namespace code
{
// TODO: UNIT tests
const std::string transaction_begin = "auto& t = db.tx_engine.begin();";
const std::string transaction_commit = "t.commit();";
const std::string vertex_accessor =
"auto vertex_accessor = db.graph.vertices.insert(t);";
const std::string args_id = "auto id = args[{}]->as<Int32>();";
const std::string vertex_accessor_args_id =
"auto vertex_accessor = db.graph.vertices.find(t, id.value);";
const std::string vertex_set_property =
"vertex_accessor.property(\"{}\", args[{}]);";
const std::string return_empty_result =
"return std::make_shared<QueryResult>();";
const std::string create_label =
"auto &{} = db.graph.label_store.find_or_create(\"{}\");";
const std::string add_label = "vertex_accessor.add_label({});";
const std::string todo = "// TODO: {}";
std::string debug_print_vertex_labels()
{
#ifdef DEBUG
return LINE("PRINT_PROPS(vertex_accessor.properties());") +
LINE("cout << \"LABELS:\" << endl;") +
LINE("for (auto label_ref : vertex_accessor.labels()) {") +
LINE("cout << label_ref.get() << endl;") + LINE("}");
#else
return "";
#endif
}
}

View File

@ -1,48 +1,99 @@
#pragma once
// TODO: wrap fmt format
#include <fmt/format.h>
#include "code.hpp"
#include "cypher/visitor/traverser.hpp"
#include "query_engine/state_machine/cypher.hpp"
#include "query_engine/util.hpp"
#include "utils/underlying_cast.hpp"
using namespace entity_search;
class ReadTraverser : public Traverser, public Code
{
private:
// TODO: change int to something bigger (int64_t)
std::map<std::string, int> internal_ids;
std::set<std::string> entities;
CypherStateMachine csm;
uint32_t index{0};
std::map<std::string, uint32_t> property_indices;
public:
std::string code;
void visit(ast::Match& match) override
void update_entities(const std::string &name)
{
code += line("auto& t = db.tx_engine.begin();");
std::cout << name << std::endl;
if (entities.find(name) == entities.end()) {
csm.init_cost(name);
property_indices[name] = index++;
entities.insert(std::move(name));
}
}
void visit(ast::Match &match) override
{
code += LINE(code::transaction_begin);
Traverser::visit(match);
};
void visit(ast::Property& property) override
void visit(ast::Node &node) override
{
code += line("auto id = args[" + std::to_string(index) + "]->as<Int32>();");
code += line("auto vertex_accessor = db.graph.vertices.find(t, id.value);");
auto identifier = node.idn;
if (identifier == nullptr) return;
++index;
auto name = identifier->name;
update_entities(name);
if (node.labels != nullptr && node.labels->value != nullptr)
csm.search_cost(name, search_label_index, label_cost);
}
void visit(ast::InternalIdExpr& internal_id) override
void visit(ast::InternalIdExpr &internal_id_expr) override
{
if (internal_id_expr.identifier == nullptr) return;
auto name = internal_id_expr.identifier->name;
// value has to exist
if (internal_id_expr.value == nullptr) {
// TODO: raise exception
}
update_entities(name);
csm.search_cost(name, search_internal_id, internal_id_cost);
}
void visit(ast::Return& ret) override
void visit(ast::Return &ret) override
{
#ifdef DEBUG
// TODO: remove from here
code += line("PRINT_PROPS(vertex_accessor.properties());");
code += line("cout << \"LABELS:\" << endl;");
code += line("for (auto label_ref : vertex_accessor.labels()) {");
code += line("cout << label_ref.get() << endl;");
code += line("}");
#endif
for (auto const &entity : entities) {
std::cout << entity << std::endl;
std::cout << underlying_cast(csm.min(entity)) << std::endl;
if (csm.min(entity) == search_internal_id) {
auto property_index = property_indices.at(entity);
code += LINE(
fmt::format(code::args_id, std::to_string(property_index)));
code += LINE(code::vertex_accessor_args_id);
continue;
}
code += line("t.commit();");
code += line("return std::make_shared<QueryResult>();");
if (csm.min(entity) == search_label_index) {
code += LINE(fmt::format(code::todo, "search label index"));
continue;
}
if (csm.min(entity) == search_main_storage) {
code += LINE(fmt::format(code::todo, "return all vertices"));
continue;
}
}
code::debug_print_vertex_labels();
code += LINE(code::transaction_commit);
code += LINE(code::return_empty_result);
}
};

View File

@ -3,6 +3,7 @@
#include <iostream>
#include <map>
#include <typeinfo>
#include <fmt/format.h>
#include "cypher/visitor/traverser.hpp"
#include "query_engine/util.hpp"
@ -19,8 +20,8 @@ public:
void visit(ast::Create &create) override
{
code += line("auto& t = db.tx_engine.begin();");
code += line("auto vertex_accessor = db.graph.vertices.insert(t);");
code += LINE(code::transaction_begin);
code += LINE(code::vertex_accessor);
Traverser::visit(create);
};
@ -34,10 +35,8 @@ public:
if (collecting_labels) {
for (auto label : labels) {
code += line("auto &" + label +
" = db.graph.label_store.find_or_create(\"" +
label + "\");");
code += line("vertex_accessor.add_label(" + label + ");");
code += LINE(fmt::format(code::create_label, label, label));
code += LINE(fmt::format(code::add_label, label));
}
labels.clear();
collecting_labels = false;
@ -52,22 +51,13 @@ public:
void visit(ast::Property &property) override
{
auto key = property.idn->name;
code += line("vertex_accessor.property(");
code += line("\t\"" + key + "\", args[" + std::to_string(index) + "]");
code += line(");");
code += LINE(fmt::format(code::vertex_set_property, key, index));
++index;
}
void visit(ast::Return &ret) override
{
#ifdef DEBUG
// TODO: remove from here
code += line("PRINT_PROPS(vertex_accessor.properties());");
#endif
code += line("t.commit();");
code += line("return std::make_shared<QueryResult>();");
code += LINE(code::transaction_commit);
code += LINE(code::return_empty_result);
}
};

View File

@ -2,4 +2,4 @@
#include <string>
std::string line(std::string line) { return "\t\t" + line + "\n"; }
std::string LINE(std::string line) { return "\t" + line + "\n"; }

View File

@ -0,0 +1,36 @@
#include <iostream>
#include "query_engine/state_machine/cypher.hpp"
#include "utils/assert.hpp"
#include "utils/underlying_cast.hpp"
using std::cout;
using std::endl;
int main()
{
// initialize cypher state machine
CypherStateMachine csm;
// set cost for label index
auto test_cost = static_cast<uint64_t>(30);
csm.search_cost("n", entity_search::search_label_index, test_cost);
// check all costs
auto max_cost = entity_search::max<uint64_t>();
permanent_assert(csm.search_cost("n", entity_search::search_internal_id) ==
max_cost,
"Search internal id cost should be max cost value");
permanent_assert(csm.search_cost("n", entity_search::search_label_index) ==
test_cost,
"Search label index cost should be test cost value");
permanent_assert(
csm.search_cost("n", entity_search::search_property_index) == max_cost,
"Search property index should be max cost value");
// check minimum cost
permanent_assert(csm.min("n") == entity_search::search_label_index,
"Search place should be label index");
return 0;
}