memgraph/tests/manual/snapshot_generation/snapshot_writer.hpp
Dominik Gleich a36753cf27 Update snapshot naming
Summary:
Snapshots should have the transaction from which they were created because we need this info for recovery later on.
Otherwise we wouldn't be able to tell the workers from which snapshots to recover. The whole cluster should be recovered
from the same transaction snapshot.

Reviewers: msantl

Reviewed By: msantl

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1338
2018-04-05 13:42:51 +02:00

146 lines
4.7 KiB
C++

#pragma once
#include <string>
#include <vector>
#include "communication/bolt/v1/encoder/base_encoder.hpp"
#include "durability/paths.hpp"
#include "durability/version.hpp"
#include "query/typed_value.hpp"
#include "graph_state.hpp"
namespace snapshot_generation {
// Snapshot layout is described in durability/version.hpp
static_assert(durability::kVersion == 5,
"Wrong snapshot version, please update!");
class SnapshotWriter {
public:
SnapshotWriter(const std::string &path, int worker_id,
uint64_t vertex_generator_local_count = 0,
uint64_t edge_generator_local_count = 0)
: worker_id_(worker_id), buffer_(path) {
encoder_.WriteRAW(durability::kMagicNumber.data(),
durability::kMagicNumber.size());
encoder_.WriteTypedValue(durability::kVersion);
encoder_.WriteInt(worker_id_);
encoder_.WriteInt(vertex_generator_local_count);
encoder_.WriteInt(edge_generator_local_count);
encoder_.WriteInt(0);
encoder_.WriteList(std::vector<query::TypedValue>{});
}
// reference to `buffer_` gets broken when moving, so let's just forbid moving
SnapshotWriter(SnapshotWriter &&rhs) = delete;
SnapshotWriter &operator=(SnapshotWriter &&rhs) = delete;
template <typename TValue>
void WriteList(const std::vector<TValue> &list) {
encoder_.WriteList(
std::vector<query::TypedValue>(list.begin(), list.end()));
}
storage::VertexAddress DefaultVertexAddress(gid::Gid gid) {
return storage::VertexAddress(gid, gid::CreatorWorker(gid));
}
storage::EdgeAddress DefaultEdgeAddress(gid::Gid gid) {
return storage::EdgeAddress(gid, gid::CreatorWorker(gid));
}
void WriteInlineEdge(const Edge &edge, bool write_from) {
encoder_.WriteInt(DefaultEdgeAddress(edge.gid).raw());
encoder_.WriteInt(write_from ? DefaultVertexAddress(edge.from).raw()
: DefaultVertexAddress(edge.to).raw());
encoder_.WriteString(edge.type);
}
void WriteNode(const Node &node,
const std::unordered_map<gid::Gid, Edge> &edges) {
encoder_.WriteRAW(underlying_cast(communication::bolt::Marker::TinyStruct) +
3);
encoder_.WriteRAW(underlying_cast(communication::bolt::Signature::Node));
encoder_.WriteInt(node.gid);
WriteList(node.labels);
encoder_.WriteMap(node.props);
encoder_.WriteInt(node.in_edges.size());
for (const auto &edge_idx : node.in_edges) {
WriteInlineEdge(edges.at(edge_idx), true);
}
encoder_.WriteInt(node.out_edges.size());
for (const auto &edge_idx : node.out_edges) {
WriteInlineEdge(edges.at(edge_idx), false);
}
++nodes_written_;
}
void WriteEdge(const Edge &edge) {
encoder_.WriteRAW(underlying_cast(communication::bolt::Marker::TinyStruct) +
5);
encoder_.WriteRAW(
underlying_cast(communication::bolt::Signature::Relationship));
encoder_.WriteInt(edge.gid);
encoder_.WriteInt(edge.from);
encoder_.WriteInt(edge.to);
encoder_.WriteString(edge.type);
encoder_.WriteMap(edge.props);
++edges_written_;
}
void Close() {
buffer_.WriteValue(nodes_written_);
buffer_.WriteValue(edges_written_);
buffer_.WriteValue(buffer_.hash());
buffer_.Close();
}
private:
int worker_id_;
int64_t nodes_written_{0};
int64_t edges_written_{0};
HashedFileWriter buffer_;
communication::bolt::BaseEncoder<HashedFileWriter> encoder_{buffer_};
};
void WriteToSnapshot(GraphState &state, const std::string &path) {
for (int worker_id = 0; worker_id < state.NumWorkers(); ++worker_id) {
const std::experimental::filesystem::path durability_dir =
path / std::experimental::filesystem::path("worker_" +
std::to_string(worker_id));
if (!durability::EnsureDir(durability_dir / "snapshots")) {
LOG(ERROR) << "Unable to create durability directory!";
exit(0);
}
// Pretend like this is coming from transaction numbered 1 - this is hack
// TODO(dgleich): Change this to something more reasonable
const auto snapshot_file =
durability::MakeSnapshotPath(durability_dir, worker_id, 1);
SnapshotWriter writer(snapshot_file, worker_id,
state.NumNodesOnWorker(worker_id),
state.NumEdgesOnWorker(worker_id));
writer.WriteList(state.Indices());
for (const auto &node : state.NodesOnWorker(worker_id)) {
writer.WriteNode(state.GetNode(node), state.GetEdges());
}
for (const auto &edge : state.EdgesOnWorker(worker_id)) {
writer.WriteEdge(state.GetEdge(edge));
}
writer.Close();
}
}
} // namespace snapshot_generation