Integrate property store
Reviewers: buda Reviewed By: buda Subscribers: buda, pullbot Differential Revision: https://phabricator.memgraph.io/D2764
This commit is contained in:
parent
3932376301
commit
b923d2bc36
@ -30,9 +30,9 @@ std::optional<size_t> FindPropertyPosition(
|
||||
/// active.
|
||||
bool LastCommittedVersionHasLabelProperty(
|
||||
const Vertex &vertex, LabelId label, const std::set<PropertyId> &properties,
|
||||
const PropertyValueArray &value_array, const Transaction &transaction,
|
||||
uint64_t commit_timestamp) {
|
||||
CHECK(properties.size() == value_array.size) << "Invalid database state!";
|
||||
const std::vector<PropertyValue> &value_array,
|
||||
const Transaction &transaction, uint64_t commit_timestamp) {
|
||||
CHECK(properties.size() == value_array.size()) << "Invalid database state!";
|
||||
|
||||
PropertyIdArray property_array(properties.size());
|
||||
bool current_value_equal_to_value[kUniqueConstraintsMaxProperties];
|
||||
@ -55,11 +55,8 @@ bool LastCommittedVersionHasLabelProperty(
|
||||
|
||||
size_t i = 0;
|
||||
for (const auto &property : properties) {
|
||||
auto it = vertex.properties.find(property);
|
||||
current_value_equal_to_value[i] = value_array.values[i]->IsNull();
|
||||
if (it != vertex.properties.end()) {
|
||||
current_value_equal_to_value[i] = it->second == *value_array.values[i];
|
||||
}
|
||||
current_value_equal_to_value[i] =
|
||||
vertex.properties.IsPropertyEqual(property, value_array[i]);
|
||||
property_array.values[i] = property;
|
||||
i++;
|
||||
}
|
||||
@ -76,7 +73,7 @@ bool LastCommittedVersionHasLabelProperty(
|
||||
auto pos = FindPropertyPosition(property_array, delta->property.key);
|
||||
if (pos) {
|
||||
current_value_equal_to_value[*pos] =
|
||||
delta->property.value == *value_array.values[*pos];
|
||||
delta->property.value == value_array[*pos];
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -147,11 +144,8 @@ bool AnyVersionHasLabelProperty(const Vertex &vertex, LabelId label,
|
||||
|
||||
size_t i = 0;
|
||||
for (const auto &property : properties) {
|
||||
auto it = vertex.properties.find(property);
|
||||
current_value_equal_to_value[i] = values[i].IsNull();
|
||||
if (it != vertex.properties.end()) {
|
||||
current_value_equal_to_value[i] = it->second == values[i];
|
||||
}
|
||||
current_value_equal_to_value[i] =
|
||||
vertex.properties.IsPropertyEqual(property, values[i]);
|
||||
property_array.values[i] = property;
|
||||
i++;
|
||||
}
|
||||
@ -228,79 +222,21 @@ bool AnyVersionHasLabelProperty(const Vertex &vertex, LabelId label,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator<(const PropertyValueArray &lhs,
|
||||
const std::vector<PropertyValue> &rhs) {
|
||||
size_t n = std::min(lhs.size, rhs.size());
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (*lhs.values[i] < rhs[i]) {
|
||||
return true;
|
||||
}
|
||||
if (rhs[i] < *lhs.values[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return lhs.size < rhs.size();
|
||||
}
|
||||
|
||||
bool operator<(const std::vector<PropertyValue> &lhs,
|
||||
const PropertyValueArray &rhs) {
|
||||
size_t n = std::min(lhs.size(), rhs.size);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (lhs[i] < *rhs.values[i]) {
|
||||
return true;
|
||||
}
|
||||
if (*rhs.values[i] < lhs[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return lhs.size() < rhs.size;
|
||||
}
|
||||
|
||||
bool operator==(const std::vector<PropertyValue> &lhs,
|
||||
const PropertyValueArray &rhs) {
|
||||
if (lhs.size() != rhs.size) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < rhs.size; ++i) {
|
||||
if (lhs[i] == *rhs.values[i]) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Helper function that, given the set of `properties`, extracts corresponding
|
||||
/// property values from the `vertex`. `PropertyValueArray` is returned instead
|
||||
/// of `std::vector` to avoid `std::bad_alloc` exception.
|
||||
std::optional<PropertyValueArray> ExtractPropertyValues(
|
||||
/// property values from the `vertex`.
|
||||
/// @throw std::bad_alloc
|
||||
std::optional<std::vector<PropertyValue>> ExtractPropertyValues(
|
||||
const Vertex &vertex, const std::set<PropertyId> &properties) {
|
||||
PropertyValueArray value_array(properties.size());
|
||||
size_t i = 0;
|
||||
std::vector<PropertyValue> value_array;
|
||||
value_array.reserve(properties.size());
|
||||
for (const auto &prop : properties) {
|
||||
auto it = vertex.properties.find(prop);
|
||||
if (it == vertex.properties.end() || it->second.IsNull()) {
|
||||
auto value = vertex.properties.GetProperty(prop);
|
||||
if (value.IsNull()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
value_array.values[i++] = &it->second;
|
||||
value_array.emplace_back(std::move(value));
|
||||
}
|
||||
return value_array;
|
||||
}
|
||||
|
||||
/// Helper function that converts optional property value array to optional
|
||||
/// `std::vector` of property values.
|
||||
/// @throw std::bad_alloc
|
||||
std::optional<std::vector<PropertyValue>> OptionalPropertyValueArrayToVector(
|
||||
const std::optional<PropertyValueArray> &value_array) {
|
||||
if (!value_array) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::vector<PropertyValue> values;
|
||||
values.reserve(value_array->size);
|
||||
for (size_t i = 0; i < value_array->size; ++i) {
|
||||
values.push_back(*value_array->values[i]);
|
||||
}
|
||||
return std::move(values);
|
||||
return std::move(value_array);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -337,22 +273,13 @@ bool UniqueConstraints::Entry::operator==(
|
||||
return values == rhs;
|
||||
}
|
||||
|
||||
bool UniqueConstraints::Entry::operator<(const PropertyValueArray &rhs) {
|
||||
return values < rhs;
|
||||
}
|
||||
|
||||
bool UniqueConstraints::Entry::operator==(const PropertyValueArray &rhs) {
|
||||
return values == rhs;
|
||||
}
|
||||
|
||||
void UniqueConstraints::UpdateBeforeCommit(const Vertex *vertex,
|
||||
const Transaction &tx) {
|
||||
for (auto &[label_props, storage] : constraints_) {
|
||||
if (!utils::Contains(vertex->labels, label_props.first)) {
|
||||
continue;
|
||||
}
|
||||
auto values = OptionalPropertyValueArrayToVector(
|
||||
ExtractPropertyValues(*vertex, label_props.second));
|
||||
auto values = ExtractPropertyValues(*vertex, label_props.second);
|
||||
if (values) {
|
||||
auto acc = storage.access();
|
||||
acc.insert(Entry{std::move(*values), vertex, tx.start_timestamp});
|
||||
@ -389,8 +316,7 @@ UniqueConstraints::CreateConstraint(
|
||||
if (vertex.deleted || !utils::Contains(vertex.labels, label)) {
|
||||
continue;
|
||||
}
|
||||
auto values = OptionalPropertyValueArrayToVector(
|
||||
ExtractPropertyValues(vertex, properties));
|
||||
auto values = ExtractPropertyValues(vertex, properties);
|
||||
if (!values) {
|
||||
continue;
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ struct FixedCapacityArray {
|
||||
}
|
||||
};
|
||||
|
||||
using PropertyValueArray = FixedCapacityArray<const PropertyValue *>;
|
||||
using PropertyIdArray = FixedCapacityArray<PropertyId>;
|
||||
|
||||
struct ConstraintViolation {
|
||||
@ -60,9 +59,6 @@ class UniqueConstraints {
|
||||
|
||||
bool operator<(const std::vector<PropertyValue> &rhs);
|
||||
bool operator==(const std::vector<PropertyValue> &rhs);
|
||||
|
||||
bool operator<(const PropertyValueArray &rhs);
|
||||
bool operator==(const PropertyValueArray &rhs);
|
||||
};
|
||||
|
||||
public:
|
||||
@ -118,6 +114,7 @@ class UniqueConstraints {
|
||||
/// Validates the given vertex against unique constraints before committing.
|
||||
/// This method should be called while commit lock is active with
|
||||
/// `commit_timestamp` being a potential commit timestamp of the transaction.
|
||||
/// @throw std::bad_alloc
|
||||
std::optional<ConstraintViolation> Validate(const Vertex &vertex,
|
||||
const Transaction &tx,
|
||||
uint64_t commit_timestamp) const;
|
||||
@ -155,7 +152,7 @@ inline utils::BasicResult<ConstraintViolation, bool> CreateExistenceConstraint(
|
||||
}
|
||||
for (const auto &vertex : vertices) {
|
||||
if (!vertex.deleted && utils::Contains(vertex.labels, label) &&
|
||||
vertex.properties.find(property) == vertex.properties.end()) {
|
||||
!vertex.properties.HasProperty(property)) {
|
||||
return ConstraintViolation{ConstraintViolation::Type::EXISTENCE, label,
|
||||
std::set<PropertyId>{property}};
|
||||
}
|
||||
@ -186,7 +183,7 @@ ValidateExistenceConstraints(const Vertex &vertex,
|
||||
const Constraints &constraints) {
|
||||
for (const auto &[label, property] : constraints.existence_constraints) {
|
||||
if (!vertex.deleted && utils::Contains(vertex.labels, label) &&
|
||||
vertex.properties.find(property) == vertex.properties.end()) {
|
||||
!vertex.properties.HasProperty(property)) {
|
||||
return ConstraintViolation{ConstraintViolation::Type::EXISTENCE, label,
|
||||
std::set<PropertyId>{property}};
|
||||
}
|
||||
|
@ -1261,12 +1261,11 @@ void WalFile::AppendDelta(const Delta &delta, const Vertex &vertex,
|
||||
wal_.WriteString(name_id_mapper_->IdToName(delta.property.key.AsUint()));
|
||||
// The property value is the value that is currently stored in the
|
||||
// vertex.
|
||||
auto it = vertex.properties.find(delta.property.key);
|
||||
if (it != vertex.properties.end()) {
|
||||
wal_.WritePropertyValue(it->second);
|
||||
} else {
|
||||
wal_.WritePropertyValue(PropertyValue());
|
||||
}
|
||||
// TODO (mferencevic): Mitigate the memory allocation introduced here
|
||||
// (with the `GetProperty` call). It is the only memory allocation in the
|
||||
// entire WAL file writing logic.
|
||||
wal_.WritePropertyValue(
|
||||
vertex.properties.GetProperty(delta.property.key));
|
||||
break;
|
||||
}
|
||||
case Delta::Action::ADD_LABEL:
|
||||
@ -1314,12 +1313,10 @@ void WalFile::AppendDelta(const Delta &delta, const Edge &edge,
|
||||
wal_.WriteString(name_id_mapper_->IdToName(delta.property.key.AsUint()));
|
||||
// The property value is the value that is currently stored in the
|
||||
// edge.
|
||||
auto it = edge.properties.find(delta.property.key);
|
||||
if (it != edge.properties.end()) {
|
||||
wal_.WritePropertyValue(it->second);
|
||||
} else {
|
||||
wal_.WritePropertyValue(PropertyValue());
|
||||
}
|
||||
// TODO (mferencevic): Mitigate the memory allocation introduced here
|
||||
// (with the `GetProperty` call). It is the only memory allocation in the
|
||||
// entire WAL file writing logic.
|
||||
wal_.WritePropertyValue(edge.properties.GetProperty(delta.property.key));
|
||||
break;
|
||||
}
|
||||
case Delta::Action::DELETE_OBJECT:
|
||||
@ -2322,7 +2319,7 @@ Durability::RecoveredSnapshot Durability::LoadSnapshot(
|
||||
if (!key) throw RecoveryFailure("Invalid snapshot data!");
|
||||
auto value = snapshot.ReadPropertyValue();
|
||||
if (!value) throw RecoveryFailure("Invalid snapshot data!");
|
||||
props.emplace(get_property_from_id(*key), std::move(*value));
|
||||
props.SetProperty(get_property_from_id(*key), *value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -2392,7 +2389,7 @@ Durability::RecoveredSnapshot Durability::LoadSnapshot(
|
||||
if (!key) throw RecoveryFailure("Invalid snapshot data!");
|
||||
auto value = snapshot.ReadPropertyValue();
|
||||
if (!value) throw RecoveryFailure("Invalid snapshot data!");
|
||||
props.emplace(get_property_from_id(*key), std::move(*value));
|
||||
props.SetProperty(get_property_from_id(*key), *value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2731,18 +2728,7 @@ Durability::RecoveryInfo Durability::LoadWal(
|
||||
delta.vertex_edge_set_property.property));
|
||||
auto &property_value = delta.vertex_edge_set_property.value;
|
||||
|
||||
auto it = vertex->properties.find(property_id);
|
||||
if (it != vertex->properties.end()) {
|
||||
if (property_value.IsNull()) {
|
||||
// remove the property
|
||||
vertex->properties.erase(it);
|
||||
} else {
|
||||
// set the value
|
||||
it->second = std::move(property_value);
|
||||
}
|
||||
} else if (!property_value.IsNull()) {
|
||||
vertex->properties.emplace(property_id, std::move(property_value));
|
||||
}
|
||||
vertex->properties.SetProperty(property_id, property_value);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -2851,18 +2837,7 @@ Durability::RecoveryInfo Durability::LoadWal(
|
||||
auto property_id = PropertyId::FromUint(name_id_mapper_->NameToId(
|
||||
delta.vertex_edge_set_property.property));
|
||||
auto &property_value = delta.vertex_edge_set_property.value;
|
||||
auto it = edge->properties.find(property_id);
|
||||
if (it != edge->properties.end()) {
|
||||
if (property_value.IsNull()) {
|
||||
// remove the property
|
||||
edge->properties.erase(it);
|
||||
} else {
|
||||
// set the value
|
||||
it->second = std::move(property_value);
|
||||
}
|
||||
} else if (!property_value.IsNull()) {
|
||||
edge->properties.emplace(property_id, std::move(property_value));
|
||||
}
|
||||
edge->properties.SetProperty(property_id, property_value);
|
||||
break;
|
||||
}
|
||||
case WalDeltaData::Type::TRANSACTION_END:
|
||||
|
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <map>
|
||||
|
||||
#include "utils/spin_lock.hpp"
|
||||
|
||||
#include "storage/v2/delta.hpp"
|
||||
#include "storage/v2/id_types.hpp"
|
||||
#include "storage/v2/property_store.hpp"
|
||||
|
||||
namespace storage {
|
||||
|
||||
@ -20,7 +20,7 @@ struct Edge {
|
||||
|
||||
Gid gid;
|
||||
|
||||
std::map<PropertyId, storage::PropertyValue> properties;
|
||||
PropertyStore properties;
|
||||
|
||||
mutable utils::SpinLock lock;
|
||||
bool deleted;
|
||||
|
@ -26,31 +26,17 @@ Result<bool> EdgeAccessor::SetProperty(PropertyId property,
|
||||
|
||||
if (edge_.ptr->deleted) return Error::DELETED_OBJECT;
|
||||
|
||||
auto it = edge_.ptr->properties.find(property);
|
||||
bool existed = it != edge_.ptr->properties.end();
|
||||
auto current_value = edge_.ptr->properties.GetProperty(property);
|
||||
bool existed = !current_value.IsNull();
|
||||
// We could skip setting the value if the previous one is the same to the new
|
||||
// one. This would save some memory as a delta would not be created as well as
|
||||
// avoid copying the value. The reason we are not doing that is because the
|
||||
// current code always follows the logical pattern of "create a delta" and
|
||||
// "modify in-place". Additionally, the created delta will make other
|
||||
// transactions get a SERIALIZATION_ERROR.
|
||||
if (it != edge_.ptr->properties.end()) {
|
||||
CreateAndLinkDelta(transaction_, edge_.ptr, Delta::SetPropertyTag(),
|
||||
property, it->second);
|
||||
if (value.IsNull()) {
|
||||
// remove the property
|
||||
edge_.ptr->properties.erase(it);
|
||||
} else {
|
||||
// set the value
|
||||
it->second = value;
|
||||
}
|
||||
} else {
|
||||
CreateAndLinkDelta(transaction_, edge_.ptr, Delta::SetPropertyTag(),
|
||||
property, PropertyValue());
|
||||
if (!value.IsNull()) {
|
||||
edge_.ptr->properties.emplace(property, value);
|
||||
}
|
||||
}
|
||||
CreateAndLinkDelta(transaction_, edge_.ptr, Delta::SetPropertyTag(), property,
|
||||
std::move(current_value));
|
||||
edge_.ptr->properties.SetProperty(property, value);
|
||||
|
||||
return !existed;
|
||||
}
|
||||
@ -65,13 +51,14 @@ Result<bool> EdgeAccessor::ClearProperties() {
|
||||
|
||||
if (edge_.ptr->deleted) return Error::DELETED_OBJECT;
|
||||
|
||||
bool removed = !edge_.ptr->properties.empty();
|
||||
for (const auto &property : edge_.ptr->properties) {
|
||||
auto properties = edge_.ptr->properties.Properties();
|
||||
bool removed = !properties.empty();
|
||||
for (const auto &property : properties) {
|
||||
CreateAndLinkDelta(transaction_, edge_.ptr, Delta::SetPropertyTag(),
|
||||
property.first, property.second);
|
||||
}
|
||||
|
||||
edge_.ptr->properties.clear();
|
||||
edge_.ptr->properties.ClearProperties();
|
||||
|
||||
return removed;
|
||||
}
|
||||
@ -86,10 +73,7 @@ Result<PropertyValue> EdgeAccessor::GetProperty(PropertyId property,
|
||||
{
|
||||
std::lock_guard<utils::SpinLock> guard(edge_.ptr->lock);
|
||||
deleted = edge_.ptr->deleted;
|
||||
auto it = edge_.ptr->properties.find(property);
|
||||
if (it != edge_.ptr->properties.end()) {
|
||||
value = it->second;
|
||||
}
|
||||
value = edge_.ptr->properties.GetProperty(property);
|
||||
delta = edge_.ptr->delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view,
|
||||
@ -134,7 +118,7 @@ Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::Properties(
|
||||
{
|
||||
std::lock_guard<utils::SpinLock> guard(edge_.ptr->lock);
|
||||
deleted = edge_.ptr->deleted;
|
||||
properties = edge_.ptr->properties;
|
||||
properties = edge_.ptr->properties.Properties();
|
||||
delta = edge_.ptr->delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view,
|
||||
|
@ -93,10 +93,8 @@ bool AnyVersionHasLabelProperty(const Vertex &vertex, LabelId label,
|
||||
{
|
||||
std::lock_guard<utils::SpinLock> guard(vertex.lock);
|
||||
has_label = utils::Contains(vertex.labels, label);
|
||||
auto it = vertex.properties.find(key);
|
||||
if (it != vertex.properties.end()) {
|
||||
current_value_equal_to_value = it->second == value;
|
||||
}
|
||||
current_value_equal_to_value =
|
||||
vertex.properties.IsPropertyEqual(key, value);
|
||||
deleted = vertex.deleted;
|
||||
delta = vertex.delta;
|
||||
}
|
||||
@ -213,10 +211,8 @@ bool CurrentVersionHasLabelProperty(const Vertex &vertex, LabelId label,
|
||||
std::lock_guard<utils::SpinLock> guard(vertex.lock);
|
||||
deleted = vertex.deleted;
|
||||
has_label = utils::Contains(vertex.labels, label);
|
||||
auto it = vertex.properties.find(key);
|
||||
if (it != vertex.properties.end()) {
|
||||
current_value_equal_to_value = it->second == value;
|
||||
}
|
||||
current_value_equal_to_value =
|
||||
vertex.properties.IsPropertyEqual(key, value);
|
||||
delta = vertex.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction, delta, view,
|
||||
@ -397,10 +393,10 @@ void LabelPropertyIndex::UpdateOnAddLabel(LabelId label, Vertex *vertex,
|
||||
if (label_prop.first != label) {
|
||||
continue;
|
||||
}
|
||||
auto it = vertex->properties.find(label_prop.second);
|
||||
if (it != vertex->properties.end() && !it->second.IsNull()) {
|
||||
auto prop_value = vertex->properties.GetProperty(label_prop.second);
|
||||
if (!prop_value.IsNull()) {
|
||||
auto acc = storage.access();
|
||||
acc.insert(Entry{it->second, vertex, tx.start_timestamp});
|
||||
acc.insert(Entry{std::move(prop_value), vertex, tx.start_timestamp});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -438,11 +434,11 @@ bool LabelPropertyIndex::CreateIndex(
|
||||
if (vertex.deleted || !utils::Contains(vertex.labels, label)) {
|
||||
continue;
|
||||
}
|
||||
auto it = vertex.properties.find(property);
|
||||
if (it == vertex.properties.end()) {
|
||||
auto value = vertex.properties.GetProperty(property);
|
||||
if (value.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
acc.insert(Entry{it->second, &vertex, 0});
|
||||
acc.insert(Entry{std::move(value), &vertex, 0});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -787,19 +787,8 @@ void Storage::Accessor::Abort() {
|
||||
break;
|
||||
}
|
||||
case Delta::Action::SET_PROPERTY: {
|
||||
auto it = vertex->properties.find(current->property.key);
|
||||
if (it != vertex->properties.end()) {
|
||||
if (current->property.value.IsNull()) {
|
||||
// remove the property
|
||||
vertex->properties.erase(it);
|
||||
} else {
|
||||
// set the value
|
||||
it->second = current->property.value;
|
||||
}
|
||||
} else if (!current->property.value.IsNull()) {
|
||||
vertex->properties.emplace(current->property.key,
|
||||
current->property.value);
|
||||
}
|
||||
vertex->properties.SetProperty(current->property.key,
|
||||
current->property.value);
|
||||
break;
|
||||
}
|
||||
case Delta::Action::ADD_IN_EDGE: {
|
||||
@ -882,19 +871,8 @@ void Storage::Accessor::Abort() {
|
||||
transaction_.transaction_id) {
|
||||
switch (current->action) {
|
||||
case Delta::Action::SET_PROPERTY: {
|
||||
auto it = edge->properties.find(current->property.key);
|
||||
if (it != edge->properties.end()) {
|
||||
if (current->property.value.IsNull()) {
|
||||
// remove the property
|
||||
edge->properties.erase(it);
|
||||
} else {
|
||||
// set the value
|
||||
it->second = current->property.value;
|
||||
}
|
||||
} else if (!current->property.value.IsNull()) {
|
||||
edge->properties.emplace(current->property.key,
|
||||
current->property.value);
|
||||
}
|
||||
edge->properties.SetProperty(current->property.key,
|
||||
current->property.value);
|
||||
break;
|
||||
}
|
||||
case Delta::Action::DELETE_OBJECT: {
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
@ -10,6 +9,7 @@
|
||||
#include "storage/v2/delta.hpp"
|
||||
#include "storage/v2/edge_ref.hpp"
|
||||
#include "storage/v2/id_types.hpp"
|
||||
#include "storage/v2/property_store.hpp"
|
||||
|
||||
namespace storage {
|
||||
|
||||
@ -22,7 +22,7 @@ struct Vertex {
|
||||
Gid gid;
|
||||
|
||||
std::vector<LabelId> labels;
|
||||
std::map<PropertyId, storage::PropertyValue> properties;
|
||||
PropertyStore properties;
|
||||
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, EdgeRef>> in_edges;
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, EdgeRef>> out_edges;
|
||||
|
@ -197,31 +197,17 @@ Result<bool> VertexAccessor::SetProperty(PropertyId property,
|
||||
|
||||
if (vertex_->deleted) return Error::DELETED_OBJECT;
|
||||
|
||||
auto it = vertex_->properties.find(property);
|
||||
bool existed = it != vertex_->properties.end();
|
||||
auto current_value = vertex_->properties.GetProperty(property);
|
||||
bool existed = !current_value.IsNull();
|
||||
// We could skip setting the value if the previous one is the same to the new
|
||||
// one. This would save some memory as a delta would not be created as well as
|
||||
// avoid copying the value. The reason we are not doing that is because the
|
||||
// current code always follows the logical pattern of "create a delta" and
|
||||
// "modify in-place". Additionally, the created delta will make other
|
||||
// transactions get a SERIALIZATION_ERROR.
|
||||
if (it != vertex_->properties.end()) {
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property,
|
||||
it->second);
|
||||
if (value.IsNull()) {
|
||||
// remove the property
|
||||
vertex_->properties.erase(it);
|
||||
} else {
|
||||
// set the value
|
||||
it->second = value;
|
||||
}
|
||||
} else {
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property,
|
||||
PropertyValue());
|
||||
if (!value.IsNull()) {
|
||||
vertex_->properties.emplace(property, value);
|
||||
}
|
||||
}
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property,
|
||||
std::move(current_value));
|
||||
vertex_->properties.SetProperty(property, value);
|
||||
|
||||
UpdateOnSetProperty(indices_, property, value, vertex_, *transaction_);
|
||||
|
||||
@ -236,15 +222,16 @@ Result<bool> VertexAccessor::ClearProperties() {
|
||||
|
||||
if (vertex_->deleted) return Error::DELETED_OBJECT;
|
||||
|
||||
bool removed = !vertex_->properties.empty();
|
||||
for (const auto &property : vertex_->properties) {
|
||||
auto properties = vertex_->properties.Properties();
|
||||
bool removed = !properties.empty();
|
||||
for (const auto &property : properties) {
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(),
|
||||
property.first, property.second);
|
||||
UpdateOnSetProperty(indices_, property.first, PropertyValue(), vertex_,
|
||||
*transaction_);
|
||||
}
|
||||
|
||||
vertex_->properties.clear();
|
||||
vertex_->properties.ClearProperties();
|
||||
|
||||
return removed;
|
||||
}
|
||||
@ -258,10 +245,7 @@ Result<PropertyValue> VertexAccessor::GetProperty(PropertyId property,
|
||||
{
|
||||
std::lock_guard<utils::SpinLock> guard(vertex_->lock);
|
||||
deleted = vertex_->deleted;
|
||||
auto it = vertex_->properties.find(property);
|
||||
if (it != vertex_->properties.end()) {
|
||||
value = it->second;
|
||||
}
|
||||
value = vertex_->properties.GetProperty(property);
|
||||
delta = vertex_->delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view,
|
||||
@ -304,7 +288,7 @@ Result<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(
|
||||
{
|
||||
std::lock_guard<utils::SpinLock> guard(vertex_->lock);
|
||||
deleted = vertex_->deleted;
|
||||
properties = vertex_->properties;
|
||||
properties = vertex_->properties.Properties();
|
||||
delta = vertex_->delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view,
|
||||
|
@ -105,24 +105,11 @@ class DeltaGenerator final {
|
||||
auto property_id =
|
||||
storage::PropertyId::FromUint(gen_->mapper_.NameToId(property));
|
||||
auto &props = vertex->properties;
|
||||
auto it = props.find(property_id);
|
||||
if (it == props.end()) {
|
||||
storage::CreateAndLinkDelta(&transaction_, &*vertex,
|
||||
storage::Delta::SetPropertyTag(),
|
||||
property_id, storage::PropertyValue());
|
||||
if (!value.IsNull()) {
|
||||
props.emplace(property_id, value);
|
||||
}
|
||||
} else {
|
||||
storage::CreateAndLinkDelta(&transaction_, &*vertex,
|
||||
storage::Delta::SetPropertyTag(),
|
||||
property_id, it->second);
|
||||
if (!value.IsNull()) {
|
||||
it->second = value;
|
||||
} else {
|
||||
props.erase(it);
|
||||
}
|
||||
}
|
||||
auto old_value = props.GetProperty(property_id);
|
||||
storage::CreateAndLinkDelta(&transaction_, &*vertex,
|
||||
storage::Delta::SetPropertyTag(), property_id,
|
||||
old_value);
|
||||
props.SetProperty(property_id, value);
|
||||
{
|
||||
storage::WalDeltaData data;
|
||||
data.type = storage::WalDeltaData::Type::VERTEX_SET_PROPERTY;
|
||||
@ -166,13 +153,8 @@ class DeltaGenerator final {
|
||||
auto property_id =
|
||||
storage::PropertyId::FromUint(gen_->mapper_.NameToId(
|
||||
data.vertex_edge_set_property.property));
|
||||
auto &props = vertex->properties;
|
||||
auto it = props.find(property_id);
|
||||
if (it == props.end()) {
|
||||
data.vertex_edge_set_property.value = storage::PropertyValue();
|
||||
} else {
|
||||
data.vertex_edge_set_property.value = it->second;
|
||||
}
|
||||
data.vertex_edge_set_property.value =
|
||||
vertex->properties.GetProperty(property_id);
|
||||
}
|
||||
gen_->data_.emplace_back(commit_timestamp, data);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user