(de)serialization rocksdb unit tests
This commit is contained in:
@@ -70,12 +70,12 @@ class RocksDBStorage {
|
||||
|
||||
// /// fetch the edge's source vertex by its GID
|
||||
// std::optional<query::VertexAccessor> FromVertex(const query::EdgeAccessor &edge_acc, query::DbAccessor &dba) {
|
||||
// return FindVertex(SerializeIdType(edge_acc.From().Gid()), dba);
|
||||
// return FindVertex(utils::SerializeIdType(edge_acc.From().Gid()), dba);
|
||||
// }
|
||||
|
||||
// /// fetch the edge's destination vertex by its GID
|
||||
// std::optional<query::VertexAccessor> ToVertex(const query::EdgeAccessor &edge_acc, query::DbAccessor &dba) {
|
||||
// return FindVertex(SerializeIdType(edge_acc.To().Gid()), dba);
|
||||
// return FindVertex(utils::SerializeIdType(edge_acc.To().Gid()), dba);
|
||||
// }
|
||||
|
||||
// /// VERTEX ACCESSOR FUNCTIONALITIES
|
||||
@@ -86,7 +86,7 @@ class RocksDBStorage {
|
||||
// /// other_vertex_gid | src_gid | 1 | ...
|
||||
// /// We use the firt way since this should be possible to optimize using Bloom filters and prefix search
|
||||
// std::vector<query::EdgeAccessor> OutEdges(const query::VertexAccessor &vertex_acc, query::DbAccessor &dba) {
|
||||
// const auto vertex_acc_gid = SerializeIdType(vertex_acc.Gid());
|
||||
// const auto vertex_acc_gid = utils::SerializeIdType(vertex_acc.Gid());
|
||||
// std::vector<query::EdgeAccessor> out_edges;
|
||||
// auto it = std::unique_ptr<rocksdb::Iterator>(db_->NewIterator(rocksdb::ReadOptions(), edge_chandle));
|
||||
// for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
||||
@@ -104,7 +104,7 @@ class RocksDBStorage {
|
||||
// /// dest_gid | other_verte_gid | 1 | ...
|
||||
// /// we use the second way since this should be possible to optimize using Bloom filters and prefix search.
|
||||
// std::vector<query::EdgeAccessor> InEdges(const query::VertexAccessor &vertex_acc, query::DbAccessor &dba) {
|
||||
// const auto vertex_acc_gid = SerializeIdType(vertex_acc.Gid());
|
||||
// const auto vertex_acc_gid = utils::SerializeIdType(vertex_acc.Gid());
|
||||
// std::vector<query::EdgeAccessor> in_edges;
|
||||
// auto it = std::unique_ptr<rocksdb::Iterator>(db_->NewIterator(rocksdb::ReadOptions(), edge_chandle));
|
||||
// for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
||||
@@ -187,13 +187,13 @@ class RocksDBStorage {
|
||||
// /// Properties are serialized as the value
|
||||
// void StoreVertex(const query::VertexAccessor &vertex_acc) {
|
||||
// AssertRocksDBStatus(db_->Put(rocksdb::WriteOptions(), vertex_chandle, SerializeVertex(vertex_acc),
|
||||
// SerializeProperties(vertex_acc.PropertyStore())));
|
||||
// utils::SerializeProperties(vertex_acc.PropertyStore())));
|
||||
// }
|
||||
|
||||
// /// Store edge as two key-value entries in the RocksDB.
|
||||
// void StoreEdge(const query::EdgeAccessor &edge_acc) {
|
||||
// auto [src_dest_key, dest_src_key] = SerializeEdge(edge_acc);
|
||||
// const std::string value = SerializeProperties(edge_acc.PropertyStore());
|
||||
// const std::string value = utils::SerializeProperties(edge_acc.PropertyStore());
|
||||
// AssertRocksDBStatus(db_->Put(rocksdb::WriteOptions(), edge_chandle, src_dest_key, value));
|
||||
// AssertRocksDBStatus(db_->Put(rocksdb::WriteOptions(), edge_chandle, dest_src_key, value));
|
||||
// }
|
||||
@@ -268,10 +268,10 @@ class RocksDBStorage {
|
||||
// /// Serialization of properties is done by saving the property store buffer
|
||||
// /// If the data is stored in the local buffer of the property store, data from the buffer is copied to the string
|
||||
// /// If the data is stored in some external buffer, the data is read from that location and copied to the string
|
||||
// inline std::string SerializeProperties(const auto &&properties) { return properties; }
|
||||
// inline std::string utils::SerializeProperties(const auto &&properties) { return properties; }
|
||||
|
||||
// /// Serialize labels delimitied by | to string
|
||||
// std::string SerializeLabels(const auto &&labels) {
|
||||
// std::string utils::SerializeLabels(const auto &&labels) {
|
||||
// if (labels.HasError() || (*labels).empty()) {
|
||||
// return "";
|
||||
// }
|
||||
@@ -284,13 +284,13 @@ class RocksDBStorage {
|
||||
// }
|
||||
|
||||
// /// Serializes id type to string
|
||||
// inline std::string SerializeIdType(const auto &id) { return std::to_string(id.AsUint()); }
|
||||
// inline std::string utils::SerializeIdType(const auto &id) { return std::to_string(id.AsUint()); }
|
||||
|
||||
// /// Serialize vertex to string
|
||||
// /// The format: | label1,label2,label3 | gid
|
||||
// std::string SerializeVertex(const query::VertexAccessor &vertex_acc) {
|
||||
// std::string result = SerializeLabels(vertex_acc.Labels(storage::View::OLD)) + "|";
|
||||
// result += SerializeIdType(vertex_acc.Gid());
|
||||
// std::string result = utils::SerializeLabels(vertex_acc.Labels(storage::View::OLD)) + "|";
|
||||
// result += utils::SerializeIdType(vertex_acc.Gid());
|
||||
// return result;
|
||||
// }
|
||||
|
||||
@@ -332,10 +332,10 @@ class RocksDBStorage {
|
||||
// // | from_gid | to_gid | direction | edge_type | edge_gid
|
||||
// std::pair<std::string, std::string> SerializeEdge(const query::EdgeAccessor &edge_acc) {
|
||||
// // Serialized objects
|
||||
// auto from_gid = SerializeIdType(edge_acc.From().Gid());
|
||||
// auto to_gid = SerializeIdType(edge_acc.To().Gid());
|
||||
// auto edge_type = SerializeIdType(edge_acc.EdgeType());
|
||||
// auto edge_gid = SerializeIdType(edge_acc.Gid());
|
||||
// auto from_gid = utils::SerializeIdType(edge_acc.From().Gid());
|
||||
// auto to_gid = utils::SerializeIdType(edge_acc.To().Gid());
|
||||
// auto edge_type = utils::SerializeIdType(edge_acc.EdgeType());
|
||||
// auto edge_gid = utils::SerializeIdType(edge_acc.Gid());
|
||||
// // source->destination key
|
||||
// std::string src_dest_key = from_gid + "|";
|
||||
// src_dest_key += to_gid + "|";
|
||||
|
||||
@@ -54,8 +54,9 @@
|
||||
// const auto &key = it->key().ToString();
|
||||
// const auto vertex_parts = utils::Split(key, "|");
|
||||
// if (const auto labels = utils::Split(vertex_parts[0], ",");
|
||||
// // TODO: (andi): When you decouple SerializeIdType, modify this to_string call to use SerializeIdType.
|
||||
// std::find(labels.begin(), labels.end(), std::to_string(label.AsUint())) != labels.end()) {
|
||||
// // TODO: (andi): When you decouple utils::SerializeIdType, modify this to_string call to use
|
||||
// utils::SerializeIdType. std::find(labels.begin(), labels.end(), std::to_string(label.AsUint())) !=
|
||||
// labels.end()) {
|
||||
// auto gid = storage::Gid::FromUint(std::stoull(vertex_parts[1]));
|
||||
// auto vertex_commit_ts = utils::ExtractTimestampFromDeserializedUserKey(key);
|
||||
// auto delta = CreateDeleteDeserializedObjectDelta(transaction, vertex_commit_ts);
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <rocksdb/options.h>
|
||||
#include <rocksdb/status.h>
|
||||
|
||||
#include "storage/v2/id_types.hpp"
|
||||
#include "storage/v2/property_store.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::storage {
|
||||
@@ -37,6 +39,7 @@ struct RocksDBStorage {
|
||||
rocksdb::ColumnFamilyHandle *edge_chandle = nullptr;
|
||||
};
|
||||
|
||||
/// RocksDB comparator that compares keys with timestamps.
|
||||
class ComparatorWithU64TsImpl : public rocksdb::Comparator {
|
||||
public:
|
||||
explicit ComparatorWithU64TsImpl();
|
||||
|
||||
@@ -75,8 +75,6 @@ using OOMExceptionEnabler = utils::MemoryTracker::OutOfMemoryExceptionEnabler;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char *outEdgeDirection = "0";
|
||||
constexpr const char *inEdgeDirection = "1";
|
||||
constexpr const char *vertexHandle = "vertex";
|
||||
constexpr const char *edgeHandle = "edge";
|
||||
constexpr const char *main_storage_path = "./rocks_experiment";
|
||||
@@ -266,84 +264,6 @@ DiskStorage::DiskAccessor::~DiskAccessor() {
|
||||
FinalizeTransaction();
|
||||
}
|
||||
|
||||
// (De)serialization utilities
|
||||
|
||||
/// TODO: (andi): Decouple this into some object/class related to rocksdb.
|
||||
std::string DiskStorage::DiskAccessor::SerializeIdType(const auto &id) const { return std::to_string(id.AsUint()); }
|
||||
|
||||
auto DiskStorage::DiskAccessor::DeserializeIdType(const std::string &str) { return Gid::FromUint(std::stoull(str)); }
|
||||
|
||||
std::string DiskStorage::DiskAccessor::SerializeTimestamp(const uint64_t ts) { return std::to_string(ts); }
|
||||
|
||||
std::string DiskStorage::DiskAccessor::SerializeLabels(const std::vector<LabelId> &labels) {
|
||||
std::string result = std::to_string(labels[0].AsUint());
|
||||
std::string ser_labels = std::accumulate(
|
||||
std::next(labels.begin()), labels.end(), result,
|
||||
[](const std::string &join, const auto &label_id) { return join + "," + std::to_string(label_id.AsUint()); });
|
||||
return ser_labels;
|
||||
}
|
||||
|
||||
std::string DiskStorage::DiskAccessor::SerializeProperties(PropertyStore &properties) {
|
||||
return properties.StringBuffer();
|
||||
}
|
||||
|
||||
std::string DiskStorage::DiskAccessor::SerializeVertex(const Result<std::vector<LabelId>> &labels, Gid gid) const {
|
||||
std::string result = labels.HasError() || (*labels).empty() ? "" : SerializeLabels(*labels) + "|";
|
||||
result += SerializeIdType(gid);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string DiskStorage::DiskAccessor::SerializeVertex(const Vertex &vertex) const {
|
||||
std::string result = SerializeLabels(vertex.labels) + "|";
|
||||
result += SerializeIdType(vertex.gid);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> DiskStorage::DiskAccessor::SerializeEdge(EdgeAccessor *edge_acc) const {
|
||||
// Serialized objects
|
||||
auto from_gid = SerializeIdType(edge_acc->FromVertex().Gid());
|
||||
auto to_gid = SerializeIdType(edge_acc->ToVertex().Gid());
|
||||
auto edge_type = SerializeIdType(edge_acc->EdgeType());
|
||||
auto edge_gid = SerializeIdType(edge_acc->Gid());
|
||||
// source->destination key
|
||||
std::string src_dest_key = from_gid + "|";
|
||||
src_dest_key += to_gid + "|";
|
||||
src_dest_key += outEdgeDirection;
|
||||
src_dest_key += "|" + edge_type + "|";
|
||||
src_dest_key += edge_gid;
|
||||
// destination->source key
|
||||
std::string dest_src_key = to_gid + "|";
|
||||
dest_src_key += from_gid + "|";
|
||||
dest_src_key += inEdgeDirection;
|
||||
dest_src_key += "|" + edge_type + "|";
|
||||
dest_src_key += edge_gid;
|
||||
return {src_dest_key, dest_src_key};
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> DiskStorage::DiskAccessor::SerializeEdge(const Gid src_vertex_gid,
|
||||
const Gid dest_vertex_gid,
|
||||
EdgeTypeId edge_type_id,
|
||||
const Edge *edge) const {
|
||||
// Serialized objects
|
||||
auto from_gid = SerializeIdType(src_vertex_gid);
|
||||
auto to_gid = SerializeIdType(dest_vertex_gid);
|
||||
auto edge_type = SerializeIdType(edge_type_id);
|
||||
auto edge_gid = SerializeIdType(edge->gid);
|
||||
// source->destination key
|
||||
std::string src_dest_key = from_gid + "|";
|
||||
src_dest_key += to_gid + "|";
|
||||
src_dest_key += outEdgeDirection;
|
||||
src_dest_key += "|" + edge_type + "|";
|
||||
src_dest_key += edge_gid;
|
||||
// destination->source key
|
||||
std::string dest_src_key = to_gid + "|";
|
||||
dest_src_key += from_gid + "|";
|
||||
dest_src_key += inEdgeDirection;
|
||||
dest_src_key += "|" + edge_type + "|";
|
||||
dest_src_key += edge_gid;
|
||||
return {src_dest_key, dest_src_key};
|
||||
}
|
||||
|
||||
std::optional<VertexAccessor> DiskStorage::DiskAccessor::DeserializeVertex(const rocksdb::Slice &key,
|
||||
const rocksdb::Slice &value) {
|
||||
OOMExceptionEnabler oom_exception;
|
||||
@@ -371,7 +291,7 @@ std::optional<VertexAccessor> DiskStorage::DiskAccessor::DeserializeVertex(const
|
||||
std::optional<EdgeAccessor> DiskStorage::DiskAccessor::DeserializeEdge(const rocksdb::Slice &key,
|
||||
const rocksdb::Slice &value) {
|
||||
const auto edge_parts = utils::Split(key.ToStringView(), "|");
|
||||
const Gid edge_gid = DeserializeIdType(edge_parts[4]);
|
||||
const Gid edge_gid = utils::DeserializeIdType(edge_parts[4]);
|
||||
|
||||
auto edge_acc = storage_->edges_.access();
|
||||
auto res = edge_acc.find(edge_gid);
|
||||
@@ -392,8 +312,8 @@ std::optional<EdgeAccessor> DiskStorage::DiskAccessor::DeserializeEdge(const roc
|
||||
edge_parts);
|
||||
|
||||
// load vertex accessors
|
||||
auto from_acc = FindVertex(DeserializeIdType(from_gid), View::OLD);
|
||||
auto to_acc = FindVertex(DeserializeIdType(to_gid), View::OLD);
|
||||
auto from_acc = FindVertex(utils::DeserializeIdType(from_gid), View::OLD);
|
||||
auto to_acc = FindVertex(utils::DeserializeIdType(to_gid), View::OLD);
|
||||
if (!from_acc || !to_acc) {
|
||||
throw utils::BasicException("Non-existing vertices found during edge deserialization");
|
||||
}
|
||||
@@ -538,7 +458,7 @@ std::optional<VertexAccessor> DiskStorage::DiskAccessor::FindVertex(storage::Gid
|
||||
for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
||||
const auto &key = it->key();
|
||||
// TODO(andi): If we change format of vertex serialization, change vertex_parts[1] to vertex_parts[0].
|
||||
if (const auto vertex_parts = utils::Split(key.ToString(), "|"); vertex_parts[1] == SerializeIdType(gid)) {
|
||||
if (const auto vertex_parts = utils::Split(key.ToString(), "|"); vertex_parts[1] == utils::SerializeIdType(gid)) {
|
||||
return DeserializeVertex(key, it->value());
|
||||
}
|
||||
}
|
||||
@@ -563,7 +483,7 @@ Result<std::optional<VertexAccessor>> DiskStorage::DiskAccessor::DeleteVertex(Ve
|
||||
|
||||
CreateAndLinkDelta(&transaction_, vertex_ptr, Delta::RecreateObjectTag());
|
||||
vertex_ptr->deleted = true;
|
||||
vertices_to_delete_.emplace_back(SerializeVertex(*vertex_ptr));
|
||||
vertices_to_delete_.emplace_back(utils::SerializeVertex(*vertex_ptr));
|
||||
|
||||
return std::make_optional<VertexAccessor>(vertex_ptr, &transaction_, &storage_->indices_, &storage_->constraints_,
|
||||
config_, true);
|
||||
@@ -633,7 +553,7 @@ DiskStorage::DiskAccessor::DetachDeleteVertex(VertexAccessor *vertex) {
|
||||
|
||||
CreateAndLinkDelta(&transaction_, vertex_ptr, Delta::RecreateObjectTag());
|
||||
vertex_ptr->deleted = true;
|
||||
vertices_to_delete_.emplace_back(SerializeVertex(*vertex_ptr));
|
||||
vertices_to_delete_.emplace_back(utils::SerializeVertex(*vertex_ptr));
|
||||
|
||||
return std::make_optional<ReturnType>(
|
||||
VertexAccessor{vertex_ptr, &transaction_, &storage_->indices_, &storage_->constraints_, config_, true},
|
||||
@@ -657,18 +577,18 @@ void DiskStorage::DiskAccessor::PrefetchEdges(const auto &prefetch_edge_filter)
|
||||
|
||||
/// TOOD(andi): Add support for fetching in edges only for one vertex. Currently, all in edges are fetched.
|
||||
void DiskStorage::DiskAccessor::PrefetchInEdges(const VertexAccessor &vertex_acc) {
|
||||
PrefetchEdges(
|
||||
[&vertex_acc, this](const std::string_view disk_edge_gid, const std::string_view disk_edge_direction) -> bool {
|
||||
return disk_edge_gid == SerializeIdType(vertex_acc.Gid()) && disk_edge_direction == inEdgeDirection;
|
||||
});
|
||||
PrefetchEdges([&vertex_acc](const std::string_view disk_edge_gid,
|
||||
const std::string_view disk_edge_direction) -> bool {
|
||||
return disk_edge_gid == utils::SerializeIdType(vertex_acc.Gid()) && disk_edge_direction == utils::inEdgeDirection;
|
||||
});
|
||||
}
|
||||
|
||||
/// TODO(andi): Functionality of this method can probably be merged with the functionality of in-edges
|
||||
void DiskStorage::DiskAccessor::PrefetchOutEdges(const VertexAccessor &vertex_acc) {
|
||||
PrefetchEdges(
|
||||
[&vertex_acc, this](const std::string_view disk_edge_gid, const std::string_view disk_edge_direction) -> bool {
|
||||
return disk_edge_gid == SerializeIdType(vertex_acc.Gid()) && disk_edge_direction == outEdgeDirection;
|
||||
});
|
||||
PrefetchEdges([&vertex_acc](const std::string_view disk_edge_gid,
|
||||
const std::string_view disk_edge_direction) -> bool {
|
||||
return disk_edge_gid == utils::SerializeIdType(vertex_acc.Gid()) && disk_edge_direction == utils::outEdgeDirection;
|
||||
});
|
||||
}
|
||||
|
||||
Result<EdgeAccessor> DiskStorage::DiskAccessor::CreateEdge(VertexAccessor *from, VertexAccessor *to,
|
||||
@@ -843,7 +763,7 @@ Result<EdgeAccessor> DiskStorage::DiskAccessor::CreateEdge(VertexAccessor *from,
|
||||
EdgeRef edge(gid);
|
||||
if (config_.properties_on_edges) {
|
||||
auto acc = storage_->edges_.access();
|
||||
auto delta = CreateDeleteObjectDelta(&transaction_);
|
||||
auto *delta = CreateDeleteObjectDelta(&transaction_);
|
||||
auto [it, inserted] = acc.insert(Edge(gid, delta));
|
||||
MG_ASSERT(inserted, "The edge must be inserted here!");
|
||||
MG_ASSERT(it != acc.end(), "Invalid Edge accessor!");
|
||||
@@ -921,7 +841,8 @@ Result<std::optional<EdgeAccessor>> DiskStorage::DiskAccessor::DeleteEdge(EdgeAc
|
||||
|
||||
auto op1 = delete_edge_from_storage(to_vertex, &from_vertex->out_edges);
|
||||
auto op2 = delete_edge_from_storage(from_vertex, &to_vertex->in_edges);
|
||||
auto [src_dest_del_key, dest_src_del_key] = SerializeEdge(from_vertex->gid, to_vertex->gid, edge_type, edge_ref.ptr);
|
||||
auto [src_dest_del_key, dest_src_del_key] =
|
||||
utils::SerializeEdge(from_vertex->gid, to_vertex->gid, edge_type, edge_ref.ptr);
|
||||
edges_to_delete_.emplace_back(src_dest_del_key);
|
||||
edges_to_delete_.emplace_back(dest_src_del_key);
|
||||
|
||||
@@ -990,18 +911,20 @@ void DiskStorage::DiskAccessor::FlushCache() {
|
||||
write_options.timestamp = &ts;
|
||||
for (Vertex &vertex : vertex_acc) {
|
||||
logging::AssertRocksDBStatus(storage_->kvstore_->db_->Put(write_options, storage_->kvstore_->vertex_chandle,
|
||||
SerializeVertex(vertex),
|
||||
SerializeProperties(vertex.properties)));
|
||||
spdlog::debug("rocksdb: Saved vertex with key {} and ts {}", SerializeVertex(vertex), *commit_timestamp_);
|
||||
utils::SerializeVertex(vertex),
|
||||
utils::SerializeProperties(vertex.properties)));
|
||||
spdlog::debug("rocksdb: Saved vertex with key {} and ts {}", utils::SerializeVertex(vertex), *commit_timestamp_);
|
||||
spdlog::debug("Vertex {} has {} out edges", vertex.gid.AsUint(), vertex.out_edges.size());
|
||||
for (auto &edge_entry : vertex.out_edges) {
|
||||
Edge *edge_ptr = std::get<2>(edge_entry).ptr;
|
||||
auto [src_dest_key, dest_src_key] =
|
||||
SerializeEdge(vertex.gid, std::get<1>(edge_entry)->gid, std::get<0>(edge_entry), edge_ptr);
|
||||
logging::AssertRocksDBStatus(storage_->kvstore_->db_->Put(
|
||||
write_options, storage_->kvstore_->edge_chandle, src_dest_key, SerializeProperties(edge_ptr->properties)));
|
||||
logging::AssertRocksDBStatus(storage_->kvstore_->db_->Put(
|
||||
write_options, storage_->kvstore_->edge_chandle, dest_src_key, SerializeProperties(edge_ptr->properties)));
|
||||
utils::SerializeEdge(vertex.gid, std::get<1>(edge_entry)->gid, std::get<0>(edge_entry), edge_ptr);
|
||||
logging::AssertRocksDBStatus(storage_->kvstore_->db_->Put(write_options, storage_->kvstore_->edge_chandle,
|
||||
src_dest_key,
|
||||
utils::SerializeProperties(edge_ptr->properties)));
|
||||
logging::AssertRocksDBStatus(storage_->kvstore_->db_->Put(write_options, storage_->kvstore_->edge_chandle,
|
||||
dest_src_key,
|
||||
utils::SerializeProperties(edge_ptr->properties)));
|
||||
spdlog::debug("rocksdb: Saved edge with key {} and ts {}", src_dest_key, *commit_timestamp_);
|
||||
spdlog::debug("rocksdb: Saved edge with key {} and ts {}", dest_src_key, *commit_timestamp_);
|
||||
num_ser_edges++;
|
||||
@@ -1332,7 +1255,10 @@ void DiskStorage::DiskAccessor::FinalizeTransaction() {
|
||||
|
||||
// this should be handled on an above level of abstraction
|
||||
std::optional<uint64_t> DiskStorage::DiskAccessor::GetTransactionId() const {
|
||||
throw utils::NotYetImplemented("GetTransactionId");
|
||||
if (is_transaction_active_) {
|
||||
return transaction_.transaction_id.load(std::memory_order_acquire);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// this should be handled on an above level of abstraction
|
||||
@@ -1380,7 +1306,8 @@ utils::BasicResult<StorageIndexDefinitionError, void> DiskStorage::CreateIndex(
|
||||
const auto &key = it->key();
|
||||
const auto vertex_parts = utils::Split(key.ToStringView(), "|");
|
||||
if (const auto labels = utils::Split(vertex_parts[0], ",");
|
||||
// TODO: (andi): When you decouple SerializeIdType, modify this to_string call to use SerializeIdType.
|
||||
// TODO: (andi): When you decouple utils::SerializeIdType, modify this to_string call to use
|
||||
// utils::SerializeIdType.
|
||||
std::find(labels.begin(), labels.end(), std::to_string(label.AsUint())) != labels.end()) {
|
||||
spdlog::debug("Found vertex with gid {} for index creation", vertex_parts[1]);
|
||||
indexed_vertices.emplace_back(key.ToString(), it->value().ToString(),
|
||||
|
||||
@@ -209,6 +209,16 @@ class DiskStorage final : public Storage {
|
||||
|
||||
std::optional<uint64_t> GetTransactionId() const override;
|
||||
|
||||
/// Deserializes vertex from the string key and stores it into the vertices_ and lru_vertices_.
|
||||
/// Properties are deserialized from the value.
|
||||
/// The method should be called only when the vertex is not in the cache.
|
||||
std::optional<storage::VertexAccessor> DeserializeVertex(const rocksdb::Slice &key, const rocksdb::Slice &value);
|
||||
|
||||
/// Deserializes edge from the string key and stores it into the edges_ cache.
|
||||
/// Properties are deserialized from the value.
|
||||
/// The method should be called only when the edge is not in the cache.
|
||||
std::optional<storage::EdgeAccessor> DeserializeEdge(const rocksdb::Slice &key, const rocksdb::Slice &value);
|
||||
|
||||
private:
|
||||
/// TODO(andi): Consolidate this vertex creation methods and find from in-memory version where are they used.
|
||||
/// Used for deserialization of vertices and edges from KV store.
|
||||
@@ -229,53 +239,6 @@ class DiskStorage final : public Storage {
|
||||
Result<EdgeAccessor> CreateEdge(VertexAccessor *from, VertexAccessor *to, EdgeTypeId edge_type, storage::Gid gid,
|
||||
uint64_t edge_commit_ts);
|
||||
|
||||
// (De)serialization utility methods
|
||||
|
||||
/// Serialize types defined with STORAGE_DEFINE_ID_TYPE
|
||||
std::string SerializeIdType(const auto &id) const;
|
||||
|
||||
/// Deserialize types defined with STORAGE_DEFINE_ID_TYPE
|
||||
static auto DeserializeIdType(const std::string &str);
|
||||
|
||||
/// Serialize timestamp to string
|
||||
static std::string SerializeTimestamp(uint64_t ts);
|
||||
|
||||
/// Serialize labels to string
|
||||
static std::string SerializeLabels(const std::vector<LabelId> &labels);
|
||||
|
||||
/// Uses the PropertyStore buffer to serialize properties to string.
|
||||
static std::string SerializeProperties(PropertyStore &properties);
|
||||
|
||||
/// Serialize vertex to string as a key in KV store
|
||||
/// label1, label2 | GID | commit_timestamp
|
||||
std::string SerializeVertex(const Result<std::vector<LabelId>> &labels, Gid gid) const;
|
||||
|
||||
/// Serialize vertex to string as a key in KV store
|
||||
/// label1, label2 | GID | commit_timestamp
|
||||
std::string SerializeVertex(const Vertex &vertex) const;
|
||||
|
||||
/// Serialize edge as two KV entries
|
||||
/// vertex_gid_1 | vertex_gid_2 | direction | edge_type | GID | commit_timestamp
|
||||
std::pair<std::string, std::string> SerializeEdge(EdgeAccessor *edge_acc) const;
|
||||
|
||||
/// Serialize edge as two KV entries
|
||||
/// vertex_gid_1 | vertex_gid_2 | direction | edge_type | GID | commit_timestamp
|
||||
/// @tparam src_vertex_gid, dest_vertex_gid: Gid of the source and destination vertices
|
||||
/// @tparam edge: Edge to be serialized
|
||||
/// @tparam edge_type_id: EdgeTypeId of the edge
|
||||
std::pair<std::string, std::string> SerializeEdge(Gid src_vertex_gid, Gid dest_vertex_gid, EdgeTypeId edge_type_id,
|
||||
const Edge *edge) const;
|
||||
|
||||
/// Deserializes vertex from the string key and stores it into the vertices_ and lru_vertices_.
|
||||
/// Properties are deserialized from the value.
|
||||
/// The method should be called only when the vertex is not in the cache.
|
||||
std::optional<VertexAccessor> DeserializeVertex(const rocksdb::Slice &key, const rocksdb::Slice &value);
|
||||
|
||||
/// Deserializes edge from the string key and stores it into the edges_ cache.
|
||||
/// Properties are deserialized from the value.
|
||||
/// The method should be called only when the edge is not in the cache.
|
||||
std::optional<EdgeAccessor> DeserializeEdge(const rocksdb::Slice &key, const rocksdb::Slice &value);
|
||||
|
||||
/// Flushes vertices and edges to the disk with the commit timestamp.
|
||||
/// At the time of calling, the commit_timestamp_ must already exist.
|
||||
/// After this method, the vertex and edge caches are cleared.
|
||||
|
||||
@@ -12,12 +12,107 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
|
||||
#include <rocksdb/db.h>
|
||||
|
||||
#include "storage/v2/edge_accessor.hpp"
|
||||
#include "storage/v2/id_types.hpp"
|
||||
#include "storage/v2/property_store.hpp"
|
||||
#include "storage/v2/vertex.hpp"
|
||||
#include "storage/v2/vertex_accessor.hpp"
|
||||
|
||||
namespace memgraph::utils {
|
||||
|
||||
constexpr const char *outEdgeDirection = "0";
|
||||
constexpr const char *inEdgeDirection = "1";
|
||||
|
||||
inline std::string SerializeIdType(const auto &id) { return std::to_string(id.AsUint()); }
|
||||
|
||||
inline auto DeserializeIdType(const std::string &str) { return storage::Gid::FromUint(std::stoull(str)); }
|
||||
|
||||
inline std::string SerializeTimestamp(const uint64_t ts) { return std::to_string(ts); }
|
||||
|
||||
inline std::string SerializeLabels(const std::vector<storage::LabelId> &labels) {
|
||||
if (labels.empty()) {
|
||||
return "";
|
||||
}
|
||||
std::string result = std::to_string(labels[0].AsUint());
|
||||
std::string ser_labels = std::accumulate(
|
||||
std::next(labels.begin()), labels.end(), result,
|
||||
[](const std::string &join, const auto &label_id) { return join + "," + std::to_string(label_id.AsUint()); });
|
||||
return ser_labels;
|
||||
}
|
||||
|
||||
inline std::string SerializeProperties(storage::PropertyStore &properties) { return properties.StringBuffer(); }
|
||||
|
||||
/// Serialize vertex to string as a key in KV store
|
||||
/// label1, label2 | GID | commit_timestamp
|
||||
inline std::string SerializeVertex(const storage::Result<std::vector<storage::LabelId>> &labels, storage::Gid gid) {
|
||||
std::string result = labels.HasError() || (*labels).empty() ? "" : utils::SerializeLabels(*labels) + "|";
|
||||
result += utils::SerializeIdType(gid);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Serialize vertex to string as a key in KV store
|
||||
/// label1, label2 | GID | commit_timestamp
|
||||
inline std::string SerializeVertex(const storage::Vertex &vertex) {
|
||||
std::string result = utils::SerializeLabels(vertex.labels) + "|";
|
||||
result += utils::SerializeIdType(vertex.gid);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Serialize edge as two KV entries
|
||||
/// vertex_gid_1 | vertex_gid_2 | direction | edge_type | GID | commit_timestamp
|
||||
inline std::pair<std::string, std::string> SerializeEdge(storage::EdgeAccessor *edge_acc) {
|
||||
// Serialized objects
|
||||
auto from_gid = utils::SerializeIdType(edge_acc->FromVertex().Gid());
|
||||
auto to_gid = utils::SerializeIdType(edge_acc->ToVertex().Gid());
|
||||
auto edge_type = utils::SerializeIdType(edge_acc->EdgeType());
|
||||
auto edge_gid = utils::SerializeIdType(edge_acc->Gid());
|
||||
// source->destination key
|
||||
std::string src_dest_key = from_gid + "|";
|
||||
src_dest_key += to_gid + "|";
|
||||
src_dest_key += outEdgeDirection;
|
||||
src_dest_key += "|" + edge_type + "|";
|
||||
src_dest_key += edge_gid;
|
||||
// destination->source key
|
||||
std::string dest_src_key = to_gid + "|";
|
||||
dest_src_key += from_gid + "|";
|
||||
dest_src_key += inEdgeDirection;
|
||||
dest_src_key += "|" + edge_type + "|";
|
||||
dest_src_key += edge_gid;
|
||||
return {src_dest_key, dest_src_key};
|
||||
}
|
||||
|
||||
/// Serialize edge as two KV entries
|
||||
/// vertex_gid_1 | vertex_gid_2 | direction | edge_type | GID | commit_timestamp
|
||||
/// @tparam src_vertex_gid, dest_vertex_gid: Gid of the source and destination vertices
|
||||
/// @tparam edge: Edge to be serialized
|
||||
/// @tparam edge_type_id: EdgeTypeId of the edge
|
||||
inline std::pair<std::string, std::string> SerializeEdge(storage::Gid src_vertex_gid, storage::Gid dest_vertex_gid,
|
||||
storage::EdgeTypeId edge_type_id, const storage::Edge *edge) {
|
||||
// Serialized objects
|
||||
auto from_gid = utils::SerializeIdType(src_vertex_gid);
|
||||
auto to_gid = utils::SerializeIdType(dest_vertex_gid);
|
||||
auto edge_type = utils::SerializeIdType(edge_type_id);
|
||||
auto edge_gid = utils::SerializeIdType(edge->gid);
|
||||
// source->destination key
|
||||
std::string src_dest_key = from_gid + "|";
|
||||
src_dest_key += to_gid + "|";
|
||||
src_dest_key += outEdgeDirection;
|
||||
src_dest_key += "|" + edge_type + "|";
|
||||
src_dest_key += edge_gid;
|
||||
// destination->source key
|
||||
std::string dest_src_key = to_gid + "|";
|
||||
dest_src_key += from_gid + "|";
|
||||
dest_src_key += inEdgeDirection;
|
||||
dest_src_key += "|" + edge_type + "|";
|
||||
dest_src_key += edge_gid;
|
||||
return {src_dest_key, dest_src_key};
|
||||
}
|
||||
|
||||
/// TODO: (andi): This can potentially be a problem on big-endian machines.
|
||||
inline void PutFixed64(std::string *dst, uint64_t value) {
|
||||
dst->append(const_cast<const char *>(reinterpret_cast<char *>(&value)), sizeof(value));
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "query/common.hpp"
|
||||
@@ -24,300 +26,92 @@
|
||||
#include "storage/v2/storage.hpp"
|
||||
#include "storage/v2/vertex_accessor.hpp"
|
||||
#include "storage/v2/view.hpp"
|
||||
#include "utils/rocksdb.hpp"
|
||||
|
||||
// class RocksDBStorageTest : public ::testing::TestWithParam<bool> {
|
||||
// public:
|
||||
// ~RocksDBStorageTest() { db.Clear(); }
|
||||
class RocksDBStorageTest : public ::testing::TestWithParam<bool> {
|
||||
public:
|
||||
RocksDBStorageTest() { storage = std::unique_ptr<memgraph::storage::Storage>(new memgraph::storage::DiskStorage()); }
|
||||
|
||||
// protected:
|
||||
// memgraph::storage::rocks::RocksDBStorage db;
|
||||
// memgraph::storage::Storage storage;
|
||||
// };
|
||||
~RocksDBStorageTest() override {}
|
||||
|
||||
// TEST_F(RocksDBStorageTest, SerializeVertexGID) {
|
||||
// // empty vertices, only gid is serialized
|
||||
// auto storage_dba = storage.Access(memgraph::storage::IsolationLevel::READ_UNCOMMITTED);
|
||||
// memgraph::query::DbAccessor dba(&storage_dba);
|
||||
// std::unordered_set<uint64_t> gids;
|
||||
// for (uint64_t i = 0; i < 5; ++i) {
|
||||
// gids.insert(i);
|
||||
// auto impl = dba.InsertVertex();
|
||||
// impl.SetGid(memgraph::storage::Gid::FromUint(i));
|
||||
// db.StoreVertex(impl);
|
||||
// }
|
||||
// // load vertices from disk
|
||||
// auto loaded_vertices = db.Vertices(dba);
|
||||
// ASSERT_EQ(loaded_vertices.size(), 5);
|
||||
// for (const auto &vertex_acc : loaded_vertices) {
|
||||
// ASSERT_TRUE(gids.contains(vertex_acc.Gid().AsUint()));
|
||||
// }
|
||||
// }
|
||||
protected:
|
||||
std::unique_ptr<memgraph::storage::Storage> storage;
|
||||
};
|
||||
|
||||
// TEST_F(RocksDBStorageTest, SerializeVertexGIDLabels) {
|
||||
// // serialize vertex's gid with its single label
|
||||
// auto storage_dba = storage.Access(memgraph::storage::IsolationLevel::READ_UNCOMMITTED);
|
||||
// memgraph::query::DbAccessor dba(&storage_dba);
|
||||
// // save vertices on disk
|
||||
// std::unordered_set<uint64_t> gids;
|
||||
// std::vector<memgraph::storage::LabelId> label_ids{dba.NameToLabel("Player"), dba.NameToLabel("Person"),
|
||||
// dba.NameToLabel("Ball")};
|
||||
// for (int i = 0; i < 5; ++i) {
|
||||
// gids.insert(i);
|
||||
// auto impl = dba.InsertVertex();
|
||||
// impl.SetGid(memgraph::storage::Gid::FromUint(i));
|
||||
// impl.AddLabel(label_ids[i % 3]);
|
||||
// db.StoreVertex(impl);
|
||||
// }
|
||||
// // load vertices from disk
|
||||
// auto loaded_vertices = db.Vertices(dba);
|
||||
// ASSERT_EQ(loaded_vertices.size(), 5);
|
||||
// for (const auto &vertex_acc : loaded_vertices) {
|
||||
// ASSERT_TRUE(gids.contains(vertex_acc.Gid().AsUint()));
|
||||
// auto labels = vertex_acc.Labels(memgraph::storage::View::OLD);
|
||||
// ASSERT_EQ(labels->size(), 1);
|
||||
// ASSERT_TRUE(std::all_of(labels->begin(), labels->end(), [&label_ids](const auto &label_id) {
|
||||
// return std::find(label_ids.begin(), label_ids.end(), label_id) != label_ids.end();
|
||||
// }));
|
||||
// }
|
||||
// }
|
||||
/// Serialize vertex which contains only GID.
|
||||
TEST_F(RocksDBStorageTest, SerializeVertexGID) {
|
||||
auto acc = storage->Access();
|
||||
auto vertex = acc->CreateVertex();
|
||||
auto gid = vertex.Gid();
|
||||
ASSERT_EQ(memgraph::utils::SerializeVertex(*vertex.vertex_), "|" + memgraph::utils::SerializeIdType(gid));
|
||||
}
|
||||
|
||||
// TEST_F(RocksDBStorageTest, SerializeVertexGIDMutlipleLabels) {
|
||||
// // serialize vertex's gid with multiple labels it contains
|
||||
// auto storage_dba = storage.Access(memgraph::storage::IsolationLevel::READ_UNCOMMITTED);
|
||||
// memgraph::query::DbAccessor dba(&storage_dba);
|
||||
// // save vertices on disk
|
||||
// std::unordered_set<uint64_t> gids;
|
||||
// std::vector<memgraph::storage::LabelId> label_ids{dba.NameToLabel("Player"), dba.NameToLabel("Person"),
|
||||
// dba.NameToLabel("Ball")};
|
||||
// for (int i = 0; i < 5; ++i) {
|
||||
// gids.insert(i);
|
||||
// auto impl = dba.InsertVertex();
|
||||
// impl.SetGid(memgraph::storage::Gid::FromUint(i));
|
||||
// impl.AddLabel(label_ids[i % 3]);
|
||||
// impl.AddLabel(label_ids[(i + 1) % 3]);
|
||||
// db.StoreVertex(impl);
|
||||
// }
|
||||
// // load vertices from disk
|
||||
// auto loaded_vertices = db.Vertices(dba);
|
||||
// ASSERT_EQ(loaded_vertices.size(), 5);
|
||||
// for (const auto &vertex_acc : loaded_vertices) {
|
||||
// ASSERT_TRUE(gids.contains(vertex_acc.Gid().AsUint()));
|
||||
// auto labels = vertex_acc.Labels(memgraph::storage::View::OLD);
|
||||
// ASSERT_EQ(labels->size(), 2);
|
||||
// ASSERT_TRUE(std::all_of(labels->begin(), labels->end(), [&label_ids](const auto &label_id) {
|
||||
// return std::find(label_ids.begin(), label_ids.end(), label_id) != label_ids.end();
|
||||
// }));
|
||||
// }
|
||||
// }
|
||||
/// Serialize vertex with gid and its single label.
|
||||
TEST_F(RocksDBStorageTest, SerializeVertexGIDLabels) {
|
||||
auto acc = storage->Access();
|
||||
auto vertex = acc->CreateVertex();
|
||||
auto ser_player_label = acc->NameToLabel("Player");
|
||||
auto player_result = vertex.AddLabel(ser_player_label);
|
||||
auto gid = vertex.Gid();
|
||||
ASSERT_EQ(memgraph::utils::SerializeVertex(*vertex.vertex_),
|
||||
std::to_string(ser_player_label.AsInt()) + "|" + memgraph::utils::SerializeIdType(gid));
|
||||
}
|
||||
|
||||
// TEST_F(RocksDBStorageTest, GetVerticesByLabel) {
|
||||
// // search vertices by label
|
||||
// auto storage_dba = storage.Access(memgraph::storage::IsolationLevel::READ_UNCOMMITTED);
|
||||
// memgraph::query::DbAccessor dba(&storage_dba);
|
||||
// // prepare labels
|
||||
// std::vector<memgraph::storage::LabelId> label_ids{dba.NameToLabel("Player"), dba.NameToLabel("Player"),
|
||||
// dba.NameToLabel("Ball")};
|
||||
// // insert vertices
|
||||
// for (int i = 0; i < 5; ++i) {
|
||||
// auto impl = dba.InsertVertex();
|
||||
// impl.AddLabel(label_ids[i % 3]);
|
||||
// db.StoreVertex(impl);
|
||||
// }
|
||||
// // load vertices from disk
|
||||
// auto player_vertices = db.Vertices(dba, dba.NameToLabel("Player"));
|
||||
// auto ball_vertices = db.Vertices(dba, dba.NameToLabel("Ball"));
|
||||
// ASSERT_EQ(player_vertices.size(), 4);
|
||||
// ASSERT_EQ(ball_vertices.size(), 1);
|
||||
// }
|
||||
/// Serialize vertex with gid and its multiple labels.
|
||||
TEST_F(RocksDBStorageTest, SerializeVertexGIDMultipleLabels) {
|
||||
auto acc = storage->Access();
|
||||
auto vertex = acc->CreateVertex();
|
||||
auto ser_player_label = acc->NameToLabel("Player");
|
||||
auto ser_person_label = acc->NameToLabel("Person");
|
||||
auto ser_ball_label = acc->NameToLabel("Ball");
|
||||
// NOLINTNEXTLINE
|
||||
auto player_res = vertex.AddLabel(ser_player_label);
|
||||
auto person_res = vertex.AddLabel(ser_person_label);
|
||||
auto ball_res = vertex.AddLabel(ser_ball_label);
|
||||
auto gid = vertex.Gid();
|
||||
ASSERT_EQ(memgraph::utils::SerializeVertex(*vertex.vertex_),
|
||||
std::to_string(ser_player_label.AsInt()) + "," + std::to_string(ser_person_label.AsInt()) + "," +
|
||||
std::to_string(ser_ball_label.AsInt()) + "|" + memgraph::utils::SerializeIdType(gid));
|
||||
}
|
||||
|
||||
// TEST_F(RocksDBStorageTest, GetVerticesByProperty) {
|
||||
// // search vertices by property value
|
||||
// auto storage_dba = storage.Access(memgraph::storage::IsolationLevel::READ_UNCOMMITTED);
|
||||
// memgraph::query::DbAccessor dba(&storage_dba);
|
||||
// // prepare ssd properties
|
||||
// std::map<memgraph::storage::PropertyId, memgraph::storage::PropertyValue> ssd_properties_1;
|
||||
// ssd_properties_1.emplace(dba.NameToProperty("price"), memgraph::storage::PropertyValue(225.84));
|
||||
// std::map<memgraph::storage::PropertyId, memgraph::storage::PropertyValue> ssd_properties_2;
|
||||
// ssd_properties_2.emplace(dba.NameToProperty("price"), memgraph::storage::PropertyValue(226.84));
|
||||
// // prepare hdd properties
|
||||
// std::map<memgraph::storage::PropertyId, memgraph::storage::PropertyValue> hdd_properties_1;
|
||||
// hdd_properties_1.emplace(dba.NameToProperty("price"), memgraph::storage::PropertyValue(125.84));
|
||||
// std::vector properties{ssd_properties_1, ssd_properties_2, hdd_properties_1, hdd_properties_1};
|
||||
// // insert vertices
|
||||
// for (int i = 0; i < 4; ++i) {
|
||||
// auto impl = dba.InsertVertex();
|
||||
// memgraph::query::MultiPropsInitChecked(&impl, properties[i]);
|
||||
// db.StoreVertex(impl);
|
||||
// }
|
||||
// // load vertices from disk
|
||||
// auto ssd_vertices_1 = db.Vertices(dba, dba.NameToProperty("price"), memgraph::storage::PropertyValue(225.84));
|
||||
// auto hdd_vertices = db.Vertices(dba, dba.NameToProperty("price"), memgraph::storage::PropertyValue(125.84));
|
||||
// auto hdd_vertices_non_existing =
|
||||
// db.Vertices(dba, dba.NameToProperty("price"), memgraph::storage::PropertyValue(125.81));
|
||||
// ASSERT_EQ(ssd_vertices_1.size(), 1);
|
||||
// ASSERT_EQ(hdd_vertices.size(), 2);
|
||||
// ASSERT_EQ(hdd_vertices_non_existing.size(), 0);
|
||||
// }
|
||||
/// Serialize edge.
|
||||
TEST_F(RocksDBStorageTest, SerializeEdge) {
|
||||
auto acc = storage->Access();
|
||||
auto vertex1 = acc->CreateVertex();
|
||||
auto vertex2 = acc->CreateVertex();
|
||||
auto edge = acc->CreateEdge(&vertex1, &vertex2, acc->NameToEdgeType("KNOWS"));
|
||||
auto gid = edge->Gid();
|
||||
auto ser_result = memgraph::utils::SerializeEdge(vertex1.Gid(), vertex2.Gid(), edge->EdgeType(), edge->edge_.ptr);
|
||||
ASSERT_EQ(ser_result.first,
|
||||
memgraph::utils::SerializeIdType(vertex1.Gid()) + "|" + memgraph::utils::SerializeIdType(vertex2.Gid()) +
|
||||
"|0|" + std::to_string(edge->EdgeType().AsInt()) + "|" + memgraph::utils::SerializeIdType(gid));
|
||||
ASSERT_EQ(ser_result.second,
|
||||
memgraph::utils::SerializeIdType(vertex2.Gid()) + "|" + memgraph::utils::SerializeIdType(vertex1.Gid()) +
|
||||
"|1|" + std::to_string(edge->EdgeType().AsInt()) + "|" + memgraph::utils::SerializeIdType(gid));
|
||||
}
|
||||
|
||||
// TEST_F(RocksDBStorageTest, DeleteVertex) {
|
||||
// // auto storage_dba = storage.Access(memgraph::storage::IsolationLevel::READ_UNCOMMITTE);
|
||||
// auto storage_dba = storage.Access();
|
||||
// memgraph::query::DbAccessor dba(&storage_dba);
|
||||
// std::map<memgraph::storage::PropertyId, memgraph::storage::PropertyValue> properties;
|
||||
// // samo 1 property stane
|
||||
// properties.emplace(dba.NameToProperty("sum"), memgraph::storage::PropertyValue("2TB"));
|
||||
// properties.emplace(dba.NameToProperty("same_type"), memgraph::storage::PropertyValue(true));
|
||||
// // properties.emplace(dba.NameToProperty("cluster_price"), memgraph::storage::PropertyValue(2000.42));
|
||||
// // create vertex
|
||||
// auto impl = dba.InsertVertex();
|
||||
// impl.AddLabel(dba.NameToLabel("Player"));
|
||||
// memgraph::query::MultiPropsInitChecked(&impl, properties);
|
||||
// db.StoreVertex(impl);
|
||||
// // find vertex should work now
|
||||
// ASSERT_TRUE(db.FindVertex(std::to_string(impl.Gid().AsUint()), dba).has_value());
|
||||
// db.FindVertex(std::to_string(impl.Gid().AsUint()), dba);
|
||||
// // RocksDB doesn't physically delete entry so deletion will pass two times
|
||||
// ASSERT_TRUE(db.DeleteVertex(impl).has_value());
|
||||
// ASSERT_TRUE(db.DeleteVertex(impl).has_value());
|
||||
// // second time you shouldn't be able to find the vertex
|
||||
// ASSERT_FALSE(db.FindVertex(std::to_string(impl.Gid().AsUint()), dba).has_value());
|
||||
// }
|
||||
TEST_F(RocksDBStorageTest, DeserializeVertex) {
|
||||
// NOTE: This test would fail in the case of snaphsot isolation because of the way in which RocksDB
|
||||
// serializes commit timestamp.
|
||||
auto serialized_vertex = "1|1";
|
||||
auto acc = storage->Access(memgraph::storage::IsolationLevel::READ_UNCOMMITTED);
|
||||
auto acc_ptr = static_cast<memgraph::storage::DiskStorage::DiskAccessor *>(acc.get());
|
||||
auto vertex = acc_ptr->DeserializeVertex(serialized_vertex, "garbage");
|
||||
ASSERT_EQ(vertex->Gid().AsInt(), 1);
|
||||
ASSERT_EQ(*vertex->HasLabel(memgraph::storage::LabelId::FromUint(1), memgraph::storage::View::OLD), true);
|
||||
}
|
||||
|
||||
// TEST_F(RocksDBStorageTest, SerializeVertexGIDProperties) {
|
||||
// // serializes vertex's gid, multiple labels and properties
|
||||
// auto storage_dba = storage.Access(memgraph::storage::IsolationLevel::READ_UNCOMMITTED);
|
||||
// memgraph::query::DbAccessor dba(&storage_dba);
|
||||
// // prepare labels
|
||||
// std::vector<memgraph::storage::LabelId> label_ids{dba.NameToLabel("Player"), dba.NameToLabel("Person"),
|
||||
// dba.NameToLabel("Ball")};
|
||||
// // prepare properties
|
||||
// std::map<memgraph::storage::PropertyId, memgraph::storage::PropertyValue> properties;
|
||||
// properties.emplace(dba.NameToProperty("name"), memgraph::storage::PropertyValue("disk"));
|
||||
// properties.emplace(dba.NameToProperty("memory"), memgraph::storage::PropertyValue("1TB"));
|
||||
// properties.emplace(dba.NameToProperty("price"), memgraph::storage::PropertyValue(1000.21));
|
||||
// properties.emplace(dba.NameToProperty("price2"), memgraph::storage::PropertyValue(1000.212));
|
||||
// // gids
|
||||
// std::unordered_set<uint64_t> gids;
|
||||
// for (int i = 0; i < 5; ++i) {
|
||||
// gids.insert(i);
|
||||
// auto impl = dba.InsertVertex();
|
||||
// impl.SetGid(memgraph::storage::Gid::FromUint(i));
|
||||
// impl.AddLabel(label_ids[i % 3]);
|
||||
// impl.AddLabel(label_ids[(i + 1) % 3]);
|
||||
// memgraph::query::MultiPropsInitChecked(&impl, properties);
|
||||
// db.StoreVertex(impl);
|
||||
// }
|
||||
// // load vertices from disk
|
||||
// auto loaded_vertices = db.Vertices(dba);
|
||||
// ASSERT_EQ(loaded_vertices.size(), 5);
|
||||
// for (const auto &vertex_acc : loaded_vertices) {
|
||||
// ASSERT_TRUE(gids.contains(vertex_acc.Gid().AsUint()));
|
||||
// // labels
|
||||
// auto labels = vertex_acc.Labels(memgraph::storage::View::OLD);
|
||||
// ASSERT_EQ(labels->size(), 2);
|
||||
// ASSERT_TRUE(std::all_of(labels->begin(), labels->end(), [&label_ids](const auto &label_id) {
|
||||
// return std::find(label_ids.begin(), label_ids.end(), label_id) != label_ids.end();
|
||||
// }));
|
||||
// // check properties
|
||||
// auto props = vertex_acc.Properties(memgraph::storage::View::OLD);
|
||||
// ASSERT_FALSE(props.HasError());
|
||||
// auto prop_name = vertex_acc.GetProperty(memgraph::storage::View::OLD, dba.NameToProperty("name"));
|
||||
// auto prop_memory = vertex_acc.GetProperty(memgraph::storage::View::OLD, dba.NameToProperty("memory"));
|
||||
// auto prop_price = vertex_acc.GetProperty(memgraph::storage::View::OLD, dba.NameToProperty("price"));
|
||||
// auto prop_unexisting = vertex_acc.GetProperty(memgraph::storage::View::OLD, dba.NameToProperty("random"));
|
||||
// ASSERT_TRUE(prop_name->IsString());
|
||||
// ASSERT_EQ(prop_name->ValueString(), "disk");
|
||||
// ASSERT_TRUE(prop_memory->IsString());
|
||||
// ASSERT_EQ(prop_memory->ValueString(), "1TB");
|
||||
// ASSERT_TRUE(prop_price->IsDouble());
|
||||
// ASSERT_DOUBLE_EQ(prop_price->ValueDouble(), 1000.21);
|
||||
// ASSERT_TRUE(prop_unexisting->IsNull());
|
||||
// }
|
||||
// }
|
||||
|
||||
// TEST_F(RocksDBStorageTest, SerializeEdge) {
|
||||
// // create two vertices and edge between them
|
||||
// // search by one of the vertices, return edge
|
||||
// // check deserialization for both vertices and edge
|
||||
// auto storage_dba = storage.Access(memgraph::storage::IsolationLevel::READ_UNCOMMITTED);
|
||||
// memgraph::query::DbAccessor dba(&storage_dba);
|
||||
// std::vector<memgraph::storage::LabelId> label_ids{dba.NameToLabel("Player"), dba.NameToLabel("Referee")};
|
||||
// std::map<memgraph::storage::PropertyId, memgraph::storage::PropertyValue> properties_1;
|
||||
// properties_1.emplace(dba.NameToProperty("price"), memgraph::storage::PropertyValue(221.84));
|
||||
// std::map<memgraph::storage::PropertyId, memgraph::storage::PropertyValue> properties_2;
|
||||
// properties_2.emplace(dba.NameToProperty("price"), memgraph::storage::PropertyValue(222.84));
|
||||
// std::vector properties{properties_1, properties_2};
|
||||
// for (int i = 0; i < 2; ++i) {
|
||||
// auto impl = dba.InsertVertex();
|
||||
// impl.AddLabel(label_ids[i]);
|
||||
// memgraph::query::MultiPropsInitChecked(&impl, properties[i]);
|
||||
// db.StoreVertex(impl);
|
||||
// }
|
||||
// // prepare edge properties
|
||||
// std::map<memgraph::storage::PropertyId, memgraph::storage::PropertyValue> edge_properties;
|
||||
// edge_properties.emplace(dba.NameToProperty("sum"), memgraph::storage::PropertyValue("2TB"));
|
||||
// edge_properties.emplace(dba.NameToProperty("same_type"), memgraph::storage::PropertyValue(true));
|
||||
// edge_properties.emplace(dba.NameToProperty("cluster_price"), memgraph::storage::PropertyValue(2000.42));
|
||||
// // Before inserting edge, find two vertices
|
||||
// // find source vertex by the property
|
||||
// auto src_vertices = db.Vertices(dba, dba.NameToProperty("price"), memgraph::storage::PropertyValue(221.84));
|
||||
// ASSERT_EQ(src_vertices.size(), 1);
|
||||
// auto src_vertex = src_vertices[0];
|
||||
// // find destination vertex by the property
|
||||
// auto dest_vertices = db.Vertices(dba, dba.NameToProperty("price"), memgraph::storage::PropertyValue(222.84));
|
||||
// ASSERT_EQ(dest_vertices.size(), 1);
|
||||
// auto dest_vertex = dest_vertices[0];
|
||||
// // insert the edge
|
||||
// uint64_t edge_gid = 2;
|
||||
// auto edge_type_id = "CONNECTION";
|
||||
// auto impl_edge = dba.InsertEdge(&src_vertex, &dest_vertex, dba.NameToEdgeType(edge_type_id));
|
||||
// ASSERT_FALSE(impl_edge.HasError());
|
||||
// (*impl_edge).SetGid(memgraph::storage::Gid::FromUint(edge_gid));
|
||||
// memgraph::query::MultiPropsInitChecked(&*impl_edge, edge_properties);
|
||||
// db.StoreEdge(*impl_edge);
|
||||
// // Test out edges of the source vertex
|
||||
// auto src_out_edges = db.OutEdges(src_vertex, dba);
|
||||
// ASSERT_EQ(src_out_edges.size(), 1);
|
||||
// auto src_out_edge = src_out_edges[0];
|
||||
// // test from edge accessor
|
||||
// auto from_out_edge_acc = src_out_edge.From();
|
||||
// ASSERT_EQ(from_out_edge_acc.Gid(), src_vertex.Gid());
|
||||
// ASSERT_EQ(from_out_edge_acc.Labels(memgraph::storage::View::OLD)->size(), 1);
|
||||
// ASSERT_EQ(from_out_edge_acc.Labels(memgraph::storage::View::OLD)->at(0), label_ids[0]);
|
||||
// ASSERT_EQ(*from_out_edge_acc.Properties(memgraph::storage::View::OLD), properties_1);
|
||||
// // test to edge accessor
|
||||
// auto to_out_edge_acc = src_out_edge.To();
|
||||
// ASSERT_EQ(to_out_edge_acc.Gid(), dest_vertex.Gid());
|
||||
// ASSERT_EQ(to_out_edge_acc.Labels(memgraph::storage::View::OLD)->size(), 1);
|
||||
// ASSERT_EQ(to_out_edge_acc.Labels(memgraph::storage::View::OLD)->at(0), label_ids[1]);
|
||||
// ASSERT_EQ(*to_out_edge_acc.Properties(memgraph::storage::View::OLD), properties_2);
|
||||
// // test edge accessor
|
||||
// ASSERT_EQ(src_out_edge.Gid().AsUint(), edge_gid);
|
||||
// ASSERT_EQ(src_out_edge.EdgeType(), dba.NameToEdgeType(edge_type_id));
|
||||
// ASSERT_EQ(*src_out_edge.Properties(memgraph::storage::View::OLD), edge_properties);
|
||||
// // Test in edge of the destination vertex
|
||||
// auto dest_in_edges = db.InEdges(dest_vertex, dba);
|
||||
// ASSERT_EQ(dest_in_edges.size(), 1);
|
||||
// auto dest_in_edge = dest_in_edges[0];
|
||||
// // test from edge accessor
|
||||
// auto from_in_edge_acc = dest_in_edge.From();
|
||||
// ASSERT_EQ(from_in_edge_acc.Gid(), from_out_edge_acc.Gid());
|
||||
// ASSERT_EQ(from_in_edge_acc.Labels(memgraph::storage::View::OLD)->size(), 1);
|
||||
// ASSERT_EQ(from_in_edge_acc.Labels(memgraph::storage::View::OLD)->at(0),
|
||||
// from_out_edge_acc.Labels(memgraph::storage::View::OLD)->at(0));
|
||||
// ASSERT_EQ(*from_in_edge_acc.Properties(memgraph::storage::View::OLD),
|
||||
// *from_out_edge_acc.Properties(memgraph::storage::View::OLD));
|
||||
// // test in edge accessors
|
||||
// auto to_in_edge_acc = dest_in_edge.To();
|
||||
// ASSERT_EQ(to_in_edge_acc.Gid(), to_out_edge_acc.Gid());
|
||||
// ASSERT_EQ(to_in_edge_acc.Labels(memgraph::storage::View::OLD)->size(), 1);
|
||||
// ASSERT_EQ(to_in_edge_acc.Labels(memgraph::storage::View::OLD)->at(0),
|
||||
// to_out_edge_acc.Labels(memgraph::storage::View::OLD)->at(0));
|
||||
// ASSERT_EQ(*to_in_edge_acc.Properties(memgraph::storage::View::OLD),
|
||||
// *to_out_edge_acc.Properties(memgraph::storage::View::OLD));
|
||||
// // test edge accessors
|
||||
// ASSERT_EQ(dest_in_edge.Gid(), src_out_edge.Gid());
|
||||
// ASSERT_EQ(dest_in_edge.EdgeType(), src_out_edge.EdgeType());
|
||||
// ASSERT_EQ(*dest_in_edge.Properties(memgraph::storage::View::OLD),
|
||||
// *src_out_edge.Properties(memgraph::storage::View::OLD));
|
||||
// }
|
||||
TEST_F(RocksDBStorageTest, DeserializeEdge) {
|
||||
// NOTE: This test would fail in the case of snaphsot isolation because of the way in which RocksDB
|
||||
// serializes commit timestamp.
|
||||
auto acc = storage->Access(memgraph::storage::IsolationLevel::READ_UNCOMMITTED);
|
||||
auto vertex1 = acc->CreateVertex();
|
||||
auto vertex2 = acc->CreateVertex();
|
||||
auto serialized_edge = fmt::format("{}|{}|0|1|2", vertex1.Gid().AsInt(), vertex2.Gid().AsInt());
|
||||
auto acc_ptr = static_cast<memgraph::storage::DiskStorage::DiskAccessor *>(acc.get());
|
||||
auto edge = acc_ptr->DeserializeEdge(serialized_edge, "garbage");
|
||||
ASSERT_EQ(edge->Gid().AsInt(), 2);
|
||||
ASSERT_EQ(edge->EdgeType().AsInt(), 1);
|
||||
ASSERT_EQ(edge->from_vertex_->gid.AsInt(), vertex1.Gid().AsInt());
|
||||
ASSERT_EQ(edge->to_vertex_->gid.AsInt(), vertex2.Gid().AsInt());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user