|
|
|
|
@@ -195,6 +195,11 @@ bool IsPropertyValueWithinInterval(const PropertyValue &value,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool disk_label_property_filter(const std::string &key, const std::string &label_property_prefix,
|
|
|
|
|
const std::unordered_set<Gid> &gids, Gid curr_gid) {
|
|
|
|
|
return key.starts_with(label_property_prefix) && !utils::Contains(gids, curr_gid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
DiskStorage::DiskStorage(Config config)
|
|
|
|
|
@@ -479,20 +484,49 @@ VerticesIterable DiskStorage::DiskAccessor::Vertices(LabelId label, View view) {
|
|
|
|
|
return VerticesIterable(disk_storage->edge_import_mode_cache_->Vertices(label, view, storage_, &transaction_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
transaction_.index_storage_.emplace_back(std::make_unique<utils::SkipList<storage::Vertex>>());
|
|
|
|
|
auto &indexed_vertices = transaction_.index_storage_.back();
|
|
|
|
|
transaction_.index_deltas_storage_.emplace_back();
|
|
|
|
|
auto &index_deltas = transaction_.index_deltas_storage_.back();
|
|
|
|
|
utils::SkipList<memgraph::storage::Vertex> *indexed_vertices{nullptr};
|
|
|
|
|
std::list<storage::Delta> *index_deltas{nullptr};
|
|
|
|
|
|
|
|
|
|
auto gids = disk_storage->MergeVerticesFromMainCacheWithLabelIndexCache(&transaction_, label, view, index_deltas,
|
|
|
|
|
indexed_vertices.get());
|
|
|
|
|
disk_storage->LoadVerticesFromDiskLabelIndex(&transaction_, label, gids, index_deltas, indexed_vertices.get());
|
|
|
|
|
auto merge_with_main_cache = [&](auto &index, auto &index_delta_storage) -> std::unordered_set<Gid> {
|
|
|
|
|
indexed_vertices = &index[label];
|
|
|
|
|
index_deltas = &index_delta_storage.emplace_back();
|
|
|
|
|
return disk_storage->MergeVerticesFromMainCacheWithLabelIndexCache(&transaction_, label, view, *index_deltas,
|
|
|
|
|
indexed_vertices);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto &cache = transaction_.label_index_cache_;
|
|
|
|
|
auto &cache_ci = transaction_.label_index_cache_ci_;
|
|
|
|
|
auto &index_delta_storage = transaction_.index_deltas_storage_;
|
|
|
|
|
|
|
|
|
|
SyncDeletedVertices(cache, label, index_delta_storage, view, merge_with_main_cache);
|
|
|
|
|
|
|
|
|
|
if (transaction_.command_id > cache_ci) {
|
|
|
|
|
cache_ci = transaction_.command_id;
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(indexed_vertices->access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
if (cache.contains(label)) {
|
|
|
|
|
if (view == View::NEW) {
|
|
|
|
|
cache[label] = utils::SkipList<Vertex>();
|
|
|
|
|
}
|
|
|
|
|
// TODO
|
|
|
|
|
// we do not need this merge if we can make sure that
|
|
|
|
|
// the removing and re-adding the same label to a given
|
|
|
|
|
// vertex within one transaction is not permitted.
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(cache[label].access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
cache[label] = utils::SkipList<Vertex>();
|
|
|
|
|
index_deltas = &index_delta_storage.emplace_back();
|
|
|
|
|
disk_storage->LoadVerticesFromDiskLabelIndex(&transaction_, label, {}, *index_deltas, &transaction_.vertices_);
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(indexed_vertices->access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerticesIterable DiskStorage::DiskAccessor::Vertices(LabelId label, PropertyId property, View view) {
|
|
|
|
|
auto *disk_storage = static_cast<DiskStorage *>(storage_);
|
|
|
|
|
const auto cache_key = std::make_pair(label, property);
|
|
|
|
|
|
|
|
|
|
if (disk_storage->edge_import_status_ == EdgeImportMode::ACTIVE) {
|
|
|
|
|
disk_storage->HandleLoadingLabelPropertyForEdgeImportCache(&transaction_, label, property);
|
|
|
|
|
|
|
|
|
|
@@ -500,34 +534,59 @@ VerticesIterable DiskStorage::DiskAccessor::Vertices(LabelId label, PropertyId p
|
|
|
|
|
view, storage_, &transaction_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
transaction_.index_storage_.emplace_back(std::make_unique<utils::SkipList<storage::Vertex>>());
|
|
|
|
|
auto &indexed_vertices = transaction_.index_storage_.back();
|
|
|
|
|
transaction_.index_deltas_storage_.emplace_back();
|
|
|
|
|
auto &index_deltas = transaction_.index_deltas_storage_.back();
|
|
|
|
|
utils::SkipList<memgraph::storage::Vertex> *indexed_vertices{nullptr};
|
|
|
|
|
std::list<storage::Delta> *index_deltas{nullptr};
|
|
|
|
|
|
|
|
|
|
const auto label_property_filter = [this](const Vertex &vertex, LabelId label, PropertyId property,
|
|
|
|
|
View view) -> bool {
|
|
|
|
|
return VertexHasLabel(vertex, label, &transaction_, view) &&
|
|
|
|
|
HasVertexProperty(vertex, property, &transaction_, view);
|
|
|
|
|
auto merge_with_main_cache = [&](auto &index, auto &index_delta_storage) -> std::unordered_set<Gid> {
|
|
|
|
|
index[cache_key] = utils::SkipList<Vertex>();
|
|
|
|
|
indexed_vertices = &index[cache_key];
|
|
|
|
|
index_deltas = &index_delta_storage.emplace_back();
|
|
|
|
|
|
|
|
|
|
const auto label_property_filter = [this](const Vertex &vertex, LabelId label, PropertyId property,
|
|
|
|
|
View view) -> bool {
|
|
|
|
|
return VertexHasLabel(vertex, label, &transaction_, view) &&
|
|
|
|
|
HasVertexProperty(vertex, property, &transaction_, view);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return disk_storage->MergeVerticesFromMainCacheWithLabelPropertyIndexCache(
|
|
|
|
|
&transaction_, label, property, view, *index_deltas, indexed_vertices, label_property_filter);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const auto gids = disk_storage->MergeVerticesFromMainCacheWithLabelPropertyIndexCache(
|
|
|
|
|
&transaction_, label, property, view, index_deltas, indexed_vertices.get(), label_property_filter);
|
|
|
|
|
auto &cache = transaction_.label_property_index_cache_;
|
|
|
|
|
auto &cache_ci = transaction_.label_property_index_cache_ci_;
|
|
|
|
|
auto &index_delta_storage = transaction_.index_deltas_storage_;
|
|
|
|
|
|
|
|
|
|
const auto disk_label_property_filter = [](const std::string &key, const std::string &label_property_prefix,
|
|
|
|
|
const std::unordered_set<Gid> &gids, Gid curr_gid) -> bool {
|
|
|
|
|
return key.starts_with(label_property_prefix) && !utils::Contains(gids, curr_gid);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
disk_storage->LoadVerticesFromDiskLabelPropertyIndex(&transaction_, label, property, gids, index_deltas,
|
|
|
|
|
indexed_vertices.get(), disk_label_property_filter);
|
|
|
|
|
SyncDeletedVertices(cache, cache_key, index_delta_storage, view, merge_with_main_cache);
|
|
|
|
|
|
|
|
|
|
if (transaction_.command_id > cache_ci) {
|
|
|
|
|
cache_ci = transaction_.command_id;
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(indexed_vertices->access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
if (cache.contains(cache_key)) {
|
|
|
|
|
if (view == View::NEW) {
|
|
|
|
|
cache[cache_key] = utils::SkipList<Vertex>();
|
|
|
|
|
}
|
|
|
|
|
// TODO
|
|
|
|
|
// we do not need this merge if we can make sure that
|
|
|
|
|
// the removing and re-adding the same label to a given
|
|
|
|
|
// vertex within one transaction is not permitted.
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(cache[cache_key].access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
cache[cache_key] = utils::SkipList<Vertex>();
|
|
|
|
|
index_deltas = &index_delta_storage.emplace_back();
|
|
|
|
|
disk_storage->LoadVerticesFromDiskLabelPropertyIndex(&transaction_, label, property, {}, *index_deltas,
|
|
|
|
|
&transaction_.vertices_, disk_label_property_filter);
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(indexed_vertices->access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerticesIterable DiskStorage::DiskAccessor::Vertices(LabelId label, PropertyId property, const PropertyValue &value,
|
|
|
|
|
View view) {
|
|
|
|
|
auto *disk_storage = static_cast<DiskStorage *>(storage_);
|
|
|
|
|
const auto cache_key = std::make_pair(label, property);
|
|
|
|
|
|
|
|
|
|
if (disk_storage->edge_import_status_ == EdgeImportMode::ACTIVE) {
|
|
|
|
|
disk_storage->HandleLoadingLabelPropertyForEdgeImportCache(&transaction_, label, property);
|
|
|
|
|
|
|
|
|
|
@@ -536,23 +595,51 @@ VerticesIterable DiskStorage::DiskAccessor::Vertices(LabelId label, PropertyId p
|
|
|
|
|
&transaction_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
transaction_.index_storage_.emplace_back(std::make_unique<utils::SkipList<storage::Vertex>>());
|
|
|
|
|
auto &indexed_vertices = transaction_.index_storage_.back();
|
|
|
|
|
transaction_.index_deltas_storage_.emplace_back();
|
|
|
|
|
auto &index_deltas = transaction_.index_deltas_storage_.back();
|
|
|
|
|
utils::SkipList<memgraph::storage::Vertex> *indexed_vertices{nullptr};
|
|
|
|
|
std::list<storage::Delta> *index_deltas{nullptr};
|
|
|
|
|
|
|
|
|
|
auto label_property_filter = [this, &value](const Vertex &vertex, LabelId label, PropertyId property,
|
|
|
|
|
View view) -> bool {
|
|
|
|
|
return VertexHasLabel(vertex, label, &transaction_, view) &&
|
|
|
|
|
VertexHasEqualPropertyValue(vertex, property, value, &transaction_, view);
|
|
|
|
|
auto merge_with_main_cache = [&](auto &index, auto &index_delta_storage) -> std::unordered_set<Gid> {
|
|
|
|
|
index[cache_key] = utils::SkipList<Vertex>();
|
|
|
|
|
indexed_vertices = &index[cache_key];
|
|
|
|
|
index_deltas = &index_delta_storage.emplace_back();
|
|
|
|
|
|
|
|
|
|
auto label_property_filter = [this, &value](const Vertex &vertex, LabelId label, PropertyId property,
|
|
|
|
|
View view) -> bool {
|
|
|
|
|
return VertexHasLabel(vertex, label, &transaction_, view) &&
|
|
|
|
|
VertexHasEqualPropertyValue(vertex, property, value, &transaction_, view);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return disk_storage->MergeVerticesFromMainCacheWithLabelPropertyIndexCache(
|
|
|
|
|
&transaction_, label, property, view, *index_deltas, indexed_vertices, label_property_filter);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const auto gids = disk_storage->MergeVerticesFromMainCacheWithLabelPropertyIndexCache(
|
|
|
|
|
&transaction_, label, property, view, index_deltas, indexed_vertices.get(), label_property_filter);
|
|
|
|
|
auto &cache = transaction_.label_property_index_cache_;
|
|
|
|
|
auto &cache_ci = transaction_.label_property_index_cache_ci_;
|
|
|
|
|
auto &index_delta_storage = transaction_.index_deltas_storage_;
|
|
|
|
|
|
|
|
|
|
disk_storage->LoadVerticesFromDiskLabelPropertyIndexWithPointValueLookup(&transaction_, label, property, gids, value,
|
|
|
|
|
index_deltas, indexed_vertices.get());
|
|
|
|
|
SyncDeletedVertices(cache, cache_key, index_delta_storage, view, merge_with_main_cache);
|
|
|
|
|
|
|
|
|
|
if (transaction_.command_id > cache_ci) {
|
|
|
|
|
cache_ci = transaction_.command_id;
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(indexed_vertices->access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
if (cache.contains(cache_key)) {
|
|
|
|
|
if (view == View::NEW) {
|
|
|
|
|
cache[cache_key] = utils::SkipList<Vertex>();
|
|
|
|
|
}
|
|
|
|
|
// TODO
|
|
|
|
|
// we do not need this merge if we can make sure that
|
|
|
|
|
// the removing and re-adding the same label to a given
|
|
|
|
|
// vertex within one transaction is not permitted.
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(cache[cache_key].access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
cache[cache_key] = utils::SkipList<Vertex>();
|
|
|
|
|
index_deltas = &index_delta_storage.emplace_back();
|
|
|
|
|
disk_storage->LoadVerticesFromDiskLabelPropertyIndex(&transaction_, label, property, {}, *index_deltas,
|
|
|
|
|
&transaction_.vertices_, disk_label_property_filter);
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(indexed_vertices->access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -561,6 +648,7 @@ VerticesIterable DiskStorage::DiskAccessor::Vertices(LabelId label, PropertyId p
|
|
|
|
|
const std::optional<utils::Bound<PropertyValue>> &upper_bound,
|
|
|
|
|
View view) {
|
|
|
|
|
auto *disk_storage = static_cast<DiskStorage *>(storage_);
|
|
|
|
|
const auto cache_key = std::make_pair(label, property);
|
|
|
|
|
if (disk_storage->edge_import_status_ == EdgeImportMode::ACTIVE) {
|
|
|
|
|
disk_storage->HandleLoadingLabelPropertyForEdgeImportCache(&transaction_, label, property);
|
|
|
|
|
|
|
|
|
|
@@ -568,17 +656,45 @@ VerticesIterable DiskStorage::DiskAccessor::Vertices(LabelId label, PropertyId p
|
|
|
|
|
view, storage_, &transaction_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
transaction_.index_storage_.emplace_back(std::make_unique<utils::SkipList<storage::Vertex>>());
|
|
|
|
|
auto &indexed_vertices = transaction_.index_storage_.back();
|
|
|
|
|
transaction_.index_deltas_storage_.emplace_back();
|
|
|
|
|
auto &index_deltas = transaction_.index_deltas_storage_.back();
|
|
|
|
|
utils::SkipList<memgraph::storage::Vertex> *indexed_vertices{nullptr};
|
|
|
|
|
std::list<storage::Delta> *index_deltas{nullptr};
|
|
|
|
|
|
|
|
|
|
const auto gids = disk_storage->MergeVerticesFromMainCacheWithLabelPropertyIndexCacheForIntervalSearch(
|
|
|
|
|
&transaction_, label, property, view, lower_bound, upper_bound, index_deltas, indexed_vertices.get());
|
|
|
|
|
auto merge_with_main_cache = [&](auto &index, auto &index_delta_storage) -> std::unordered_set<Gid> {
|
|
|
|
|
index[cache_key] = utils::SkipList<Vertex>();
|
|
|
|
|
indexed_vertices = &index[cache_key];
|
|
|
|
|
index_deltas = &index_delta_storage.emplace_back();
|
|
|
|
|
|
|
|
|
|
disk_storage->LoadVerticesFromDiskLabelPropertyIndexForIntervalSearch(
|
|
|
|
|
&transaction_, label, property, gids, lower_bound, upper_bound, index_deltas, indexed_vertices.get());
|
|
|
|
|
return disk_storage->MergeVerticesFromMainCacheWithLabelPropertyIndexCacheForIntervalSearch(
|
|
|
|
|
&transaction_, label, property, view, lower_bound, upper_bound, *index_deltas, indexed_vertices);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto &cache = transaction_.label_property_index_cache_;
|
|
|
|
|
auto &cache_ci = transaction_.label_property_index_cache_ci_;
|
|
|
|
|
auto &index_delta_storage = transaction_.index_deltas_storage_;
|
|
|
|
|
|
|
|
|
|
SyncDeletedVertices(cache, cache_key, index_delta_storage, view, merge_with_main_cache);
|
|
|
|
|
|
|
|
|
|
if (transaction_.command_id > cache_ci) {
|
|
|
|
|
cache_ci = transaction_.command_id;
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(indexed_vertices->access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
if (cache.contains(cache_key)) {
|
|
|
|
|
if (view == View::NEW) {
|
|
|
|
|
cache[cache_key] = utils::SkipList<Vertex>();
|
|
|
|
|
}
|
|
|
|
|
// TODO
|
|
|
|
|
// we do not need this merge if we can make sure that
|
|
|
|
|
// the removing and re-adding the same label to a given
|
|
|
|
|
// vertex within one transaction is not permitted.
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(cache[cache_key].access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
cache[cache_key] = utils::SkipList<Vertex>();
|
|
|
|
|
index_deltas = &index_delta_storage.emplace_back();
|
|
|
|
|
disk_storage->LoadVerticesFromDiskLabelPropertyIndex(&transaction_, label, property, {}, *index_deltas,
|
|
|
|
|
&transaction_.vertices_, disk_label_property_filter);
|
|
|
|
|
merge_with_main_cache(cache, index_delta_storage);
|
|
|
|
|
return VerticesIterable(AllVerticesIterable(indexed_vertices->access(), storage_, &transaction_, view));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1181,10 +1297,22 @@ bool DiskStorage::DeleteEdgeFromConnectivityIndex(Transaction *transaction, cons
|
|
|
|
|
Transaction *transaction) {
|
|
|
|
|
std::vector<std::vector<PropertyValue>> unique_storage;
|
|
|
|
|
|
|
|
|
|
for (const auto &vec : transaction->index_storage_) {
|
|
|
|
|
if (auto vertices_res = FlushVertices(transaction, vec->access(), unique_storage); vertices_res.HasError()) {
|
|
|
|
|
return vertices_res.GetError();
|
|
|
|
|
auto flush_index = [&](auto &index_storage) -> utils::BasicResult<StorageManipulationError, void> {
|
|
|
|
|
for (const auto &[k, v] : index_storage) {
|
|
|
|
|
if (auto vertices_res = FlushVertices(transaction, v.access(), unique_storage); vertices_res.HasError()) {
|
|
|
|
|
return vertices_res.GetError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (auto res = flush_index(transaction->label_index_cache_); res.HasError()) {
|
|
|
|
|
return res.GetError();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auto res = flush_index(transaction->label_property_index_cache_); res.HasError()) {
|
|
|
|
|
return res.GetError();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
@@ -1309,12 +1437,24 @@ std::optional<VertexAccessor> DiskStorage::FindVertex(storage::Gid gid, Transact
|
|
|
|
|
if (vertex_it != acc.end()) {
|
|
|
|
|
return VertexAccessor::Create(&*vertex_it, this, transaction, view);
|
|
|
|
|
}
|
|
|
|
|
for (const auto &vec : transaction->index_storage_) {
|
|
|
|
|
acc = vec->access();
|
|
|
|
|
auto index_it = acc.find(gid);
|
|
|
|
|
if (index_it != acc.end()) {
|
|
|
|
|
return VertexAccessor::Create(&*index_it, this, transaction, view);
|
|
|
|
|
|
|
|
|
|
auto find_in_indices = [&](auto &index_storage) -> std::optional<VertexAccessor> {
|
|
|
|
|
for (auto &[k, v] : index_storage) {
|
|
|
|
|
acc = v.access();
|
|
|
|
|
auto index_it = acc.find(gid);
|
|
|
|
|
if (index_it != acc.end()) {
|
|
|
|
|
return VertexAccessor::Create(&*index_it, this, transaction, view);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (auto vertex = find_in_indices(transaction->label_index_cache_)) {
|
|
|
|
|
return *vertex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auto vertex = find_in_indices(transaction->label_property_index_cache_)) {
|
|
|
|
|
return *vertex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rocksdb::ReadOptions read_opts;
|
|
|
|
|
|