From 476968e2c8d56cdaaaeaa2780b5a5492709da17e Mon Sep 17 00:00:00 2001 From: gvolfing <107616712+gvolfing@users.noreply.github.com> Date: Mon, 21 Aug 2023 16:45:36 +0200 Subject: [PATCH] Fix concurrent query module race condition (#1158) Concurrent access to the same query module had a race condition on the pointer that was used to handle the custom memory management. With this commit, a mapping has been added to keep information about what thread used the pointer to handle the memory resources. This should be fine since the respected query executions are running on a dedicated thread. Access to the mapping itself is threadsafe. A simple RAII wrapper for the mapping container has also been added for simpler client-side use. --- include/mgp.hpp | 379 +++++++++++------- query_modules/example.cpp | 38 +- tests/e2e/CMakeLists.txt | 1 + .../procedures/batch_c_read.cpp | 10 +- .../concurrent_query_modules/CMakeLists.txt | 8 + tests/e2e/concurrent_query_modules/client.py | 33 ++ .../con_query_modules.py | 19 + .../test_query_modules/CMakeLists.txt | 3 + .../test_query_modules/module_test.cpp | 59 +++ .../concurrent_query_modules/workloads.yaml | 33 ++ tests/unit/cpp_api.cpp | 3 +- 11 files changed, 427 insertions(+), 159 deletions(-) create mode 100644 tests/e2e/concurrent_query_modules/CMakeLists.txt create mode 100644 tests/e2e/concurrent_query_modules/client.py create mode 100644 tests/e2e/concurrent_query_modules/con_query_modules.py create mode 100644 tests/e2e/concurrent_query_modules/test_query_modules/CMakeLists.txt create mode 100644 tests/e2e/concurrent_query_modules/test_query_modules/module_test.cpp create mode 100644 tests/e2e/concurrent_query_modules/workloads.yaml diff --git a/include/mgp.hpp b/include/mgp.hpp index 2dcc6870e..4329fb79c 100644 --- a/include/mgp.hpp +++ b/include/mgp.hpp @@ -15,11 +15,19 @@ #include #include #include +#include #include +#include #include #include +#include +#include #include +#include +#include +#include + #include "_mgp.hpp" #include "mg_exceptions.hpp" #include "mg_procedure.h" @@ -91,8 +99,77 @@ class Value; struct StealType {}; inline constexpr StealType steal{}; +class MemoryDispatcher final { + public: + MemoryDispatcher() = default; + ~MemoryDispatcher() = default; + MemoryDispatcher(const MemoryDispatcher &) = delete; + MemoryDispatcher(MemoryDispatcher &&) = delete; + MemoryDispatcher &operator=(const MemoryDispatcher &) = delete; + MemoryDispatcher &operator=(MemoryDispatcher &&) = delete; + + mgp_memory *GetMemoryResource() noexcept { + const auto this_id = std::this_thread::get_id(); + std::shared_lock lock(mut_); + return map_[this_id]; + } + + void Register(mgp_memory *mem) noexcept { + const auto this_id = std::this_thread::get_id(); + std::unique_lock lock(mut_); + map_[this_id] = mem; + } + + void UnRegister() noexcept { + const auto this_id = std::this_thread::get_id(); + std::unique_lock lock(mut_); + map_.erase(this_id); + } + + private: + std::unordered_map map_; + std::shared_mutex mut_; +}; + +// The use of this object, with the help of MemoryDispatcherGuard +// should be the prefered way to pass the memory pointer to this +// header. The use of the 'mgp_memory *memory' pointer is deprecated +// and will be removed in upcoming releases. +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +inline extern MemoryDispatcher mrd{}; + +// TODO - Once we deprecate this we should remove this +// and make sure nothing relies on it anymore. This alone +// can not guarantee threadsafe use of query procedures. inline mgp_memory *memory{nullptr}; +class MemoryDispatcherGuard final { + public: + explicit MemoryDispatcherGuard(mgp_memory *mem) { mrd.Register(mem); }; + + MemoryDispatcherGuard(const MemoryDispatcherGuard &) = delete; + MemoryDispatcherGuard(MemoryDispatcherGuard &&) = delete; + MemoryDispatcherGuard &operator=(const MemoryDispatcherGuard &) = delete; + MemoryDispatcherGuard &operator=(MemoryDispatcherGuard &&) = delete; + + ~MemoryDispatcherGuard() { mrd.UnRegister(); } +}; + +// Currently we want to preserve both ways(using mgp::memory and +// MemoryDispatcherGuard) of setting the correct memory resource +// from the shared object files. This forwarding function is a +// helper function for that purpose. Once we get rid of the +// 'mgp_memory *memory' pointer this function will not be needed +// anymore and the calls to the memory resource should rely on +// the mapping instead. +template +inline decltype(auto) MemHandlerCallback(Func &&func, Args &&...args) { + if (memory) { + return std::forward(func)(std::forward(args)..., memory); + } + return std::forward(func)(std::forward(args)..., mrd.GetMemoryResource()); +} + /* #region Graph (Id, Graph, Nodes, GraphRelationships, Relationships & Labels) */ /// Wrapper for int64_t IDs to prevent dangerous implicit conversions. @@ -1529,7 +1606,7 @@ inline bool MapsEqual(mgp_map *map1, mgp_map *map2) { if (mgp::map_size(map1) != mgp::map_size(map2)) { return false; } - auto items_it = mgp::map_iter_items(map1, memory); + auto items_it = mgp::MemHandlerCallback(map_iter_items, map1); for (auto item = mgp::map_items_iterator_get(items_it); item; item = mgp::map_items_iterator_next(items_it)) { if (mgp::map_item_key(item) == mgp::map_item_key(item)) { return false; @@ -1794,7 +1871,7 @@ inline int64_t Graph::Size() const { } inline GraphNodes Graph::Nodes() const { - auto nodes_it = mgp::graph_iter_vertices(graph_, memory); + auto nodes_it = mgp::MemHandlerCallback(graph_iter_vertices, graph_); if (nodes_it == nullptr) { throw mg_exception::NotEnoughMemoryException(); } @@ -1804,7 +1881,7 @@ inline GraphNodes Graph::Nodes() const { inline GraphRelationships Graph::Relationships() const { return GraphRelationships(graph_); } inline Node Graph::GetNodeById(const Id node_id) const { - auto mgp_node = mgp::graph_get_vertex_by_id(graph_, mgp_vertex_id{.as_int = node_id.AsInt()}, memory); + auto mgp_node = mgp::MemHandlerCallback(graph_get_vertex_by_id, graph_, mgp_vertex_id{.as_int = node_id.AsInt()}); if (mgp_node == nullptr) { mgp::vertex_destroy(mgp_node); throw NotFoundException("Node with ID " + std::to_string(node_id.AsUint()) + " not found!"); @@ -1815,7 +1892,7 @@ inline Node Graph::GetNodeById(const Id node_id) const { } inline bool Graph::ContainsNode(const Id node_id) const { - auto mgp_node = mgp::graph_get_vertex_by_id(graph_, mgp_vertex_id{.as_int = node_id.AsInt()}, memory); + auto mgp_node = mgp::MemHandlerCallback(graph_get_vertex_by_id, graph_, mgp_vertex_id{.as_int = node_id.AsInt()}); if (mgp_node == nullptr) { return false; } @@ -1847,7 +1924,7 @@ inline bool Graph::ContainsRelationship(const Relationship &relationship) const inline bool Graph::IsMutable() const { return mgp::graph_is_mutable(graph_); } inline Node Graph::CreateNode() { - auto *vertex = mgp::graph_create_vertex(graph_, memory); + auto *vertex = mgp::MemHandlerCallback(graph_create_vertex, graph_); auto node = Node(vertex); mgp::vertex_destroy(vertex); @@ -1860,7 +1937,8 @@ inline void Graph::DeleteNode(const Node &node) { mgp::graph_delete_vertex(graph inline void Graph::DetachDeleteNode(const Node &node) { mgp::graph_detach_delete_vertex(graph_, node.ptr_); }; inline Relationship Graph::CreateRelationship(const Node &from, const Node &to, const std::string_view type) { - auto *edge = mgp::graph_create_edge(graph_, from.ptr_, to.ptr_, mgp_edge_type{.name = type.data()}, memory); + auto *edge = + mgp::MemHandlerCallback(graph_create_edge, graph_, from.ptr_, to.ptr_, mgp_edge_type{.name = type.data()}); auto relationship = Relationship(edge); mgp::edge_destroy(edge); @@ -1967,7 +2045,7 @@ inline GraphRelationships::Iterator::Iterator(mgp_vertices_iterator *nodes_itera } // Check if node has out-relationships - out_relationships_iterator_ = mgp::vertex_iter_out_edges(node, memory); + out_relationships_iterator_ = mgp::MemHandlerCallback(vertex_iter_out_edges, node); auto relationship = mgp::edges_iterator_get(out_relationships_iterator_); if (relationship != nullptr) { return; @@ -2018,7 +2096,7 @@ inline GraphRelationships::Iterator &GraphRelationships::Iterator::operator++() } // Check if node has out-relationships - out_relationships_iterator_ = mgp::vertex_iter_out_edges(node, memory); + out_relationships_iterator_ = mgp::MemHandlerCallback(vertex_iter_out_edges, node); auto relationship = mgp::edges_iterator_get(out_relationships_iterator_); if (relationship != nullptr) { return *this; @@ -2062,13 +2140,13 @@ inline const Relationship GraphRelationships::Iterator::operator*() const { } inline GraphRelationships::Iterator GraphRelationships::begin() const { - return Iterator(mgp::graph_iter_vertices(graph_, memory)); + return Iterator(mgp::MemHandlerCallback(graph_iter_vertices, graph_)); } inline GraphRelationships::Iterator GraphRelationships::end() const { return Iterator(nullptr); } inline GraphRelationships::Iterator GraphRelationships::cbegin() const { - return Iterator(mgp::graph_iter_vertices(graph_, memory)); + return Iterator(mgp::MemHandlerCallback(graph_iter_vertices, graph_)); } inline GraphRelationships::Iterator GraphRelationships::cend() const { return Iterator(nullptr); } @@ -2150,7 +2228,7 @@ inline Relationships::Iterator Relationships::cend() const { return Iterator(nul // Labels: -inline Labels::Labels(mgp_vertex *node_ptr) : node_ptr_(mgp::vertex_copy(node_ptr, memory)) {} +inline Labels::Labels(mgp_vertex *node_ptr) : node_ptr_(mgp::MemHandlerCallback(vertex_copy, node_ptr)) {} inline Labels::Labels(const Labels &other) noexcept : Labels(other.node_ptr_) {} @@ -2160,7 +2238,7 @@ inline Labels &Labels::operator=(const Labels &other) noexcept { if (this != &other) { mgp::vertex_destroy(node_ptr_); - node_ptr_ = mgp::vertex_copy(other.node_ptr_, memory); + node_ptr_ = mgp::MemHandlerCallback(vertex_copy, other.node_ptr_); } return *this; } @@ -2216,27 +2294,29 @@ inline Labels::Iterator Labels::cend() { return Iterator(this, Size()); } // List: -inline List::List(mgp_list *ptr) : ptr_(mgp::list_copy(ptr, memory)) {} +inline List::List(mgp_list *ptr) : ptr_(mgp::MemHandlerCallback(list_copy, ptr)) {} -inline List::List(const mgp_list *const_ptr) : ptr_(mgp::list_copy(const_cast(const_ptr), memory)) {} +inline List::List(const mgp_list *const_ptr) + : ptr_(mgp::MemHandlerCallback(list_copy, const_cast(const_ptr))) {} -inline List::List() : ptr_(mgp::list_make_empty(0, memory)) {} +inline List::List() : ptr_(mgp::MemHandlerCallback(list_make_empty, 0)) {} -inline List::List(size_t capacity) : ptr_(mgp::list_make_empty(capacity, memory)) {} +inline List::List(size_t capacity) : ptr_(mgp::MemHandlerCallback(list_make_empty, capacity)) {} -inline List::List(const std::vector &values) : ptr_(mgp::list_make_empty(values.size(), memory)) { +inline List::List(const std::vector &values) : ptr_(mgp::MemHandlerCallback(list_make_empty, values.size())) { for (const auto &value : values) { AppendExtend(value); } } -inline List::List(std::vector &&values) : ptr_(mgp::list_make_empty(values.size(), memory)) { +inline List::List(std::vector &&values) : ptr_(mgp::MemHandlerCallback(list_make_empty, values.size())) { for (auto &value : values) { Append(std::move(value)); } } -inline List::List(const std::initializer_list values) : ptr_(mgp::list_make_empty(values.size(), memory)) { +inline List::List(const std::initializer_list values) + : ptr_(mgp::MemHandlerCallback(list_make_empty, values.size())) { for (const auto &value : values) { AppendExtend(value); } @@ -2250,7 +2330,7 @@ inline List &List::operator=(const List &other) noexcept { if (this != &other) { mgp::list_destroy(ptr_); - ptr_ = mgp::list_copy(other.ptr_, memory); + ptr_ = mgp::MemHandlerCallback(list_copy, other.ptr_); } return *this; } @@ -2327,26 +2407,26 @@ inline bool MapItem::operator<(const MapItem &other) const { return key < other. // Map: -inline Map::Map(mgp_map *ptr) : ptr_(mgp::map_copy(ptr, memory)) {} +inline Map::Map(mgp_map *ptr) : ptr_(mgp::MemHandlerCallback(map_copy, ptr)) {} -inline Map::Map(const mgp_map *const_ptr) : ptr_(mgp::map_copy(const_cast(const_ptr), memory)) {} +inline Map::Map(const mgp_map *const_ptr) : ptr_(mgp::MemHandlerCallback(map_copy, const_cast(const_ptr))) {} -inline Map::Map() : ptr_(mgp::map_make_empty(memory)) {} +inline Map::Map() : ptr_(mgp::MemHandlerCallback(map_make_empty)) {} -inline Map::Map(const std::map &items) : ptr_(mgp::map_make_empty(memory)) { +inline Map::Map(const std::map &items) : ptr_(mgp::MemHandlerCallback(map_make_empty)) { for (const auto &[key, value] : items) { Insert(key, value); } } -inline Map::Map(std::map &&items) : ptr_(mgp::map_make_empty(memory)) { +inline Map::Map(std::map &&items) : ptr_(mgp::MemHandlerCallback(map_make_empty)) { for (auto &[key, value] : items) { Insert(key, value); } } inline Map::Map(const std::initializer_list> items) - : ptr_(mgp::map_make_empty(memory)) { + : ptr_(mgp::MemHandlerCallback(map_make_empty)) { for (const auto &[key, value] : items) { Insert(key, value); } @@ -2360,7 +2440,7 @@ inline Map &Map::operator=(const Map &other) noexcept { if (this != &other) { mgp::map_destroy(ptr_); - ptr_ = mgp::map_copy(other.ptr_, memory); + ptr_ = mgp::MemHandlerCallback(map_copy, other.ptr_); } return *this; } @@ -2456,11 +2536,11 @@ inline const MapItem Map::Iterator::operator*() const { return MapItem{.key = map_key, .value = map_value}; } -inline Map::Iterator Map::begin() const { return Iterator(mgp::map_iter_items(ptr_, memory)); } +inline Map::Iterator Map::begin() const { return Iterator(mgp::MemHandlerCallback(map_iter_items, ptr_)); } inline Map::Iterator Map::end() const { return Iterator(nullptr); } -inline Map::Iterator Map::cbegin() const { return Iterator(mgp::map_iter_items(ptr_, memory)); } +inline Map::Iterator Map::cbegin() const { return Iterator(mgp::MemHandlerCallback(map_iter_items, ptr_)); } inline Map::Iterator Map::cend() const { return Iterator(nullptr); } @@ -2492,9 +2572,10 @@ inline bool Map::operator!=(const Map &other) const { return !(*this == other); // Node: -inline Node::Node(mgp_vertex *ptr) : ptr_(mgp::vertex_copy(ptr, memory)) {} +inline Node::Node(mgp_vertex *ptr) : ptr_(MemHandlerCallback(vertex_copy, ptr)) {} -inline Node::Node(const mgp_vertex *const_ptr) : ptr_(mgp::vertex_copy(const_cast(const_ptr), memory)) {} +inline Node::Node(const mgp_vertex *const_ptr) + : ptr_(mgp::MemHandlerCallback(vertex_copy, const_cast(const_ptr))) {} inline Node::Node(const Node &other) noexcept : Node(other.ptr_) {} @@ -2504,7 +2585,7 @@ inline Node &Node::operator=(const Node &other) noexcept { if (this != &other) { mgp::vertex_destroy(ptr_); - ptr_ = mgp::vertex_copy(other.ptr_, memory); + ptr_ = mgp::MemHandlerCallback(vertex_copy, other.ptr_); } return *this; } @@ -2539,7 +2620,7 @@ inline bool Node::HasLabel(std::string_view label) const { } inline Relationships Node::InRelationships() const { - auto relationship_iterator = mgp::vertex_iter_in_edges(ptr_, memory); + auto relationship_iterator = mgp::MemHandlerCallback(vertex_iter_in_edges, ptr_); if (relationship_iterator == nullptr) { throw mg_exception::NotEnoughMemoryException(); } @@ -2547,7 +2628,7 @@ inline Relationships Node::InRelationships() const { } inline Relationships Node::OutRelationships() const { - auto relationship_iterator = mgp::vertex_iter_out_edges(ptr_, memory); + auto relationship_iterator = mgp::MemHandlerCallback(vertex_iter_out_edges, ptr_); if (relationship_iterator == nullptr) { throw mg_exception::NotEnoughMemoryException(); } @@ -2563,7 +2644,7 @@ inline void Node::RemoveLabel(const std::string_view label) { } inline std::map Node::Properties() const { - mgp_properties_iterator *properties_iterator = mgp::vertex_iter_properties(ptr_, memory); + mgp_properties_iterator *properties_iterator = mgp::MemHandlerCallback(vertex_iter_properties, ptr_); std::map property_map; for (auto *property = mgp::properties_iterator_get(properties_iterator); property; property = mgp::properties_iterator_next(properties_iterator)) { @@ -2580,7 +2661,7 @@ inline void Node::SetProperty(std::string property, Value value) { inline void Node::RemoveProperty(std::string property) { SetProperty(property, Value()); } inline Value Node::GetProperty(const std::string &property) const { - mgp_value *vertex_prop = mgp::vertex_get_property(ptr_, property.data(), memory); + mgp_value *vertex_prop = mgp::MemHandlerCallback(vertex_get_property, ptr_, property.data()); return Value(steal, vertex_prop); } @@ -2592,10 +2673,10 @@ inline bool Node::operator!=(const Node &other) const { return !(*this == other) // Relationship: -inline Relationship::Relationship(mgp_edge *ptr) : ptr_(mgp::edge_copy(ptr, memory)) {} +inline Relationship::Relationship(mgp_edge *ptr) : ptr_(mgp::MemHandlerCallback(edge_copy, ptr)) {} inline Relationship::Relationship(const mgp_edge *const_ptr) - : ptr_(mgp::edge_copy(const_cast(const_ptr), memory)) {} + : ptr_(mgp::MemHandlerCallback(edge_copy, const_cast(const_ptr))) {} inline Relationship::Relationship(const Relationship &other) noexcept : Relationship(other.ptr_) {} @@ -2605,7 +2686,7 @@ inline Relationship &Relationship::operator=(const Relationship &other) noexcept if (this != &other) { mgp::edge_destroy(ptr_); - ptr_ = mgp::edge_copy(other.ptr_, memory); + ptr_ = mgp::MemHandlerCallback(edge_copy, other.ptr_); } return *this; } @@ -2631,7 +2712,7 @@ inline mgp::Id Relationship::Id() const { return Id::FromInt(mgp::edge_get_id(pt inline std::string_view Relationship::Type() const { return mgp::edge_get_type(ptr_).name; } inline std::map Relationship::Properties() const { - mgp_properties_iterator *properties_iterator = mgp::edge_iter_properties(ptr_, memory); + mgp_properties_iterator *properties_iterator = mgp::MemHandlerCallback(edge_iter_properties, ptr_); std::map property_map; for (mgp_property *property = mgp::properties_iterator_get(properties_iterator); property; property = mgp::properties_iterator_next(properties_iterator)) { @@ -2646,7 +2727,7 @@ inline void Relationship::SetProperty(std::string property, Value value) { } inline Value Relationship::GetProperty(const std::string &property) const { - mgp_value *edge_prop = mgp::edge_get_property(ptr_, property.data(), memory); + mgp_value *edge_prop = mgp::MemHandlerCallback(edge_get_property, ptr_, property.data()); return Value(steal, edge_prop); } @@ -2664,11 +2745,12 @@ inline bool Relationship::operator!=(const Relationship &other) const { return ! // Path: -inline Path::Path(mgp_path *ptr) : ptr_(mgp::path_copy(ptr, memory)) {} +inline Path::Path(mgp_path *ptr) : ptr_(mgp::MemHandlerCallback(path_copy, ptr)) {} -inline Path::Path(const mgp_path *const_ptr) : ptr_(mgp::path_copy(const_cast(const_ptr), memory)) {} +inline Path::Path(const mgp_path *const_ptr) + : ptr_(mgp::MemHandlerCallback(path_copy, const_cast(const_ptr))) {} -inline Path::Path(const Node &start_node) : ptr_(mgp::path_make_with_start(start_node.ptr_, memory)) {} +inline Path::Path(const Node &start_node) : ptr_(mgp::MemHandlerCallback(path_make_with_start, start_node.ptr_)) {} inline Path::Path(const Path &other) noexcept : Path(other.ptr_) {} @@ -2678,7 +2760,7 @@ inline Path &Path::operator=(const Path &other) noexcept { if (this != &other) { mgp::path_destroy(ptr_); - ptr_ = mgp::path_copy(other.ptr_, memory); + ptr_ = mgp::MemHandlerCallback(path_copy, other.ptr_); } return *this; } @@ -2729,15 +2811,16 @@ inline bool Path::operator!=(const Path &other) const { return !(*this == other) // Date: -inline Date::Date(mgp_date *ptr) : ptr_(mgp::date_copy(ptr, memory)) {} +inline Date::Date(mgp_date *ptr) : ptr_(mgp::MemHandlerCallback(date_copy, ptr)) {} -inline Date::Date(const mgp_date *const_ptr) : ptr_(mgp::date_copy(const_cast(const_ptr), memory)) {} +inline Date::Date(const mgp_date *const_ptr) + : ptr_(mgp::MemHandlerCallback(date_copy, const_cast(const_ptr))) {} -inline Date::Date(std::string_view string) : ptr_(mgp::date_from_string(string.data(), memory)) {} +inline Date::Date(std::string_view string) : ptr_(mgp::MemHandlerCallback(date_from_string, string.data())) {} inline Date::Date(int year, int month, int day) { mgp_date_parameters params{.year = year, .month = month, .day = day}; - ptr_ = mgp::date_from_parameters(¶ms, memory); + ptr_ = mgp::MemHandlerCallback(date_from_parameters, ¶ms); } inline Date::Date(const Date &other) noexcept : Date(other.ptr_) {} @@ -2748,7 +2831,7 @@ inline Date &Date::operator=(const Date &other) noexcept { if (this != &other) { mgp::date_destroy(ptr_); - ptr_ = mgp::date_copy(other.ptr_, memory); + ptr_ = mgp::MemHandlerCallback(date_copy, other.ptr_); } return *this; } @@ -2770,7 +2853,7 @@ inline Date::~Date() { } inline Date Date::Now() { - auto mgp_date = mgp::date_now(memory); + auto mgp_date = mgp::MemHandlerCallback(date_now); auto date = Date(mgp_date); mgp::date_destroy(mgp_date); @@ -2788,7 +2871,7 @@ inline int64_t Date::Timestamp() const { return mgp::date_timestamp(ptr_); } inline bool Date::operator==(const Date &other) const { return util::DatesEqual(ptr_, other.ptr_); } inline Date Date::operator+(const Duration &dur) const { - auto mgp_sum = mgp::date_add_duration(ptr_, dur.ptr_, memory); + auto mgp_sum = mgp::MemHandlerCallback(date_add_duration, ptr_, dur.ptr_); auto sum = Date(mgp_sum); mgp::date_destroy(mgp_sum); @@ -2796,7 +2879,7 @@ inline Date Date::operator+(const Duration &dur) const { } inline Date Date::operator-(const Duration &dur) const { - auto mgp_difference = mgp::date_add_duration(ptr_, dur.ptr_, memory); + auto mgp_difference = mgp::MemHandlerCallback(date_add_duration, ptr_, dur.ptr_); auto difference = Date(mgp_difference); mgp::date_destroy(mgp_difference); @@ -2804,7 +2887,7 @@ inline Date Date::operator-(const Duration &dur) const { } inline Duration Date::operator-(const Date &other) const { - auto mgp_difference = mgp::date_diff(ptr_, other.ptr_, memory); + auto mgp_difference = mgp::MemHandlerCallback(date_diff, ptr_, other.ptr_); auto difference = Duration(mgp_difference); mgp::duration_destroy(mgp_difference); @@ -2812,7 +2895,7 @@ inline Duration Date::operator-(const Date &other) const { } inline bool Date::operator<(const Date &other) const { - auto difference = mgp::date_diff(ptr_, other.ptr_, memory); + auto difference = mgp::MemHandlerCallback(date_diff, ptr_, other.ptr_); auto is_less = (mgp::duration_get_microseconds(difference) < 0); mgp::duration_destroy(difference); @@ -2821,17 +2904,18 @@ inline bool Date::operator<(const Date &other) const { // LocalTime: -inline LocalTime::LocalTime(mgp_local_time *ptr) : ptr_(mgp::local_time_copy(ptr, memory)) {} +inline LocalTime::LocalTime(mgp_local_time *ptr) : ptr_(mgp::MemHandlerCallback(local_time_copy, ptr)) {} inline LocalTime::LocalTime(const mgp_local_time *const_ptr) - : ptr_(mgp::local_time_copy(const_cast(const_ptr), memory)) {} + : ptr_(mgp::MemHandlerCallback(local_time_copy, const_cast(const_ptr))) {} -inline LocalTime::LocalTime(std::string_view string) : ptr_(mgp::local_time_from_string(string.data(), memory)) {} +inline LocalTime::LocalTime(std::string_view string) + : ptr_(mgp::MemHandlerCallback(local_time_from_string, string.data())) {} inline LocalTime::LocalTime(int hour, int minute, int second, int millisecond, int microsecond) { mgp_local_time_parameters params{ .hour = hour, .minute = minute, .second = second, .millisecond = millisecond, .microsecond = microsecond}; - ptr_ = mgp::local_time_from_parameters(¶ms, memory); + ptr_ = mgp::MemHandlerCallback(local_time_from_parameters, ¶ms); } inline LocalTime::LocalTime(const LocalTime &other) noexcept : LocalTime(other.ptr_) {} @@ -2842,7 +2926,7 @@ inline LocalTime &LocalTime::operator=(const LocalTime &other) noexcept { if (this != &other) { mgp::local_time_destroy(ptr_); - ptr_ = mgp::local_time_copy(other.ptr_, memory); + ptr_ = mgp::MemHandlerCallback(local_time_copy, other.ptr_); } return *this; } @@ -2864,7 +2948,7 @@ inline LocalTime::~LocalTime() { } inline LocalTime LocalTime::Now() { - auto mgp_local_time = mgp::local_time_now(memory); + auto mgp_local_time = mgp::MemHandlerCallback(local_time_now); auto local_time = LocalTime(mgp_local_time); mgp::local_time_destroy(mgp_local_time); @@ -2886,7 +2970,7 @@ inline int64_t LocalTime::Timestamp() const { return mgp::local_time_timestamp(p inline bool LocalTime::operator==(const LocalTime &other) const { return util::LocalTimesEqual(ptr_, other.ptr_); } inline LocalTime LocalTime::operator+(const Duration &dur) const { - auto mgp_sum = mgp::local_time_add_duration(ptr_, dur.ptr_, memory); + auto mgp_sum = mgp::MemHandlerCallback(local_time_add_duration, ptr_, dur.ptr_); auto sum = LocalTime(mgp_sum); mgp::local_time_destroy(mgp_sum); @@ -2894,7 +2978,7 @@ inline LocalTime LocalTime::operator+(const Duration &dur) const { } inline LocalTime LocalTime::operator-(const Duration &dur) const { - auto mgp_difference = mgp::local_time_sub_duration(ptr_, dur.ptr_, memory); + auto mgp_difference = mgp::MemHandlerCallback(local_time_sub_duration, ptr_, dur.ptr_); auto difference = LocalTime(mgp_difference); mgp::local_time_destroy(mgp_difference); @@ -2902,7 +2986,7 @@ inline LocalTime LocalTime::operator-(const Duration &dur) const { } inline Duration LocalTime::operator-(const LocalTime &other) const { - auto mgp_difference = mgp::local_time_diff(ptr_, other.ptr_, memory); + auto mgp_difference = mgp::MemHandlerCallback(local_time_diff, ptr_, other.ptr_); auto difference = Duration(mgp_difference); mgp::duration_destroy(mgp_difference); @@ -2910,7 +2994,7 @@ inline Duration LocalTime::operator-(const LocalTime &other) const { } inline bool LocalTime::operator<(const LocalTime &other) const { - auto difference = mgp::local_time_diff(ptr_, other.ptr_, memory); + auto difference = mgp::MemHandlerCallback(local_time_diff, ptr_, other.ptr_); auto is_less = (mgp::duration_get_microseconds(difference) < 0); mgp::duration_destroy(difference); @@ -2919,13 +3003,14 @@ inline bool LocalTime::operator<(const LocalTime &other) const { // LocalDateTime: -inline LocalDateTime::LocalDateTime(mgp_local_date_time *ptr) : ptr_(mgp::local_date_time_copy(ptr, memory)) {} +inline LocalDateTime::LocalDateTime(mgp_local_date_time *ptr) + : ptr_(mgp::MemHandlerCallback(local_date_time_copy, ptr)) {} inline LocalDateTime::LocalDateTime(const mgp_local_date_time *const_ptr) - : ptr_(mgp::local_date_time_copy(const_cast(const_ptr), memory)) {} + : ptr_(mgp::MemHandlerCallback(local_date_time_copy, const_cast(const_ptr))) {} inline LocalDateTime::LocalDateTime(std::string_view string) - : ptr_(mgp::local_date_time_from_string(string.data(), memory)) {} + : ptr_(mgp::MemHandlerCallback(local_date_time_from_string, string.data())) {} inline LocalDateTime::LocalDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond) { @@ -2936,7 +3021,7 @@ inline LocalDateTime::LocalDateTime(int year, int month, int day, int hour, int .hour = hour, .minute = minute, .second = second, .millisecond = millisecond, .microsecond = microsecond }; mgp_local_date_time_parameters params{.date_parameters = &date_params, .local_time_parameters = &local_time_params}; - ptr_ = mgp::local_date_time_from_parameters(¶ms, memory); + ptr_ = mgp::MemHandlerCallback(local_date_time_from_parameters, ¶ms); } inline LocalDateTime::LocalDateTime(const LocalDateTime &other) noexcept : LocalDateTime(other.ptr_) {} @@ -2947,7 +3032,7 @@ inline LocalDateTime &LocalDateTime::operator=(const LocalDateTime &other) noexc if (this != &other) { mgp::local_date_time_destroy(ptr_); - ptr_ = mgp::local_date_time_copy(other.ptr_, memory); + ptr_ = mgp::MemHandlerCallback(local_date_time_copy, other.ptr_); } return *this; } @@ -2969,7 +3054,7 @@ inline LocalDateTime::~LocalDateTime() { } inline LocalDateTime LocalDateTime::Now() { - auto mgp_local_date_time = mgp::local_date_time_now(memory); + auto mgp_local_date_time = mgp::MemHandlerCallback(local_date_time_now); auto local_date_time = LocalDateTime(mgp_local_date_time); mgp::local_date_time_destroy(mgp_local_date_time); @@ -2999,7 +3084,7 @@ inline bool LocalDateTime::operator==(const LocalDateTime &other) const { } inline LocalDateTime LocalDateTime::operator+(const Duration &dur) const { - auto mgp_sum = mgp::local_date_time_add_duration(ptr_, dur.ptr_, memory); + auto mgp_sum = mgp::MemHandlerCallback(local_date_time_add_duration, ptr_, dur.ptr_); auto sum = LocalDateTime(mgp_sum); mgp::local_date_time_destroy(mgp_sum); @@ -3007,7 +3092,7 @@ inline LocalDateTime LocalDateTime::operator+(const Duration &dur) const { } inline LocalDateTime LocalDateTime::operator-(const Duration &dur) const { - auto mgp_difference = mgp::local_date_time_sub_duration(ptr_, dur.ptr_, memory); + auto mgp_difference = mgp::MemHandlerCallback(local_date_time_sub_duration, ptr_, dur.ptr_); auto difference = LocalDateTime(mgp_difference); mgp::local_date_time_destroy(mgp_difference); @@ -3015,7 +3100,7 @@ inline LocalDateTime LocalDateTime::operator-(const Duration &dur) const { } inline Duration LocalDateTime::operator-(const LocalDateTime &other) const { - auto mgp_difference = mgp::local_date_time_diff(ptr_, other.ptr_, memory); + auto mgp_difference = mgp::MemHandlerCallback(local_date_time_diff, ptr_, other.ptr_); auto difference = Duration(mgp_difference); mgp::duration_destroy(mgp_difference); @@ -3023,7 +3108,7 @@ inline Duration LocalDateTime::operator-(const LocalDateTime &other) const { } inline bool LocalDateTime::operator<(const LocalDateTime &other) const { - auto difference = mgp::local_date_time_diff(ptr_, other.ptr_, memory); + auto difference = mgp::MemHandlerCallback(local_date_time_diff, ptr_, other.ptr_); auto is_less = (mgp::duration_get_microseconds(difference) < 0); mgp::duration_destroy(difference); @@ -3032,14 +3117,16 @@ inline bool LocalDateTime::operator<(const LocalDateTime &other) const { // Duration: -inline Duration::Duration(mgp_duration *ptr) : ptr_(mgp::duration_copy(ptr, memory)) {} +inline Duration::Duration(mgp_duration *ptr) : ptr_(mgp::MemHandlerCallback(duration_copy, ptr)) {} inline Duration::Duration(const mgp_duration *const_ptr) - : ptr_(mgp::duration_copy(const_cast(const_ptr), memory)) {} + : ptr_(mgp::MemHandlerCallback(duration_copy, const_cast(const_ptr))) {} -inline Duration::Duration(std::string_view string) : ptr_(mgp::duration_from_string(string.data(), memory)) {} +inline Duration::Duration(std::string_view string) + : ptr_(mgp::MemHandlerCallback(duration_from_string, string.data())) {} -inline Duration::Duration(int64_t microseconds) : ptr_(mgp::duration_from_microseconds(microseconds, memory)) {} +inline Duration::Duration(int64_t microseconds) + : ptr_(mgp::MemHandlerCallback(duration_from_microseconds, microseconds)) {} inline Duration::Duration(double day, double hour, double minute, double second, double millisecond, double microsecond) { @@ -3049,7 +3136,7 @@ inline Duration::Duration(double day, double hour, double minute, double second, .second = second, .millisecond = millisecond, .microsecond = microsecond}; - ptr_ = mgp::duration_from_parameters(¶ms, memory); + ptr_ = mgp::MemHandlerCallback(duration_from_parameters, ¶ms); } inline Duration::Duration(const Duration &other) noexcept : Duration(other.ptr_) {} @@ -3060,7 +3147,7 @@ inline Duration &Duration::operator=(const Duration &other) noexcept { if (this != &other) { mgp::duration_destroy(ptr_); - ptr_ = mgp::duration_copy(other.ptr_, memory); + ptr_ = mgp::MemHandlerCallback(duration_copy, other.ptr_); } return *this; } @@ -3086,7 +3173,7 @@ inline int64_t Duration::Microseconds() const { return mgp::duration_get_microse inline bool Duration::operator==(const Duration &other) const { return util::DurationsEqual(ptr_, other.ptr_); } inline Duration Duration::operator+(const Duration &other) const { - auto mgp_sum = mgp::duration_add(ptr_, other.ptr_, memory); + auto mgp_sum = mgp::MemHandlerCallback(duration_add, ptr_, other.ptr_); auto sum = Duration(mgp_sum); mgp::duration_destroy(mgp_sum); @@ -3094,7 +3181,7 @@ inline Duration Duration::operator+(const Duration &other) const { } inline Duration Duration::operator-(const Duration &other) const { - auto mgp_difference = mgp::duration_sub(ptr_, other.ptr_, memory); + auto mgp_difference = mgp::MemHandlerCallback(duration_sub, ptr_, other.ptr_); auto difference = Duration(mgp_difference); mgp::duration_destroy(mgp_difference); @@ -3102,7 +3189,7 @@ inline Duration Duration::operator-(const Duration &other) const { } inline Duration Duration::operator-() const { - auto mgp_neg = mgp::duration_neg(ptr_, memory); + auto mgp_neg = mgp::MemHandlerCallback(duration_neg, ptr_); auto neg = Duration(mgp_neg); mgp::duration_destroy(mgp_neg); @@ -3110,7 +3197,7 @@ inline Duration Duration::operator-() const { } inline bool Duration::operator<(const Duration &other) const { - auto difference = mgp::duration_sub(ptr_, other.ptr_, memory); + auto difference = mgp::MemHandlerCallback(duration_sub, ptr_, other.ptr_); auto is_less = (mgp::duration_get_microseconds(difference) < 0); mgp::duration_destroy(difference); @@ -3123,36 +3210,36 @@ inline bool Duration::operator<(const Duration &other) const { /* #region Value */ -inline Value::Value(mgp_value *ptr) : ptr_(mgp::value_copy(ptr, memory)) {} +inline Value::Value(mgp_value *ptr) : ptr_(mgp::MemHandlerCallback(value_copy, ptr)) {} inline Value::Value(StealType /*steal*/, mgp_value *ptr) : ptr_{ptr} {} -inline Value::Value() : ptr_(mgp::value_make_null(memory)) {} +inline Value::Value() : ptr_(mgp::MemHandlerCallback(value_make_null)) {} -inline Value::Value(const bool value) : ptr_(mgp::value_make_bool(value, memory)) {} +inline Value::Value(const bool value) : ptr_(mgp::MemHandlerCallback(value_make_bool, value)) {} -inline Value::Value(const int64_t value) : ptr_(mgp::value_make_int(value, memory)) {} +inline Value::Value(const int64_t value) : ptr_(mgp::MemHandlerCallback(value_make_int, value)) {} -inline Value::Value(const double value) : ptr_(mgp::value_make_double(value, memory)) {} +inline Value::Value(const double value) : ptr_(mgp::MemHandlerCallback(value_make_double, value)) {} -inline Value::Value(const char *value) : ptr_(mgp::value_make_string(value, memory)) {} +inline Value::Value(const char *value) : ptr_(mgp::MemHandlerCallback(value_make_string, value)) {} -inline Value::Value(const std::string_view value) : ptr_(mgp::value_make_string(value.data(), memory)) {} +inline Value::Value(const std::string_view value) : ptr_(mgp::MemHandlerCallback(value_make_string, value.data())) {} -inline Value::Value(const List &list) : ptr_(mgp::value_make_list(mgp::list_copy(list.ptr_, memory))) {} +inline Value::Value(const List &list) : ptr_(mgp::value_make_list(mgp::MemHandlerCallback(list_copy, list.ptr_))) {} inline Value::Value(List &&list) { ptr_ = mgp::value_make_list(list.ptr_); list.ptr_ = nullptr; } -inline Value::Value(const Map &map) : ptr_(mgp::value_make_map(mgp::map_copy(map.ptr_, memory))) {} +inline Value::Value(const Map &map) : ptr_(mgp::value_make_map(mgp::MemHandlerCallback(map_copy, map.ptr_))) {} inline Value::Value(Map &&map) { ptr_ = mgp::value_make_map(map.ptr_); map.ptr_ = nullptr; } -inline Value::Value(const Node &node) : ptr_(mgp::value_make_vertex(mgp::vertex_copy(node.ptr_, memory))) {} +inline Value::Value(const Node &node) : ptr_(mgp::value_make_vertex(mgp::MemHandlerCallback(vertex_copy, node.ptr_))) {} inline Value::Value(Node &&node) { ptr_ = mgp::value_make_vertex(const_cast(node.ptr_)); @@ -3160,21 +3247,21 @@ inline Value::Value(Node &&node) { } inline Value::Value(const Relationship &relationship) - : ptr_(mgp::value_make_edge(mgp::edge_copy(relationship.ptr_, memory))) {} + : ptr_(mgp::value_make_edge(mgp::MemHandlerCallback(edge_copy, relationship.ptr_))) {} inline Value::Value(Relationship &&relationship) { ptr_ = mgp::value_make_edge(const_cast(relationship.ptr_)); relationship.ptr_ = nullptr; } -inline Value::Value(const Path &path) : ptr_(mgp::value_make_path(mgp::path_copy(path.ptr_, memory))) {} +inline Value::Value(const Path &path) : ptr_(mgp::value_make_path(mgp::MemHandlerCallback(path_copy, path.ptr_))) {} inline Value::Value(Path &&path) { ptr_ = mgp::value_make_path(path.ptr_); path.ptr_ = nullptr; } -inline Value::Value(const Date &date) : ptr_(mgp::value_make_date(mgp::date_copy(date.ptr_, memory))) {} +inline Value::Value(const Date &date) : ptr_(mgp::value_make_date(mgp::MemHandlerCallback(date_copy, date.ptr_))) {} inline Value::Value(Date &&date) { ptr_ = mgp::value_make_date(date.ptr_); @@ -3182,7 +3269,7 @@ inline Value::Value(Date &&date) { } inline Value::Value(const LocalTime &local_time) - : ptr_(mgp::value_make_local_time(mgp::local_time_copy(local_time.ptr_, memory))) {} + : ptr_(mgp::value_make_local_time(mgp::MemHandlerCallback(local_time_copy, local_time.ptr_))) {} inline Value::Value(LocalTime &&local_time) { ptr_ = mgp::value_make_local_time(local_time.ptr_); @@ -3190,7 +3277,7 @@ inline Value::Value(LocalTime &&local_time) { } inline Value::Value(const LocalDateTime &local_date_time) - : ptr_(mgp::value_make_local_date_time(mgp::local_date_time_copy(local_date_time.ptr_, memory))) {} + : ptr_(mgp::value_make_local_date_time(mgp::MemHandlerCallback(local_date_time_copy, local_date_time.ptr_))) {} inline Value::Value(LocalDateTime &&local_date_time) { ptr_ = mgp::value_make_local_date_time(local_date_time.ptr_); @@ -3198,7 +3285,7 @@ inline Value::Value(LocalDateTime &&local_date_time) { } inline Value::Value(const Duration &duration) - : ptr_(mgp::value_make_duration(mgp::duration_copy(duration.ptr_, memory))) {} + : ptr_(mgp::value_make_duration(mgp::MemHandlerCallback(duration_copy, duration.ptr_))) {} inline Value::Value(Duration &&duration) { ptr_ = mgp::value_make_duration(duration.ptr_); @@ -3213,7 +3300,7 @@ inline Value &Value::operator=(const Value &other) noexcept { if (this != &other) { mgp::value_destroy(ptr_); - ptr_ = mgp::value_copy(other.ptr_, memory); + ptr_ = mgp::MemHandlerCallback(value_copy, other.ptr_); } return *this; } @@ -3589,85 +3676,85 @@ inline std::ostream &operator<<(std::ostream &os, const mgp::Type &type) { inline Record::Record(mgp_result_record *record) : record_(record) {} inline void Record::Insert(const char *field_name, bool value) { - auto mgp_val = mgp::value_make_bool(value, memory); + auto mgp_val = mgp::MemHandlerCallback(value_make_bool, value); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, std::int64_t value) { - auto mgp_val = mgp::value_make_int(value, memory); + auto mgp_val = mgp::MemHandlerCallback(value_make_int, value); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, double value) { - auto mgp_val = mgp::value_make_double(value, memory); + auto mgp_val = mgp::MemHandlerCallback(value_make_double, value); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, std::string_view value) { - auto mgp_val = mgp::value_make_string(value.data(), memory); + auto mgp_val = mgp::MemHandlerCallback(value_make_string, value.data()); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, const char *value) { - auto mgp_val = mgp::value_make_string(value, memory); + auto mgp_val = mgp::MemHandlerCallback(value_make_string, value); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, const List &list) { - auto mgp_val = mgp::value_make_list(mgp::list_copy(list.ptr_, memory)); + auto mgp_val = mgp::value_make_list(mgp::MemHandlerCallback(list_copy, list.ptr_)); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, const Map &map) { - auto mgp_val = mgp::value_make_map(mgp::map_copy(map.ptr_, memory)); + auto mgp_val = mgp::value_make_map(mgp::MemHandlerCallback(map_copy, map.ptr_)); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, const Node &node) { - auto mgp_val = mgp::value_make_vertex(mgp::vertex_copy(node.ptr_, memory)); + auto mgp_val = mgp::value_make_vertex(mgp::MemHandlerCallback(vertex_copy, node.ptr_)); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, const Relationship &relationship) { - auto mgp_val = mgp::value_make_edge(mgp::edge_copy(relationship.ptr_, memory)); + auto mgp_val = mgp::value_make_edge(mgp::MemHandlerCallback(edge_copy, relationship.ptr_)); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, const Path &path) { - auto mgp_val = mgp::value_make_path(mgp::path_copy(path.ptr_, memory)); + auto mgp_val = mgp::value_make_path(mgp::MemHandlerCallback(path_copy, path.ptr_)); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, const Date &date) { - auto mgp_val = mgp::value_make_date(mgp::date_copy(date.ptr_, memory)); + auto mgp_val = mgp::value_make_date(mgp::MemHandlerCallback(date_copy, date.ptr_)); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, const LocalTime &local_time) { - auto mgp_val = mgp::value_make_local_time(mgp::local_time_copy(local_time.ptr_, memory)); + auto mgp_val = mgp::value_make_local_time(mgp::MemHandlerCallback(local_time_copy, local_time.ptr_)); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, const LocalDateTime &local_date_time) { - auto mgp_val = mgp::value_make_local_date_time(mgp::local_date_time_copy(local_date_time.ptr_, memory)); + auto mgp_val = mgp::value_make_local_date_time(mgp::MemHandlerCallback(local_date_time_copy, local_date_time.ptr_)); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } inline void Record::Insert(const char *field_name, const Duration &duration) { - auto mgp_val = mgp::value_make_duration(mgp::duration_copy(duration.ptr_, memory)); + auto mgp_val = mgp::value_make_duration(mgp::MemHandlerCallback(duration_copy, duration.ptr_)); { mgp::result_record_insert(record_, field_name, mgp_val); } mgp::value_destroy(mgp_val); } @@ -3731,95 +3818,95 @@ inline void RecordFactory::SetErrorMessage(const char *error_msg) const { inline Result::Result(mgp_func_result *result) : result_(result) {} inline void Result::SetValue(bool value) { - auto mgp_val = mgp::value_make_bool(value, memory); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::MemHandlerCallback(value_make_bool, value); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(std::int64_t value) { - auto mgp_val = mgp::value_make_int(value, memory); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::MemHandlerCallback(value_make_int, value); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(double value) { - auto mgp_val = mgp::value_make_double(value, memory); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::MemHandlerCallback(value_make_double, value); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(std::string_view value) { - auto mgp_val = mgp::value_make_string(value.data(), memory); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::MemHandlerCallback(value_make_string, value.data()); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(const char *value) { - auto mgp_val = mgp::value_make_string(value, memory); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::MemHandlerCallback(value_make_string, value); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(const List &list) { - auto mgp_val = mgp::value_make_list(mgp::list_copy(list.ptr_, memory)); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::value_make_list(mgp::MemHandlerCallback(list_copy, list.ptr_)); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(const Map &map) { - auto mgp_val = mgp::value_make_map(mgp::map_copy(map.ptr_, memory)); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::value_make_map(mgp::MemHandlerCallback(map_copy, map.ptr_)); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(const Node &node) { - auto mgp_val = mgp::value_make_vertex(mgp::vertex_copy(node.ptr_, memory)); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::value_make_vertex(mgp::MemHandlerCallback(vertex_copy, node.ptr_)); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(const Relationship &relationship) { - auto mgp_val = mgp::value_make_edge(mgp::edge_copy(relationship.ptr_, memory)); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::value_make_edge(mgp::MemHandlerCallback(edge_copy, relationship.ptr_)); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(const Path &path) { - auto mgp_val = mgp::value_make_path(mgp::path_copy(path.ptr_, memory)); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::value_make_path(mgp::MemHandlerCallback(path_copy, path.ptr_)); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(const Date &date) { - auto mgp_val = mgp::value_make_date(mgp::date_copy(date.ptr_, memory)); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::value_make_date(mgp::MemHandlerCallback(date_copy, date.ptr_)); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(const LocalTime &local_time) { - auto mgp_val = mgp::value_make_local_time(mgp::local_time_copy(local_time.ptr_, memory)); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::value_make_local_time(mgp::MemHandlerCallback(local_time_copy, local_time.ptr_)); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(const LocalDateTime &local_date_time) { - auto mgp_val = mgp::value_make_local_date_time(mgp::local_date_time_copy(local_date_time.ptr_, memory)); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::value_make_local_date_time(mgp::MemHandlerCallback(local_date_time_copy, local_date_time.ptr_)); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetValue(const Duration &duration) { - auto mgp_val = mgp::value_make_duration(mgp::duration_copy(duration.ptr_, memory)); - { mgp::func_result_set_value(result_, mgp_val, memory); } + auto mgp_val = mgp::value_make_duration(mgp::MemHandlerCallback(duration_copy, duration.ptr_)); + { mgp::MemHandlerCallback(func_result_set_value, result_, mgp_val); } mgp::value_destroy(mgp_val); } inline void Result::SetErrorMessage(const std::string_view error_msg) const { - mgp::func_result_set_error_msg(result_, error_msg.data(), memory); + mgp::MemHandlerCallback(func_result_set_error_msg, result_, error_msg.data()); } inline void Result::SetErrorMessage(const char *error_msg) const { - mgp::func_result_set_error_msg(result_, error_msg, memory); + mgp::MemHandlerCallback(func_result_set_error_msg, result_, error_msg); } /* #endregion */ diff --git a/query_modules/example.cpp b/query_modules/example.cpp index 8e9e80007..a539c4b3a 100644 --- a/query_modules/example.cpp +++ b/query_modules/example.cpp @@ -1,4 +1,4 @@ -// Copyright 2022 Memgraph Ltd. +// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -18,7 +18,11 @@ void ProcImpl(std::vector arguments, mgp::Graph graph, mgp::RecordFa void SampleReadProc(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { try { - mgp::memory = memory; + // The outcommented way of assigning the memory pointer is still + // working, but it is deprecated because of certain concurrency + // issues. Please use the guard instead. + // mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); std::vector arguments; for (size_t i = 0; i < mgp::list_size(args); i++) { @@ -34,7 +38,11 @@ void SampleReadProc(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *resul } void AddXNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + // The outcommented way of assigning the memory pointer is still + // working, but it is deprecated because of certain concurrency + // issues. Please use the guard instead. + // mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); auto graph = mgp::Graph(memgraph_graph); std::vector arguments; @@ -49,7 +57,11 @@ void AddXNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mg } void Multiply(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + // The outcommented way of assigning the memory pointer is still + // working, but it is deprecated because of certain concurrency + // issues. Please use the guard instead. + // mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); std::vector arguments; for (size_t i = 0; i < mgp::list_size(args); i++) { @@ -67,7 +79,11 @@ void Multiply(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_m extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + // The outcommented way of assigning the memory pointer is still + // working, but it is deprecated because of certain concurrency + // issues. Please use the guard instead. + // mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); AddProcedure(SampleReadProc, "return_true", mgp::ProcedureType::Read, {mgp::Parameter("param_1", mgp::Type::Int), mgp::Parameter("param_2", mgp::Type::Double, 2.3)}, @@ -77,7 +93,11 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem } try { - mgp::memory = memory; + // The outcommented way of assigning the memory pointer is still + // working, but it is deprecated because of certain concurrency + // issues. Please use the guard instead. + // mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); mgp::AddProcedure(AddXNodes, "add_x_nodes", mgp::ProcedureType::Write, {mgp::Parameter("param_1", mgp::Type::Int)}, {}, module, memory); @@ -87,7 +107,11 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem } try { - mgp::memory = memory; + // The outcommented way of assigning the memory pointer is still + // working, but it is deprecated because of certain concurrency + // issues. Please use the guard instead. + // mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); mgp::AddFunction(Multiply, "multiply", {mgp::Parameter("int", mgp::Type::Int), mgp::Parameter("int", mgp::Type::Int, (int64_t)3)}, module, diff --git a/tests/e2e/CMakeLists.txt b/tests/e2e/CMakeLists.txt index 188515b32..b839dedc5 100644 --- a/tests/e2e/CMakeLists.txt +++ b/tests/e2e/CMakeLists.txt @@ -61,6 +61,7 @@ add_subdirectory(load_csv) add_subdirectory(init_file_flags) add_subdirectory(analytical_mode) add_subdirectory(batched_procedures) +add_subdirectory(concurrent_query_modules) copy_e2e_python_files(pytest_runner pytest_runner.sh "") file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/memgraph-selfsigned.crt DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/tests/e2e/batched_procedures/procedures/batch_c_read.cpp b/tests/e2e/batched_procedures/procedures/batch_c_read.cpp index 8d9221727..53dd6daa3 100644 --- a/tests/e2e/batched_procedures/procedures/batch_c_read.cpp +++ b/tests/e2e/batched_procedures/procedures/batch_c_read.cpp @@ -30,7 +30,7 @@ static int returned_strings{0}; const char *kReturnOutput = "output"; void NumsBatchInit(struct mgp_list *args, mgp_graph *graph, struct mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); const auto arguments = mgp::List(args); if (arguments.Empty()) { throw std::runtime_error("Expected to recieve argument"); @@ -43,7 +43,7 @@ void NumsBatchInit(struct mgp_list *args, mgp_graph *graph, struct mgp_memory *m } void NumsBatch(struct mgp_list *args, mgp_graph *graph, mgp_result *result, struct mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); if (returned_ints < num_ints) { @@ -58,7 +58,7 @@ void NumsBatchCleanup() { } void StringsBatchInit(struct mgp_list *args, mgp_graph *graph, struct mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); const auto arguments = mgp::List(args); if (arguments.Empty()) { throw std::runtime_error("Expected to recieve argument"); @@ -71,7 +71,7 @@ void StringsBatchInit(struct mgp_list *args, mgp_graph *graph, struct mgp_memory } void StringsBatch(struct mgp_list *args, mgp_graph *graph, mgp_result *result, struct mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); @@ -117,7 +117,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard(memory); mgp::AddBatchProcedure(StringsBatch, StringsBatchInit, StringsBatchCleanup, "batch_strings", mgp::ProcedureType::Read, {mgp::Parameter("num_strings", mgp::Type::Int)}, {mgp::Return("output", mgp::Type::String)}, module, memory); diff --git a/tests/e2e/concurrent_query_modules/CMakeLists.txt b/tests/e2e/concurrent_query_modules/CMakeLists.txt new file mode 100644 index 000000000..6c92387cb --- /dev/null +++ b/tests/e2e/concurrent_query_modules/CMakeLists.txt @@ -0,0 +1,8 @@ +function(copy_concurrent_query_modules_e2e_python_files FILE_NAME) + copy_e2e_python_files(concurrent_query_modules ${FILE_NAME}) +endfunction() + +copy_concurrent_query_modules_e2e_python_files(client.py) +copy_concurrent_query_modules_e2e_python_files(con_query_modules.py) + +add_subdirectory(test_query_modules) diff --git a/tests/e2e/concurrent_query_modules/client.py b/tests/e2e/concurrent_query_modules/client.py new file mode 100644 index 000000000..559058edc --- /dev/null +++ b/tests/e2e/concurrent_query_modules/client.py @@ -0,0 +1,33 @@ +import multiprocessing + +import mgclient +import pytest + + +def inner(query, number_of_executions): + connection = mgclient.connect(host="127.0.0.1", port=7687) + connection.autocommit = True + cursor = connection.cursor() + for _ in range(number_of_executions): + cursor.execute(query) + cursor.fetchall() + + +class MemgraphClient: + def __init__(self): + self.query_list = [] + + def initialize_to_execute(self, query: str, number_of_executions): + self.query_list.append((query, number_of_executions)) + + def execute_queries(self): + num_processes = len(self.query_list) + with multiprocessing.Pool(processes=num_processes) as pool: + pool.starmap(inner, self.query_list) + + return True + + +@pytest.fixture +def client() -> MemgraphClient: + return MemgraphClient() diff --git a/tests/e2e/concurrent_query_modules/con_query_modules.py b/tests/e2e/concurrent_query_modules/con_query_modules.py new file mode 100644 index 000000000..b249e949b --- /dev/null +++ b/tests/e2e/concurrent_query_modules/con_query_modules.py @@ -0,0 +1,19 @@ +import sys + +import pytest +from client import * + +query = "MATCH (my_person:Person)-[:FOLLOW]->(follow_person:Person) MATCH (follow_person)-[: LIKE]->(post:Post) WHERE post.indexedAt IS NOT NULL AND NOT exists((post)-[:ROOT]->(:Post)) WITH localDateTime() - post.indexedAt as duration, post, follow_person WHERE duration.day < 5 WITH (duration.day * 24) + duration.hour as hour_age, post, follow_person ORDER BY post.indexedAt DESC LIMIT 500 MATCH(: Person) - [l: LIKE] -> (post) WITH count(l) as likes, hour_age, post, follow_person CALL libmodule_test.hacker_news(likes, 123, 4.1) YIELD score RETURN ID(post), post.uri, hour_age, likes, score, follow_person ORDER BY score DESC, hour_age ASC, post.indexedAt DESC LIMIT 100;" + + +def test_concurrent_module_access(client): + client.initialize_to_execute(query, 200) + client.initialize_to_execute(query, 200) + client.initialize_to_execute(query, 200) + + success = client.execute_queries() + assert success + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__, "-rA"])) diff --git a/tests/e2e/concurrent_query_modules/test_query_modules/CMakeLists.txt b/tests/e2e/concurrent_query_modules/test_query_modules/CMakeLists.txt new file mode 100644 index 000000000..3baf80449 --- /dev/null +++ b/tests/e2e/concurrent_query_modules/test_query_modules/CMakeLists.txt @@ -0,0 +1,3 @@ +project(TestSharedObjects) +add_library(module_test SHARED module_test.cpp) +target_include_directories(module_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../include) diff --git a/tests/e2e/concurrent_query_modules/test_query_modules/module_test.cpp b/tests/e2e/concurrent_query_modules/test_query_modules/module_test.cpp new file mode 100644 index 000000000..44479d900 --- /dev/null +++ b/tests/e2e/concurrent_query_modules/test_query_modules/module_test.cpp @@ -0,0 +1,59 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#include + +#include +#include +#include +#include + +constexpr char *kProcedureHackerNews = "hacker_news"; +constexpr char *kArgumentHackerNewsVotes = "votes"; +constexpr char *kArgumentHackerNewsItemHourAge = "item_hour_age"; +constexpr char *kArgumentHackerNewsGravity = "gravity"; +constexpr char *kReturnHackerNewsScore = "score"; + +void HackerNews(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { + mgp::MemoryDispatcherGuard guard(memory); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + const auto &arguments = mgp::List(args); + const auto record_factory = mgp::RecordFactory(result); + try { + const auto votes = arguments[0].ValueInt(); + const auto item_hour_age = arguments[1].ValueInt(); + const auto gravity = arguments[2].ValueDouble(); + const auto score = 1000000.0 * (votes / pow((item_hour_age + 2), gravity)); + auto record = record_factory.NewRecord(); + record.Insert(kReturnHackerNewsScore, score); + } catch (const std::exception &e) { + record_factory.SetErrorMessage(e.what()); + return; + } +} + +extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { + try { + mgp::MemoryDispatcherGuard guard(memory); + std::vector params = { + mgp::Parameter(kArgumentHackerNewsVotes, mgp::Type::Int), + mgp::Parameter(kArgumentHackerNewsItemHourAge, mgp::Type::Int), + mgp::Parameter(kArgumentHackerNewsGravity, mgp::Type::Double), + }; + std::vector returns = {mgp::Return(kReturnHackerNewsScore, mgp::Type::Double)}; + AddProcedure(HackerNews, kProcedureHackerNews, mgp::ProcedureType::Read, params, returns, module, memory); + } catch (const std::exception &e) { + return 1; + } + return 0; +} + +extern "C" int mgp_shutdown_module() { return 0; } diff --git a/tests/e2e/concurrent_query_modules/workloads.yaml b/tests/e2e/concurrent_query_modules/workloads.yaml new file mode 100644 index 000000000..9e69d1ed4 --- /dev/null +++ b/tests/e2e/concurrent_query_modules/workloads.yaml @@ -0,0 +1,33 @@ +args: &args + - "--bolt-port" + - "7687" + - "--log-level" + - "TRACE" + +in_memory_cluster: &in_memory_cluster + cluster: + main: + args: *args + log_file: "concurrent-query-modules-e2e.log" + setup_queries: [] + validation_queries: [] + +disk_cluster: &disk_cluster + cluster: + main: + args: *args + log_file: "concurrent-query-modules-e2e.log" + setup_queries: ["STORAGE MODE ON_DISK_TRANSACTIONAL"] + validation_queries: [] + +workloads: + - name: "Concurrent query modules" + binary: "tests/e2e/pytest_runner.sh" + proc: "tests/e2e/concurrent_query_modules/test_query_modules/" + args: ["concurrent_query_modules/con_query_modules.py"] + <<: *in_memory_cluster + - name: "Disk concurrent query modules" + binary: "tests/e2e/pytest_runner.sh" + proc: "tests/e2e/concurrent_query_modules/test_query_modules/" + args: ["concurrent_query_modules/con_query_modules.py"] + <<: *disk_cluster diff --git a/tests/unit/cpp_api.cpp b/tests/unit/cpp_api.cpp index 5f0dfa15f..d2c65b349 100644 --- a/tests/unit/cpp_api.cpp +++ b/tests/unit/cpp_api.cpp @@ -27,12 +27,13 @@ template struct CppApiTestFixture : public ::testing::Test { protected: - virtual void SetUp() override { mgp::memory = &memory; } + virtual void SetUp() override { mgp::mrd.Register(&memory); } void TearDown() override { if (std::is_same::value) { disk_test_utils::RemoveRocksDbDirs(testSuite); } + mgp::mrd.UnRegister(); } mgp_graph CreateGraph(const memgraph::storage::View view = memgraph::storage::View::NEW) {