query engine better version
This commit is contained in:
parent
8a3aee1ba6
commit
396f0d9c31
@ -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);
|
||||
}
|
||||
|
||||
|
4
src/query_engine/compiled/cpu/.gitignore
vendored
4
src/query_engine/compiled/cpu/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
4
src/query_engine/compiled/gpu/.gitignore
vendored
4
src/query_engine/compiled/gpu/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
@ -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));
|
||||
}
|
||||
|
||||
|
124
src/query_engine/state_machine/cypher.hpp
Normal file
124
src/query_engine/state_machine/cypher.hpp
Normal 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;
|
||||
};
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 update_entities(const std::string &name)
|
||||
{
|
||||
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("auto& t = db.tx_engine.begin();");
|
||||
|
||||
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
|
||||
{
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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"; }
|
||||
|
36
tests/unit/cypher_state_machine.cpp
Normal file
36
tests/unit/cypher_state_machine.cpp
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user