query engine can now generate, compile and run dummy code, everything is ready to generate code for dummy the query: CREATE (n {...}) RETURN n

This commit is contained in:
Marko Budiselic 2016-02-07 22:56:52 +01:00
parent dbe1464f9b
commit 7d8c5a7f7e
21 changed files with 312 additions and 43 deletions

11
config/config.hpp Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "utils/config/config.hpp"
namespace config
{
constexpr const char * COMPILE_CPU_PATH = "compile_cpu_path";
constexpr const char * TEMPLATE_CPU_PATH = "template_cpu_path";
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "utils/command_line/arguments.hpp"
#include "utils/string/filereader.hpp"
#include "utils/string/file.hpp"
std::string extract_query(const vector_str& arguments)
{
@ -10,6 +10,6 @@ std::string extract_query(const vector_str& arguments)
auto default_file = "query.cypher";
auto file = get_argument(arguments, "-f", default_file);
// TODO: error handling
return read_file(file.c_str());
return utils::read_file(file.c_str());
}

View File

@ -1,38 +1,15 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <iterator>
#include <cstdlib>
#include "example/db.hpp"
#include "dynamic_lib.hpp"
#include "utils/string/file.hpp"
using std::cout;
using std::endl;
void write(const std::string& path, const std::string& content)
{
ofstream stream;
stream.open (path.c_str());
stream << content;
stream.close();
}
std::string join(const std::vector<std::string>& strings, const char *separator)
{
std::ostringstream oss;
std::copy(strings.begin(), strings.end(),
std::ostream_iterator<std::string>(oss, separator));
return oss.str();
}
template<typename... Args>
std::string prints(const Args&... args)
{
std::vector<std::string> strings = {args...};
return join(strings, " ");
}
// dependent on specific dynamic code
// "configuration" of DynamicLib
// DynamicLib<MemgraphDynamicLib>
@ -47,10 +24,9 @@ public:
const std::string MemgraphDynamicLib::produce_name = "produce";
const std::string MemgraphDynamicLib::destruct_name = "destruct";
int main()
int main()
{
// -- compile example
// string tmp_file_path = "tmp/tmp.cpp";
// string tmp_so_path = "tmp/tmp.so";
// string for_compile = "#include <iostream>\nint main() { std::cout << \"test\" << std::endl; return 0; }";
@ -58,7 +34,6 @@ int main()
// write(tmp_file_path, for_compile);
// string test_command = prints("clang++", tmp_file_path, "-o", "test.out");
// system(test_command.c_str());
// -- end compile example
// -- load example

View File

@ -1,5 +1,22 @@
#pragma once
#include <string>
#include "utils/string/join.hpp"
class CodeCompiler
{
public:
void compile(const std::string& in_file, const std::string& out_file)
{
auto compile_command = utils::prints(
"clang++",
"-std=c++1y",
in_file,
"-o", out_file,
"-I../",
"-shared -fPIC"
);
system(compile_command.c_str());
}
};

View File

@ -4,6 +4,7 @@
#include "i_code_cpu.hpp"
#include "database/db.hpp"
#include "utils/log/logger.hpp"
class CodeExecutor
{
@ -11,10 +12,11 @@ public:
void execute(ICodeCPU *code_cpu)
{
code_cpu->name();
log.info(code_cpu->query());
code_cpu->run(db);
}
private:
Db db;
Logger log;
};

View File

@ -1,5 +1,33 @@
#pragma once
#include "utils/string/file.hpp"
#include "template_engine/engine.hpp"
#include "config/config.hpp"
#include "utils/log/logger.hpp"
using std::string;
class CodeGenerator
{
public:
void generate(const std::string& query, const std::string& path)
{
string template_path =
config::Config::instance()[config::TEMPLATE_CPU_PATH];
string template_file = utils::read_file(template_path.c_str());
// TODO instead of code should be generated code
// use query visitor to build the code
string generated = template_engine.render(
template_file,
{
{"class_name", "Code"},
{"query", "\"" + query + "\""},
{"code", "cout << \"test code\" << endl;"}
}
);
utils::write_file(generated, path);
}
private:
template_engine::TemplateEngine template_engine;
Logger log;
};

View File

@ -9,6 +9,8 @@
#include "code_compiler.hpp"
#include "code_generator.hpp"
#include "utils/hashing/fnv.hpp"
#include "utils/log/logger.hpp"
#include "config/config.hpp"
using std::string;
using std::cout;
@ -27,19 +29,35 @@ public:
ICodeCPU* load_code_cpu(const string& query)
{
// TODO implement me
// for now returns already compiled code
auto stripped = stripper.strip(query);
// TODO move to logger
cout << "Stripped query is: " << stripped << endl;
log.info("stripped_query=" + stripped);
auto stripped_hash = fnv(stripped);
// TODO move to logger
cout << "Query hash is: " << stripped_hash << endl;
auto code_lib = load_code_lib("./compiled/cpu/create_return.so");
auto hash_string = std::to_string(stripped_hash);
log.info("query_hash=" + hash_string);
auto code_lib_iter = code_libs.find(stripped_hash);
// code is already compiled and loaded, just return runnable
// instance
if (code_lib_iter != code_libs.end())
// TODO also return extracted arguments
return code_lib_iter->second->instance();
// code has to be generated, compiled and loaded
// TODO load output path from config
auto base_path = config::Config::instance()[config::COMPILE_CPU_PATH];
auto path_cpp = base_path + hash_string + ".cpp";
code_generator.generate(query, path_cpp);
// TODO compile generated code
auto path_so = base_path + hash_string + ".so";
code_compiler.compile(path_cpp, path_so);
// loads dynamic lib and store it
auto code_lib = load_code_lib(path_so);
code_libs.insert({{stripped_hash, code_lib}});
// return instance of runnable code (ICodeCPU)
return code_lib->instance();
}
@ -53,6 +71,7 @@ private:
CodeGenerator code_generator;
CodeCompiler code_compiler;
Logger log;
sptr_code_lib load_code_lib(const string& path)
{

View File

@ -4,4 +4,5 @@
cd compiled/cpu
clang++ -std=c++1y create_return.cpp -o create_return.so -I../../../ -shared -fPIC
cd ../..
clang++ -std=c++1y -g -I../ main.cpp ../cypher/cypher.cpp -o engine -ldl
# clang++ -std=c++1y -g -I../ -I ../lib/yaml-cpp/include main.cpp ../cypher/cypher.cpp -o engine -L ../lib/yaml-cpp/build -l yaml-cpp -l dl
clang++ -std=c++1y -g -I../ main.cpp ../cypher/cypher.cpp -o engine -l dl

4
query_engine/compiled/cpu/.gitignore vendored Normal file
View File

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

View File

@ -1,4 +1,5 @@
#include <iostream>
#include <string>
#include "query_engine/i_code_cpu.hpp"
@ -9,9 +10,9 @@ class CreateReturn : public ICodeCPU
{
public:
void name() const override
std::string query() const override
{
cout << "CRETE RETURN QUERY" << endl;
return "CRETE RETURN QUERY";
}
void run(Db& db) const override

4
query_engine/compiled/gpu/.gitignore vendored Normal file
View File

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

3
query_engine/config.yaml Normal file
View File

@ -0,0 +1,3 @@
# Memgraph test config
compile_cpu_path: ./compiled/cpu/

Binary file not shown.

View File

@ -1,11 +1,13 @@
#pragma once
#include <string>
#include "database/db.hpp"
class ICodeCPU
{
public:
virtual void name() const = 0;
virtual std::string query() const = 0;
virtual void run(Db& db) const = 0;
virtual ~ICodeCPU() {}
};

View File

@ -29,6 +29,7 @@ public:
decltype(auto) strip(const std::string& query)
{
// TODO return hash and arguments
auto tokenizer = lexer->tokenize(query);
std::string stripped = "";
int counter = 0;

View File

@ -0,0 +1,34 @@
#include <iostream>
#include <string>
#include "query_engine/i_code_cpu.hpp"
using std::cout;
using std::endl;
class {{class_name}} : public ICodeCPU
{
public:
std::string query() const override
{
return {{query}};
}
void run(Db& db) const override
{
{{code}}
}
~{{class_name}}() {}
};
extern "C" ICodeCPU* produce()
{
return new {{class_name}}();
}
extern "C" void destruct(ICodeCPU* p)
{
delete p;
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <string>
#include <unordered_map>
#include "utils/string/replace.hpp"
namespace template_engine
{
using std::string;
using data = std::unordered_map<string, string>;
class TemplateEngine
{
public:
string render(const string& form, const data& partials)
{
// TODO more optimal implementation
// if more optimal implementation is to expensive
// use some templating engine like https://github.com/no1msd/mstch
// but it has to be wrapped
string rendered = form;
for (auto partial : partials) {
string key = "{{" + partial.first + "}}";
rendered = utils::replace(rendered, key, partial.second);
}
return rendered;
}
};
}

58
utils/config/config.hpp Normal file
View File

@ -0,0 +1,58 @@
#pragma once
// #define YAML_CPP_DLL
// there are some problems with the yaml-cpp linking, something is missing
// cmake and make have passed fine
// and it seems that everything is included and linked
// the yaml-cpp lib is strange
// TODO debug yaml-cpp installation or write own yaml parser like a boss
// #include "yaml-cpp/yaml.h"
#include <cstring>
#include <string>
#include <stdexcept>
namespace config
{
class Config
{
private:
// YAML::Node _config;
Config()
{
// TODO: config places: priority
// 1. default system |
// 2. default user |
// 3. ENV var |
// 4. program argument \ /
// _config = YAML::LoadFile("config.yaml");
}
public:
static Config& instance()
{
// TODO resolve multithreading problems
static Config config;
return config;
}
std::string operator[](const char* key)
{
// TODO write proper implementation, remove memgraph dependant
// stuff from here
if (0 == std::strcmp(key, "compile_cpu_path"))
return "./compiled/cpu/";
if (std::strcmp(key, "template_cpu_path") == 0)
return "./template/template_code_cpu.cpp";
throw std::runtime_error("implement me");
// TODO optimize access
// return _config[key].as<std::string>();
}
};
}

37
utils/log/logger.hpp Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <string>
#include <iostream>
#include <ctime>
#include <iomanip>
class Logger
{
public:
Logger() = default;
// TODO logger name support
// TODO level support
// TODO handlers support:
// * log format support
void info(const std::string& text)
{
stdout_log(text);
}
void debug(const std::string& text)
{
stdout_log(text);
}
private:
void stdout_log(const std::string& text)
{
auto now = std::time(nullptr);
std::cout << std::put_time(std::gmtime(&now), "[%F %T]: ")
<< text << std::endl;
}
};

View File

@ -1,10 +1,14 @@
#pragma once
#include <fstream>
#include <ostream>
#include <streambuf>
#include <string>
#include <cerrno>
namespace utils
{
std::string read_file(const char *filename)
{
std::ifstream in(filename, std::ios::in | std::ios::binary);
@ -13,3 +17,13 @@ std::string read_file(const char *filename)
std::istreambuf_iterator<char>());
throw(errno);
}
void write_file(const std::string& content, const std::string& path)
{
std::ofstream stream;
stream.open(path.c_str());
stream << content;
stream.close();
}
}

26
utils/string/join.hpp Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
namespace utils
{
std::string join(const std::vector<std::string>& strings, const char *separator)
{
std::ostringstream oss;
std::copy(strings.begin(), strings.end(),
std::ostream_iterator<std::string>(oss, separator));
return oss.str();
}
template<typename... Args>
std::string prints(const Args&... args)
{
std::vector<std::string> strings = {args...};
return join(strings, " ");
}
}