Skip to content

Commit a5b0896

Browse files
authored
Implement meta stats util (#296)
1 parent c412c1b commit a5b0896

File tree

37 files changed

+928
-0
lines changed

37 files changed

+928
-0
lines changed

cpp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ add_subdirectory(do_module)
147147
add_subdirectory(periodic_module)
148148
add_subdirectory(map_module)
149149
add_subdirectory(collections_module)
150+
add_subdirectory(meta_module)
150151
add_subdirectory(node_module)
151152
add_subdirectory(text_module)
152153
add_subdirectory(label_module)

cpp/meta_module/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
set(meta_module_src
2+
meta_module.cpp
3+
algorithm/meta.cpp)
4+
5+
add_query_module(meta 1 "${meta_module_src}")

cpp/meta_module/algorithm/meta.cpp

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
#include "meta.hpp"
2+
3+
#include <atomic>
4+
#include <mutex>
5+
6+
#include "mgp.hpp"
7+
8+
namespace Meta {
9+
10+
namespace {
11+
12+
struct Metadata {
13+
Metadata() : node_cnt{0}, relationship_cnt{0} {}
14+
15+
void Reset();
16+
void UpdateLabels(const mgp::Node &node, int add, bool online);
17+
void UpdatePropertyKeyCnt(const auto &node_or_relationship, int add, bool online);
18+
void UpdateRelationshipTypes(const mgp::Relationship &relationship, int add, bool online);
19+
void UpdateRelationshipTypesCnt(const mgp::Relationship &relationship, int add, bool online);
20+
21+
std::atomic<int64_t> node_cnt;
22+
std::atomic<int64_t> relationship_cnt;
23+
24+
std::unordered_map<std::string, int64_t> labels;
25+
std::unordered_map<std::string, int64_t> property_key_cnt;
26+
std::unordered_map<std::string, int64_t> relationship_types;
27+
std::unordered_map<std::string, int64_t> relationship_types_cnt;
28+
29+
std::mutex labels_mutex;
30+
std::mutex property_key_cnt_mutex;
31+
std::mutex relationship_types_mutex;
32+
std::mutex relationship_types_cnt_mutex;
33+
};
34+
35+
// Global variable
36+
Metadata metadata;
37+
38+
void LockAndExecuteMaybe(std::mutex &mutex, bool online, auto function) {
39+
if (online) {
40+
const std::lock_guard<std::mutex> lock(mutex);
41+
function();
42+
return;
43+
}
44+
function();
45+
}
46+
47+
auto LockAndExecuteMaybeReturn(std::mutex &mutex, bool online, auto function) {
48+
if (online) {
49+
const std::lock_guard<std::mutex> lock(mutex);
50+
return function();
51+
}
52+
return function();
53+
}
54+
55+
void Insert(std::unordered_map<std::string, int64_t> &map, std::string &key, int64_t add) {
56+
auto iterator = map.find(key);
57+
if (iterator != map.end()) {
58+
(*iterator).second += add;
59+
if ((*iterator).second == 0) {
60+
map.erase(iterator);
61+
}
62+
} else {
63+
map[key] = add;
64+
}
65+
}
66+
67+
void Metadata::Reset() {
68+
node_cnt = 0;
69+
relationship_cnt = 0;
70+
71+
auto clear_map = [](std::mutex &mutex, auto &map) { LockAndExecuteMaybe(mutex, true, [&]() { map.clear(); }); };
72+
73+
clear_map(metadata.labels_mutex, labels);
74+
clear_map(metadata.property_key_cnt_mutex, property_key_cnt);
75+
clear_map(metadata.relationship_types_mutex, relationship_types);
76+
clear_map(metadata.relationship_types_cnt_mutex, relationship_types_cnt);
77+
}
78+
79+
void Metadata::UpdateLabels(const mgp::Node &node, int add, bool online) {
80+
auto iterate_and_insert = [&]() {
81+
for (const auto &label : node.Labels()) {
82+
auto key = std::string(label);
83+
Insert(labels, key, add);
84+
}
85+
};
86+
87+
LockAndExecuteMaybe(metadata.labels_mutex, online, iterate_and_insert);
88+
}
89+
90+
void Metadata::UpdatePropertyKeyCnt(const auto &node_or_relationship, int add, bool online) {
91+
auto iterate_and_insert = [&]() {
92+
for (const auto &[property, _] : node_or_relationship.Properties()) {
93+
auto key = std::string(property);
94+
Insert(property_key_cnt, key, add);
95+
}
96+
};
97+
98+
LockAndExecuteMaybe(metadata.property_key_cnt_mutex, online, iterate_and_insert);
99+
}
100+
101+
void Metadata::UpdateRelationshipTypes(const mgp::Relationship &relationship, int add, bool online) {
102+
auto iterate_and_insert = [&]() {
103+
const auto type = relationship.Type();
104+
105+
for (const auto &label : relationship.From().Labels()) {
106+
auto key = "(:" + std::string(label) + ")-[:" + std::string(type) + "]->()";
107+
Insert(relationship_types, key, add);
108+
}
109+
for (const auto &label : relationship.To().Labels()) {
110+
auto key = "()-[:" + std::string(type) + "]->(:" + std::string(label) + ")";
111+
Insert(relationship_types, key, add);
112+
}
113+
114+
auto key = "()-[:" + std::string(type) + "]->()";
115+
Insert(relationship_types, key, add);
116+
};
117+
118+
LockAndExecuteMaybe(metadata.relationship_types_mutex, online, iterate_and_insert);
119+
}
120+
121+
void Metadata::UpdateRelationshipTypesCnt(const mgp::Relationship &relationship, int add, bool online) {
122+
auto iterate_and_insert = [&]() {
123+
auto key = std::string(relationship.Type());
124+
Insert(relationship_types_cnt, key, add);
125+
};
126+
LockAndExecuteMaybe(metadata.relationship_types_cnt_mutex, online, iterate_and_insert);
127+
}
128+
129+
void UpdateAllMetadata(mgp_graph *memgraph_graph, Metadata &data, bool online) {
130+
const mgp::Graph graph{memgraph_graph};
131+
132+
for (const auto node : graph.Nodes()) {
133+
data.node_cnt++;
134+
data.UpdateLabels(node, 1, online);
135+
data.UpdatePropertyKeyCnt(node, 1, online);
136+
}
137+
138+
for (const auto relationship : graph.Relationships()) {
139+
data.relationship_cnt++;
140+
data.UpdateRelationshipTypes(relationship, 1, online);
141+
data.UpdateRelationshipTypesCnt(relationship, 1, online);
142+
data.UpdatePropertyKeyCnt(relationship, 1, online);
143+
}
144+
}
145+
146+
void OutputFromMetadata(Metadata &data, const mgp::RecordFactory &record_factory, bool online) {
147+
auto record = record_factory.NewRecord();
148+
mgp::Map stats{};
149+
150+
int64_t label_count = LockAndExecuteMaybeReturn(metadata.labels_mutex, online,
151+
[&]() { return static_cast<int64_t>(data.labels.size()); });
152+
record.Insert(std::string(kReturnStats1).c_str(), label_count);
153+
stats.Insert("labelCount", mgp::Value(label_count));
154+
155+
int64_t relationship_type_count = LockAndExecuteMaybeReturn(metadata.relationship_types_cnt_mutex, online, [&]() {
156+
return static_cast<int64_t>(data.relationship_types_cnt.size());
157+
});
158+
record.Insert(std::string(kReturnStats2).c_str(), relationship_type_count);
159+
stats.Insert("relationshipTypeCount", mgp::Value(relationship_type_count));
160+
161+
int64_t property_key_count = LockAndExecuteMaybeReturn(
162+
metadata.property_key_cnt_mutex, online, [&]() { return static_cast<int64_t>(data.property_key_cnt.size()); });
163+
record.Insert(std::string(kReturnStats3).c_str(), property_key_count);
164+
stats.Insert("propertyKeyCount", mgp::Value(property_key_count));
165+
166+
record.Insert(std::string(kReturnStats4).c_str(), data.node_cnt);
167+
stats.Insert("nodeCount", mgp::Value(data.node_cnt));
168+
169+
record.Insert(std::string(kReturnStats5).c_str(), data.relationship_cnt);
170+
stats.Insert("relationshipCount", mgp::Value(data.relationship_cnt));
171+
172+
auto create_map = [](const auto &map) {
173+
mgp::Map result;
174+
for (const auto &[key, value] : map) {
175+
result.Insert(key, mgp::Value(value));
176+
}
177+
return result;
178+
};
179+
180+
auto labels_map = LockAndExecuteMaybeReturn(metadata.labels_mutex, online, [&]() { return create_map(data.labels); });
181+
record.Insert(std::string(kReturnStats6).c_str(), labels_map);
182+
stats.Insert("labels", mgp::Value(std::move(labels_map)));
183+
184+
auto relationship_types_map = LockAndExecuteMaybeReturn(metadata.relationship_types_mutex, online,
185+
[&]() { return create_map(data.relationship_types); });
186+
record.Insert(std::string(kReturnStats7).c_str(), relationship_types_map);
187+
stats.Insert("relationshipTypes", mgp::Value(std::move(relationship_types_map)));
188+
189+
auto relationship_types_count_map = LockAndExecuteMaybeReturn(
190+
metadata.relationship_types_cnt_mutex, online, [&]() { return create_map(data.relationship_types_cnt); });
191+
record.Insert(std::string(kReturnStats8).c_str(), relationship_types_count_map);
192+
stats.Insert("relationshipTypesCount", mgp::Value(std::move(relationship_types_count_map)));
193+
194+
record.Insert(std::string(kReturnStats9).c_str(), stats);
195+
}
196+
197+
} // namespace
198+
199+
void Update(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
200+
mgp::memory = memory;
201+
const auto arguments = mgp::List(args);
202+
const auto record_factory = mgp::RecordFactory(result);
203+
204+
try {
205+
const auto created_objects{arguments[0].ValueList()};
206+
const auto deleted_objects{arguments[1].ValueList()};
207+
const auto removed_vertex_properties{arguments[2].ValueList()};
208+
const auto removed_edge_properties{arguments[3].ValueList()};
209+
const auto set_vertex_labels{arguments[4].ValueList()};
210+
const auto removed_vertex_labels{arguments[5].ValueList()};
211+
212+
auto update_object = [](const auto &objects, std::string_view vertex_event, std::string_view edge_event, int add) {
213+
for (const auto &object : objects) {
214+
const auto event{object.ValueMap()};
215+
216+
const auto event_type = event["event_type"].ValueString();
217+
if (event_type == vertex_event) {
218+
Meta::metadata.node_cnt += add;
219+
const auto vertex = event["vertex"].ValueNode();
220+
Meta::metadata.UpdateLabels(vertex, add, true);
221+
Meta::metadata.UpdatePropertyKeyCnt(vertex, add, true);
222+
} else if (event_type == edge_event) {
223+
Meta::metadata.relationship_cnt += add;
224+
const auto edge = event["edge"].ValueRelationship();
225+
Meta::metadata.UpdateRelationshipTypes(edge, add, true);
226+
Meta::metadata.UpdateRelationshipTypesCnt(edge, add, true);
227+
Meta::metadata.UpdatePropertyKeyCnt(edge, add, true);
228+
} else {
229+
throw mgp::ValueException("Unexpected event type");
230+
}
231+
}
232+
};
233+
234+
update_object(created_objects, "created_vertex", "created_edge", 1);
235+
update_object(deleted_objects, "deleted_vertex", "deleted_edge", -1);
236+
237+
for (const auto &object : removed_vertex_properties) {
238+
const auto event{object.ValueMap()};
239+
LockAndExecuteMaybe(metadata.property_key_cnt_mutex, true, [&]() {
240+
auto key = std::string(event["key"].ValueString());
241+
Insert(Meta::metadata.property_key_cnt, key, -1);
242+
});
243+
}
244+
245+
for (const auto &object : removed_edge_properties) {
246+
const auto event{object.ValueMap()};
247+
LockAndExecuteMaybe(metadata.property_key_cnt_mutex, true, [&]() {
248+
auto key = std::string(event["key"].ValueString());
249+
Insert(Meta::metadata.property_key_cnt, key, -1);
250+
});
251+
}
252+
253+
for (const auto &object : set_vertex_labels) {
254+
const auto event{object.ValueMap()};
255+
LockAndExecuteMaybe(metadata.property_key_cnt_mutex, true, [&]() {
256+
auto key = std::string(event["label"].ValueString());
257+
Insert(Meta::metadata.labels, key, static_cast<int64_t>(event["vertices"].ValueList().Size()));
258+
});
259+
}
260+
261+
for (const auto &object : removed_vertex_labels) {
262+
const auto event{object.ValueMap()};
263+
LockAndExecuteMaybe(metadata.property_key_cnt_mutex, true, [&]() {
264+
auto key = std::string(event["label"].ValueString());
265+
Insert(Meta::metadata.labels, key, static_cast<int64_t>(-event["vertices"].ValueList().Size()));
266+
});
267+
}
268+
269+
} catch (const std::exception &e) {
270+
record_factory.SetErrorMessage(e.what());
271+
return;
272+
}
273+
}
274+
275+
void StatsOnline(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
276+
mgp::memory = memory;
277+
const auto arguments = mgp::List(args);
278+
const auto record_factory = mgp::RecordFactory(result);
279+
280+
try {
281+
bool update_stats = arguments[0].ValueBool();
282+
283+
if (update_stats) {
284+
Meta::metadata.Reset();
285+
UpdateAllMetadata(memgraph_graph, metadata, true);
286+
OutputFromMetadata(metadata, record_factory, true);
287+
} else {
288+
OutputFromMetadata(metadata, record_factory, true);
289+
}
290+
291+
} catch (const std::exception &e) {
292+
record_factory.SetErrorMessage(e.what());
293+
return;
294+
}
295+
}
296+
297+
void StatsOffline(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
298+
mgp::memory = memory;
299+
const auto arguments = mgp::List(args);
300+
const auto record_factory = mgp::RecordFactory(result);
301+
302+
try {
303+
Metadata local_metadata;
304+
UpdateAllMetadata(memgraph_graph, local_metadata, false);
305+
OutputFromMetadata(local_metadata, record_factory, false);
306+
307+
} catch (const std::exception &e) {
308+
record_factory.SetErrorMessage(e.what());
309+
return;
310+
}
311+
}
312+
313+
void Reset(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
314+
mgp::memory = memory;
315+
const auto record_factory = mgp::RecordFactory(result);
316+
317+
try {
318+
metadata.Reset();
319+
320+
} catch (const std::exception &e) {
321+
record_factory.SetErrorMessage(e.what());
322+
return;
323+
}
324+
}
325+
326+
} // namespace Meta

cpp/meta_module/algorithm/meta.hpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#pragma once
2+
3+
#include <mgp.hpp>
4+
#include <string_view>
5+
6+
namespace Meta {
7+
8+
/* update constants */
9+
constexpr std::string_view kProcedureUpdate = "update";
10+
constexpr std::string_view kUpdateArg1 = "createdObjects";
11+
constexpr std::string_view kUpdateArg2 = "deletedObjects";
12+
constexpr std::string_view kUpdateArg3 = "removedVertexProperties";
13+
constexpr std::string_view kUpdateArg4 = "removedEdgeProperties";
14+
constexpr std::string_view kUpdateArg5 = "setVertexLabels";
15+
constexpr std::string_view kUpdateArg6 = "removedVertexLabels";
16+
17+
/* stats constants */
18+
constexpr std::string_view kProcedureStatsOnline = "stats_online";
19+
constexpr std::string_view kProcedureStatsOffline = "stats_offline";
20+
constexpr std::string_view kStatsOnlineArg1 = "update_stats";
21+
constexpr std::string_view kReturnStats1 = "labelCount";
22+
constexpr std::string_view kReturnStats2 = "relationshipTypeCount";
23+
constexpr std::string_view kReturnStats3 = "propertyKeyCount";
24+
constexpr std::string_view kReturnStats4 = "nodeCount";
25+
constexpr std::string_view kReturnStats5 = "relationshipCount";
26+
constexpr std::string_view kReturnStats6 = "labels";
27+
constexpr std::string_view kReturnStats7 = "relationshipTypes";
28+
constexpr std::string_view kReturnStats8 = "relationshipTypesCount";
29+
constexpr std::string_view kReturnStats9 = "stats";
30+
31+
/* reset constants */
32+
constexpr std::string_view kProcedureReset = "reset";
33+
34+
void Update(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory);
35+
36+
void StatsOnline(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory);
37+
38+
void StatsOffline(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory);
39+
40+
void Reset(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory);
41+
42+
} // namespace Meta

0 commit comments

Comments
 (0)