From 70a8b93b0b02e474773cced3a4648ceea6e4d16a Mon Sep 17 00:00:00 2001 From: florijan Date: Wed, 15 Feb 2017 14:10:16 +0100 Subject: [PATCH] Major properties system and database accessor refactor: first stable state (compiles). --- CMakeLists.txt | 4 +- include/communication/bolt/v1/session.hpp | 2 +- .../bolt/v1/transport/bolt_encoder.hpp | 4 + include/database/graph_db.hpp | 22 +- include/database/graph_db_accessor.hpp | 42 +- include/dbms/dbms.hpp | 27 +- include/mvcc/record.hpp | 12 + include/mvcc/version_list.hpp | 11 +- .../query/backend/cpp_old/clause_action.hpp | 26 -- include/query/backend/cpp_old/code.hpp | 226 ----------- .../query/backend/cpp_old/cpp_generator.hpp | 85 ---- include/query/backend/cpp_old/cypher.hpp | 57 --- .../query/backend/cpp_old/cypher_state.hpp | 215 ----------- .../query/backend/cpp_old/entity_search.hpp | 131 ------- .../query/backend/cpp_old/handlers/all.hpp | 11 - .../query/backend/cpp_old/handlers/create.hpp | 74 ---- .../query/backend/cpp_old/handlers/delete.hpp | 34 -- .../backend/cpp_old/handlers/includes.hpp | 44 --- .../query/backend/cpp_old/handlers/match.hpp | 84 ---- .../query/backend/cpp_old/handlers/return.hpp | 132 ------- .../query/backend/cpp_old/handlers/set.hpp | 72 ---- .../cpp_old/handlers/transaction_begin.hpp | 8 - .../cpp_old/handlers/transaction_commit.hpp | 9 - include/query/backend/cpp_old/namer.hpp | 18 - .../query/backend/cpp_old/query_action.hpp | 16 - .../backend/cpp_old/query_action_data.hpp | 187 --------- include/query/backend/cpp_old/structures.hpp | 19 - include/query/engine.hpp | 19 +- include/query/plan_generator.hpp | 29 -- include/query/plan_interface.hpp | 2 +- include/query/preprocessor.hpp | 2 - include/query/stripped.hpp | 25 +- include/query/stripper.hpp | 6 +- include/storage/edge.hpp | 10 +- include/storage/edge_accessor.hpp | 2 +- include/storage/model/typed_value.hpp | 117 ------ include/storage/model/typed_value_store.hpp | 82 ---- include/storage/model/typed_value_utils.h | 57 --- include/storage/record_accessor.hpp | 68 ++-- include/storage/typed_value_store.hpp | 68 +++- include/storage/util.hpp | 24 ++ include/storage/vertex.hpp | 7 +- include/storage/vertex_accessor.hpp | 28 +- include/utils/hashing/fnv.hpp | 4 + .../bolt/v1/serialization/bolt_serializer.cpp | 21 +- src/communication/bolt/v1/session.cpp | 2 +- src/communication/bolt/v1/states/executor.cpp | 7 +- src/database/graph_db.cpp | 19 +- src/database/graph_db_accessor.cpp | 90 ++++- src/dbms/dbms.cpp | 19 +- src/storage/edge_accessor.cpp | 40 +- src/storage/model/typed_value.cpp | 363 ------------------ src/storage/model/typed_value_store.cpp | 68 ---- src/storage/typed_value.cpp | 48 +-- src/storage/typed_value_store.cpp | 3 +- src/storage/vertex_accessor.cpp | 66 ++-- tests/benchmark/query/strip/stripper.cpp | 2 +- tests/integration/cleaning.cpp | 109 ------ tests/integration/index.cpp | 283 -------------- tests/integration/query_engine.cpp | 8 +- tests/integration/query_engine_common.hpp | 17 +- tests/integration/snapshot.cpp | 292 -------------- .../stream/print_record_stream.hpp | 174 +++------ tests/manual/query_engine.cpp | 8 +- tests/manual/query_hash.cpp | 2 +- tests/unit/cypher_state_machine.cpp | 39 -- tests/unit/parameter_index.cpp | 24 -- tests/unit/typed_value.cpp | 16 +- tests/unit/typed_value_store.cpp | 17 +- 69 files changed, 535 insertions(+), 3324 deletions(-) delete mode 100644 include/query/backend/cpp_old/clause_action.hpp delete mode 100644 include/query/backend/cpp_old/code.hpp delete mode 100644 include/query/backend/cpp_old/cpp_generator.hpp delete mode 100644 include/query/backend/cpp_old/cypher.hpp delete mode 100644 include/query/backend/cpp_old/cypher_state.hpp delete mode 100644 include/query/backend/cpp_old/entity_search.hpp delete mode 100644 include/query/backend/cpp_old/handlers/all.hpp delete mode 100644 include/query/backend/cpp_old/handlers/create.hpp delete mode 100644 include/query/backend/cpp_old/handlers/delete.hpp delete mode 100644 include/query/backend/cpp_old/handlers/includes.hpp delete mode 100644 include/query/backend/cpp_old/handlers/match.hpp delete mode 100644 include/query/backend/cpp_old/handlers/return.hpp delete mode 100644 include/query/backend/cpp_old/handlers/set.hpp delete mode 100644 include/query/backend/cpp_old/handlers/transaction_begin.hpp delete mode 100644 include/query/backend/cpp_old/handlers/transaction_commit.hpp delete mode 100644 include/query/backend/cpp_old/namer.hpp delete mode 100644 include/query/backend/cpp_old/query_action.hpp delete mode 100644 include/query/backend/cpp_old/query_action_data.hpp delete mode 100644 include/query/backend/cpp_old/structures.hpp delete mode 100644 include/query/plan_generator.hpp delete mode 100644 include/storage/model/typed_value.hpp delete mode 100644 include/storage/model/typed_value_store.hpp delete mode 100644 include/storage/model/typed_value_utils.h create mode 100644 include/storage/util.hpp delete mode 100644 src/storage/model/typed_value.cpp delete mode 100644 src/storage/model/typed_value_store.cpp delete mode 100644 tests/integration/cleaning.cpp delete mode 100644 tests/integration/index.cpp delete mode 100644 tests/integration/snapshot.cpp delete mode 100644 tests/unit/cypher_state_machine.cpp delete mode 100644 tests/unit/parameter_index.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d82ac26b8..ed7c03532 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -314,7 +314,6 @@ set(memgraph_src_files # ${src_dir}/snapshot/snapshot_encoder.cpp # ${src_dir}/snapshot/snapshot_decoder.cpp ${src_dir}/storage/typed_value.cpp - ${src_dir}/storage/typed_value_store.cpp ${src_dir}/storage/locking/record_lock.cpp # ${src_dir}/storage/garbage/garbage.cpp ${src_dir}/storage/vertex_accessor.cpp @@ -330,7 +329,6 @@ set(memgraph_src_files ${src_dir}/logging/logs/async_log.cpp ${src_dir}/logging/default.cpp ${src_dir}/logging/log.cpp - ${src_dir}/io/network/tls.cpp ${src_dir}/database/graph_db.cpp ${src_dir}/database/graph_db_accessor.cpp ) @@ -388,7 +386,7 @@ if (MEMGRAPH) target_link_libraries(${MEMGRAPH_BUILD_NAME} cypher_lib) if (UNIX) - target_link_libraries(${MEMGRAPH_BUILD_NAME} crypto) +# target_link_libraries(${MEMGRAPH_BUILD_NAME} crypto) # target_link_libraries(${MEMGRAPH_BUILD_NAME} ssl) target_link_libraries(${MEMGRAPH_BUILD_NAME} ${fmt_static_lib}) target_link_libraries(${MEMGRAPH_BUILD_NAME} ${yaml_static_lib}) diff --git a/include/communication/bolt/v1/session.hpp b/include/communication/bolt/v1/session.hpp index bcb007619..b20b97109 100644 --- a/include/communication/bolt/v1/session.hpp +++ b/include/communication/bolt/v1/session.hpp @@ -29,7 +29,7 @@ namespace bolt { Bolt &bolt; - GraphDb &active_db(); + GraphDbAccessor active_db(); Decoder decoder; OutputStream output_stream{socket}; diff --git a/include/communication/bolt/v1/transport/bolt_encoder.hpp b/include/communication/bolt/v1/transport/bolt_encoder.hpp index e6c259b85..1637a36d4 100644 --- a/include/communication/bolt/v1/transport/bolt_encoder.hpp +++ b/include/communication/bolt/v1/transport/bolt_encoder.hpp @@ -140,6 +140,10 @@ public: } } + void write(const std::string& str) { + write_string(str); + } + void write_string(const std::string &str) { write_string(str.c_str(), str.size()); diff --git a/include/database/graph_db.hpp b/include/database/graph_db.hpp index 82b6d19a5..ddf141a47 100644 --- a/include/database/graph_db.hpp +++ b/include/database/graph_db.hpp @@ -31,26 +31,6 @@ public: using EdgeType = std::string*; using Property = std::string*; - /** - * This constructor will create a database with the name "default" - * - * NOTE: explicit is here to prevent compiler from evaluating const char * - * into a bool. - * - * @param import_snapshot will in constructor import latest snapshot - * into the db. - */ - explicit GraphDb(bool import_snapshot = true); - - /** - * Construct database with a custom name. - * - * @param name database name - * @param import_snapshot will in constructor import latest snapshot - * into the db. - */ - GraphDb(const char *name, bool import_snapshot = true); - /** * Construct database with a custom name. * @@ -80,8 +60,8 @@ public: const std::string name_; // main storage for the graph - SkipList*> edges_; SkipList*> vertices_; + SkipList*> edges_; // unique object stores ConcurrentSet labels_; diff --git a/include/database/graph_db_accessor.hpp b/include/database/graph_db_accessor.hpp index decd0c2a0..6d18fb6e1 100644 --- a/include/database/graph_db_accessor.hpp +++ b/include/database/graph_db_accessor.hpp @@ -10,9 +10,21 @@ class GraphDbAccessor { - GraphDbAccessor(GraphDb& db); public: + + /** + * Creates an accessor for the given database. + * + * @param db The database + */ + GraphDbAccessor(GraphDb& db); + + /** + * Returns the name of the database of this accessor. + */ + const std::string& name() const; + /** * Creates a new Vertex and returns an accessor to it. * @@ -20,6 +32,24 @@ public: */ VertexAccessor insert_vertex(); + /** + * Removes the vertex of the given accessor. If the vertex has any outgoing + * or incoming edges, it is not deleted. See `detach_remove_vertex` if you + * want to remove a vertex regardless of connectivity. + * + * @param vertex_accessor Accessor to vertex. + * @return If or not the vertex was deleted. + */ + bool remove_vertex(VertexAccessor &vertex_accessor); + + /** + * Removes the vertex of the given accessor along with all it's outgoing + * and incoming connections. + * + * @param vertex_accessor Accessor to a vertex. + */ + void detach_remove_vertex(VertexAccessor &vertex_accessor); + /** * Creates a new Edge and returns an accessor to it. * @@ -30,6 +60,13 @@ public: */ EdgeAccessor insert_edge(VertexAccessor& from, VertexAccessor& to, GraphDb::EdgeType type); + /** + * Removes an edge from the graph. + * + * @param edge_accessor The accessor to an edge. + */ + void remove_edge(EdgeAccessor& edge_accessor); + /** * Obtains the Label for the label's name. * @return See above. @@ -77,7 +114,4 @@ public: private: GraphDb& db_; - - // for privileged access to some RecordAccessor functionality (and similar) - const PassKey pass_key; }; diff --git a/include/dbms/dbms.hpp b/include/dbms/dbms.hpp index c25edc2cb..83b7b9948 100644 --- a/include/dbms/dbms.hpp +++ b/include/dbms/dbms.hpp @@ -3,27 +3,36 @@ #include "config/config.hpp" #include "data_structures/concurrent/concurrent_map.hpp" #include "database/graph_db.hpp" +#include "database/graph_db_accessor.hpp" + //#include "dbms/cleaner.hpp" //#include "snapshot/snapshoter.hpp" class Dbms { public: - Dbms() { create_default(); } + Dbms() { + // create the default database and set is a active + active("default"); + } - // returns active database - GraphDb &active(); + /** + * Returns an accessor to the active database. + */ + GraphDbAccessor active(); - // set active database - // if active database doesn't exist creates one - GraphDb &active(const std::string &name); + /** + * Set the database with the given name to be active. + * If there is no database with the given name, + * it's created. + * + * @return an accessor to the database with the given name. + */ + GraphDbAccessor active(const std::string &name); // TODO: DELETE action private: - // creates default database - GraphDb &create_default() { return active("default"); } - // dbs container ConcurrentMap dbs; diff --git a/include/mvcc/record.hpp b/include/mvcc/record.hpp index d7d005ed0..2d6bd440f 100644 --- a/include/mvcc/record.hpp +++ b/include/mvcc/record.hpp @@ -23,6 +23,18 @@ template class Record : public Version { public: + + Record() = default; + + // The copy constructor ignores tx, cmd, hints and super because + // they contain atomic variables that can't be copied + // it's still useful to have this copy constructor so that subclass + // data can easily be copied + // TODO maybe disable the copy-constructor and instead use a + // data variable in the version_list update() function (and similar) + // like it was in Dominik's implementation + Record(const Record &other) {} + // tx.cre is the id of the transaction that created the record // and tx.exp is the id of the transaction that deleted the record // these values are used to determine the visibility of the record diff --git a/include/mvcc/version_list.hpp b/include/mvcc/version_list.hpp index 025998cdd..a48bc7891 100644 --- a/include/mvcc/version_list.hpp +++ b/include/mvcc/version_list.hpp @@ -118,12 +118,16 @@ namespace mvcc { return r; } - T *insert(tx::Transaction &t) { + /** + * @Args forwarded to the constructor of T + */ + template + T *insert(tx::Transaction &t, Args&&... args) { assert(head == nullptr); // create a first version of the record // TODO replace 'new' with something better - auto v1 = new T(); + auto v1 = new T(std::forward(args)...); // mark the record as created by the transaction t v1->mark_created(t); @@ -150,8 +154,7 @@ namespace mvcc { // It could be done with unique_ptr but while this could mean memory // leak on exception, unique_ptr could mean use after free. Memory // leak is less dangerous. - auto updated = new T(); - updated->data = record->data; + auto updated = new T(*record); updated->mark_created(t); record->mark_deleted(t); diff --git a/include/query/backend/cpp_old/clause_action.hpp b/include/query/backend/cpp_old/clause_action.hpp deleted file mode 100644 index 5c6225acb..000000000 --- a/include/query/backend/cpp_old/clause_action.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -enum class ClauseAction : uint32_t -{ - Undefined, - CreateNode, - MatchNode, - UpdateNode, - DeleteNode, - CreateRelationship, - MatchRelationship, - UpdateRelationship, - DeleteRelationship, - ReturnNode, - ReturnRelationship, - ReturnPack, - ReturnProjection, - ReturnCount, - ReturnLabels, - - UpdateEntityLabels, - UpdateEntityLabels_Identifier, - UpdateEntityLabels_Labels -}; diff --git a/include/query/backend/cpp_old/code.hpp b/include/query/backend/cpp_old/code.hpp deleted file mode 100644 index bae141747..000000000 --- a/include/query/backend/cpp_old/code.hpp +++ /dev/null @@ -1,226 +0,0 @@ -#pragma once - -// !! DEPRICATED !! - -#include - -#include "query/util.hpp" - -class Code -{ -public: - std::string code; - - void reset() { code = ""; } -}; - -namespace code -{ - -// TODO: one more abstraction level -// TODO: UNIT tests - -const std::string transaction_begin = "DbAccessor t(db);"; - -const std::string transaction_commit = "t.commit();"; - -const std::string set_property = "{}.set({}, std::move(args[{}]));"; - -// create vertex e.g. CREATE (n:PERSON {name: "Test", age: 23}) -const std::string create_vertex = "auto {} = t.vertex_insert();"; -const std::string create_label = "auto &{0} = t.label_find_or_create(\"{0}\");"; -const std::string add_label = "{}.add_label({});"; - -const std::string vertex_property_key = - "auto {}=t.vertex_property_key(\"{}\",args[{}].key.flags());"; -const std::string edge_property_key = - "auto {}=t.edge_property_key(\"{}\",args[{}].key.flags());"; - -// create edge e.g CREATE (n1)-[r:COST {cost: 100}]->(n2) -const std::string create_edge = "auto {} = t.edge_insert({},{});"; -const std::string find_type = "auto &{0} = t.type_find_or_create(\"{0}\");"; -const std::string set_type = "{}.edge_type({});"; - -const std::string args_id = "Int32 id = args[{}].as();"; - -const std::string vertex_accessor_args_id = - "auto vertex_accessor = t.vertex_find(id.value());"; - -const std::string match_vertex_by_id = - "auto option_{0} = t.vertex_find(args[{1}].as().value());\n" - " if (!option_fill(option_{0})) return t.commit(), false;\n" - " auto {0}=option_{0}.take();"; -const std::string match_edge_by_id = - "auto option_{0} = t.edge_find(args[{1}].as().value());\n" - " if (!option_fill(option_{0})) return t.commit(), false;\n" - " auto {0}=option_{0}.take();"; - -const std::string write_entity = "stream.write_field(\"{0}\");\n" - " stream.write_record();\n" - " stream.write_list_header(1);\n" - " stream.write({0});\n" - " stream.chunk();" - " stream.write_meta(\"rw\");\n"; - -const std::string write_vertex_accessor = - " stream.write_record();\n" - " stream.write_list_header(1);\n" - " stream.write(vertex_accessor);\n" - " stream.chunk();\n"; - -const std::string write_all_vertices = - "stream.write_field(\"{0}\");\n" - " iter::for_all(t.vertex_access(), [&](auto vertex_accessor) {{\n" - " if (vertex_accessor.fill()) {{\n" - + write_vertex_accessor + - " }}\n" - " }});\n" - " stream.write_meta(\"rw\");\n"; - -const std::string find_and_write_vertices_by_label = - "auto &label = t.label_find_or_create(\"{1}\");\n" - " stream.write_field(\"{0}\");\n" - " label.index().for_range(t).for_all([&](auto vertex_accessor) {{\n" - + write_vertex_accessor + - " }});\n" - " stream.write_meta(\"rw\");\n"; - -const std::string find_and_write_vertices_by_label_and_properties = - "{{\n" - " DbAccessor _t(db);\n" - " {0}\n" - " auto properties = query_properties(indices, args);\n" - " auto &label = _t.label_find_or_create(\"{1}\");\n" - " stream.write_field(\"{2}\");\n" - " label.index().for_range(_t).properties_filter(_t, properties).for_all(\n" - " [&](auto vertex_accessor) -> void {{\n" - " "+ write_vertex_accessor + - " }});\n" - " stream.write_meta(\"rw\");\n" - " _t.commit();" - "}}\n"; - -// -- LABELS -const std::string set_vertex_element = - "{{\n" - " DbAccessor _t(db);" // TODO: HACK (set labels should somehow persist the state) - " {0}\n" - " auto properties = query_properties(indices, args);\n" - " auto &label = _t.label_find_or_create(\"{1}\");\n" - " label.index().for_range(_t).properties_filter(_t, properties).for_all(\n" - " [&](auto vertex_accessor) -> void {{\n" - " auto {2} = _t.vertex_property_key(\"{2}\", args[{3}].key.flags());\n" - " vertex_accessor.set({2}, std::move(args[{3}]));\n" - " }}\n" - " );\n" - " _t.commit();\n" - "}}"; - -const std::string set_labels_start = - " {{\n" - " DbAccessor _t(db);" // TODO: HACK (set labels should somehow persist the state) - " {0}\n" - " auto properties = query_properties(indices, args);\n" - " auto &label = _t.label_find_or_create(\"{1}\");\n" - " label.index().for_range(_t).properties_filter(_t, properties).for_all(\n" - " [&](auto vertex_accessor) -> void {{\n"; -const std::string set_label = - " auto &{0} = _t.label_find_or_create(\"{0}\");\n" - " vertex_accessor.add_label({0});\n"; -const std::string set_labels_end = - " }}\n" - " );\n" - " _t.commit();" - " }}"; - -const std::string return_labels = - "{{\n" - " DbAccessor _t(db);" // TODO: HACK (set labels should somehow persist the state) - " {0}\n" - " auto properties = query_properties(indices, args);\n" - " auto &label = _t.label_find_or_create(\"{1}\");\n" - " stream.write_field(\"labels({2})\");\n" - " label.index().for_range(_t).properties_filter(_t, properties).for_all(\n" - " [&](auto vertex_accessor) -> void {{\n" - " auto &labels = vertex_accessor.labels();\n" - " stream.write_record();\n" - " stream.write_list_header(1);\n" // TODO: figure out why - " stream.write_list_header(labels.size());\n" - " for (auto &label : labels) {{\n" - " stream.write(label.get().str());\n" - " }}\n" - " stream.chunk();\n" - " }}\n" - " );\n" - " stream.write_meta(\"rw\");\n" - " _t.commit();\n" - "}}"; - -const std::string write_all_edges = - "stream.write_field(\"{0}\");\n" - " iter::for_all(t.edge_access(), [&](auto edge) {{\n" - " if (edge.fill()) {{\n" - " stream.write_record();\n" - " stream.write_list_header(1);\n" - " stream.write(edge);\n" - " stream.chunk();\n" - " }}\n" - " }});\n" - " stream.write_meta(\"rw\");\n"; - -const std::string find_and_write_edges_by_type = - "auto &type = t.type_find_or_create(\"{1}\");\n" - " stream.write_field(\"{0}\");\n" - " type.index().for_range(t).for_all([&](auto edge) {{\n" - " stream.write_record();\n" - " stream.write_list_header(1);\n" - " stream.write(edge);\n" - " stream.chunk();\n" - " }});\n" - " stream.write_meta(\"rw\");\n"; - -const std::string count_vertices_for_one_label = - "size_t count = 0;\n" - "auto &label = t.label_find_or_create(\"{1}\");\n" - " label.index().for_range(t).for_all([&](auto vertex) {{\n" - " count++;\n" - " }});\n" - " stream.write_field(\"count({0})\");\n" - " stream.write_record();\n" - " stream.write_list_header(1);\n" - " stream.write(Int64(count));\n" - " stream.chunk();\n" - " stream.write_meta(\"r\");\n"; - -// TODO: vertices and edges -const std::string count = - "size_t count = 0;\n" - " t.vertex_access().fill().for_all(\n" - " [&](auto vertex) {{ ++count; }});\n" - " stream.write_field(\"count({0})\");\n" - " stream.write_record();\n" - " stream.write_list_header(1);\n" - " stream.write(Int64(count));\n" - " stream.chunk();\n" - " stream.write_meta(\"r\");\n"; - -const std::string return_true = "return true;"; - -const std::string todo = "// TODO: {}"; -const std::string print_properties = - "cout << \"{0}\" << endl;\n" - " cout_properties({0}.properties());"; -const std::string print_property = - "cout_property(\"{0}\", {0}.property(\"{1}\"));"; -} - -// DELETE -const std::string delete_all_detached_nodes = - "t.vertex_access().fill().isolated().for_all(\n" - " [&](auto a) {{ a.remove(); }});\n" - " stream.write_empty_fields();\n" - " stream.write_meta(\"w\");\n"; -const std::string delete_whole_graph = - "t.edge_access().fill().for_all(\n" - " [&](auto e) { e.remove(); }\n" - ");\n" + delete_all_detached_nodes; diff --git a/include/query/backend/cpp_old/cpp_generator.hpp b/include/query/backend/cpp_old/cpp_generator.hpp deleted file mode 100644 index 90e2c22c3..000000000 --- a/include/query/backend/cpp_old/cpp_generator.hpp +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include - -#include "query/backend/cpp_old/cypher_state.hpp" -#include "query/backend/cpp_old/handlers/all.hpp" -#include "query/backend/cpp_old/query_action.hpp" -#include "query/exception/cpp_code_generator.hpp" - -class CppGenerator -{ -public: - // !! multithread problem - // two threads shouldn't use this implementation at the same time - // !! TODO: REFACTOR - - CppGenerator() : unprocessed_index(0), processed_index(0) { setup(); } - - void state(CypherState state) { _cypher_state = state; } - - CypherState state() { return _cypher_state; } - - std::string generate() - { - std::string code = ""; - - for (uint64_t i = processed_index; i < unprocessed_index; ++i) - { - auto &action = actions.at(i); - auto query_action = action.first; - if (action_functions.find(query_action) == action_functions.end()) - throw CppCodeGeneratorException( - "Query Action Function is not defined"); - auto &action_data = action.second; - code += action_functions[query_action](_cypher_data, action_data); - ++processed_index; - } - - return code; - } - - QueryActionData &add_action(const QueryAction &query_action) - { - unprocessed_index++; - actions.push_back(std::make_pair(query_action, QueryActionData())); - return action_data(); - } - - QueryActionData &action_data() { return actions.back().second; } - - CypherStateData &cypher_data() { return _cypher_data; } - - void clear() - { - processed_index = 0; - unprocessed_index = 0; - actions.clear(); - } - -private: - // TODO: setup function is going to be called every time - // when object of this class is constructed (optimize this) - void setup() - { - action_functions[QueryAction::TransactionBegin] = - transaction_begin_action; - action_functions[QueryAction::Create] = create_query_action; - action_functions[QueryAction::Match] = match_query_action; - action_functions[QueryAction::Return] = return_query_action; - action_functions[QueryAction::Set] = set_query_action; - action_functions[QueryAction::Delete] = delete_query_action; - action_functions[QueryAction::TransactionCommit] = - transaction_commit_action; - } - - uint64_t unprocessed_index; - uint64_t processed_index; - std::vector> actions; - std::map> - action_functions; - CypherState _cypher_state; - CypherStateData _cypher_data; -}; diff --git a/include/query/backend/cpp_old/cypher.hpp b/include/query/backend/cpp_old/cypher.hpp deleted file mode 100644 index 869b06fe8..000000000 --- a/include/query/backend/cpp_old/cypher.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -// DEPRICATED! -#include "config/config.hpp" -#include "query/frontend/cypher/traverser.hpp" -#include "query/language/cypher/errors.hpp" -#include "template_engine/engine.hpp" -#include "utils/string/file.hpp" -#include "utils/type_discovery.hpp" - -template -class CypherBackend -{ -public: - CypherBackend() : logger(logging::log->logger("CypherBackend")) - { - // load template file - std::string template_path = CONFIG(config::TEMPLATE_CPP_PATH); - template_text = utils::read_text(fs::path(template_path)); - } - - template - // TODO: query and path shoud be distinct types - void generate_code(const Tree &tree, const std::string &query, - const uint64_t stripped_hash, const std::string &path) - { - CppTraverser cpp_traverser; - cpp_traverser.reset(); - - try { - tree.root->accept(cpp_traverser); - } catch (const CypherSemanticError &e) { - throw e; - } catch (const std::exception &e) { - logger.error("AST traversal error: {}", std::string(e.what())); - throw e; - } - - // save the code - std::string generated = template_engine::render( - template_text.str(), {{"class_name", "CPUPlan"}, - {"stripped_hash", std::to_string(stripped_hash)}, - {"query", query}, - {"stream", type_name().to_string()}, - {"code", cpp_traverser.code}}); - - logger.trace("generated code: {}", generated); - - utils::write(utils::Text(generated), fs::path(path)); - } - -protected: - Logger logger; - -private: - utils::Text template_text; -}; diff --git a/include/query/backend/cpp_old/cypher_state.hpp b/include/query/backend/cpp_old/cypher_state.hpp deleted file mode 100644 index e477f5f9e..000000000 --- a/include/query/backend/cpp_old/cypher_state.hpp +++ /dev/null @@ -1,215 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "query/backend/cpp_old/namer.hpp" -#include "query/exception/cpp_code_generator.hpp" -#include "storage/model/properties/flags.hpp" - -// main states that are used while ast is traversed -// in order to generate ActionSequence -enum class CypherState : uint8_t -{ - Undefined, - Match, - Where, - Create, - Set, - Return, - Delete -}; - -enum class EntityStatus : uint8_t -{ - None, - Matched, - Created -}; - -enum class EntityType : uint8_t -{ - None, - Node, - Relationship -}; - -// where OR how entity can be found -enum class EntitySource : uint8_t -{ - None, - InternalId, - LabelIndex, - TypeIndex, - MainStorage -}; - -// TODO: reduce copying -class CypherStateData -{ -public: - using tags_type = std::vector; - using properties_type = std::map; - -private: - std::map entity_status; - std::map entity_type; - std::map entity_source; - std::map entity_tags; - std::map entity_properties; - -public: - bool exist(const std::string &name) const - { - return entity_status.find(name) != entity_status.end(); - } - - EntityStatus status(const std::string &name) - { - if (entity_status.find(name) == entity_status.end()) - return EntityStatus::None; - - return entity_status.at(name); - } - - EntityType type(const std::string &name) const - { - if (entity_type.find(name) == entity_type.end()) - return EntityType::None; - - return entity_type.at(name); - } - - EntitySource source(const std::string &name) const - { - if (entity_source.find(name) == entity_source.end()) - return EntitySource::None; - return entity_source.at(name); - } - - const std::map &all_typed_enteties() - { - return entity_type; - } - - void node_matched(const std::string &name) - { - entity_type[name] = EntityType::Node; - entity_status[name] = EntityStatus::Matched; - } - - void node_created(const std::string &name) - { - entity_type[name] = EntityType::Node; - entity_status[name] = EntityStatus::Created; - } - - void relationship_matched(const std::string &name) - { - entity_type[name] = EntityType::Relationship; - entity_status[name] = EntityStatus::Matched; - } - - void relationship_created(const std::string &name) - { - entity_type[name] = EntityType::Relationship; - entity_status[name] = EntityStatus::Created; - } - - void source(const std::string &name, EntitySource source) - { - entity_source[name] = source; - } - - // entity tags - auto tags(const std::string &name) const - { - if (entity_tags.find(name) == entity_tags.end()) - throw CppCodeGeneratorException("No tags for specified entity"); - return entity_tags.at(name); - } - - void tags(const std::string &name, tags_type tags) - { - entity_tags[name] = tags; - } - - void tag(const std::string &name, const std::string &new_tag) - { - if (entity_tags.find(name) == entity_tags.end()) - { - entity_tags[name] = std::vector{}; - } - entity_tags[name].emplace_back(new_tag); - } - - auto has_properties(const std::string& name) - { - return entity_properties.find(name) != entity_properties.end(); - } - - // entity properties - auto properties(const std::string &name) const - { - if (entity_properties.find(name) == entity_properties.end()) - throw CppCodeGeneratorException( - "No properties for specified entity: " + name); - return entity_properties.at(name); - } - - void properties(const std::string &name, properties_type properties) - { - entity_properties[name] = properties; - } - - void index(const std::string &entity, const std::string &property, - int64_t index) - { - if (entity_properties.find(entity) == entity_properties.end()) - { - entity_properties[entity] = properties_type{}; - } - entity_properties[entity][property] = index; - } - - auto index(const std::string &entity, const std::string &property_name) - { - if (entity_properties.find(entity) == entity_properties.end()) - throw CppCodeGeneratorException( - "No properties for specified entity"); - - auto properties = entity_properties.at(entity); - - if (properties.find(property_name) == properties.end()) - throw CppCodeGeneratorException( - "No property for specified property name"); - - return properties[property_name]; - } - - using iter_t = properties_type::iterator; - auto print_indices(const std::string &name, - const std::string &variable_name = "indices") - { - // TODO: find out smarter way it's not hard - std::string print = - "std::map " + variable_name + " = {"; - - auto indices = entity_properties.at(name); - size_t i = 0; - iter_t it = indices.begin(); - - for (; it != indices.end(); ++it, ++i) - { - print += - "{\"" + it->first + "\"," + std::to_string(it->second) + "}"; - if (i < indices.size() - 1) print += ","; - } - - print += "};"; - - return print; - } -}; diff --git a/include/query/backend/cpp_old/entity_search.hpp b/include/query/backend/cpp_old/entity_search.hpp deleted file mode 100644 index 30f06ea62..000000000 --- a/include/query/backend/cpp_old/entity_search.hpp +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#include -#include -#include - -// TODO: remove -#include "utils/underlying_cast.hpp" -#include - -// entities are nodes or relationship - -namespace entity_search -{ -// returns maximum value for given template argument (for give type) -template -constexpr T max() -{ - return std::numeric_limits::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 type_cost = 1000; -constexpr cost_t max_cost = max(); - -template -class SearchCost -{ -public: - enum class SearchPlace : int - { - internal_id, - label_index, - type_index, - property_index, - main_storage - }; - - using costs_t = std::map; - using cost_pair_t = std::pair; - - SearchCost() - { - costs[SearchPlace::internal_id] = max(); - costs[SearchPlace::label_index] = max(); - costs[SearchPlace::type_index] = max(); - costs[SearchPlace::property_index] = max(); - costs[SearchPlace::main_storage] = max(); - } - - 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; - -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_type_index = search_cost_t::SearchPlace::type_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 - { - if (_search_costs.find(entity) == _search_costs.end()) - return entity_search::search_cost_t::SearchPlace::main_storage; - - return _search_costs.at(entity).min(); - } - -private: - std::map _search_costs; -}; diff --git a/include/query/backend/cpp_old/handlers/all.hpp b/include/query/backend/cpp_old/handlers/all.hpp deleted file mode 100644 index f7d54eba2..000000000 --- a/include/query/backend/cpp_old/handlers/all.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -// TODO: refactor build state machine instead of ifs - -#include "query/backend/cpp_old/handlers/create.hpp" -#include "query/backend/cpp_old/handlers/delete.hpp" -#include "query/backend/cpp_old/handlers/match.hpp" -#include "query/backend/cpp_old/handlers/return.hpp" -#include "query/backend/cpp_old/handlers/set.hpp" -#include "query/backend/cpp_old/handlers/transaction_begin.hpp" -#include "query/backend/cpp_old/handlers/transaction_commit.hpp" diff --git a/include/query/backend/cpp_old/handlers/create.hpp b/include/query/backend/cpp_old/handlers/create.hpp deleted file mode 100644 index 746792925..000000000 --- a/include/query/backend/cpp_old/handlers/create.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "includes.hpp" - -auto create_query_action = - [](CypherStateData &cypher_data, - const QueryActionData &action_data) -> std::string { - - std::string code = ""; - - for (auto const &kv : action_data.actions) { - - if (kv.second == ClauseAction::CreateNode) { - // create node - auto &name = kv.first; - code += code_line(code::create_vertex, name); - - // update properties - code += update_properties(cypher_data, action_data, name); - - // update labels - auto entity_data = action_data.get_entity_property(name); - for (auto &label : entity_data.tags) { - code += code_line(code::create_label, label); - code += code_line(code::add_label, name, label); - } - - // mark node as created - cypher_data.node_created(name); - } - - if (kv.second == ClauseAction::CreateRelationship) { - auto name = kv.first; - - // find start and end node - auto &relationships_data = action_data.relationship_data; - if (relationships_data.find(name) == relationships_data.end()) - throw CppCodeGeneratorException("Unable to find data for: " + - name); - auto &relationship_data = relationships_data.at(name); - auto left_node = relationship_data.nodes.first; - auto right_node = relationship_data.nodes.second; - - // TODO: If node isn't already matched or created it has to be - // created here. It is not possible for now. - if (cypher_data.status(left_node) != EntityStatus::Matched) { - throw CypherSemanticError("Create Relationship: node " + - left_node + " can't be found"); - } - if (cypher_data.status(right_node) != EntityStatus::Matched) { - throw CypherSemanticError("Create Relationship: node " + - right_node + " can't be found"); - } - - // create relationship - code += code_line(code::create_edge, name, left_node, right_node); - - // update properties - code += update_properties(cypher_data, action_data, name); - - // update tag - auto entity_data = action_data.get_entity_property(name); - for (auto &tag : entity_data.tags) { - code += code_line(code::find_type, tag); - code += code_line(code::set_type, name, tag); - } - - // mark relationship as created - cypher_data.relationship_created(name); - } - } - - return code; -}; diff --git a/include/query/backend/cpp_old/handlers/delete.hpp b/include/query/backend/cpp_old/handlers/delete.hpp deleted file mode 100644 index f8aec6e1f..000000000 --- a/include/query/backend/cpp_old/handlers/delete.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "includes.hpp" - -auto delete_query_action = - [](CypherStateData &cypher_data, - const QueryActionData &action_data) -> std::string { - - std::string code = ""; - - // TODO: don't delete the whole graph - - for (auto const &kv : action_data.actions) - { - auto entity = kv.first; - - if (kv.second == ClauseAction::DeleteNode && action_data.is_detach) - { - code += code_line(delete_whole_graph); - } - - if (kv.second == ClauseAction::DeleteNode && !action_data.is_detach) - { - code += code_line(delete_all_detached_nodes); - } - - if (kv.second == ClauseAction::DeleteRelationship) - { - code += code_line("// DELETE Relationship({})", entity); - } - } - - return code; -}; diff --git a/include/query/backend/cpp_old/handlers/includes.hpp b/include/query/backend/cpp_old/handlers/includes.hpp deleted file mode 100644 index eea8a96d7..000000000 --- a/include/query/backend/cpp_old/handlers/includes.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "query/backend/cpp_old/cypher_state.hpp" -#include "query/backend/cpp_old/namer.hpp" -#include "query/backend/cpp_old/query_action_data.hpp" -#include "query/backend/cpp_old/code.hpp" -#include "query/util.hpp" -#include "query/exception/cpp_code_generator.hpp" -#include "query/language/cypher/errors.hpp" - -using ParameterIndexKey::Type::InternalId; -using Direction = RelationshipData::Direction; - -namespace -{ - -auto update_properties(const CypherStateData &cypher_state, - const QueryActionData &action_data, - const std::string &name) -{ - std::string code = ""; - - auto entity_data = action_data.get_entity_property(name); - for (auto &property : entity_data.properties) { - auto index = - action_data.parameter_index.at(ParameterIndexKey(name, property)); - auto tmp_name = name::unique(); - // TODO: ERROR! why - code += code_line((cypher_state.type(name) == EntityType::Node - ? code::vertex_property_key - : code::edge_property_key), - tmp_name, property, index); - code += code_line(code::set_property, name, tmp_name, index); - } - - return code; -} -} diff --git a/include/query/backend/cpp_old/handlers/match.hpp b/include/query/backend/cpp_old/handlers/match.hpp deleted file mode 100644 index e47318b42..000000000 --- a/include/query/backend/cpp_old/handlers/match.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include "includes.hpp" - -namespace -{ - -bool already_matched(CypherStateData &cypher_data, const std::string &name, - EntityType type) -{ - if (cypher_data.type(name) == type && - cypher_data.status(name) == EntityStatus::Matched) - return true; - else - return false; -} - -auto fetch_internal_index(const QueryActionData &action_data, - const std::string &name) -{ - return action_data.parameter_index.at(ParameterIndexKey(InternalId, name)); -} -} - -auto match_query_action = - [](CypherStateData &cypher_data, - const QueryActionData &action_data) -> std::string { - - std::string code = ""; - - for (auto const &kv : action_data.actions) { - - auto name = kv.first; - - // TODO: duplicated code -> BIG PROBLEM - // find node - if (kv.second == ClauseAction::MatchNode) { - if (already_matched(cypher_data, name, EntityType::Node)) - continue; - cypher_data.node_matched(name); - auto place = action_data.csm.min(name); - if (place == entity_search::search_internal_id) { - auto index = fetch_internal_index(action_data, name); - code += code_line(code::match_vertex_by_id, name, index); - cypher_data.source(name, EntitySource::InternalId); - } - if (place == entity_search::search_main_storage) { - cypher_data.source(name, EntitySource::MainStorage); - } - if (place == entity_search::search_label_index) { - if (action_data.entity_data.at(name).tags.size() > 1) { - throw CypherSemanticError("Multiple label match (currently NOT supported)"); - } - cypher_data.source(name, EntitySource::LabelIndex); - cypher_data.tags(name, action_data.entity_data.at(name).tags); - } - } - - // find relationship - if (kv.second == ClauseAction::MatchRelationship) { - if (already_matched(cypher_data, name, EntityType::Relationship)) - continue; - cypher_data.relationship_matched(name); - auto place = action_data.csm.min(name); - if (place == entity_search::search_internal_id) { - auto index = fetch_internal_index(action_data, name); - code += code_line(code::match_edge_by_id, name, index); - cypher_data.source(name, EntitySource::InternalId); - } - if (place == entity_search::search_main_storage) { - cypher_data.source(name, EntitySource::MainStorage); - } - if (place == entity_search::search_type_index) { - if (action_data.entity_data.at(name).tags.size() > 1) { - throw CypherSemanticError("Multiple type match (currently NOT supported)"); - } - cypher_data.source(name, EntitySource::TypeIndex); - cypher_data.tags(name, action_data.entity_data.at(name).tags); - } - } - } - - return code; -}; diff --git a/include/query/backend/cpp_old/handlers/return.hpp b/include/query/backend/cpp_old/handlers/return.hpp deleted file mode 100644 index 845388a03..000000000 --- a/include/query/backend/cpp_old/handlers/return.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once - -#include "includes.hpp" - -// TODO: total fuck up; replace this with IR + Backend - -auto return_query_action = - [](CypherStateData &cypher_data, - const QueryActionData &action_data) -> std::string { - - std::string code = ""; - - const auto &elements = action_data.return_elements; - code += code_line("// number of elements {}", elements.size()); - - for (const auto &element : elements) - { - auto &entity = element.entity; - - if (!cypher_data.exist(entity)) - throw CypherSemanticError( - fmt::format("{} couldn't be found (RETURN clause).", entity)); - - if (element.is_entity_only()) - { - // if the node has just recently been created on can be found - // with the internal id then it can be sent to the client - if (cypher_data.status(entity) == EntityStatus::Created || - (cypher_data.source(entity) == EntitySource::InternalId && - cypher_data.status(entity) == EntityStatus::Matched)) - { - code += code_line(code::write_entity, entity); - } - // the client has to receive all elements from the main storage - if (cypher_data.source(entity) == EntitySource::MainStorage) - { - if (cypher_data.type(entity) == EntityType::Node) - code += code_line(code::write_all_vertices, entity); - else if (cypher_data.type(entity) == EntityType::Relationship) - code += code_line(code::write_all_edges, entity); - } - // the client will receive entities from label index - if (cypher_data.status(entity) != EntityStatus::Created && - cypher_data.source(entity) == EntitySource::LabelIndex) - { - if (cypher_data.tags(entity).size() == 0) - throw CppCodeGeneratorException("node has no labels"); - - // node and no other property - if (cypher_data.type(entity) == EntityType::Node) - { - auto label = cypher_data.tags(entity).at(0); - if (cypher_data.has_properties(entity)) - { - code += code_line( - code:: - find_and_write_vertices_by_label_and_properties, - cypher_data.print_indices(entity), label, entity); - } - else - { - code += - code_line(code::find_and_write_vertices_by_label, - entity, label); - } - } - } - - if (cypher_data.source(entity) == EntitySource::TypeIndex) - { - if (cypher_data.type(entity) == EntityType::Relationship) - { - if (cypher_data.tags(entity).size() == 0) - throw CppCodeGeneratorException("edge has no tag"); - auto type = cypher_data.tags(entity).at(0); - code += code_line(code::find_and_write_edges_by_type, - entity, type); - } - } - } - else if (element.is_projection()) - { - code += code_line("// TODO: implement projection"); - // auto &property = element.property; - // code += code_line(code::print_property, entity, property); - } - } - - // return functions - for (auto const &kv : action_data.actions) - { - auto name = kv.first; - - if (kv.second == ClauseAction::ReturnCount) - { - if (cypher_data.source(name) == EntitySource::MainStorage) - { - code += code_line(code::count, name); - } - - if (cypher_data.source(name) == EntitySource::LabelIndex) - { - auto tags = cypher_data.tags(name); - if (tags.size() == 1) - { - auto label = tags.at(0); - code += code_line(code::count_vertices_for_one_label, name, - label); - } - // TODO: do for more, isn't easy because of - // multiple iterators, but we have iterator infrastructure - // to do that - } - } - if (kv.second == ClauseAction::ReturnLabels) - { - if (cypher_data.source(name) == EntitySource::LabelIndex) - { - auto tags = cypher_data.tags(name); - if (tags.size() == 1) - { - auto label = tags.at(0); - code += code_line(code::return_labels, - cypher_data.print_indices(name), label, - name); - } - } - } - } - - return code; -}; diff --git a/include/query/backend/cpp_old/handlers/set.hpp b/include/query/backend/cpp_old/handlers/set.hpp deleted file mode 100644 index 970eb0917..000000000 --- a/include/query/backend/cpp_old/handlers/set.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include "includes.hpp" - -auto set_query_action = [](CypherStateData &cypher_data, - const QueryActionData &action_data) -> std::string { - - std::string code = ""; - - for (auto const &kv : action_data.actions) - { - auto name = kv.first; - - if (kv.second == ClauseAction::UpdateNode && - cypher_data.status(name) == EntityStatus::Matched && - cypher_data.source(name) == EntitySource::InternalId && - cypher_data.type(name) == EntityType::Node) - { - code += update_properties(cypher_data, action_data, name); - } - - if (kv.second == ClauseAction::UpdateNode && - cypher_data.status(name) == EntityStatus::Matched && - cypher_data.source(name) == EntitySource::LabelIndex && - cypher_data.type(name) == EntityType::Node) - { - auto entity_data = action_data.get_entity_property(name); - for (auto &property : entity_data.properties) - { - auto index = action_data.parameter_index.at( - ParameterIndexKey(name, property)); - auto tmp_name = name::unique(); - auto label = cypher_data.tags(name).at(0); - // TODO: move this code inside the loop (in generated code) - code += code_line(code::set_vertex_element, - cypher_data.print_indices(name), label, - property, index); - } - } - - if (kv.second == ClauseAction::UpdateRelationship && - cypher_data.status(name) == EntityStatus::Matched && - cypher_data.type(name) == EntityType::Relationship) - { - code += update_properties(cypher_data, action_data, name); - } - } - - for (auto const &set_entity_labels : action_data.label_set_elements) - { - auto &entity = set_entity_labels.entity; - - if (cypher_data.status(entity) == EntityStatus::Matched && - cypher_data.source(entity) == EntitySource::LabelIndex) - { - auto label = cypher_data.tags(entity).at(0); - if (cypher_data.has_properties(entity)) - { - code += code_line(code::set_labels_start, - cypher_data.print_indices(entity), label); - auto labels = set_entity_labels.labels; - for (auto const &set_label : labels) - { - code += code_line(code::set_label, set_label); - } - code += code_line(code::set_labels_end); - } - } - } - - return code; -}; diff --git a/include/query/backend/cpp_old/handlers/transaction_begin.hpp b/include/query/backend/cpp_old/handlers/transaction_begin.hpp deleted file mode 100644 index 1030a766c..000000000 --- a/include/query/backend/cpp_old/handlers/transaction_begin.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "includes.hpp" - -auto transaction_begin_action = [](CypherStateData &, - const QueryActionData &) -> std::string { - return code_line(code::transaction_begin); -}; diff --git a/include/query/backend/cpp_old/handlers/transaction_commit.hpp b/include/query/backend/cpp_old/handlers/transaction_commit.hpp deleted file mode 100644 index 71998a8de..000000000 --- a/include/query/backend/cpp_old/handlers/transaction_commit.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "includes.hpp" - -auto transaction_commit_action = [](CypherStateData &, - const QueryActionData &) -> std::string { - return code_line(code::transaction_commit) + - code_line(code::return_true); -}; diff --git a/include/query/backend/cpp_old/namer.hpp b/include/query/backend/cpp_old/namer.hpp deleted file mode 100644 index 37425223e..000000000 --- a/include/query/backend/cpp_old/namer.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "storage/model/properties/flags.hpp" - -// This namespace names stuff -namespace -{ -namespace name -{ - -std::string variable_property_key(const std::string &property_name, Type type) -{ - return "prop_" + property_name + "_" + type.to_str(); -} - -std::string unique() { return "unique_" + std::to_string(std::rand()); } -} -} diff --git a/include/query/backend/cpp_old/query_action.hpp b/include/query/backend/cpp_old/query_action.hpp deleted file mode 100644 index 3f130d304..000000000 --- a/include/query/backend/cpp_old/query_action.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -// any entity (node or relationship) inside cypher query has an action -// that is associated with that entity -enum class QueryAction : uint32_t -{ - TransactionBegin, - Create, - Match, - Set, - Return, - Delete, - TransactionCommit -}; diff --git a/include/query/backend/cpp_old/query_action_data.hpp b/include/query/backend/cpp_old/query_action_data.hpp deleted file mode 100644 index faa7db64a..000000000 --- a/include/query/backend/cpp_old/query_action_data.hpp +++ /dev/null @@ -1,187 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "query/backend/cpp_old/clause_action.hpp" -#include "query/backend/cpp_old/entity_search.hpp" -#include "query/exception/cpp_code_generator.hpp" -#include "storage/model/properties/all.hpp" -#include "utils/assert.hpp" -#include "utils/underlying_cast.hpp" - -// used for storing data related to an entity (node or relationship) -// data can be: -// * tags: labels or type -// * props: property name, property value -struct EntityData -{ - std::vector tags; - std::vector properties; - - void add_tag(const std::string &tag) { tags.push_back(tag); } - void add_property(const std::string &property) - { - properties.push_back(property); - } -}; - -// used for storing indices of parameters (parameters are stripped before -// compiling process into the array), so somehow the compiler has to know -// how to find appropriate parameter during the compile process -// -// parameter index key can be related to: -// * internal_id and entity_name, e.g.: -// ID(n)=35445 -> ID(n)=2 -> index[PropertyIndexKey(Type::InternalId, n)] = -// 2 -// * entity_name and entity_property, e.g.: -// n.name = "test" -> n.name = 3 -> index[PropertyIndexKey(entity_name, -// entity_property)] = 3 -struct ParameterIndexKey -{ - enum class Type : uint8_t - { - InternalId, - Projection - }; - - ParameterIndexKey(Type type, const std::string &entity_name) - : type(type), entity_name(entity_name) - { - } - - ParameterIndexKey(const std::string &entity_name, - const std::string &entity_property) - : type(Type::Projection), entity_name(entity_name), - entity_property(entity_property) - { - } - - const Type type; - const std::string entity_name; - const std::string entity_property; - - bool operator<(const ParameterIndexKey &rhs) const - { - runtime_assert(type == rhs.type, - "ParameterIndexKey types should be the same"); - - if (type == Type::InternalId) return entity_name < rhs.entity_name; - - if (entity_name == rhs.entity_name) - return entity_property < rhs.entity_property; - - return entity_name < rhs.entity_name; - } -}; - -struct RelationshipData -{ - enum class Direction - { - Left, - Right - }; - - using nodes_t = std::pair; - - RelationshipData(nodes_t nodes, Direction direction) - : nodes(nodes), direction(direction) - { - } - - std::pair nodes; - Direction direction; -}; - -struct ReturnElement -{ - ReturnElement(const std::string &entity) : entity(entity) {} - ReturnElement(const std::string &entity, const std::string &property) - : entity(entity), property(property){}; - - std::string entity; - std::string property; - - bool has_entity() const { return !entity.empty(); } - bool has_property() const { return !property.empty(); } - - bool is_entity_only() const { return has_entity() && !has_property(); } - bool is_projection() const { return has_entity() && has_property(); } -}; - -struct LabelSetElement -{ - std::string entity; - std::vector labels; - - LabelSetElement() = default; - LabelSetElement(const LabelSetElement&) = default; - LabelSetElement(LabelSetElement&&) = default; - - void clear() - { - entity.clear(); - labels.clear(); - } -}; - -struct QueryActionData -{ - std::map parameter_index; - std::map actions; - std::map entity_data; - std::map relationship_data; - std::vector return_elements; - std::vector label_set_elements; - bool is_detach; - CypherStateMachine csm; - - QueryActionData() = default; - QueryActionData(QueryActionData &&other) = default; - - void create_entity(const std::string &entity) - { - if (entity_data.find(entity) == entity_data.end()) - entity_data.emplace(entity, EntityData()); - } - - void add_entity_tag(const std::string &entity, const std::string &tag) - { - create_entity(entity); - entity_data.at(entity).add_tag(tag); - } - - void add_entitiy_property(const std::string &entity, - const std::string &property) - { - create_entity(entity); - entity_data.at(entity).add_property(property); - } - - // TODO: refactor name - auto get_entity_property(const std::string &entity) const - { - if (entity_data.find(entity) == entity_data.end()) - throw CppCodeGeneratorException("Entity " + entity + " doesn't exist"); - - return entity_data.at(entity); - } - - auto get_tags(const std::string& entity) const - { - if (entity_data.find(entity) == entity_data.end()) - throw CppCodeGeneratorException("Entity " + entity + "doesn't exist"); - - return entity_data.at(entity).tags; - } - - void print() const - { - for (auto const &action : actions) { - std::cout << action.first << " " << underlying_cast(action.second) - << std::endl; - } - } -}; diff --git a/include/query/backend/cpp_old/structures.hpp b/include/query/backend/cpp_old/structures.hpp deleted file mode 100644 index f24247b94..000000000 --- a/include/query/backend/cpp_old/structures.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#include "utils/assert.hpp" - -template -class Vector : public std::vector -{ -public: - using pair = std::pair; - - pair last_two() - { - runtime_assert(this->size() > 1, "Array size shoud be bigger than 1"); - - return std::make_pair(*(this->end() - 1), *(this->end() - 2)); - } -}; diff --git a/include/query/engine.hpp b/include/query/engine.hpp index ffd223583..cd707b5a4 100644 --- a/include/query/engine.hpp +++ b/include/query/engine.hpp @@ -3,11 +3,13 @@ #include namespace fs = std::experimental::filesystem; +#include "utils/exceptions/not_yet_implemented.hpp" +#include "config/config.hpp" + #include "database/graph_db.hpp" #include "logging/loggable.hpp" #include "query/exception/query_engine.hpp" #include "query/plan_compiler.hpp" -#include "query/plan_generator.hpp" #include "query/plan_interface.hpp" #include "query/preprocessor.hpp" #include "utils/dynamic_lib.hpp" @@ -15,8 +17,6 @@ namespace fs = std::experimental::filesystem; // TODO: replace with openCypher and Antlr #include "query/frontend/cypher.hpp" -// TODO: depricated -#include "query/backend/cpp_old/cypher.hpp" /** * Responsible for query execution. @@ -34,7 +34,6 @@ class QueryEngine : public Loggable { private: using QueryPlanLib = DynamicLib>; - using HashT = QueryPreprocessor::HashT; public: QueryEngine() : Loggable("QueryEngine") {} @@ -149,7 +148,7 @@ private: * * @return runnable query plan */ - auto LoadCypher(const StrippedQuery &stripped) + auto LoadCypher(const StrippedQuery &stripped) { auto plans_accessor = query_plans.access(); @@ -169,8 +168,9 @@ private: // generate query plan auto generated_path = fs::path(CONFIG(config::COMPILE_PATH) + std::to_string(stripped.hash) + ".cpp"); - plan_generator.generate_plan(stripped.query, stripped.hash, - generated_path); + // TODO implement CPP generator + // plan_generator.generate_plan(stripped.query, stripped.hash, generated_path); + throw NotYetImplemented(); return LoadCpp(generated_path, stripped.hash); } @@ -183,7 +183,7 @@ private: * * @return runnable query plan */ - auto LoadCpp(const fs::path &path_cpp, const QueryPreprocessor::HashT hash) + auto LoadCpp(const fs::path &path_cpp, const HashType hash) { auto plans_accessor = query_plans.access(); @@ -216,8 +216,7 @@ private: } QueryPreprocessor preprocessor; - PlanGenerator> plan_generator; PlanCompiler plan_compiler; - ConcurrentMap> + ConcurrentMap> query_plans; }; diff --git a/include/query/plan_generator.hpp b/include/query/plan_generator.hpp deleted file mode 100644 index 90201821a..000000000 --- a/include/query/plan_generator.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "config/config.hpp" -#include "query/language/cypher/ast/ast.hpp" -#include "query/language/cypher/compiler.hpp" -#include "logging/loggable.hpp" -#include "template_engine/engine.hpp" -#include "utils/string/file.hpp" -#include "utils/type_discovery.hpp" - -template -class PlanGenerator : public Loggable -{ -public: - PlanGenerator() : Loggable("PlanGenerator") {} - - void generate_plan(const std::string &query, const uint64_t stripped_hash, - const std::string &path) - { - // TODO: multithread environment TEST - // multiple connections for the same query at the beginning - auto ir = frontend.generate_ir(query); - backend.generate_code(ir, query, stripped_hash, path); - } - -private: - Frontend frontend; - Backend backend; -}; diff --git a/include/query/plan_interface.hpp b/include/query/plan_interface.hpp index c80163db0..04feccd23 100644 --- a/include/query/plan_interface.hpp +++ b/include/query/plan_interface.hpp @@ -25,7 +25,7 @@ public: * * @return bool status after execution (success OR fail) */ - virtual bool run(GraphDbAccessor &db_accessor, const PlanArgsT &args, Stream &stream) = 0; + virtual bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args, Stream &stream) = 0; /** * Virtual destructor in base class. diff --git a/include/query/preprocessor.hpp b/include/query/preprocessor.hpp index 0646f77c3..1b3d9162c 100644 --- a/include/query/preprocessor.hpp +++ b/include/query/preprocessor.hpp @@ -28,8 +28,6 @@ private: using QueryStripperT = QueryStripper; public: - using HashT = QueryStripperT::HashT; - QueryPreprocessor() : Loggable("QueryPreprocessor"), stripper(make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL)) { diff --git a/include/query/stripped.hpp b/include/query/stripped.hpp index 146af6123..aaee243a1 100644 --- a/include/query/stripped.hpp +++ b/include/query/stripped.hpp @@ -1,28 +1,19 @@ #pragma once -#include "storage/model/properties/property.hpp" - -/* - * Query Plan Arguments Type - */ -using PlanArgsT = std::vector; +#include "storage/typed_value_store.hpp" +#include "utils/hashing/fnv.hpp" /* * StrippedQuery contains: * * stripped query * * plan arguments stripped from query * * hash of stripped query -* -* @tparam THash a type of query hash */ -template -struct StrippedQuery -{ - StrippedQuery(const std::string &&query, PlanArgsT &&arguments, THash hash) +struct StrippedQuery { + + StrippedQuery(const std::string &&query, TypedValueStore<> &&arguments, HashType hash) : query(std::forward(query)), - arguments(std::forward(arguments)), hash(hash) - { - } + arguments(std::forward>(arguments)), hash(hash) {} /** * Copy constructor is deleted because we don't want to make unecessary @@ -46,10 +37,10 @@ struct StrippedQuery /** * Stripped arguments */ - const PlanArgsT arguments; + const TypedValueStore<> arguments; /** * Hash based on stripped query. */ - const THash hash; + const HashType hash; }; diff --git a/include/query/stripper.hpp b/include/query/stripper.hpp index c7b9a817c..79a085343 100644 --- a/include/query/stripper.hpp +++ b/include/query/stripper.hpp @@ -100,9 +100,9 @@ public: } // TODO: hash function should be a template parameter - auto hash = fnv(stripped_query); - return StrippedQuery(std::move(stripped_query), - std::move(stripped_arguments), hash); + HashType hash = fnv(stripped_query); + return StrippedQuery(std::move(stripped_query), + std::move(stripped_arguments), hash); } private: diff --git a/include/storage/edge.hpp b/include/storage/edge.hpp index 5a56a922a..05d6b4f40 100644 --- a/include/storage/edge.hpp +++ b/include/storage/edge.hpp @@ -10,8 +10,14 @@ class Vertex; class Edge : public mvcc::Record { public: - mvcc::VersionList* from_; - mvcc::VersionList* to_; + + Edge(mvcc::VersionList& from, + mvcc::VersionList& to, + GraphDb::EdgeType edge_type) + : from_(from), to_(to), edge_type_(edge_type) {} + + mvcc::VersionList& from_; + mvcc::VersionList& to_; GraphDb::EdgeType edge_type_; TypedValueStore properties_; }; diff --git a/include/storage/edge_accessor.hpp b/include/storage/edge_accessor.hpp index 6d6640728..0a4797e9c 100644 --- a/include/storage/edge_accessor.hpp +++ b/include/storage/edge_accessor.hpp @@ -20,5 +20,5 @@ public: VertexAccessor to() const; - void remove(); +// void remove(); }; diff --git a/include/storage/model/typed_value.hpp b/include/storage/model/typed_value.hpp deleted file mode 100644 index 4a0aaf296..000000000 --- a/include/storage/model/typed_value.hpp +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "utils/underlying_cast.hpp" -#include "utils/total_ordering.hpp" -#include "utils/exceptions/basic_exception.hpp" - -/** - * Encapsulation of a value and it's type encapsulated in a class that has no - * compiled-time info about that type. - * - * Values can be of a number of predefined types that are enumerated in - * TypedValue::Type. Each such type corresponds to exactly one C++ type. - */ -class TypedValue : public TotalOrdering { - -private: - /** Private default constructor, makes Null */ - TypedValue() : type_(Type::Null) {} - -public: - - /** A value type. Each type corresponds to exactly one C++ type */ - enum class Type : unsigned { - Null, - String, - Bool, - Int, - Float - }; - - // single static reference to Null, used whenever Null should be returned - static const TypedValue Null; - - // constructors for primitive types - TypedValue(bool value) : type_(Type::Bool) { bool_v = value; } - TypedValue(int value) : type_(Type::Int) { int_v = value; } - TypedValue(float value) : type_(Type::Float) { float_v = value; } - - /// constructors for non-primitive types (shared pointers) - TypedValue(const std::string &value) : type_(Type::String) { - new (&string_v) std::shared_ptr(new std::string(value)); - } - TypedValue(const char* value) : type_(Type::String) { - new (&string_v) std::shared_ptr(new std::string(value)); - } - - // assignment ops - TypedValue& operator=(TypedValue& other); - TypedValue& operator=(TypedValue&& other); - - TypedValue(const TypedValue& other); - ~TypedValue(); - - /** - * Returns the value of the property as given type T. - * The behavior of this function is undefined if - * T does not correspond to this property's type_. - * - * @tparam T Type to interpret the value as. - * @return The value as type T. - */ - template T Value() const; - - friend std::ostream& operator<<(std::ostream& stream, const TypedValue& prop); - - /** - * The Type of property. - */ - const Type type_; - -private: - // storage for the value of the property - union { - bool bool_v; - int int_v; - float float_v; - std::shared_ptr string_v; - }; -}; - -/** - * An exception raised by the TypedValue system. Typically when - * trying to perform operations (such as addition) on TypedValues - * of incompatible Types. - */ -class TypedValueException : public BasicException { - -public: - using ::BasicException::BasicException; -}; - -// comparison operators -// they return TypedValue because Null can be returned -TypedValue operator==(const TypedValue& a, const TypedValue& b); -TypedValue operator<(const TypedValue& a, const TypedValue& b); -TypedValue operator!(const TypedValue& a); - -// arithmetic operators -TypedValue operator-(const TypedValue& a); -TypedValue operator+(const TypedValue& a, const TypedValue& b); -TypedValue operator-(const TypedValue& a, const TypedValue& b); -TypedValue operator/(const TypedValue& a, const TypedValue& b); -TypedValue operator*(const TypedValue& a, const TypedValue& b); -TypedValue operator%(const TypedValue& a, const TypedValue& b); - -// binary bool operators -TypedValue operator&&(const TypedValue& a, const TypedValue& b); -TypedValue operator||(const TypedValue& a, const TypedValue& b); - -// stream output -std::ostream &operator<<(std::ostream &os, const TypedValue::Type type); diff --git a/include/storage/model/typed_value_store.hpp b/include/storage/model/typed_value_store.hpp deleted file mode 100644 index efaf00be7..000000000 --- a/include/storage/model/typed_value_store.hpp +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include -#include - -#include "typed_value.hpp" - -/** - * A collection of properties accessed in a map-like way - * using a key of type Properties::TKey. - * - * The underlying implementation is not necessarily std::map. - */ -class TypedValueStore { -public: - using sptr = std::shared_ptr; - - /** The type of key used to get and set properties */ - using TKey = uint32_t; - - /** - * Returns a TypedValue (by reference) at the given key. - * If the key does not exist, the Null property is returned. - * - * This is NOT thread-safe, the reference might not be valid - * when used in a multithreaded scenario. - * - * @param key The key for which a TypedValue is sought. - * @return See above. - */ - const TypedValue &at(const TKey &key) const; - - /** - * Sets the value for the given key. A new TypedValue instance - * is created for the given value (which is of raw type). - * - * @tparam TValue Type of value. It must be one of the - * predefined possible TypedValue values (bool, string, int...) - * @param key The key for which the property is set. The previous - * value at the same key (if there was one) is replaced. - * @param value The value to set. - */ - template - void set(const TKey &key, const TValue &value); - - /** - * Set overriding for character constants. Forces conversion - * to std::string, otherwise templating might cast the pointer - * to something else (bool) and mess things up. - * - * @param key The key for which the property is set. The previous - * value at the same key (if there was one) is replaced. - * @param value The value to set. - */ - void set(const TKey &key, const char *value); - - /** - * Removes the TypedValue for the given key. - * - * @param key The key for which to remove the property. - * @return The number of removed properties (0 or 1). - */ - size_t erase(const TKey &key); - - /** - * @return The number of Properties in this collection. - */ - size_t size() const; - - - /** - * Accepts two functions. - * - * @param handler Called for each TypedValue in this collection. - * @param finish Called once in the end. - */ - void Accept(std::function handler, - std::function finish = {}) const; - -private: - std::vector> props_; -}; diff --git a/include/storage/model/typed_value_utils.h b/include/storage/model/typed_value_utils.h deleted file mode 100644 index 5b5af377f..000000000 --- a/include/storage/model/typed_value_utils.h +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright 2017 Memgraph -// Created by Florijan Stamenkovic on 01.02.17. -// - -#pragma once - -#include -#include "storage/model/typed_value_store.hpp" - - -/** - * Writes all of the values from the given store in JSON format - * to the given output stream. - * - * @param store The store that should be serialized to JSON. - * @param ostream The stream to write to. - */ -void TypedValuesToJson(const TypedValueStore& store, - std::ostream& ostream=std::cout) { - - bool first = true; - - auto write_key = [&ostream, &first](const TypedValueStore::TKey &key) -> std::ostream& { - if (first) { - ostream << '{'; - first = false; - } else - ostream << ','; - - return ostream << '"' << key << "\":"; - }; - - auto handler = [&ostream, &write_key](const TypedValueStore::TKey& key, - const TypedValue& value) { - switch (value.type_) { - case TypedValue::Type::Null: - break; - case TypedValue::Type::Bool: - write_key(key) << (value.Value() ? "true" : "false"); - break; - case TypedValue::Type::String: - write_key(key) << '"' << value.Value() << '"'; - break; - case TypedValue::Type::Int: - write_key(key) << value.Value(); - break; - case TypedValue::Type::Float: - write_key(key) << value.Value(); - break; - } - }; - - auto finish = [&ostream]() { ostream << '}' << std::endl; }; - - store.Accept(handler, finish); -} diff --git a/include/storage/record_accessor.hpp b/include/storage/record_accessor.hpp index 9369d593a..eea1773b3 100644 --- a/include/storage/record_accessor.hpp +++ b/include/storage/record_accessor.hpp @@ -11,18 +11,36 @@ class RecordAccessor { public: - RecordAccessor(mvcc::VersionList *vlist, GraphDbAccessor *db_accessor) - : vlist_(vlist), db_accessor_(db_accessor) { - record_ = vlist->find(db_accessor->transaction_); + /** + * The GraphDbAccessor is friend to this accessor so it can + * operate on it's data (mvcc version-list and the record itself). + * This is legitemate because GraphDbAccessor creates RecordAccessors + * and is semantically their parent/owner. It is necessary because + * the GraphDbAccessor handles insertions and deletions, and these + * operations modify data intensively. + */ + friend GraphDbAccessor; + + RecordAccessor(mvcc::VersionList& vlist, + GraphDbAccessor& db_accessor) + : vlist_(vlist), record_(vlist_.find(db_accessor.transaction_)), db_accessor_(db_accessor) { + assert(record_ != nullptr); + } + + RecordAccessor(mvcc::VersionList& vlist, + TRecord& record, + GraphDbAccessor& db_accessor) + : vlist_(vlist), record_(&record), db_accessor_(db_accessor) { + assert(record_ != nullptr); } template void PropsSet(GraphDb::Property key, TValue value) { - update()->props_.set(key, value); + update().props_.set(key, value); } size_t PropsErase(GraphDb::Property key) { - return update()->props_.erase(key); + return update().props_.erase(key); } const TypedValueStore &Properties() const { @@ -31,7 +49,7 @@ public: void PropertiesAccept(std::function handler, std::function finish = {}) const { - view()->props_.Accept(handler, finish); + view().props_.Accept(handler, finish); } // Assumes same transaction @@ -47,21 +65,20 @@ public: } /** - * Exposes the version list only to the GraphDb. + * Returns a GraphDB accessor of this record accessor. * - * @param pass_key Ignored. - * @return The version list of this accessor. + * @return See above. */ - mvcc::VersionList *vlist(PassKey pass_key) const { - return vlist_; + GraphDbAccessor& db_accessor() { + return db_accessor_; } /** - * Returns a GraphDB accessor of this record accessor. + * Returns a const GraphDB accessor of this record accessor. * - * @return + * @return See above. */ - const GraphDbAccessor &db_accessor() const { + const GraphDbAccessor& db_accessor() const { return db_accessor_; } @@ -72,14 +89,13 @@ protected: * * @return See above. */ - TRecord *update() { + TRecord& update() { // TODO consider renaming this to something more indicative // of the underlying MVCC functionality (like "new_version" or so) + if (!record_->is_visible_write(db_accessor_.transaction_)) + record_ = vlist_.update(record_, db_accessor_.transaction_); - if (!record_->is_visible_write(db_accessor_->transaction_)) - record_ = vlist_->update(db_accessor_->transaction_); - - return record_; + return *record_; } /** @@ -87,22 +103,26 @@ protected: * * @return See above. */ - const TRecord *view() const { - return record_; + const TRecord& view() const { + return *record_; } // The record (edge or vertex) this accessor provides access to. - mvcc::VersionList *vlist_; + // Immutable, set in the constructor and never changed. + mvcc::VersionList& vlist_; // The database accessor for which this record accessor is created // Provides means of getting to the transaction and database functions. - GraphDbAccessor *db_accessor_; + // Immutable, set in the constructor and never changed. + GraphDbAccessor& db_accessor_; private: /* The version of the record currently used in this transaction. Defaults to the * latest viewable version (set in the constructor). After the first update done * through this accessor a new, editable version, is created for this transaction, * and set as the value of this variable. + * + * Stored as a pointer due to it's mutability (the update() function changes it). */ - TRecord *record_; + TRecord* record_; }; diff --git a/include/storage/typed_value_store.hpp b/include/storage/typed_value_store.hpp index f7838418b..ab8d4d4f7 100644 --- a/include/storage/typed_value_store.hpp +++ b/include/storage/typed_value_store.hpp @@ -28,7 +28,13 @@ public: * @param key The key for which a TypedValue is sought. * @return See above. */ - const TypedValue &at(const TKey &key) const; + const TypedValue& at(const TKey &key) const { + for (const auto& kv : props_) + if (kv.first == key) + return kv.second; + + return TypedValue::Null; + } /** * Sets the value for the given key. A new TypedValue instance @@ -41,7 +47,17 @@ public: * @param value The value to set. */ template - void set(const TKey &key, const TValue &value); + void set(const TKey &key, const TValue &value) { + for (auto& kv: props_) + if (kv.first == key) { + kv.second = TypedValue(value); + return; + } + + // there is no value for the given key, add new + // TODO consider vector size increment optimization + props_.push_back(std::move(std::make_pair(key, value))); + } /** * Set overriding for character constants. Forces conversion @@ -52,7 +68,9 @@ public: * value at the same key (if there was one) is replaced. * @param value The value to set. */ - void set(const TKey &key, const char *value); + void set(const TKey &key, const char *value) { + set(key, std::string(value)); + } /** * Removes the TypedValue for the given key. @@ -60,13 +78,41 @@ public: * @param key The key for which to remove the property. * @return The number of removed properties (0 or 1). */ - size_t erase(const TKey &key); + size_t erase(const TKey &key) { + + auto found = std::find_if( + props_.begin(), + props_.end(), + [&key](std::pair &kv){return kv.first == key;} + ); + + if (found != props_.end()) { + props_.erase(found); + return 1; + } + return 0; + } /** * @return The number of Properties in this collection. */ - size_t size() const; + size_t size() const { + return props_.size(); + } + /** + * Returns a const iterator over key-value pairs. + * + * @return See above. + */ + const auto begin() const { return props_.begin(); } + + /** + * Returns an end iterator. + * + * @return See above. + */ + const auto end() const { return props_.end(); } /** * Accepts two functions. @@ -74,8 +120,16 @@ public: * @param handler Called for each TypedValue in this collection. * @param finish Called once in the end. */ - void Accept(std::function handler, - std::function finish = {}) const; + void Accept(std::function handler, + std::function finish = {}) const { + if (handler) + for (const auto& prop : props_) + handler(prop.first, prop.second); + + if (finish) + finish(); + + } private: std::vector> props_; diff --git a/include/storage/util.hpp b/include/storage/util.hpp new file mode 100644 index 000000000..9ad669f1f --- /dev/null +++ b/include/storage/util.hpp @@ -0,0 +1,24 @@ + +/** + * Creates a vector of records accessors (Edge or Vertex). + * + * @tparam TAccessor The type of accessor to create a vector of. + * @tparam TCollection An iterable of pointers to version list objects. + * + * @param records An iterable of version list pointers for which accessors + * need to be created. + * @param db_accessor A database accessor to create the record accessors with. + */ +template +std::vector make_accessors( + const TCollection &records, + GraphDbAccessor &db_accessor) { + + std::vector accessors; + accessors.reserve(records.size()); + + for (auto record : records) + accessors.emplace_back(*record, db_accessor); + + return accessors; +} diff --git a/include/storage/vertex.hpp b/include/storage/vertex.hpp index 85c901ea2..353260f3c 100644 --- a/include/storage/vertex.hpp +++ b/include/storage/vertex.hpp @@ -1,5 +1,8 @@ #pragma once +#include +#include + #include "database/graph_db.hpp" #include "mvcc/record.hpp" #include "mvcc/version_list.hpp" @@ -11,8 +14,8 @@ class Edge; class Vertex : public mvcc::Record { public: - std::vector *> out_; - std::vector *> in_; + std::vector*> out_; + std::vector*> in_; std::set labels_; TypedValueStore properties_; }; diff --git a/include/storage/vertex_accessor.hpp b/include/storage/vertex_accessor.hpp index af46f2f81..e3d7b2376 100644 --- a/include/storage/vertex_accessor.hpp +++ b/include/storage/vertex_accessor.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "storage/record_accessor.hpp" @@ -25,27 +26,12 @@ public: const std::set& labels() const; - // TODO add in/out functions that return (collection|iterator) over EdgeAccessor + std::vector in(); + + std::vector out(); // returns if remove was possible due to connections - bool remove(); - - void detach_remove(); - - /** - * Adds the given Edge version list to this Vertex's incoming edges. - * - * @param edge_vlist The Edge to add. - * @param pass_key Ensures only GraphDb has access to this method. - */ - void attach_in(mvcc::VersionList* edge_vlist, PassKey pass_key); - - /** - * Adds the given Edge version list to this Vertex's outgoing edges. - * - * @param edge_vlist The Edge to add. - * @param pass_key Ensures only GraphDb has access to this method. - */ - void attach_out(mvcc::VersionList* edge_vlist, PassKey pass_key); - +// bool remove(); +// +// void detach_remove(); }; diff --git a/include/utils/hashing/fnv.hpp b/include/utils/hashing/fnv.hpp index 265f483c1..dd46682c0 100644 --- a/include/utils/hashing/fnv.hpp +++ b/include/utils/hashing/fnv.hpp @@ -22,6 +22,8 @@ uint64_t fnv(const T& data) return fnv1a64(data); } +using HashType = uint64_t; + #elif template @@ -30,6 +32,8 @@ uint32_t fnv(const T& data) return fnv1a32(data); } +using HashType = uint32_t; + #endif } diff --git a/src/communication/bolt/v1/serialization/bolt_serializer.cpp b/src/communication/bolt/v1/serialization/bolt_serializer.cpp index 375d4a178..b6051a32a 100644 --- a/src/communication/bolt/v1/serialization/bolt_serializer.cpp +++ b/src/communication/bolt/v1/serialization/bolt_serializer.cpp @@ -5,6 +5,9 @@ #include "communication/bolt/v1/transport/socket_stream.hpp" #include "io/network/socket.hpp" +#include "database/graph_db.hpp" +#include "storage/typed_value_store.hpp" + template void bolt::BoltSerializer::write(const VertexAccessor &vertex) { @@ -25,11 +28,11 @@ void bolt::BoltSerializer::write(const VertexAccessor &vertex) { encoder.write_string(vertex.db_accessor().label_name(label)); // write the properties - const TypedValueStore &props = vertex.Properties(); + const TypedValueStore &props = vertex.Properties(); encoder.write_map_header(props.size()); - props.Accept([&vertex](const TypedValueStore::TKey &prop_name, const TypedValue &value) { - write(vertex.db_accessor().property_name(prop_name)); - write(value); + props.Accept([this, &vertex](const GraphDb::Property prop, const TypedValue &value) { + this->encoder.write(vertex.db_accessor().property_name(prop)); + this->write(value); }); } @@ -48,14 +51,14 @@ void bolt::BoltSerializer::write(const EdgeAccessor &edge) { encoder.write_integer(0); // write the type of the edge - encoder.write_string(edge.edge_type()); + encoder.write(edge.db_accessor().edge_type_name(edge.edge_type())); // write the property map - const TypedValueStore& props = edge.Properties(); + const TypedValueStore& props = edge.Properties(); encoder.write_map_header(props.size()); - props.Accept([&edge](const TypedValueStore::TKey &prop_name, const TypedValue &value) { - write(edge.db_accessor().property_name(prop_name)); - write(value); + props.Accept([this, &edge](GraphDb::Property prop, const TypedValue &value) { + this->encoder.write(edge.db_accessor().property_name(prop)); + this->write(value); }); } diff --git a/src/communication/bolt/v1/session.cpp b/src/communication/bolt/v1/session.cpp index 2e8a504b1..d1303bdf9 100644 --- a/src/communication/bolt/v1/session.cpp +++ b/src/communication/bolt/v1/session.cpp @@ -43,5 +43,5 @@ void Session::close() bolt.close(this); } -GraphDb &Session::active_db() { return bolt.dbms.active(); } +GraphDbAccessor Session::active_db() { return bolt.dbms.active(); } } diff --git a/src/communication/bolt/v1/states/executor.cpp b/src/communication/bolt/v1/states/executor.cpp index ab59f46cb..bac0965d6 100644 --- a/src/communication/bolt/v1/states/executor.cpp +++ b/src/communication/bolt/v1/states/executor.cpp @@ -1,5 +1,6 @@ #include "communication/bolt/v1/states/executor.hpp" #include "communication/bolt/v1/messaging/codes.hpp" +#include "database/graph_db_accessor.hpp" #ifdef BARRIER #include "barrier/barrier.cpp" @@ -83,11 +84,11 @@ State *Executor::run(Session &session, Query &query) { logger.trace("[Run] '{}'", query.statement); - auto &db = session.active_db(); - logger.debug("[ActiveDB] '{}'", db.name()); + auto db_accessor = session.active_db(); + logger.debug("[ActiveDB] '{}'", db_accessor.name()); auto is_successfully_executed = - query_engine.Run(query.statement, db, session.output_stream); + query_engine.Run(query.statement, db_accessor, session.output_stream); if (!is_successfully_executed) { diff --git a/src/database/graph_db.cpp b/src/database/graph_db.cpp index b9d101ab5..9f2bfb4e9 100644 --- a/src/database/graph_db.cpp +++ b/src/database/graph_db.cpp @@ -2,20 +2,9 @@ #include #include "database/creation_exception.hpp" #include "database/graph_db.hpp" -#include "snapshot/snapshoter.hpp" +//#include "snapshot/snapshoter.hpp" -#include "storage/vertex.hpp" -#include "storage/vertex_accessor.hpp" -#include "storage/edge.hpp" -#include "storage/edge_accessor.hpp" - -GraphDb::GraphDb(bool import_snapshot) : GraphDb("default", import_snapshot) {} - -GraphDb::GraphDb(const std::string &name, bool import_snapshot) - : GraphDb(name.c_str(), import_snapshot) { +GraphDb::GraphDb(const std::string &name, bool import_snapshot) : name_(name) { +// if (import_snapshot) +// snap_engine.import(); } - -//GraphDb::GraphDb(const char *name, bool import_snapshot) : name_(name) { -// if (import_snapshot) snap_engine.import(); -//} - diff --git a/src/database/graph_db_accessor.cpp b/src/database/graph_db_accessor.cpp index 2b2c8ab27..20da50450 100644 --- a/src/database/graph_db_accessor.cpp +++ b/src/database/graph_db_accessor.cpp @@ -1,52 +1,106 @@ #include #include "database/graph_db_accessor.hpp" +#include "storage/vertex.hpp" +#include "storage/vertex_accessor.hpp" +#include "storage/edge.hpp" +#include "storage/edge_accessor.hpp" + GraphDbAccessor::GraphDbAccessor(GraphDb& db) : db_(db), transaction_(std::move(db.tx_engine.begin())) {} -VertexAccessor GraphDbAccessor::insert_vertex() { - auto vertex_vlist = new mvcc::VersionList(); - vertex_vlist->insert(transaction_); +const std::string& GraphDbAccessor::name() const { + return db_.name_; +} - // TODO make this configurable +VertexAccessor GraphDbAccessor::insert_vertex() { + + // create a vertex + auto vertex_vlist = new mvcc::VersionList(); + Vertex *vertex = vertex_vlist->insert(transaction_); + + // insert the newly created record into the main storage + // TODO make the number of tries configurable configurable for (int i = 0; i < 5; ++i) { bool success = db_.vertices_.access().insert(vertex_vlist).second; if (success) - return VertexAccessor(vertex_vlist, transaction_); - // TODO sleep for some amount of time + return VertexAccessor(*vertex_vlist, *vertex, *this); + // TODO sleep for some configurable amount of time } throw CreationException("Unable to create a Vertex after 5 attempts"); } +bool GraphDbAccessor::remove_vertex(VertexAccessor &vertex_accessor) { + // TODO consider if this works well with MVCC + if (vertex_accessor.out_degree() > 0 || vertex_accessor.in_degree() > 0) + return false; + + vertex_accessor.vlist_.remove(&vertex_accessor.update(), transaction_); + + // TODO remove the vertex from the main storage once it gets garbage collected + + return true; +} + +void GraphDbAccessor::detach_remove_vertex(VertexAccessor &vertex_accessor) { + // removing edges via accessors is both safe + // and it should remove all the pointers in the relevant + // vertices (including this one) + for (auto edge_accessor : vertex_accessor.in()) + remove_edge(edge_accessor); + + for (auto edge_accessor : vertex_accessor.out()) + remove_edge(edge_accessor); + + // mvcc removal of the vertex + vertex_accessor.vlist_.remove(&vertex_accessor.update(), transaction_); + + // TODO remove the vertex from the main storage once it gets garbage collected +} + EdgeAccessor GraphDbAccessor::insert_edge( VertexAccessor& from, VertexAccessor& to, - GraphDb::EdgeType type) { + GraphDb::EdgeType edge_type) { + // create an edge auto edge_vlist = new mvcc::VersionList(); - Edge* edge = edge_vlist->insert(transaction_); + Edge* edge = edge_vlist->insert(transaction_, from.vlist_, to.vlist_, edge_type); - // set the given values of the new edge - edge->edge_type_ = type; - // connect the edge to vertices - edge->from_ = from.vlist(pass_key); - edge->to_ = to.vlist(pass_key); - // TODO connect the vertices to edge - from.add_to_out(edge_vlist, pass_key); - to.add_to_in(edge_vlist, pass_key); + // set the vertex connections to this edge + from.update().out_.emplace_back(edge_vlist); + to.update().in_.emplace_back(edge_vlist); - // TODO make this configurable + // insert the newly created record into the main storage + // TODO make the number of tries configurable for (int i = 0; i < 5; ++i) { bool success = db_.edges_.access().insert(edge_vlist).second; if (success) - return EdgeAccessor(edge_vlist, transaction_); + return EdgeAccessor(*edge_vlist, *edge, *this); // TODO sleep for some amount of time } throw CreationException("Unable to create an Edge after 5 attempts"); } +void GraphDbAccessor::remove_edge(EdgeAccessor& edge_accessor) { + // remove this edge's reference from the "from" vertex + auto& vertex_from = edge_accessor.from().update(); + std::remove(vertex_from.out_.begin(), + vertex_from.out_.end(), + &edge_accessor.vlist_); + + // remove this edge's reference from the "to" vertex + auto& vertex_to = edge_accessor.to().update(); + std::remove(vertex_to.in_.begin(), + vertex_to.in_.end(), + &edge_accessor.vlist_); + + // remove this record from the database via MVCC + edge_accessor.vlist_.remove(&edge_accessor.update(), transaction_); +} + GraphDb::Label GraphDbAccessor::label(const std::string& label_name) { return &(*db_.labels_.access().insert(label_name).first); } diff --git a/src/dbms/dbms.cpp b/src/dbms/dbms.cpp index 9e12947dd..b04734dd3 100644 --- a/src/dbms/dbms.cpp +++ b/src/dbms/dbms.cpp @@ -1,21 +1,10 @@ #include "dbms/dbms.hpp" -// returns active database -GraphDb &Dbms::active() -{ - GraphDb *active = active_db.load(std::memory_order_acquire); - if (UNLIKELY(active == nullptr)) { - // There is no active database. - return create_default(); - } else { - return *active; - } +GraphDbAccessor Dbms::active() { + return GraphDbAccessor(*active_db.load(std::memory_order_acquire)); } -// set active database -// if active database doesn't exist create one -GraphDb &Dbms::active(const std::string &name) -{ +GraphDbAccessor Dbms::active(const std::string &name) { auto acc = dbs.access(); // create db if it doesn't exist auto it = acc.find(name); @@ -28,5 +17,5 @@ GraphDb &Dbms::active(const std::string &name) // set and return active db auto &db = it->second; active_db.store(&db, std::memory_order_release); - return db; + return GraphDbAccessor(db); } diff --git a/src/storage/edge_accessor.cpp b/src/storage/edge_accessor.cpp index 7b252e954..c471ff414 100644 --- a/src/storage/edge_accessor.cpp +++ b/src/storage/edge_accessor.cpp @@ -2,35 +2,35 @@ #include "storage/vertex_accessor.hpp" void EdgeAccessor::set_edge_type(GraphDb::EdgeType edge_type) { - this->update()->edge_type_ = edge_type; + this->update().edge_type_ = edge_type; } GraphDb::EdgeType EdgeAccessor::edge_type() const { - return this->view()->edge_type_; + return this->view().edge_type_; } VertexAccessor EdgeAccessor::from() const { - return VertexAccessor(this->view()->from_, this->db_accessor_->transaction_); + return VertexAccessor(view().from_, db_accessor_); } VertexAccessor EdgeAccessor::to() const { - return VertexAccessor(this->view()->to_, this->db_accessor_->transaction_); + return VertexAccessor(view().to_, db_accessor_); } -void EdgeAccessor::remove() { - // remove this edge's reference from the "from" vertex - auto vertex_from = from().update(); - std::remove(vertex_from->out_.begin(), - vertex_from->out_.end(), - vlist_); - - // remove this edge's reference from the "to" vertex - auto vertex_to = to().update(); - std::remove(vertex_to->in_.begin(), - vertex_to->in_.end(), - vlist_); - - // remove this record from the database via MVCC - vlist_->remove(update(), db_accessor_->transaction_); -} +//void EdgeAccessor::remove() { +// // remove this edge's reference from the "from" vertex +// auto& vertex_from = from().update(); +// std::remove(vertex_from.out_.begin(), +// vertex_from.out_.end(), +// vlist_); +// +// // remove this edge's reference from the "to" vertex +// auto& vertex_to = to().update(); +// std::remove(vertex_to.in_.begin(), +// vertex_to.in_.end(), +// vlist_); +// +// // remove this record from the database via MVCC +// vlist_.remove(&update(), db_accessor_.transaction_); +//} diff --git a/src/storage/model/typed_value.cpp b/src/storage/model/typed_value.cpp deleted file mode 100644 index eeb4a39fe..000000000 --- a/src/storage/model/typed_value.cpp +++ /dev/null @@ -1,363 +0,0 @@ -#include -#include -#include -#include - -#include "storage/model/typed_value.hpp" -#include "utils/assert.hpp" - -// Value extraction template instantiations -template<> -bool TypedValue::Value() const { - runtime_assert(type_ == TypedValue::Type::Bool, "Incompatible template param and type"); - return bool_v; -} - -template<> -std::string TypedValue::Value() const { - runtime_assert(type_ == TypedValue::Type::String, "Incompatible template param and type"); - return *string_v; -} - -template<> -int TypedValue::Value() const { - runtime_assert(type_ == TypedValue::Type::Int, "Incompatible template param and type"); - return int_v; -} - -template<> -float TypedValue::Value() const { - runtime_assert(type_ == TypedValue::Type::Float, "Incompatible template param and type"); - return float_v; -} - -TypedValue::TypedValue(const TypedValue &other) : type_(other.type_) { - switch (other.type_) { - case TypedValue::Type::Null: - return; - - case TypedValue::Type::Bool: - this->bool_v = other.bool_v; - return; - - case TypedValue::Type::String: - new(&string_v) std::shared_ptr(other.string_v); - return; - - case Type::Int: - this->int_v = other.int_v; - return; - - case Type::Float: - this->float_v = other.float_v; - return; - } - - permanent_fail("Unsupported TypedValue::Type"); -} - -std::ostream &operator<<(std::ostream &os, const TypedValue::Type type) { - switch (type) { - case TypedValue::Type::Null: - return os << "null"; - case TypedValue::Type::Bool: - return os << "bool"; - case TypedValue::Type::String: - return os << "string"; - case TypedValue::Type::Int: - return os << "int"; - case TypedValue::Type::Float: - return os << "float"; - } - permanent_fail("Unsupported TypedValue::Type"); -} - -std::ostream &operator<<(std::ostream &os, const TypedValue &property) { - switch (property.type_) { - case TypedValue::Type::Null: - return os << "Null"; - case TypedValue::Type::Bool: - return os << (property.Value() ? "true" : "false"); - case TypedValue::Type::String: - return os << property.Value(); - case TypedValue::Type::Int: - return os << property.Value(); - case TypedValue::Type::Float: - return os << property.Value(); - } - permanent_fail("Unsupported TypedValue::Type"); -} - -TypedValue &TypedValue::operator=(TypedValue &&other) { - - // set the type of this - const_cast(type_) = other.type_; - - if (this != &other) { - switch (other.type_) { - case TypedValue::Type::Null: - case TypedValue::Type::Bool: - this->bool_v = other.bool_v; - return *this; - case TypedValue::Type::String: - this->string_v = std::move(other.string_v); - return *this; - case TypedValue::Type::Int: - this->int_v = other.int_v; - return *this; - case TypedValue::Type::Float: - this->float_v = other.float_v; - return *this; - } - } - permanent_fail("Unsupported TypedValue::Type"); -} - -const TypedValue TypedValue::Null = TypedValue(); - -TypedValue::~TypedValue() { - - switch (type_) { - // destructor for primitive types does nothing - case Type::Null: - case Type::Bool: - case Type::Int: - case Type::Float: - return; - - // destructor for shared pointer must release - case Type::String: - string_v.~shared_ptr(); - return; - } - permanent_fail("Unsupported TypedValue::Type"); -} - -/** - * Returns the float value of a property. - * The property MUST be either Float or Int. - * - * @param prop - * @return - */ -float ToFloat(const TypedValue& prop) { - switch (prop.type_) { - case TypedValue::Type::Int: - return (float)prop.Value(); - case TypedValue::Type::Float: - return prop.Value(); - - default: - permanent_fail("Unsupported TypedValue::Type"); - } -} - -TypedValue operator<(const TypedValue& a, const TypedValue& b) { - if (a.type_ == TypedValue::Type::Bool || b.type_ == TypedValue::Type::Bool) - throw TypedValueException("Invalid 'less' operand types({} + {})", a.type_, b.type_); - - if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null) - return TypedValue::Null; - - if (a.type_ == TypedValue::Type::String || b.type_ == TypedValue::Type::String) { - if (a.type_ != b.type_) - throw TypedValueException("Invalid equality operand types({} + {})", a.type_, b.type_); - else - return a.Value() < b.Value(); - } - - // at this point we only have int and float - if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float) - return ToFloat(a) < ToFloat(b); - else - return a.Value() < b.Value(); -} - -TypedValue operator==(const TypedValue& a, const TypedValue& b) { - - if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null) - return TypedValue::Null; - - if (a.type_ == TypedValue::Type::String || b.type_ == TypedValue::Type::String) { - if (a.type_ != b.type_) - throw TypedValueException("Invalid equality operand types({} + {})", a.type_, b.type_); - else - return a.Value() == b.Value(); - } - - if (a.type_ == TypedValue::Type::Bool || b.type_ == TypedValue::Type::Bool) { - if (a.type_ != b.type_) - throw TypedValueException("Invalid equality operand types({} + {})", a.type_, b.type_); - else - return a.Value() == b.Value(); - } - // at this point we only have int and float - if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){ - return ToFloat(a) == ToFloat(b); - } else - return a.Value() == b.Value(); - -} - -TypedValue operator!(const TypedValue& a) { - switch (a.type_) { - case TypedValue::Type::Null: - return TypedValue::Null; - case TypedValue::Type::Bool: - return TypedValue(!a.Value()); - - default: - throw TypedValueException("Invalid logical not operand type (!{})", a.type_); - } -} - -/** - * Turns a numeric or string property into a string. - * - * @param prop Property. - * @return A string. - */ -std::string PropToString(const TypedValue& prop) { - switch (prop.type_) { - case TypedValue::Type::String: - return prop.Value(); - case TypedValue::Type::Int: - return std::to_string(prop.Value()); - case TypedValue::Type::Float: - return fmt::format("{}", prop.Value()); - - // unsupported situations - default: - permanent_fail("Unsupported TypedValue::Type"); - } -} - -TypedValue operator-(const TypedValue &a) { - switch (a.type_) { - case TypedValue::Type::Null: - return TypedValue::Null; - case TypedValue::Type::Int: - return -a.Value(); - case TypedValue::Type::Float: - return -a.Value(); - - default: - throw TypedValueException("Invalid unary minus operand type (-{})", a.type_); - } -} - -/** - * Raises a PropertyException if the given properties do not support arithmetic - * operations. If they do, nothing happens. - * - * @param a First prop. - * @param b Second prop. - * @param string_ok If or not for the given operation it's valid to work with - * String values (typically it's OK only for sum). - * @param op_name Name of the operation, used only for exception description, - * if raised. - */ -inline void EnsureArithmeticallyOk(const TypedValue& a, const TypedValue& b, - bool string_ok, const std::string& op_name) { - if (a.type_ == TypedValue::Type::Bool || b.type_ == TypedValue::Type::Bool) - throw TypedValueException("Invalid {} operand types {}, {}", op_name, a.type_, b.type_); - - if (string_ok) - return; - - if (a.type_ == TypedValue::Type::String || b.type_ == TypedValue::Type::String) - throw TypedValueException("Invalid subtraction operands types {}, {}", a.type_, b.type_); -} - -TypedValue operator+(const TypedValue& a, const TypedValue& b){ - EnsureArithmeticallyOk(a, b, true, "addition"); - if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null) - return TypedValue::Null; - - // no more Bool nor Null, summing works on anything from here onward - - if (a.type_ == TypedValue::Type::String || b.type_ == TypedValue::Type::String) - return PropToString(a) + PropToString(b); - - // at this point we only have int and float - if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){ - return ToFloat(a) + ToFloat(b); - } else - return a.Value() + b.Value(); -} - -TypedValue operator-(const TypedValue& a, const TypedValue& b){ - EnsureArithmeticallyOk(a, b, false, "subtraction"); - - if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null) - return TypedValue::Null; - - // at this point we only have int and float - if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){ - return ToFloat(a) - ToFloat(b); - } else - return a.Value() - b.Value(); -} - -TypedValue operator/(const TypedValue& a, const TypedValue& b){ - EnsureArithmeticallyOk(a, b, false, "division"); - - if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null) - return TypedValue::Null; - - // at this point we only have int and float - if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){ - return ToFloat(a) / ToFloat(b); - } else - return a.Value() / b.Value(); -} - -TypedValue operator*(const TypedValue& a, const TypedValue& b){ - EnsureArithmeticallyOk(a, b, false, "multiplication"); - - if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null) - return TypedValue::Null; - - // at this point we only have int and float - if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){ - return ToFloat(a) * ToFloat(b); - } else - return a.Value() * b.Value(); -} - -TypedValue operator%(const TypedValue& a, const TypedValue& b){ - EnsureArithmeticallyOk(a, b, false, "modulo"); - - if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null) - return TypedValue::Null; - - // at this point we only have int and float - if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){ - return (float)fmod(ToFloat(a), ToFloat(b)); - } else - return a.Value() % b.Value(); -} - -inline bool IsLogicallyOk(const TypedValue& a) { - return a.type_ == TypedValue::Type::Bool || a.type_ == TypedValue::Type::Null; -} - -TypedValue operator&&(const TypedValue& a, const TypedValue& b) { - if(IsLogicallyOk(a) && IsLogicallyOk(b)){ - if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null) - return TypedValue::Null; - else - return a.Value() && b.Value(); - } else - throw TypedValueException("Invalid logical and operand types({} && {})", a.type_, b.type_); -} - -TypedValue operator||(const TypedValue& a, const TypedValue& b) { - if(IsLogicallyOk(a) && IsLogicallyOk(b)){ - if (a.type_ == TypedValue::Type::Null || b.type_ == TypedValue::Type::Null) - return TypedValue::Null; - else - return a.Value() || b.Value(); - } else - throw TypedValueException("Invalid logical and operand types({} && {})", a.type_, b.type_); -} diff --git a/src/storage/model/typed_value_store.cpp b/src/storage/model/typed_value_store.cpp deleted file mode 100644 index 9e538afb8..000000000 --- a/src/storage/model/typed_value_store.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include - -#include "storage/model/typed_value_store.hpp" - -const TypedValue& TypedValueStore::at(const TKey &key) const { - for (const auto& kv : props_) - if (kv.first == key) - return kv.second; - - return TypedValue::Null; -} - -template -void TypedValueStore::set(const TKey &key, const TValue &value) { - for (auto& kv: props_) - if (kv.first == key) { - kv.second = TypedValue(value); - return; - } - - // there is no value for the given key, add new - // TODO consider vector size increment optimization - props_.push_back(std::move(std::make_pair(key, value))); -} - -// instantiations of the TypedValueStore::set function -// instances must be made for all of the supported C++ types -template void TypedValueStore::set(const TKey &key, const std::string &value); -template void TypedValueStore::set(const TKey &key, const bool &value); -template void TypedValueStore::set(const TKey &key, const int &value); -template void TypedValueStore::set(const TKey &key, const float &value); - -/** - * Set overriding for character constants. Forces conversion - * to std::string, otherwise templating might cast the pointer - * to something else (bool) and mess things up. - * - * @param key The key for which the property is set. The previous - * value at the same key (if there was one) is replaced. - * @param value The value to set. - */ -void TypedValueStore::set(const TKey &key, const char *value) { - set(key, std::string(value)); -} - -size_t TypedValueStore::erase(const TKey &key) { - auto found = std::find_if(props_.begin(), props_.end(), [&key](std::pair &kv){return kv.first == key;}); - if (found != props_.end()) { - props_.erase(found); - return 1; - } - return 0; -} - -size_t TypedValueStore::size() const { return props_.size(); } - -void TypedValueStore::Accept(std::function handler, - std::function finish) const { - if (handler) - for (const auto& prop : props_) - handler(prop.first, prop.second); - - if (finish) - finish(); - -} - - diff --git a/src/storage/typed_value.cpp b/src/storage/typed_value.cpp index 43be7e04e..ecffd3b8b 100644 --- a/src/storage/typed_value.cpp +++ b/src/storage/typed_value.cpp @@ -72,18 +72,18 @@ std::ostream &operator<<(std::ostream &os, const TypedValue::Type type) { permanent_fail("Unsupported TypedValue::Type"); } -std::ostream &operator<<(std::ostream &os, const TypedValue &property) { - switch (property.type_) { +std::ostream &operator<<(std::ostream &os, const TypedValue &value) { + switch (value.type_) { case TypedValue::Type::Null: return os << "Null"; case TypedValue::Type::Bool: - return os << (property.Value() ? "true" : "false"); + return os << (value.Value() ? "true" : "false"); case TypedValue::Type::String: - return os << property.Value(); + return os << value.Value(); case TypedValue::Type::Int: - return os << property.Value(); + return os << value.Value(); case TypedValue::Type::Float: - return os << property.Value(); + return os << value.Value(); } permanent_fail("Unsupported TypedValue::Type"); } @@ -134,18 +134,18 @@ TypedValue::~TypedValue() { } /** - * Returns the float value of a property. - * The property MUST be either Float or Int. + * Returns the float value of a value. + * The value MUST be either Float or Int. * - * @param prop + * @param value * @return */ -float ToFloat(const TypedValue& prop) { - switch (prop.type_) { +float ToFloat(const TypedValue& value) { + switch (value.type_) { case TypedValue::Type::Int: - return (float)prop.Value(); + return (float)value.Value(); case TypedValue::Type::Float: - return prop.Value(); + return value.Value(); default: permanent_fail("Unsupported TypedValue::Type"); @@ -212,19 +212,19 @@ TypedValue operator!(const TypedValue& a) { } /** - * Turns a numeric or string property into a string. + * Turns a numeric or string value into a string. * - * @param prop Property. + * @param value a value. * @return A string. */ -std::string PropToString(const TypedValue& prop) { - switch (prop.type_) { +std::string ValueToString(const TypedValue &value) { + switch (value.type_) { case TypedValue::Type::String: - return prop.Value(); + return value.Value(); case TypedValue::Type::Int: - return std::to_string(prop.Value()); + return std::to_string(value.Value()); case TypedValue::Type::Float: - return fmt::format("{}", prop.Value()); + return fmt::format("{}", value.Value()); // unsupported situations default: @@ -247,11 +247,11 @@ TypedValue operator-(const TypedValue &a) { } /** - * Raises a PropertyException if the given properties do not support arithmetic + * Raises a TypedValueException if the given values do not support arithmetic * operations. If they do, nothing happens. * - * @param a First prop. - * @param b Second prop. + * @param a First value. + * @param b Second value. * @param string_ok If or not for the given operation it's valid to work with * String values (typically it's OK only for sum). * @param op_name Name of the operation, used only for exception description, @@ -277,7 +277,7 @@ TypedValue operator+(const TypedValue& a, const TypedValue& b){ // no more Bool nor Null, summing works on anything from here onward if (a.type_ == TypedValue::Type::String || b.type_ == TypedValue::Type::String) - return PropToString(a) + PropToString(b); + return ValueToString(a) + ValueToString(b); // at this point we only have int and float if (a.type_ == TypedValue::Type::Float || b.type_ == TypedValue::Type::Float){ diff --git a/src/storage/typed_value_store.cpp b/src/storage/typed_value_store.cpp index 725b13a84..bc5804c69 100644 --- a/src/storage/typed_value_store.cpp +++ b/src/storage/typed_value_store.cpp @@ -2,6 +2,7 @@ #include "storage/typed_value_store.hpp" +template const TypedValue& TypedValueStore::at(const TKey &key) const { for (const auto& kv : props_) if (kv.first == key) @@ -10,7 +11,7 @@ const TypedValue& TypedValueStore::at(const TKey &key) const { return TypedValue::Null; } -template +template void TypedValueStore::set(const TKey &key, const TValue &value) { for (auto& kv: props_) if (kv.first == key) { diff --git a/src/storage/vertex_accessor.cpp b/src/storage/vertex_accessor.cpp index 2378f75b6..fe5d51fec 100644 --- a/src/storage/vertex_accessor.cpp +++ b/src/storage/vertex_accessor.cpp @@ -1,57 +1,65 @@ #include "storage/edge_accessor.hpp" #include "storage/vertex_accessor.hpp" +#include "storage/util.hpp" size_t VertexAccessor::out_degree() const { - return this->view()->out_.size(); + return this->view().out_.size(); } size_t VertexAccessor::in_degree() const { - return this->view()->in_.size(); + return this->view().in_.size(); } bool VertexAccessor::add_label(GraphDb::Label label) { - return this->update()->labels_.emplace(label).second; + return this->update().labels_.emplace(label).second; } size_t VertexAccessor::remove_label(GraphDb::Label label) { - return this->update()->labels_.erase(label); + return this->update().labels_.erase(label); } bool VertexAccessor::has_label(GraphDb::Label label) const { - auto &label_set = this->view()->labels_; + auto &label_set = this->view().labels_; return label_set.find(label) != label_set.end(); } const std::set& VertexAccessor::labels() const { - return this->view()->labels_; + return this->view().labels_; } -bool VertexAccessor::remove() { - // TODO consider if this works well with MVCC - if (out_degree() > 0 || in_degree() > 0) - return false; +std::vector VertexAccessor::in() { + const Vertex& record = view(); + std::vector in; + in.reserve(record.in_.size()); + for (auto edge_vlist_ptr : record.in_) + in.emplace_back(EdgeAccessor(*edge_vlist_ptr, db_accessor_)); - vlist_->remove(view(), db_accessor_->transaction_); - return true; + return in; } -void VertexAccessor::detach_remove() { - // removing edges via accessors is both safe - // and it should remove all the pointers in the relevant - // vertices (including this one) - for (auto edge_vlist : view()->out_) - EdgeAccessor(edge_vlist, db_accessor_->transaction_).remove(); - - for (auto edge_vlist : view()->in_) - EdgeAccessor(edge_vlist, db_accessor_->transaction_).remove(); - - vlist_->remove(view(), db_accessor_->transaction_); +std::vector VertexAccessor::out() { + return make_accessors(view().in_, db_accessor_); } -void VertexAccessor::attach_in(mvcc::VersionList* edge_vlist, PassKey) { - this->update()->in_.emplace_back(edge_vlist); -} -void VertexAccessor::attach_out(mvcc::VersionList* edge_vlist, PassKey) { - this->update()->out_.emplace_back(edge_vlist); -} +//bool VertexAccessor::remove() { +// // TODO consider if this works well with MVCC +// if (out_degree() > 0 || in_degree() > 0) +// return false; +// +// vlist_.remove(&update(), db_accessor_.transaction_); +// return true; +//} +// +//void VertexAccessor::detach_remove() { +// // removing edges via accessors is both safe +// // and it should remove all the pointers in the relevant +// // vertices (including this one) +// for (auto edge_vlist : view().out_) +// EdgeAccessor(*edge_vlist, db_accessor_).remove(); +// +// for (auto edge_vlist : view().in_) +// EdgeAccessor(*edge_vlist, db_accessor_).remove(); +// +// vlist_.remove(&update(), db_accessor_.transaction_); +//} diff --git a/tests/benchmark/query/strip/stripper.cpp b/tests/benchmark/query/strip/stripper.cpp index e15210b46..0303cceba 100644 --- a/tests/benchmark/query/strip/stripper.cpp +++ b/tests/benchmark/query/strip/stripper.cpp @@ -27,7 +27,7 @@ int main(int argc, char **argv) QueryPreprocessor processor; using std::placeholders::_1; - std::function(const std::string &query)> preprocess = + std::function preprocess = std::bind(&QueryPreprocessor::preprocess, &processor, _1); auto tests = dataset["benchmark_queries"].as>(); diff --git a/tests/integration/cleaning.cpp b/tests/integration/cleaning.cpp deleted file mode 100644 index 5c5549845..000000000 --- a/tests/integration/cleaning.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// TODO: refactor (backlog task) - -#include "_hardcoded_query/basic.hpp" -#include "logging/default.hpp" -#include "logging/streams/stdout.hpp" -#include "query/preprocessor.hpp" -#include "query/stripper.hpp" -#include "utils/assert.hpp" -#include "utils/sysinfo/memory.hpp" - -template -void run(size_t n, std::string &query, Q &qf) -{ - QueryPreprocessor preprocessor; - auto stripped = preprocessor.preprocess(query); - - logging::info("Running query [{}] x {}.", stripped.hash, n); - - for (int i = 0; i < n; i++) - { - properties_t vec = stripped.arguments; - permanent_assert(qf[stripped.hash](std::move(vec)), "Query failed!"); - } -} - -void clean_vertex(Db &db) -{ - DbTransaction t(db); - t.clean_vertex_section(); - t.trans.commit(); -} - -int main(void) -{ - logging::init_sync(); - logging::log->pipe(std::make_unique()); - - Db db("cleaning"); - - size_t entities_number = 1000; - auto query_functions = hardcode::load_basic_functions(db); - - std::string create_vertex_label = - "CREATE (n:LABEL {name: \"cleaner_test\"}) RETURN n"; - std::string create_vertex_other = - "CREATE (n:OTHER {name: \"cleaner_test\"}) RETURN n"; - std::string delete_label_vertices = "MATCH (n:LABEL) DELETE n"; - std::string delete_all_vertices = "MATCH (n) DELETE n"; - - // ******************************* TEST 1 ********************************// - // add vertices a - // clean vertices - // delete vertices a - // clean vertices - run(entities_number, create_vertex_label, query_functions); - permanent_assert(db.graph.vertices.access().size() == entities_number, - "Entities number doesn't match"); - - clean_vertex(db); - permanent_assert(db.graph.vertices.access().size() == entities_number, - "Entities number doesn't match (after cleaning)"); - - run(1, delete_label_vertices, query_functions); - permanent_assert(db.graph.vertices.access().size() == entities_number, - "Entities number doesn't match (delete label vertices)"); - - clean_vertex(db); - permanent_assert(db.graph.vertices.access().size() == 0, - "Db should be empty"); - - // ******************************* TEST 2 ********************************// - // add vertices a - // add vertices b - // clean vertices - // delete vertices a - // clean vertices - // delete vertices all - run(entities_number, create_vertex_label, query_functions); - permanent_assert(db.graph.vertices.access().size() == entities_number, - "Entities number doesn't match"); - - run(entities_number, create_vertex_other, query_functions); - permanent_assert(db.graph.vertices.access().size() == entities_number * 2, - "Entities number doesn't match"); - - clean_vertex(db); - permanent_assert(db.graph.vertices.access().size() == entities_number * 2, - "Entities number doesn't match"); - - run(1, delete_label_vertices, query_functions); - permanent_assert(db.graph.vertices.access().size() == entities_number * 2, - "Entities number doesn't match"); - - clean_vertex(db); - permanent_assert(db.graph.vertices.access().size() == entities_number, - "Entities number doesn't match"); - - run(1, delete_all_vertices, query_functions); - permanent_assert(db.graph.vertices.access().size() == entities_number, - "Entities number doesn't match"); - - clean_vertex(db); - permanent_assert(db.graph.vertices.access().size() == 0, - "Db should be empty"); - - // TODO: more tests - - return 0; -} diff --git a/tests/integration/index.cpp b/tests/integration/index.cpp deleted file mode 100644 index 28b57b365..000000000 --- a/tests/integration/index.cpp +++ /dev/null @@ -1,283 +0,0 @@ -// TODO: refactor (backlog task) - -#include - -#include "_hardcoded_query/basic.hpp" -#include "logging/default.hpp" -#include "logging/streams/stdout.hpp" -#include "query/preprocessor.hpp" -#include "query/stripper.hpp" -#include "storage/indexes/indexes.hpp" -#include "utils/assert.hpp" -#include "utils/signals/handler.hpp" -#include "utils/stacktrace/log.hpp" -#include "utils/sysinfo/memory.hpp" - -// Returns uniform random size_t generator from range [0,n> -auto rand_gen(size_t n) -{ - std::default_random_engine generator; - std::uniform_int_distribution distribution(0, n - 1); - return std::bind(distribution, generator); -} - -void run(size_t n, std::string &query, Db &db) -{ - auto qf = hardcode::load_basic_functions(db); - QueryPreprocessor preprocessor; - auto stripped = preprocessor.preprocess(query); - - logging::info("Running query [{}] x {}.", stripped.hash, n); - - for (int i = 0; i < n; i++) - { - properties_t vec = stripped.arguments; - auto commited = qf[stripped.hash](std::move(vec)); - permanent_assert(commited, "Query execution failed"); - } -} - -void add_edge(size_t n, Db &db) -{ - auto qf = hardcode::load_basic_functions(db); - std::string query = "MATCH (n1), (n2) WHERE ID(n1)=0 AND " - "ID(n2)=1 CREATE (n1)<-[r:IS {age: " - "25,weight: 70}]-(n2) RETURN r"; - QueryPreprocessor preprocessor; - auto stripped = preprocessor.preprocess(query); - - logging::info("Running query [{}] (add edge) x {}", stripped.hash, n); - - std::vector vertices; - for (auto &v : db.graph.vertices.access()) - { - vertices.push_back(v.second.id); - } - permanent_assert(vertices.size() > 0, "Vertices size is zero"); - - auto rand = rand_gen(vertices.size()); - for (int i = 0; i < n; i++) - { - properties_t vec = stripped.arguments; - vec[0] = Property(Int64(vertices[rand()]), Flags::Int64); - vec[1] = Property(Int64(vertices[rand()]), Flags::Int64); - permanent_assert(qf[stripped.hash](std::move(vec)), "Add edge failed"); - } -} - -void add_property(Db &db, StoredProperty &prop) -{ - DbAccessor t(db); - - t.vertex_access().fill().update().for_all([&](auto va) { va.set(prop); }); - - permanent_assert(t.commit(), "Add property failed"); -} - -void add_vertex_property_serial_int(Db &db, PropertyFamily &f) -{ - DbAccessor t(db); - - auto key = f.get(Int64::type).family_key(); - - size_t i = 0; - t.vertex_access().fill().update().for_all([&](auto va) mutable { - va.set(StoredProperty(Int64(i), key)); - i++; - }); - - permanent_assert(t.commit(), "Add vertex property serial int failed"); -} - -void add_edge_property_serial_int(Db &db, PropertyFamily &f) -{ - DbAccessor t(db); - - auto key = f.get(Int64::type).family_key(); - - size_t i = 0; - t.edge_access().fill().update().for_all([&](auto va) mutable { - va.set(StoredProperty(Int64(i), key)); - i++; - }); - - permanent_assert(t.commit(), "Add Edge property serial int failed"); -} - -template -size_t size(Db &db, IndexHolder &h) -{ - DbAccessor t(db); - - size_t count = 0; - auto oin = h.get_read(); - if (oin.is_present()) - { - oin.get()->for_range(t).for_all([&](auto va) mutable { count++; }); - } - - t.commit(); - - return count; -} - -void assert_empty(Db &db) -{ - permanent_assert(db.graph.vertices.access().size() == 0, - "DB isn't empty (vertices)"); - permanent_assert(db.graph.edges.access().size() == 0, - "DB isn't empty (edges)"); -} - -void clean_vertex(Db &db) -{ - DbTransaction t(db); - t.clean_vertex_section(); - t.trans.commit(); -} - -void clean_edge(Db &db) -{ - DbTransaction t(db); - t.clean_edge_section(); - t.trans.commit(); -} - -void clear_database(Db &db) -{ - std::string delete_all_vertices = "MATCH (n) DELETE n"; - std::string delete_all_edges = "MATCH ()-[r]-() DELETE r"; - - run(1, delete_all_edges, db); - run(1, delete_all_vertices, db); - clean_vertex(db); - clean_edge(db); - assert_empty(db); -} - -bool equal(Db &a, Db &b) -{ - { - auto acc_a = a.graph.vertices.access(); - auto acc_b = b.graph.vertices.access(); - - if (acc_a.size() != acc_b.size()) - { - return false; - } - - auto it_a = acc_a.begin(); - auto it_b = acc_b.begin(); - - for (auto i = acc_a.size(); i > 0; i--) - { - // TODO: compare - } - } - - { - auto acc_a = a.graph.edges.access(); - auto acc_b = b.graph.edges.access(); - - if (acc_a.size() != acc_b.size()) - { - return false; - } - - auto it_a = acc_a.begin(); - auto it_b = acc_b.begin(); - - for (auto i = acc_a.size(); i > 0; i--) - { - // TODO: compare - } - } - - return true; -} - -int main(void) -{ - logging::init_sync(); - logging::log->pipe(std::make_unique()); - - SignalHandler::register_handler(Signal::SegmentationFault, []() { - log_stacktrace("SegmentationFault signal raised"); - std::exit(EXIT_FAILURE); - }); - - SignalHandler::register_handler(Signal::BusError, []() { - log_stacktrace("Bus error signal raised"); - std::exit(EXIT_FAILURE); - }); - - size_t cvl_n = 1; - - std::string create_vertex_label = - "CREATE (n:LABEL {name: \"cleaner_test\"}) RETURN n"; - std::string create_vertex_other = - "CREATE (n:OTHER {name: \"cleaner_test\"}) RETURN n"; - std::string delete_label_vertices = "MATCH (n:LABEL) DELETE n"; - std::string delete_all_vertices = "MATCH (n) DELETE n"; - - IndexDefinition vertex_property_nonunique_unordered = { - IndexLocation{VertexSide, Option("prop"), - Option(), Option()}, - IndexType{false, None}}; - IndexDefinition edge_property_nonunique_unordered = { - IndexLocation{EdgeSide, Option("prop"), - Option(), Option()}, - IndexType{false, None}}; - IndexDefinition edge_property_unique_ordered = { - IndexLocation{EdgeSide, Option("prop"), - Option(), Option()}, - IndexType{true, Ascending}}; - IndexDefinition vertex_property_unique_ordered = { - IndexLocation{VertexSide, Option("prop"), - Option(), Option()}, - IndexType{true, Ascending}}; - - // ******************************* TEST 1 ********************************// - { - logging::info("TEST 1"); - // add indexes - // add vertices LABEL - // add edges - // add vertices property - // assert index size. - Db db("index", false); - permanent_assert( - db.indexes().add_index(vertex_property_nonunique_unordered), - "Add vertex index failed"); - permanent_assert( - db.indexes().add_index(edge_property_nonunique_unordered), - "Add edge index failed"); - - run(cvl_n, create_vertex_label, db); - auto sp = StoredProperty( - Int64(0), db.graph.vertices.property_family_find_or_create("prop") - .get(Int64::type) - .family_key()); - add_property(db, sp); - - permanent_assert( - cvl_n == size(db, db.graph.vertices - .property_family_find_or_create("prop") - .index), - "Create vertex property failed"); - - add_edge(cvl_n, db); - add_edge_property_serial_int( - db, db.graph.edges.property_family_find_or_create("prop")); - - permanent_assert( - cvl_n == - size(db, db.graph.edges.property_family_find_or_create("prop") - .index), - "Create edge property failed"); - } - - // TODO: more tests - - return 0; -} diff --git a/tests/integration/query_engine.cpp b/tests/integration/query_engine.cpp index 7fa61c15e..04215173c 100644 --- a/tests/integration/query_engine.cpp +++ b/tests/integration/query_engine.cpp @@ -1,4 +1,5 @@ #include "query_engine_common.hpp" +#include "dbms/dbms.hpp" using namespace std::chrono_literals; using namespace tests::integration; @@ -23,13 +24,14 @@ int main(int argc, char *argv[]) * init engine */ auto log = init_logging("IntegrationQueryEngine"); - Db db; + Dbms dbms; StreamT stream(std::cout); QueryEngineT query_engine; // IMPORTANT: PrintRecordStream can be replaces with a smarter // object that can test the results - - WarmUpEngine(log, query_engine, db, stream); + + auto db_accessor = dbms.active(); + WarmUpEngine(log, query_engine, db_accessor, stream); return 0; } diff --git a/tests/integration/query_engine_common.hpp b/tests/integration/query_engine_common.hpp index b2785cd31..8340f9280 100644 --- a/tests/integration/query_engine_common.hpp +++ b/tests/integration/query_engine_common.hpp @@ -3,7 +3,7 @@ #include #include namespace fs = std::experimental::filesystem; -#include "database/db.hpp" +#include "database/graph_db_accessor.hpp" #include "logging/default.hpp" #include "logging/streams/stdout.cpp" #include "query/engine.hpp" @@ -20,7 +20,7 @@ namespace integration { using namespace utils; -using QueryHashesT = std::set; +using QueryHashesT = std::set; using QueryEngineT = QueryEngine; using StreamT = PrintRecordStream; @@ -123,13 +123,13 @@ auto LoadQueryPlans(Logger &log, QueryEngineT &engine, * * @param log external logger reference * @param engine query engine - * @param db a database agains the query plans are going to be executed + * @param db_accessor a database accessor on which the query plans are executed * @param path path a queries file * @param stream used by query plans to output the results * * @return void */ -auto ExecuteQueryPlans(Logger &log, QueryEngineT &engine, Db &db, +auto ExecuteQueryPlans(Logger &log, QueryEngineT &engine, GraphDbAccessor &db_accessor, const fs::path &path, StreamT &stream) { log.info("*** Execute the queries from the queries_file ***"); @@ -140,7 +140,7 @@ auto ExecuteQueryPlans(Logger &log, QueryEngineT &engine, Db &db, if (query.empty()) continue; permanent_assert(engine.Loaded(trim(query)), "Implementation wasn't loaded"); - engine.Run(query, db, stream); + engine.Run(query, db_accessor, stream); } } @@ -152,12 +152,13 @@ auto ExecuteQueryPlans(Logger &log, QueryEngineT &engine, Db &db, * * @param log external logger reference * @param engine query engine - * @param db a database agains the query plans are going to be executed + * @param db_accessor a database accessor on which the query plans are executed * @param stream used by query plans to output the results * * @return void */ -auto WarmUpEngine(Logger &log, QueryEngineT &engine, Db &db, StreamT &stream) +auto WarmUpEngine(Logger &log, QueryEngineT &engine, GraphDbAccessor &db_accessor, + StreamT &stream) { // path to a file with queries auto queries_file = fs::path( @@ -173,7 +174,7 @@ auto WarmUpEngine(Logger &log, QueryEngineT &engine, Db &db, StreamT &stream) LoadQueryPlans(log, engine, query_hashes, implementations_folder); // execute all loaded query plasn - ExecuteQueryPlans(log, engine, db, queries_file, stream); + ExecuteQueryPlans(log, engine, db_accessor, queries_file, stream); } } } diff --git a/tests/integration/snapshot.cpp b/tests/integration/snapshot.cpp deleted file mode 100644 index 9ea02fba1..000000000 --- a/tests/integration/snapshot.cpp +++ /dev/null @@ -1,292 +0,0 @@ -// TODO: refactor (backlog task) - -#include - -#include "_hardcoded_query/basic.hpp" -#include "logging/default.hpp" -#include "logging/streams/stdout.hpp" -#include "query/preprocessor.hpp" -#include "query/stripper.hpp" -#include "storage/indexes/indexes.hpp" -#include "utils/assert.hpp" -#include "utils/signals/handler.hpp" -#include "utils/stacktrace/log.hpp" -#include "utils/sysinfo/memory.hpp" - -// Returns uniform random size_t generator from range [0,n> -auto rand_gen(size_t n) -{ - std::default_random_engine generator; - std::uniform_int_distribution distribution(0, n - 1); - return std::bind(distribution, generator); -} - -void run(size_t n, std::string &query, Db &db) -{ - auto qf = hardcode::load_basic_functions(db); - QueryPreprocessor preprocessor; - auto stripped = preprocessor.preprocess(query); - - logging::info("Running query {} [{}] x {}.", query, stripped.hash, n); - - for (int i = 0; i < n; i++) - { - properties_t vec = stripped.arguments; - permanent_assert(qf[stripped.hash](std::move(vec)), "Query aborted"); - } -} - -void add_edge(size_t n, Db &db) -{ - auto qf = hardcode::load_basic_functions(db); - - std::string query = "MATCH (n1), (n2) WHERE ID(n1)=0 AND " - "ID(n2)=1 CREATE (n1)<-[r:IS {age: " - "25,weight: 70}]-(n2) RETURN r"; - QueryPreprocessor preprocessor; - auto stripped = preprocessor.preprocess(query); - - logging::info("Running query {} [{}] x {}.", query, stripped.hash, n); - - std::vector vertices; - for (auto &v : db.graph.vertices.access()) - { - vertices.push_back(v.second.id); - } - - auto rand = rand_gen(vertices.size()); - for (int i = 0; i < n; i++) - { - properties_t vec = stripped.arguments; - vec[0] = Property(Int64(vertices[rand()]), Flags::Int64); - vec[1] = Property(Int64(vertices[rand()]), Flags::Int64); - permanent_assert(qf[stripped.hash](std::move(vec)), "Query aborted"); - } -} - -void add_property(Db &db, StoredProperty &prop) -{ - DbAccessor t(db); - - t.vertex_access().fill().for_all([&](auto va) { va.set(prop); }); - - permanent_assert(t.commit(), "add property query aborted"); - ; -} - -void add_property_different_int(Db &db, PropertyFamily &f) -{ - DbAccessor t(db); - - auto key = f.get(Int64::type).family_key(); - - size_t i = 0; - t.vertex_access().fill().for_all([&](auto va) mutable { - va.set(StoredProperty(Int64(i), key)); - i++; - }); - - permanent_assert(t.commit(), "add property different int aborted"); -} - -size_t size(Db &db, IndexHolder &h) -{ - DbAccessor t(db); - - size_t count = 0; - auto oin = h.get_read(); - if (oin.is_present()) - { - oin.get()->for_range(t).for_all([&](auto va) mutable { count++; }); - } - - t.commit(); - - return count; -} - -void assert_empty(Db &db) -{ - permanent_assert(db.graph.vertices.access().size() == 0, "Db isn't empty"); - permanent_assert(db.graph.edges.access().size() == 0, "Db isn't empty"); -} - -void clean_vertex(Db &db) -{ - DbTransaction t(db); - t.clean_vertex_section(); - t.trans.commit(); -} - -void clean_edge(Db &db) -{ - DbTransaction t(db); - t.clean_edge_section(); - t.trans.commit(); -} - -void clear_database(Db &db) -{ - std::string delete_all_vertices = "MATCH (n) DELETE n"; - std::string delete_all_edges = "MATCH ()-[r]-() DELETE r"; - - run(1, delete_all_edges, db); - run(1, delete_all_vertices, db); - clean_vertex(db); - clean_edge(db); - assert_empty(db); -} - -bool equal(Db &a, Db &b) -{ - { - auto acc_a = a.graph.vertices.access(); - auto acc_b = b.graph.vertices.access(); - - if (acc_a.size() != acc_b.size()) - { - return false; - } - - auto it_a = acc_a.begin(); - auto it_b = acc_b.begin(); - - for (auto i = acc_a.size(); i > 0; i--) - { - // TODO: compare - } - } - - { - auto acc_a = a.graph.edges.access(); - auto acc_b = b.graph.edges.access(); - - if (acc_a.size() != acc_b.size()) - { - return false; - } - - auto it_a = acc_a.begin(); - auto it_b = acc_b.begin(); - - for (auto i = acc_a.size(); i > 0; i--) - { - // TODO: compare - } - } - - return true; -} - -int main(void) -{ - logging::init_sync(); - logging::log->pipe(std::make_unique()); - - SignalHandler::register_handler(Signal::SegmentationFault, []() { - log_stacktrace("SegmentationFault signal raised"); - std::exit(EXIT_FAILURE); - }); - - size_t cvl_n = 1000; - - std::string create_vertex_label = - "CREATE (n:LABEL {name: \"cleaner_test\"}) RETURN n"; - std::string create_vertex_other = - "CREATE (n:OTHER {name: \"cleaner_test\"}) RETURN n"; - std::string delete_label_vertices = "MATCH (n:LABEL) DELETE n"; - std::string delete_all_vertices = "MATCH (n) DELETE n"; - - { - logging::info("TEST 1"); - // make snapshot of empty db - // add vertexs - // add edges - // empty database - // import snapshot - // assert database empty - Db db("snapshot", false); - db.snap_engine.make_snapshot(); - run(cvl_n, create_vertex_label, db); - add_edge(cvl_n, db); - clear_database(db); - db.snap_engine.import(); - assert_empty(db); - logging::info("END of TEST 1"); - } - - { - logging::info("TEST 2"); - // add vertexs - // add edges - // make snapshot of db - // empty database - // import snapshot - // create new db - // compare database with new db - Db db("snapshot", false); - run(cvl_n, create_vertex_label, db); - add_edge(cvl_n, db); - db.snap_engine.make_snapshot(); - clear_database(db); - db.snap_engine.import(); - { - Db db2("snapshot"); - permanent_assert(equal(db, db2), "Dbs aren't equal"); - } - } - - { - logging::info("TEST 3"); - // add vertexs - // add edges - // make snapshot of db - // compare database with different named database - Db db("snapshot", false); - run(cvl_n, create_vertex_label, db); - add_edge(cvl_n, db); - db.snap_engine.make_snapshot(); - { - Db db2("not_snapshot"); - permanent_assert(!equal(db, db2), "Dbs are equal"); - } - } - - { - logging::info("TEST 4"); - // add vertices LABEL - // add properties - // add vertices LABEL - // add index on proprety - // assert index containts vertices - // make snapshot - // create new db - // assert index on LABEL in new db exists - // assert index in new db containts vertice - Db db("snapshot", false); - run(cvl_n, create_vertex_label, db); - auto &family = db.graph.vertices.property_family_find_or_create("prop"); - add_property_different_int(db, family); - run(cvl_n, create_vertex_other, db); - IndexDefinition idef = { - IndexLocation{VertexSide, Option("prop"), - Option(), Option()}, - IndexType{false, None}}; - permanent_assert(db.indexes().add_index(idef), "Index isn't added"); - permanent_assert(cvl_n == size(db, family.index), - "Index size isn't valid"); - db.snap_engine.make_snapshot(); - { - Db db2("snapshot"); - permanent_assert( - cvl_n == size(db, db2.graph.vertices - .property_family_find_or_create("prop") - .index), - "Index size isn't valid"); - } - } - - // TODO: more tests - - return 0; -} diff --git a/tests/integration/stream/print_record_stream.hpp b/tests/integration/stream/print_record_stream.hpp index ac3e893f1..dac6485f1 100644 --- a/tests/integration/stream/print_record_stream.hpp +++ b/tests/integration/stream/print_record_stream.hpp @@ -7,134 +7,82 @@ #include "utils/exceptions/not_yet_implemented.hpp" -class PrintRecordStream -{ +class PrintRecordStream { private: - std::ostream& stream; + std::ostream &stream; public: - PrintRecordStream(std::ostream &stream) : stream(stream) {} + PrintRecordStream(std::ostream &stream) : stream(stream) {} - void write_success() - { - stream << "SUCCESS\n"; + void write_success() { + stream << "SUCCESS\n"; + } + + void write_success_empty() { + stream << "SUCCESS EMPTY\n"; + } + + void write_ignored() { + stream << "IGNORED\n"; + } + + void write_empty_fields() { + stream << "EMPTY FIELDS\n"; + } + + void write_fields(const std::vector &fields) { + stream << "FIELDS:"; + for (auto &field : fields) { + stream << " " << field; } + stream << '\n'; + } - void write_success_empty() - { - stream << "SUCCESS EMPTY\n"; - } + void write_field(const std::string &field) { + stream << "Field: " << field << '\n'; + } - void write_ignored() - { - stream << "IGNORED\n"; - } + void write_list_header(size_t size) { + stream << "List: " << size << '\n'; + } - void write_empty_fields() - { - stream << "EMPTY FIELDS\n"; - } + void write_record() { + stream << "Record\n"; + } - void write_fields(const std::vector &fields) - { - stream << "FIELDS:"; - for (auto &field : fields) - { - stream << " " << field; - } - stream << '\n'; - } + void write_meta(const std::string &type) { + stream << "Meta: " << type << std::endl; + } - void write_field(const std::string &field) - { - stream << "Field: " << field << '\n'; - } + void write_failure(const std::map &data) { + throw NotYetImplemented(); + } - void write_list_header(size_t size) - { - stream << "List: " << size << '\n'; - } + void write_count(const size_t count) { + throw NotYetImplemented(); + } - void write_record() - { - stream << "Record\n"; - } + void write(const VertexAccessor &vertex) { + throw NotYetImplemented(); + } - void write_meta(const std::string &type) - { - stream << "Meta: " << type << std::endl; - } + void write_vertex_record(const VertexAccessor &va) { + throw NotYetImplemented(); + } - void write_failure(const std::map &data) - { - throw NotYetImplemented(); - } + void write(const EdgeAccessor &edge) { + throw NotYetImplemented(); + } - void write_count(const size_t count) - { - throw NotYetImplemented(); - } + void write_edge_record(const EdgeAccessor &ea) { + throw NotYetImplemented(); + } - void write(const VertexAccessor &vertex) - { - throw NotYetImplemented(); - } + void send() { + throw NotYetImplemented(); + } - void write_vertex_record(const VertexAccessor& va) - { - va.stream_repr(stream); - stream << std::endl; - } - - void write(const EdgeAccessor &edge) - { - throw NotYetImplemented(); - } - - void write_edge_record(const EdgeAccessor& ea) - { - throw NotYetImplemented(); - } - - void write(const StoredProperty &prop) - { - throw NotYetImplemented(); - } - - void write(const StoredProperty &prop) - { - throw NotYetImplemented(); - } - - void write(const Null &prop) - { - throw NotYetImplemented(); - } - - void write(const Bool &prop) - { - throw NotYetImplemented(); - } - - void write(const Float &prop) { throw NotYetImplemented(); } - void write(const Int32 &prop) { throw NotYetImplemented(); } - void write(const Int64 &prop) { throw NotYetImplemented(); } - void write(const Double &prop) { throw NotYetImplemented(); } - void write(const String &prop) { throw NotYetImplemented(); } - void write(const ArrayBool &prop) { throw NotYetImplemented(); } - void write(const ArrayInt32 &prop) { throw NotYetImplemented(); } - void write(const ArrayInt64 &prop) { throw NotYetImplemented(); } - void write(const ArrayFloat &prop) { throw NotYetImplemented(); } - void write(const ArrayDouble &prop) { throw NotYetImplemented(); } - void write(const ArrayString &prop) { throw NotYetImplemented(); } - - void send() - { - throw NotYetImplemented(); - } - - void chunk() - { - throw NotYetImplemented(); - } + void chunk() { + throw NotYetImplemented(); + } }; diff --git a/tests/manual/query_engine.cpp b/tests/manual/query_engine.cpp index f95c8c53a..a638f9fdd 100644 --- a/tests/manual/query_engine.cpp +++ b/tests/manual/query_engine.cpp @@ -1,4 +1,5 @@ #include "../integration/query_engine_common.hpp" +#include "dbms/dbms.hpp" #include "utils/fswatcher.hpp" @@ -16,13 +17,14 @@ int main(int argc, char *argv[]) // init engine auto log = init_logging("ManualQueryEngine"); - Db db; + Dbms dbms; + auto db_accessor = dbms.active(); StreamT stream(std::cout); QueryEngineT query_engine; // IMPORTANT: PrintRecordStream can be replaces with a smarter // object that can test the results - WarmUpEngine(log, query_engine, db, stream); + WarmUpEngine(log, query_engine, db_accessor, stream); // init watcher FSWatcher watcher; @@ -51,7 +53,7 @@ int main(int argc, char *argv[]) query_engine.Unload(query); try { query_engine.ReloadCustom(query, event.path); - query_engine.Run(query, db, stream); + query_engine.Run(query, db_accessor, stream); } catch (PlanCompilationException& e) { log.info("Query compilation failed: {}", e.what()); } catch (std::exception& e) { diff --git a/tests/manual/query_hash.cpp b/tests/manual/query_hash.cpp index bf3574a26..96bd797f5 100644 --- a/tests/manual/query_hash.cpp +++ b/tests/manual/query_hash.cpp @@ -34,7 +34,7 @@ int main(int argc, char **argv) println("Query hash: ", preprocessed.hash); println("Property values:"); for (auto property : preprocessed.arguments) { - println(" ", property); + println(" ", property.second); } println(""); diff --git a/tests/unit/cypher_state_machine.cpp b/tests/unit/cypher_state_machine.cpp deleted file mode 100644 index fd00f8fc5..000000000 --- a/tests/unit/cypher_state_machine.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include - -#include "gtest/gtest.h" - -#include "query/backend/cpp_old/entity_search.hpp" -#include "utils/assert.hpp" -#include "utils/underlying_cast.hpp" - -TEST(CypherStateMachine, Basic) -{ - // initialize cypher state machine - CypherStateMachine csm; - - // set cost for label index - auto test_cost = static_cast(30); - csm.search_cost("n", entity_search::search_label_index, test_cost); - - // check all costs - auto max_cost = entity_search::max(); - 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"); -} - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/tests/unit/parameter_index.cpp b/tests/unit/parameter_index.cpp deleted file mode 100644 index 1ea7ecb41..000000000 --- a/tests/unit/parameter_index.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "gtest/gtest.h" - -#include "query/backend/cpp_old/query_action_data.hpp" -#include "utils/assert.hpp" - -using ParameterIndexKey::Type::InternalId; -using ParameterIndexKey::Type::Projection; - -TEST(ParameterIndexKey, Basic) -{ - std::map parameter_index; - - parameter_index[ParameterIndexKey(InternalId, "n1")] = 0; - parameter_index[ParameterIndexKey(InternalId, "n2")] = 1; - - permanent_assert(parameter_index.size() == 2, - "Parameter index size should be 2"); -} - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/tests/unit/typed_value.cpp b/tests/unit/typed_value.cpp index d46a3c9fd..5a7d6cb2d 100644 --- a/tests/unit/typed_value.cpp +++ b/tests/unit/typed_value.cpp @@ -7,11 +7,11 @@ #include "gtest/gtest.h" -#include "storage/model/typed_value.hpp" -#include "storage/model/typed_value_store.hpp" +#include "storage/typed_value.hpp" +#include "storage/typed_value_store.hpp" -TypedValueStore MakePropsAllTypes() { - TypedValueStore props; +TypedValueStore<> MakePropsAllTypes() { + TypedValueStore<> props; props.set(0, true); props.set(1, "something"); props.set(2, 42); @@ -87,7 +87,7 @@ TEST(TypedValue, Equals) { TEST(TypedValue, Less) { // not_bool_type < bool -> exception - TypedValueStore props = MakePropsAllTypes(); + TypedValueStore<> props = MakePropsAllTypes(); for (int i = 0; i < props.size() + 1; ++i) { if (props.at(i).type_ == TypedValue::Type::Bool) continue; @@ -157,7 +157,7 @@ TEST(TypedValue, UnaryMinus) { */ void ExpectArithmeticThrowsAndNull(bool string_ok, std::function op) { // arithmetic ops that raise - TypedValueStore props = MakePropsAllTypes(); + TypedValueStore<> props = MakePropsAllTypes(); for (int i = 0; i < props.size() + 1; ++i) { EXPECT_THROW(op(TypedValue(true), props.at(i)), TypedValueException); EXPECT_THROW(op(props.at(i), TypedValue(true)), TypedValueException); @@ -243,7 +243,7 @@ TEST(TypedValue, Modulo) { } TEST(TypedValue, TypeIncompatibility) { - TypedValueStore props = MakePropsAllTypes(); + TypedValueStore<> props = MakePropsAllTypes(); // iterate over all the props, plus one, what will return // the Null property, which must be incompatible with all @@ -262,7 +262,7 @@ TEST(TypedValue, TypeIncompatibility) { * @param op The logical operation to test. */ void TestLogicalThrows(std::function op) { - TypedValueStore props = MakePropsAllTypes(); + TypedValueStore<> props = MakePropsAllTypes(); for (int i = 0; i < props.size() + 1; ++i) { auto p1 = props.at(i); for (int j = 0; j < props.size() + 1; ++j) { diff --git a/tests/unit/typed_value_store.cpp b/tests/unit/typed_value_store.cpp index 32495972b..337b73496 100644 --- a/tests/unit/typed_value_store.cpp +++ b/tests/unit/typed_value_store.cpp @@ -6,8 +6,7 @@ #include "gtest/gtest.h" -#include "storage/model/typed_value.hpp" -#include "storage/model/typed_value_store.hpp" +#include "storage/typed_value_store.hpp" using std::string; @@ -15,7 +14,7 @@ TEST(TypedValueStore, At) { std::string some_string = "something"; - TypedValueStore props; + TypedValueStore<> props; EXPECT_EQ(TypedValue(props.at(0)).type_, TypedValue::Type::Null); props.set(0, some_string); EXPECT_EQ(TypedValue(props.at(0)).Value(), some_string); @@ -24,7 +23,7 @@ TEST(TypedValueStore, At) { } TEST(TypedValueStore, AtNull) { - TypedValueStore props; + TypedValueStore<> props; EXPECT_EQ(props.at(0).type_, TypedValue::Type::Null); EXPECT_EQ(props.at(100).type_, TypedValue::Type::Null); @@ -36,7 +35,7 @@ TEST(TypedValueStore, AtNull) { TEST(TypedValueStore, Remove) { // set some props - TypedValueStore props; + TypedValueStore<> props; props.set(11, "a"); props.set(30, "b"); EXPECT_NE(props.at(11).type_, TypedValue::Type::Null); @@ -55,7 +54,7 @@ TEST(TypedValueStore, Remove) { } TEST(TypedValueStore, Replace) { - TypedValueStore props; + TypedValueStore<> props; props.set(10, 42); EXPECT_EQ(props.at(10).Value(), 42); props.set(10, 0.25f); @@ -65,7 +64,7 @@ TEST(TypedValueStore, Replace) { TEST(TypedValueStore, Size) { - TypedValueStore props; + TypedValueStore<> props; EXPECT_EQ(props.size(), 0); props.set(0, "something"); @@ -92,14 +91,14 @@ TEST(TypedValueStore, Accept) { int count_props = 0; int count_finish = 0; - auto handler = [&](const TypedValueStore::TKey key, const TypedValue& prop) { + auto handler = [&](const uint32_t key, const TypedValue& prop) { count_props += 1; }; auto finish = [&]() { count_finish += 1; }; - TypedValueStore props; + TypedValueStore props; props.Accept(handler, finish); EXPECT_EQ(count_props, 0); EXPECT_EQ(count_finish, 1);