diff --git a/src/storage/v2/property_store.cpp b/src/storage/v2/property_store.cpp index df5280715..549da207f 100644 --- a/src/storage/v2/property_store.cpp +++ b/src/storage/v2/property_store.cpp @@ -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; @@ -1146,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::map &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; diff --git a/src/storage/v2/property_store.hpp b/src/storage/v2/property_store.hpp index 95de116c7..1b7423c8b 100644 --- a/src/storage/v2/property_store.hpp +++ b/src/storage/v2/property_store.hpp @@ -61,6 +61,8 @@ class PropertyStore { /// @throw std::bad_alloc bool SetProperty(PropertyId property, const PropertyValue &value); + bool SetProperties(std::map &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). diff --git a/src/storage/v2/vertex_accessor.cpp b/src/storage/v2/vertex_accessor.cpp index 9a2fe1c8e..12361f155 100644 --- a/src/storage/v2/vertex_accessor.cpp +++ b/src/storage/v2/vertex_accessor.cpp @@ -258,10 +258,12 @@ Result> VertexAccessor::SetBatchProperties( if (vertex_->deleted) return Error::DELETED_OBJECT; std::vector 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); - vertex_->properties.SetProperty(property, value); UpdateOnSetProperty(indices_, property, value, vertex_, *transaction_); new_values.emplace_back(current_value); }