Compare commits

...

8 Commits

Author SHA1 Message Date
antoniofilipovic
11edd65757 add fix for property lookup 2023-02-08 18:18:23 +01:00
antoniofilipovic
8c58eddd54 add option for gperftools 2023-02-08 15:40:24 +01:00
antoniofilipovic
13c33149e5 add std::vector instead of std::map 2023-02-08 15:38:48 +01:00
antoniofilipovic
af519d517a implement SetProperties in PropertyStore 2023-02-07 11:20:19 +01:00
antoniofilipovic
49eb6390ff add SetBatchProperties functionality in storage::VertexAccessor 2023-02-06 12:21:22 +01:00
antoniofilipovic
b9ae685c48 introduce std::unordered_map in Parameters to reduce lookup 2023-02-02 13:38:41 +01:00
antoniofilipovic
41622cb765 implement ReferenceExpressionEvaluator with Visitor to Identifier to retrieve pointer to object from frame 2023-02-01 16:21:25 +01:00
antoniofilipovic
a34a2f4140 test reading speed 2023-01-30 14:59:07 +01:00
10 changed files with 271 additions and 48 deletions

View File

@@ -52,7 +52,7 @@ target_link_libraries(memgraph ${mg_single_node_v2_libs})
# NOTE: `include/mg_procedure.syms` describes a pattern match for symbols which
# should be dynamically exported, so that `dlopen` can correctly link the
# symbols in custom procedure module libraries.
target_link_libraries(memgraph "-Wl,--dynamic-list=${CMAKE_SOURCE_DIR}/include/mg_procedure.syms")
target_link_libraries(memgraph "-Wl,--dynamic-list=${CMAKE_SOURCE_DIR}/include/mg_procedure.syms" "-lprofiler")
set_target_properties(memgraph PROPERTIES
# Set the executable output name to include version information.

View File

@@ -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
@@ -125,6 +125,11 @@ class VertexAccessor final {
return impl_.SetProperty(key, value);
}
storage::Result<std::vector<storage::PropertyValue>> SetProperties(
std::vector<std::pair<storage::PropertyId, storage::PropertyValue>> &properties) {
return impl_.SetProperties(properties);
}
storage::Result<storage::PropertyValue> RemoveProperty(storage::PropertyId key) {
return SetProperty(key, storage::PropertyValue());
}

View File

@@ -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
@@ -31,6 +31,78 @@
namespace memgraph::query {
static std::chrono::duration<double> total2;
static std::chrono::duration<double> new_print2;
class ReferenceExpressionEvaluator : public ExpressionVisitor<TypedValue *> {
public:
ReferenceExpressionEvaluator(Frame *frame, const SymbolTable *symbol_table, const EvaluationContext *ctx,
DbAccessor *dba, storage::View view)
: frame_(frame), symbol_table_(symbol_table), ctx_(ctx), dba_(dba), view_(view) {}
using ExpressionVisitor<TypedValue *>::Visit;
utils::MemoryResource *GetMemoryResource() const { return ctx_->memory; }
#define UNSUCCESFUL_VISIT(expr_name) \
TypedValue *Visit(expr_name &expr) override { return nullptr; }
TypedValue *Visit(Identifier &ident) override { return &frame_->at(symbol_table_->at(ident)); }
UNSUCCESFUL_VISIT(NamedExpression);
UNSUCCESFUL_VISIT(OrOperator);
UNSUCCESFUL_VISIT(XorOperator);
UNSUCCESFUL_VISIT(AdditionOperator);
UNSUCCESFUL_VISIT(SubtractionOperator);
UNSUCCESFUL_VISIT(MultiplicationOperator);
UNSUCCESFUL_VISIT(DivisionOperator);
UNSUCCESFUL_VISIT(ModOperator);
UNSUCCESFUL_VISIT(NotEqualOperator);
UNSUCCESFUL_VISIT(EqualOperator);
UNSUCCESFUL_VISIT(LessOperator);
UNSUCCESFUL_VISIT(GreaterOperator);
UNSUCCESFUL_VISIT(LessEqualOperator);
UNSUCCESFUL_VISIT(GreaterEqualOperator);
UNSUCCESFUL_VISIT(NotOperator);
UNSUCCESFUL_VISIT(UnaryPlusOperator);
UNSUCCESFUL_VISIT(UnaryMinusOperator);
UNSUCCESFUL_VISIT(AndOperator);
UNSUCCESFUL_VISIT(IfOperator);
UNSUCCESFUL_VISIT(InListOperator);
UNSUCCESFUL_VISIT(SubscriptOperator);
UNSUCCESFUL_VISIT(ListSlicingOperator);
UNSUCCESFUL_VISIT(IsNullOperator);
UNSUCCESFUL_VISIT(PropertyLookup);
UNSUCCESFUL_VISIT(LabelsTest);
UNSUCCESFUL_VISIT(PrimitiveLiteral);
UNSUCCESFUL_VISIT(ListLiteral);
UNSUCCESFUL_VISIT(MapLiteral);
UNSUCCESFUL_VISIT(Aggregation);
UNSUCCESFUL_VISIT(Coalesce);
UNSUCCESFUL_VISIT(Function);
UNSUCCESFUL_VISIT(Reduce);
UNSUCCESFUL_VISIT(Extract);
UNSUCCESFUL_VISIT(All);
UNSUCCESFUL_VISIT(Single);
UNSUCCESFUL_VISIT(Any);
UNSUCCESFUL_VISIT(None);
UNSUCCESFUL_VISIT(ParameterLookup);
UNSUCCESFUL_VISIT(RegexMatch);
private:
Frame *frame_;
const SymbolTable *symbol_table_;
const EvaluationContext *ctx_;
DbAccessor *dba_;
// which switching approach should be used when evaluating
storage::View view_;
};
class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
public:
ExpressionEvaluator(Frame *frame, const SymbolTable &symbol_table, const EvaluationContext &ctx, DbAccessor *dba,
@@ -159,49 +231,51 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
}
TypedValue Visit(SubscriptOperator &list_indexing) override {
auto lhs = list_indexing.expression1_->Accept(*this);
ReferenceExpressionEvaluator referenceExpressionEvaluator(frame_, symbol_table_, ctx_, dba_, view_);
auto *lhs = list_indexing.expression1_->Accept(referenceExpressionEvaluator);
auto index = list_indexing.expression2_->Accept(*this);
if (!lhs.IsList() && !lhs.IsMap() && !lhs.IsVertex() && !lhs.IsEdge() && !lhs.IsNull())
if (!lhs->IsList() && !lhs->IsMap() && !lhs->IsVertex() && !lhs->IsEdge() && !lhs->IsNull())
throw QueryRuntimeException(
"Expected a list, a map, a node or an edge to index with '[]', got "
"{}.",
lhs.type());
if (lhs.IsNull() || index.IsNull()) return TypedValue(ctx_->memory);
if (lhs.IsList()) {
lhs->type());
if (lhs->IsNull() || index.IsNull()) return TypedValue(ctx_->memory);
if (lhs->IsList()) {
if (!index.IsInt()) throw QueryRuntimeException("Expected an integer as a list index, got {}.", index.type());
auto index_int = index.ValueInt();
// NOTE: Take non-const reference to list, so that we can move out the
// indexed element as the result.
auto &list = lhs.ValueList();
const auto &list = lhs->ValueList();
if (index_int < 0) {
index_int += static_cast<int64_t>(list.size());
}
if (index_int >= static_cast<int64_t>(list.size()) || index_int < 0) return TypedValue(ctx_->memory);
// NOTE: Explicit move is needed, so that we return the move constructed
// value and preserve the correct MemoryResource.
return std::move(list[index_int]);
return TypedValue(list[index_int]);
}
if (lhs.IsMap()) {
if (lhs->IsMap()) {
if (!index.IsString()) throw QueryRuntimeException("Expected a string as a map index, got {}.", index.type());
// NOTE: Take non-const reference to map, so that we can move out the
// looked-up element as the result.
auto &map = lhs.ValueMap();
const auto &map = lhs->ValueMap();
auto found = map.find(index.ValueString());
if (found == map.end()) return TypedValue(ctx_->memory);
// NOTE: Explicit move is needed, so that we return the move constructed
// value and preserve the correct MemoryResource.
return std::move(found->second);
return TypedValue(found->second);
}
if (lhs.IsVertex()) {
if (lhs->IsVertex()) {
if (!index.IsString()) throw QueryRuntimeException("Expected a string as a property name, got {}.", index.type());
return TypedValue(GetProperty(lhs.ValueVertex(), index.ValueString()), ctx_->memory);
return TypedValue(GetProperty(lhs->ValueVertex(), index.ValueString()), ctx_->memory);
}
if (lhs.IsEdge()) {
if (lhs->IsEdge()) {
if (!index.IsString()) throw QueryRuntimeException("Expected a string as a property name, got {}.", index.type());
return TypedValue(GetProperty(lhs.ValueEdge(), index.ValueString()), ctx_->memory);
return TypedValue(GetProperty(lhs->ValueEdge(), index.ValueString()), ctx_->memory);
}
// lhs is Null
@@ -258,7 +332,10 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
}
TypedValue Visit(PropertyLookup &property_lookup) override {
auto expression_result = property_lookup.expression_->Accept(*this);
ReferenceExpressionEvaluator referenceExpressionEvaluator(frame_, symbol_table_, ctx_, dba_, view_);
auto *expression_result = property_lookup.expression_->Accept(referenceExpressionEvaluator);
// auto expression_result = property_lookup.expression_->Accept(*this);
auto maybe_date = [this](const auto &date, const auto &prop_name) -> std::optional<TypedValue> {
if (prop_name == "year") {
return TypedValue(date.year, ctx_->memory);
@@ -332,42 +409,42 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
}
return std::nullopt;
};
switch (expression_result.type()) {
switch (expression_result->type()) {
case TypedValue::Type::Null:
return TypedValue(ctx_->memory);
case TypedValue::Type::Vertex:
return TypedValue(GetProperty(expression_result.ValueVertex(), property_lookup.property_), ctx_->memory);
return TypedValue(GetProperty(expression_result->ValueVertex(), property_lookup.property_), ctx_->memory);
case TypedValue::Type::Edge:
return TypedValue(GetProperty(expression_result.ValueEdge(), property_lookup.property_), ctx_->memory);
return TypedValue(GetProperty(expression_result->ValueEdge(), property_lookup.property_), ctx_->memory);
case TypedValue::Type::Map: {
// NOTE: Take non-const reference to map, so that we can move out the
// looked-up element as the result.
auto &map = expression_result.ValueMap();
auto &map = expression_result->ValueMap();
auto found = map.find(property_lookup.property_.name.c_str());
if (found == map.end()) return TypedValue(ctx_->memory);
// NOTE: Explicit move is needed, so that we return the move constructed
// value and preserve the correct MemoryResource.
return std::move(found->second);
return TypedValue(found->second, ctx_->memory);
}
case TypedValue::Type::Duration: {
const auto &prop_name = property_lookup.property_.name;
const auto &dur = expression_result.ValueDuration();
const auto &dur = expression_result->ValueDuration();
if (auto dur_field = maybe_duration(dur, prop_name); dur_field) {
return std::move(*dur_field);
return TypedValue(*dur_field, ctx_->memory);
}
throw QueryRuntimeException("Invalid property name {} for Duration", prop_name);
}
case TypedValue::Type::Date: {
const auto &prop_name = property_lookup.property_.name;
const auto &date = expression_result.ValueDate();
const auto &date = expression_result->ValueDate();
if (auto date_field = maybe_date(date, prop_name); date_field) {
return std::move(*date_field);
return TypedValue(*date_field, ctx_->memory);
}
throw QueryRuntimeException("Invalid property name {} for Date", prop_name);
}
case TypedValue::Type::LocalTime: {
const auto &prop_name = property_lookup.property_.name;
const auto &lt = expression_result.ValueLocalTime();
const auto &lt = expression_result->ValueLocalTime();
if (auto lt_field = maybe_local_time(lt, prop_name); lt_field) {
return std::move(*lt_field);
}
@@ -375,20 +452,20 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
}
case TypedValue::Type::LocalDateTime: {
const auto &prop_name = property_lookup.property_.name;
const auto &ldt = expression_result.ValueLocalDateTime();
const auto &ldt = expression_result->ValueLocalDateTime();
if (auto date_field = maybe_date(ldt.date, prop_name); date_field) {
return std::move(*date_field);
}
if (auto lt_field = maybe_local_time(ldt.local_time, prop_name); lt_field) {
return std::move(*lt_field);
return TypedValue(*lt_field, ctx_->memory);
}
throw QueryRuntimeException("Invalid property name {} for LocalDateTime", prop_name);
}
case TypedValue::Type::Graph: {
const auto &prop_name = property_lookup.property_.name;
const auto &graph = expression_result.ValueGraph();
const auto &graph = expression_result->ValueGraph();
if (auto graph_field = maybe_graph(graph, prop_name); graph_field) {
return std::move(*graph_field);
return TypedValue(*graph_field, ctx_->memory);
}
throw QueryRuntimeException("Invalid property name {} for Graph", prop_name);
}

View File

@@ -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
@@ -32,7 +32,7 @@ struct Parameters {
* @param position Token position in query of value.
* @param value
*/
void Add(int position, const storage::PropertyValue &value) { storage_.emplace_back(position, value); }
void Add(int position, const storage::PropertyValue &value) { storage_.emplace(position, value); }
/**
* Returns the value found for the given token position.
@@ -41,9 +41,8 @@ struct Parameters {
* @return Value for the given token position.
*/
const storage::PropertyValue &AtTokenPosition(int position) const {
auto found = std::find_if(storage_.begin(), storage_.end(), [&](const auto &a) { return a.first == position; });
MG_ASSERT(found != storage_.end(), "Token position must be present in container");
return found->second;
MG_ASSERT(storage_.contains(position), "Token position must be present in container");
return storage_.at(position);
}
/**
@@ -53,9 +52,9 @@ struct Parameters {
* @param position Which stripped param is sought.
* @return Token position and value for sought param.
*/
const std::pair<int, storage::PropertyValue> &At(int position) const {
const storage::PropertyValue &At(int position) const {
MG_ASSERT(position < static_cast<int>(storage_.size()), "Invalid position");
return storage_[position];
return storage_.at(position);
}
/** Returns the number of arguments in this container */
@@ -65,7 +64,7 @@ struct Parameters {
auto end() const { return storage_.end(); }
private:
std::vector<std::pair<int, storage::PropertyValue>> storage_;
std::unordered_map<int, storage::PropertyValue> storage_;
};
} // namespace memgraph::query

View File

@@ -155,6 +155,9 @@ uint64_t ComputeProfilingKey(const T *obj) {
#define SCOPED_PROFILE_OP(name) ScopedProfile profile{ComputeProfilingKey(this), name, &context};
std::chrono::duration<double> total;
std::chrono::duration<double> new_print;
bool Once::OnceCursor::Pull(Frame &, ExecutionContext &context) {
SCOPED_PROFILE_OP("Once");
@@ -208,10 +211,14 @@ VertexAccessor &CreateLocalVertex(const NodeCreationInfo &node_info, Frame *fram
storage::View::NEW);
// TODO: PropsSetChecked allocates a PropertyValue, make it use context.memory
// when we update PropertyValue with custom allocator.
std::vector<std::pair<storage::PropertyId, storage::PropertyValue>> properties;
if (const auto *node_info_properties = std::get_if<PropertiesMapList>(&node_info.properties)) {
for (const auto &[key, value_expression] : *node_info_properties) {
PropsSetChecked(&new_node, key, value_expression->Accept(evaluator));
properties.emplace_back(key, value_expression->Accept(evaluator));
// PropsSetChecked(&new_node, key, );
}
new_node.SetProperties(properties);
} else {
auto property_map = evaluator.Visit(*std::get<ParameterLookup *>(node_info.properties));
for (const auto &[key, value] : property_map.ValueMap()) {
@@ -4579,6 +4586,7 @@ class LoadCsvCursor : public Cursor {
// have to read at most cardinality(n) rows (but we can read less and stop
// pulling MATCH).
if (!input_is_once_ && !input_pulled) return false;
auto row = reader_->GetNextRow(context.evaluation_context.memory);
if (!row) {
return false;

View File

@@ -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
@@ -26,6 +26,9 @@
namespace memgraph::query {
std::chrono::duration<double> total;
std::chrono::duration<double> new_print;
TypedValue::TypedValue(const storage::PropertyValue &value)
// TODO: MemoryResource in storage::PropertyValue
: TypedValue(value, utils::NewDeleteResource()) {}
@@ -289,8 +292,18 @@ TypedValue::operator storage::PropertyValue() const {
return storage::PropertyValue(int_v);
case TypedValue::Type::Double:
return storage::PropertyValue(double_v);
case TypedValue::Type::String:
return storage::PropertyValue(std::string(string_v));
case TypedValue::Type::String: {
auto start = std::chrono::steady_clock::now();
auto value = storage::PropertyValue(std::string(string_v));
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> dif = end - start;
total += dif;
if (total > new_print) {
std::cout << "Time typed value difference = " << total.count() << "[s]" << std::endl;
new_print += static_cast<std::chrono::duration<double>>(10.0);
}
return value;
}
case TypedValue::Type::List:
return storage::PropertyValue(std::vector<storage::PropertyValue>(list_v.begin(), list_v.end()));
case TypedValue::Type::Map: {

View File

@@ -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
@@ -869,6 +869,26 @@ SpecificPropertyAndBufferInfo FindSpecificPropertyAndBufferInfo(Reader *reader,
return {property_begin, property_end, property_end - property_begin, all_begin, all_end, all_end - all_begin};
}
// Function used to move to the position where the property should be in the data
// buffer.
// The `property_size` will be `0`
// and `property_begin` will be equal to `property_end`. Positions and size of
// all properties is always calculated (even if the specific property isn't
// found).
//
// @sa FindSpecificProperty
SpecificPropertyAndBufferInfo SkipReaderAndGetBufferInfo(Reader *reader, uint64_t size) {
uint64_t property_begin = reader->GetPosition();
uint64_t property_end = reader->GetPosition();
uint64_t all_begin = reader->GetPosition();
uint64_t all_end = reader->GetPosition();
reader->SkipBytes(size);
property_begin = reader->GetPosition();
property_end = reader->GetPosition();
all_end = reader->GetPosition();
return {property_begin, property_end, property_end - property_begin, all_begin, all_end, all_end - all_begin};
}
// All data buffers will be allocated to a power of 8 size.
uint64_t ToPowerOf8(uint64_t size) {
uint64_t mod = size % 8;
@@ -971,6 +991,8 @@ PropertyValue PropertyStore::GetProperty(PropertyId property) const {
return value;
}
PropertyValue PropertyStore::GetEmptyProperty() const { return PropertyValue(); }
bool PropertyStore::HasProperty(PropertyId property) const {
uint64_t size;
const uint8_t *data;
@@ -1144,6 +1166,57 @@ bool PropertyStore::SetProperty(PropertyId property, const PropertyValue &value)
return !existed;
}
// use this function only when inserting new properties
bool PropertyStore::SetProperties(std::vector<std::pair<storage::PropertyId, storage::PropertyValue>> &properties) {
uint64_t size;
uint8_t *data;
std::tie(size, data) = GetSizeData(buffer_);
MG_ASSERT(size == 0, "Invalid database state!");
uint64_t property_size = 0;
{
Writer writer;
for (const auto &[property, value] : properties) {
EncodeProperty(&writer, property, value);
property_size = writer.Written();
}
}
auto property_size_to_power_of_8 = ToPowerOf8(property_size);
if (property_size <= sizeof(buffer_) - 1) {
// Use the local buffer.
buffer_[0] = kUseLocalBuffer;
size = sizeof(buffer_) - 1;
data = &buffer_[1];
} else {
// Allocate a new external buffer.
auto alloc_data = new uint8_t[property_size_to_power_of_8];
auto alloc_size = property_size_to_power_of_8;
SetSizeData(buffer_, alloc_size, alloc_data);
size = alloc_size;
data = alloc_data;
}
// Encode the property into the data buffer.
Writer writer(data, size);
for (const auto &[property, value] : properties) {
MG_ASSERT(EncodeProperty(&writer, property, value), "Invalid database state!");
property_size = writer.Written();
}
auto metadata = writer.WriteMetadata();
if (metadata) {
// If there is any space left in the buffer we add a tombstone to
// indicate that there are no more properties to be decoded.
metadata->Set({Type::EMPTY});
}
return true;
}
bool PropertyStore::ClearProperties() {
bool in_local_buffer = false;
uint64_t size;

View File

@@ -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
@@ -42,6 +42,8 @@ class PropertyStore {
/// complexity of this function is O(n).
bool HasProperty(PropertyId property) const;
PropertyValue GetEmptyProperty() const;
/// Checks whether the property `property` is equal to the specified value
/// `value`. This function doesn't perform any memory allocations while
/// performing the equality check. The time complexity of this function is
@@ -59,6 +61,8 @@ class PropertyStore {
/// @throw std::bad_alloc
bool SetProperty(PropertyId property, const PropertyValue &value);
bool SetProperties(std::vector<std::pair<storage::PropertyId, storage::PropertyValue>> &properties);
/// Remove all properties and return `true` if any removal took place.
/// `false` is returned if there were no properties to remove. The time
/// complexity of this function is O(1).

View File

@@ -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
@@ -13,6 +13,7 @@
#include <memory>
#include <chrono>
#include "storage/v2/edge_accessor.hpp"
#include "storage/v2/id_types.hpp"
#include "storage/v2/indices.hpp"
@@ -60,6 +61,9 @@ std::pair<bool, bool> IsVisible(Vertex *vertex, Transaction *transaction, View v
} // namespace
} // namespace detail
std::chrono::duration<double> total;
std::chrono::duration<double> new_print;
std::optional<VertexAccessor> VertexAccessor::Create(Vertex *vertex, Transaction *transaction, Indices *indices,
Constraints *constraints, Config::Items config, View view) {
if (const auto [exists, deleted] = detail::IsVisible(vertex, transaction, view); !exists || deleted) {
@@ -208,6 +212,8 @@ Result<std::vector<LabelId>> VertexAccessor::Labels(View view) const {
}
Result<PropertyValue> VertexAccessor::SetProperty(PropertyId property, const PropertyValue &value) {
// auto start = std::chrono::steady_clock::now();
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
std::lock_guard<utils::SpinLock> guard(vertex_->lock);
@@ -227,9 +233,44 @@ Result<PropertyValue> VertexAccessor::SetProperty(PropertyId property, const Pro
UpdateOnSetProperty(indices_, property, value, vertex_, *transaction_);
// auto end = std::chrono::steady_clock::now();
// std::chrono::duration<double> dif = end - start;
// total += dif;
// if (total > new_print) {
// std::cout << "Time difference = " << total.count() << "[s]" << std::endl;
// new_print += static_cast<std::chrono::duration<double>>(2.0);
// }
return std::move(current_value);
}
Result<std::vector<storage::PropertyValue>> VertexAccessor::SetProperties(
std::vector<std::pair<storage::PropertyId, storage::PropertyValue>> &properties) {
// Be careful when calling this function
// It will set properties in batch, without checking if property already exists
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
std::lock_guard<utils::SpinLock> guard(vertex_->lock);
if (!PrepareForWrite(transaction_, vertex_)) return Error::SERIALIZATION_ERROR;
if (vertex_->deleted) return Error::DELETED_OBJECT;
std::vector<storage::PropertyValue> new_values;
vertex_->properties.SetProperties(properties);
for (const auto &[property, value] : properties) {
auto current_value = vertex_->properties.GetEmptyProperty();
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property, current_value);
UpdateOnSetProperty(indices_, property, value, vertex_, *transaction_);
new_values.emplace_back(current_value);
}
return new_values;
}
Result<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
std::lock_guard<utils::SpinLock> guard(vertex_->lock);

View File

@@ -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
@@ -68,6 +68,9 @@ class VertexAccessor final {
/// @throw std::bad_alloc
Result<PropertyValue> SetProperty(PropertyId property, const PropertyValue &value);
Result<std::vector<storage::PropertyValue>> SetProperties(
std::vector<std::pair<storage::PropertyId, storage::PropertyValue>> &properties);
/// Remove all properties and return the values of the removed properties.
/// @throw std::bad_alloc
Result<std::map<PropertyId, PropertyValue>> ClearProperties();