Refactor database::StateDelta
Summary: Refactor in two ways. First, expose members without getters as we will need most of them in distributed. And this was always the sensible thing to do. Second, add storage type values to deltas. This is also a sensible thing to do, and it will be very beneficial in distributed. We didn't do it before because name<->value type mappings aren't guaranteed to be the same after recovery. A task has been added to address this (preserve mappings in durability). Reviewers: dgleich, buda Reviewed By: dgleich Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1167
This commit is contained in:
parent
583f6f1794
commit
1d5d67aeac
@ -219,9 +219,9 @@ void GraphDbAccessor::EnableIndex(const LabelPropertyIndex::Key &key) {
|
||||
// built at this point even if this DBA's transaction aborts for some
|
||||
// reason.
|
||||
auto wal_build_index_tx_id = transaction_id();
|
||||
wal().Emplace(database::StateDelta::BuildIndex(wal_build_index_tx_id,
|
||||
LabelName(key.label_),
|
||||
PropertyName(key.property_)));
|
||||
wal().Emplace(database::StateDelta::BuildIndex(
|
||||
wal_build_index_tx_id, key.label_, LabelName(key.label_), key.property_,
|
||||
PropertyName(key.property_)));
|
||||
|
||||
// After these two operations we are certain that everything is contained in
|
||||
// the index under the assumption that the original index creation transaction
|
||||
@ -419,7 +419,7 @@ EdgeAccessor GraphDbAccessor::InsertEdge(
|
||||
// outcomes are success or error (serialization, timeout).
|
||||
}
|
||||
wal().Emplace(database::StateDelta::CreateEdge(
|
||||
transaction_.id_, edge_vlist->gid_, from.gid(), to.gid(),
|
||||
transaction_.id_, edge_vlist->gid_, from.gid(), to.gid(), edge_type,
|
||||
EdgeTypeName(edge_type)));
|
||||
return EdgeAccessor(edge_vlist, *this, from.address(), to.address(),
|
||||
edge_type);
|
||||
|
@ -6,12 +6,6 @@
|
||||
|
||||
namespace database {
|
||||
|
||||
std::pair<std::string, std::string> StateDelta::IndexName() const {
|
||||
CHECK(StateDelta::type() == StateDelta::Type::BUILD_INDEX)
|
||||
<< "Invalid operation type to try to get index name";
|
||||
return std::make_pair(label_, property_);
|
||||
}
|
||||
|
||||
StateDelta StateDelta::TxBegin(tx::transaction_id_t tx_id) {
|
||||
return {StateDelta::Type::TRANSACTION_BEGIN, tx_id};
|
||||
}
|
||||
@ -27,128 +21,147 @@ StateDelta StateDelta::TxAbort(tx::transaction_id_t tx_id) {
|
||||
StateDelta StateDelta::CreateVertex(tx::transaction_id_t tx_id,
|
||||
gid::Gid vertex_id) {
|
||||
StateDelta op(StateDelta::Type::CREATE_VERTEX, tx_id);
|
||||
op.vertex_id_ = vertex_id;
|
||||
op.vertex_id = vertex_id;
|
||||
return op;
|
||||
}
|
||||
|
||||
StateDelta StateDelta::CreateEdge(tx::transaction_id_t tx_id, gid::Gid edge_id,
|
||||
gid::Gid vertex_from_id,
|
||||
gid::Gid vertex_to_id,
|
||||
const std::string &edge_type) {
|
||||
storage::EdgeType edge_type,
|
||||
const std::string &edge_type_name) {
|
||||
StateDelta op(StateDelta::Type::CREATE_EDGE, tx_id);
|
||||
op.edge_id_ = edge_id;
|
||||
op.vertex_from_id_ = vertex_from_id;
|
||||
op.vertex_to_id_ = vertex_to_id;
|
||||
op.edge_type_ = edge_type;
|
||||
op.edge_id = edge_id;
|
||||
op.vertex_from_id = vertex_from_id;
|
||||
op.vertex_to_id = vertex_to_id;
|
||||
op.edge_type = edge_type;
|
||||
op.edge_type_name = edge_type_name;
|
||||
return op;
|
||||
}
|
||||
|
||||
StateDelta StateDelta::PropsSetVertex(tx::transaction_id_t tx_id,
|
||||
gid::Gid vertex_id,
|
||||
const std::string &property,
|
||||
storage::Property property,
|
||||
const std::string &property_name,
|
||||
const PropertyValue &value) {
|
||||
StateDelta op(StateDelta::Type::SET_PROPERTY_VERTEX, tx_id);
|
||||
op.vertex_id_ = vertex_id;
|
||||
op.property_ = property;
|
||||
op.value_ = value;
|
||||
op.vertex_id = vertex_id;
|
||||
op.property = property;
|
||||
op.property_name = property_name;
|
||||
op.value = value;
|
||||
return op;
|
||||
}
|
||||
|
||||
StateDelta StateDelta::PropsSetEdge(tx::transaction_id_t tx_id,
|
||||
gid::Gid edge_id,
|
||||
const std::string &property,
|
||||
storage::Property property,
|
||||
const std::string &property_name,
|
||||
const PropertyValue &value) {
|
||||
StateDelta op(StateDelta::Type::SET_PROPERTY_EDGE, tx_id);
|
||||
op.edge_id_ = edge_id;
|
||||
op.property_ = property;
|
||||
op.value_ = value;
|
||||
op.edge_id = edge_id;
|
||||
op.property = property;
|
||||
op.property_name = property_name;
|
||||
op.value = value;
|
||||
return op;
|
||||
}
|
||||
|
||||
StateDelta StateDelta::AddLabel(tx::transaction_id_t tx_id, gid::Gid vertex_id,
|
||||
const std::string &label) {
|
||||
storage::Label label,
|
||||
const std::string &label_name) {
|
||||
StateDelta op(StateDelta::Type::ADD_LABEL, tx_id);
|
||||
op.vertex_id_ = vertex_id;
|
||||
op.label_ = label;
|
||||
op.vertex_id = vertex_id;
|
||||
op.label = label;
|
||||
op.label_name = label_name;
|
||||
return op;
|
||||
}
|
||||
|
||||
StateDelta StateDelta::RemoveLabel(tx::transaction_id_t tx_id,
|
||||
gid::Gid vertex_id,
|
||||
const std::string &label) {
|
||||
gid::Gid vertex_id, storage::Label label,
|
||||
const std::string &label_name) {
|
||||
StateDelta op(StateDelta::Type::REMOVE_LABEL, tx_id);
|
||||
op.vertex_id_ = vertex_id;
|
||||
op.label_ = label;
|
||||
op.vertex_id = vertex_id;
|
||||
op.label = label;
|
||||
op.label_name = label_name;
|
||||
return op;
|
||||
}
|
||||
|
||||
StateDelta StateDelta::RemoveVertex(tx::transaction_id_t tx_id,
|
||||
gid::Gid vertex_id) {
|
||||
StateDelta op(StateDelta::Type::REMOVE_VERTEX, tx_id);
|
||||
op.vertex_id_ = vertex_id;
|
||||
op.vertex_id = vertex_id;
|
||||
return op;
|
||||
}
|
||||
|
||||
StateDelta StateDelta::RemoveEdge(tx::transaction_id_t tx_id,
|
||||
gid::Gid edge_id) {
|
||||
StateDelta op(StateDelta::Type::REMOVE_EDGE, tx_id);
|
||||
op.edge_id_ = edge_id;
|
||||
op.edge_id = edge_id;
|
||||
return op;
|
||||
}
|
||||
|
||||
StateDelta StateDelta::BuildIndex(tx::transaction_id_t tx_id,
|
||||
const std::string &label,
|
||||
const std::string &property) {
|
||||
storage::Label label,
|
||||
const std::string &label_name,
|
||||
storage::Property property,
|
||||
const std::string &property_name) {
|
||||
StateDelta op(StateDelta::Type::BUILD_INDEX, tx_id);
|
||||
op.label_ = label;
|
||||
op.property_ = property;
|
||||
op.label = label;
|
||||
op.label_name = label_name;
|
||||
op.property = property;
|
||||
op.property_name = property_name;
|
||||
return op;
|
||||
}
|
||||
|
||||
void StateDelta::Encode(
|
||||
HashedFileWriter &writer,
|
||||
communication::bolt::PrimitiveEncoder<HashedFileWriter> &encoder) const {
|
||||
encoder.WriteInt(static_cast<int64_t>(type_));
|
||||
encoder.WriteInt(static_cast<int64_t>(transaction_id_));
|
||||
encoder.WriteInt(static_cast<int64_t>(type));
|
||||
encoder.WriteInt(static_cast<int64_t>(transaction_id));
|
||||
|
||||
switch (type_) {
|
||||
switch (type) {
|
||||
case Type::TRANSACTION_BEGIN:
|
||||
case Type::TRANSACTION_COMMIT:
|
||||
case Type::TRANSACTION_ABORT:
|
||||
break;
|
||||
case Type::CREATE_VERTEX:
|
||||
encoder.WriteInt(vertex_id_);
|
||||
encoder.WriteInt(vertex_id);
|
||||
break;
|
||||
case Type::CREATE_EDGE:
|
||||
encoder.WriteInt(edge_id_);
|
||||
encoder.WriteInt(vertex_from_id_);
|
||||
encoder.WriteInt(vertex_to_id_);
|
||||
encoder.WriteString(edge_type_);
|
||||
encoder.WriteInt(edge_id);
|
||||
encoder.WriteInt(vertex_from_id);
|
||||
encoder.WriteInt(vertex_to_id);
|
||||
encoder.WriteInt(edge_type.storage());
|
||||
encoder.WriteString(edge_type_name);
|
||||
break;
|
||||
case Type::SET_PROPERTY_VERTEX:
|
||||
encoder.WriteInt(vertex_id_);
|
||||
encoder.WriteString(property_);
|
||||
encoder.WritePropertyValue(value_);
|
||||
encoder.WriteInt(vertex_id);
|
||||
encoder.WriteInt(property.storage());
|
||||
encoder.WriteString(property_name);
|
||||
encoder.WritePropertyValue(value);
|
||||
break;
|
||||
case Type::SET_PROPERTY_EDGE:
|
||||
encoder.WriteInt(edge_id_);
|
||||
encoder.WriteString(property_);
|
||||
encoder.WritePropertyValue(value_);
|
||||
encoder.WriteInt(edge_id);
|
||||
encoder.WriteInt(property.storage());
|
||||
encoder.WriteString(property_name);
|
||||
encoder.WritePropertyValue(value);
|
||||
break;
|
||||
case Type::ADD_LABEL:
|
||||
case Type::REMOVE_LABEL:
|
||||
encoder.WriteInt(vertex_id_);
|
||||
encoder.WriteString(label_);
|
||||
encoder.WriteInt(vertex_id);
|
||||
encoder.WriteInt(label.storage());
|
||||
encoder.WriteString(label_name);
|
||||
break;
|
||||
case Type::REMOVE_VERTEX:
|
||||
encoder.WriteInt(vertex_id_);
|
||||
encoder.WriteInt(vertex_id);
|
||||
break;
|
||||
case Type::REMOVE_EDGE:
|
||||
encoder.WriteInt(edge_id_);
|
||||
encoder.WriteInt(edge_id);
|
||||
break;
|
||||
case Type::BUILD_INDEX:
|
||||
encoder.WriteString(label_);
|
||||
encoder.WriteString(property_);
|
||||
encoder.WriteInt(label.storage());
|
||||
encoder.WriteString(label_name);
|
||||
encoder.WriteInt(property.storage());
|
||||
encoder.WriteString(property_name);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -159,6 +172,10 @@ void StateDelta::Encode(
|
||||
if (!decoder.ReadValue(&dv)) return nullopt; \
|
||||
r_val.member = dv.value_f();
|
||||
|
||||
#define DECODE_MEMBER_CAST(member, value_f, type) \
|
||||
if (!decoder.ReadValue(&dv)) return nullopt; \
|
||||
r_val.member = static_cast<type>(dv.value_f());
|
||||
|
||||
std::experimental::optional<StateDelta> StateDelta::Decode(
|
||||
HashedFileReader &reader,
|
||||
communication::bolt::Decoder<HashedFileReader> &decoder) {
|
||||
@ -170,49 +187,55 @@ std::experimental::optional<StateDelta> StateDelta::Decode(
|
||||
|
||||
try {
|
||||
if (!decoder.ReadValue(&dv)) return nullopt;
|
||||
r_val.type_ = static_cast<enum StateDelta::Type>(dv.ValueInt());
|
||||
DECODE_MEMBER(transaction_id_, ValueInt)
|
||||
r_val.type = static_cast<enum StateDelta::Type>(dv.ValueInt());
|
||||
DECODE_MEMBER(transaction_id, ValueInt)
|
||||
|
||||
switch (r_val.type_) {
|
||||
switch (r_val.type) {
|
||||
case Type::TRANSACTION_BEGIN:
|
||||
case Type::TRANSACTION_COMMIT:
|
||||
case Type::TRANSACTION_ABORT:
|
||||
break;
|
||||
case Type::CREATE_VERTEX:
|
||||
DECODE_MEMBER(vertex_id_, ValueInt)
|
||||
DECODE_MEMBER(vertex_id, ValueInt)
|
||||
break;
|
||||
case Type::CREATE_EDGE:
|
||||
DECODE_MEMBER(edge_id_, ValueInt)
|
||||
DECODE_MEMBER(vertex_from_id_, ValueInt)
|
||||
DECODE_MEMBER(vertex_to_id_, ValueInt)
|
||||
DECODE_MEMBER(edge_type_, ValueString)
|
||||
DECODE_MEMBER(edge_id, ValueInt)
|
||||
DECODE_MEMBER(vertex_from_id, ValueInt)
|
||||
DECODE_MEMBER(vertex_to_id, ValueInt)
|
||||
DECODE_MEMBER_CAST(edge_type, ValueInt, storage::EdgeType)
|
||||
DECODE_MEMBER(edge_type_name, ValueString)
|
||||
break;
|
||||
case Type::SET_PROPERTY_VERTEX:
|
||||
DECODE_MEMBER(vertex_id_, ValueInt)
|
||||
DECODE_MEMBER(property_, ValueString)
|
||||
DECODE_MEMBER(vertex_id, ValueInt)
|
||||
DECODE_MEMBER_CAST(property, ValueInt, storage::Property)
|
||||
DECODE_MEMBER(property_name, ValueString)
|
||||
if (!decoder.ReadValue(&dv)) return nullopt;
|
||||
r_val.value_ = static_cast<PropertyValue>(dv);
|
||||
r_val.value = static_cast<PropertyValue>(dv);
|
||||
break;
|
||||
case Type::SET_PROPERTY_EDGE:
|
||||
DECODE_MEMBER(edge_id_, ValueInt)
|
||||
DECODE_MEMBER(property_, ValueString)
|
||||
DECODE_MEMBER(edge_id, ValueInt)
|
||||
DECODE_MEMBER_CAST(property, ValueInt, storage::Property)
|
||||
DECODE_MEMBER(property_name, ValueString)
|
||||
if (!decoder.ReadValue(&dv)) return nullopt;
|
||||
r_val.value_ = static_cast<PropertyValue>(dv);
|
||||
r_val.value = static_cast<PropertyValue>(dv);
|
||||
break;
|
||||
case Type::ADD_LABEL:
|
||||
case Type::REMOVE_LABEL:
|
||||
DECODE_MEMBER(vertex_id_, ValueInt)
|
||||
DECODE_MEMBER(label_, ValueString)
|
||||
DECODE_MEMBER(vertex_id, ValueInt)
|
||||
DECODE_MEMBER_CAST(label, ValueInt, storage::Label)
|
||||
DECODE_MEMBER(label_name, ValueString)
|
||||
break;
|
||||
case Type::REMOVE_VERTEX:
|
||||
DECODE_MEMBER(vertex_id_, ValueInt)
|
||||
DECODE_MEMBER(vertex_id, ValueInt)
|
||||
break;
|
||||
case Type::REMOVE_EDGE:
|
||||
DECODE_MEMBER(edge_id_, ValueInt)
|
||||
DECODE_MEMBER(edge_id, ValueInt)
|
||||
break;
|
||||
case Type::BUILD_INDEX:
|
||||
DECODE_MEMBER(label_, ValueString)
|
||||
DECODE_MEMBER(property_, ValueString)
|
||||
DECODE_MEMBER_CAST(label, ValueInt, storage::Label)
|
||||
DECODE_MEMBER(label_name, ValueString)
|
||||
DECODE_MEMBER_CAST(property, ValueInt, storage::Property)
|
||||
DECODE_MEMBER(property_name, ValueString)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -232,7 +255,7 @@ std::experimental::optional<StateDelta> StateDelta::Decode(
|
||||
#undef DECODE_MEMBER
|
||||
|
||||
void StateDelta::Apply(GraphDbAccessor &dba) const {
|
||||
switch (type_) {
|
||||
switch (type) {
|
||||
// Transactional state is not recovered.
|
||||
case Type::TRANSACTION_BEGIN:
|
||||
case Type::TRANSACTION_COMMIT:
|
||||
@ -240,48 +263,48 @@ void StateDelta::Apply(GraphDbAccessor &dba) const {
|
||||
LOG(FATAL) << "Transaction handling not handled in Apply";
|
||||
break;
|
||||
case Type::CREATE_VERTEX:
|
||||
dba.InsertVertex(vertex_id_);
|
||||
dba.InsertVertex(vertex_id);
|
||||
break;
|
||||
case Type::CREATE_EDGE: {
|
||||
auto from = dba.FindVertex(vertex_from_id_, true);
|
||||
auto to = dba.FindVertex(vertex_to_id_, true);
|
||||
auto from = dba.FindVertex(vertex_from_id, true);
|
||||
auto to = dba.FindVertex(vertex_to_id, true);
|
||||
DCHECK(from) << "Failed to find vertex.";
|
||||
DCHECK(to) << "Failed to find vertex.";
|
||||
dba.InsertEdge(*from, *to, dba.EdgeType(edge_type_), edge_id_);
|
||||
dba.InsertEdge(*from, *to, dba.EdgeType(edge_type_name), edge_id);
|
||||
break;
|
||||
}
|
||||
case Type::SET_PROPERTY_VERTEX: {
|
||||
auto vertex = dba.FindVertex(vertex_id_, true);
|
||||
auto vertex = dba.FindVertex(vertex_id, true);
|
||||
DCHECK(vertex) << "Failed to find vertex.";
|
||||
vertex->PropsSet(dba.Property(property_), value_);
|
||||
vertex->PropsSet(dba.Property(property_name), value);
|
||||
break;
|
||||
}
|
||||
case Type::SET_PROPERTY_EDGE: {
|
||||
auto edge = dba.FindEdge(edge_id_, true);
|
||||
auto edge = dba.FindEdge(edge_id, true);
|
||||
DCHECK(edge) << "Failed to find edge.";
|
||||
edge->PropsSet(dba.Property(property_), value_);
|
||||
edge->PropsSet(dba.Property(property_name), value);
|
||||
break;
|
||||
}
|
||||
case Type::ADD_LABEL: {
|
||||
auto vertex = dba.FindVertex(vertex_id_, true);
|
||||
auto vertex = dba.FindVertex(vertex_id, true);
|
||||
DCHECK(vertex) << "Failed to find vertex.";
|
||||
vertex->add_label(dba.Label(label_));
|
||||
vertex->add_label(dba.Label(label_name));
|
||||
break;
|
||||
}
|
||||
case Type::REMOVE_LABEL: {
|
||||
auto vertex = dba.FindVertex(vertex_id_, true);
|
||||
auto vertex = dba.FindVertex(vertex_id, true);
|
||||
DCHECK(vertex) << "Failed to find vertex.";
|
||||
vertex->remove_label(dba.Label(label_));
|
||||
vertex->remove_label(dba.Label(label_name));
|
||||
break;
|
||||
}
|
||||
case Type::REMOVE_VERTEX: {
|
||||
auto vertex = dba.FindVertex(vertex_id_, true);
|
||||
auto vertex = dba.FindVertex(vertex_id, true);
|
||||
DCHECK(vertex) << "Failed to find vertex.";
|
||||
dba.DetachRemoveVertex(*vertex);
|
||||
break;
|
||||
}
|
||||
case Type::REMOVE_EDGE: {
|
||||
auto edge = dba.FindEdge(edge_id_, true);
|
||||
auto edge = dba.FindEdge(edge_id, true);
|
||||
DCHECK(edge) << "Failed to find edge.";
|
||||
dba.RemoveEdge(*edge);
|
||||
break;
|
||||
|
@ -10,9 +10,16 @@
|
||||
namespace database {
|
||||
/** Describes single change to the database state. Used for durability (WAL) and
|
||||
* state communication over network in HA and for distributed remote storage
|
||||
* changes*/
|
||||
class StateDelta {
|
||||
public:
|
||||
* changes.
|
||||
*
|
||||
* Labels, Properties and EdgeTypes are stored both as values (integers) and
|
||||
* strings (their names). The values are used when applying deltas in a running
|
||||
* database. Names are used when recovering the database as it's not guaranteed
|
||||
* that after recovery the old name<->value mapping will be preserved.
|
||||
*
|
||||
* TODO: ensure the mapping is preserved after recovery and don't save strings
|
||||
* in StateDeltas. */
|
||||
struct StateDelta {
|
||||
/** Defines StateDelta type. For each type the comment indicates which values
|
||||
* need to be stored. All deltas have the transaction_id member, so that's
|
||||
* omitted in the comment. */
|
||||
@ -21,20 +28,21 @@ class StateDelta {
|
||||
TRANSACTION_COMMIT,
|
||||
TRANSACTION_ABORT,
|
||||
CREATE_VERTEX, // vertex_id
|
||||
CREATE_EDGE, // edge_id, from_vertex_id, to_vertex_id, edge_type
|
||||
SET_PROPERTY_VERTEX, // vertex_id, property, property_value
|
||||
SET_PROPERTY_EDGE, // edge_id, property, property_value
|
||||
CREATE_EDGE, // edge_id, from_vertex_id, to_vertex_id, edge_type,
|
||||
// edge_type_name
|
||||
SET_PROPERTY_VERTEX, // vertex_id, property, property_name, property_value
|
||||
SET_PROPERTY_EDGE, // edge_id, property, property_name, property_value
|
||||
// remove property is done by setting a PropertyValue::Null
|
||||
ADD_LABEL, // vertex_id, label
|
||||
REMOVE_LABEL, // vertex_id, label
|
||||
ADD_LABEL, // vertex_id, label, label_name
|
||||
REMOVE_LABEL, // vertex_id, label, label_name
|
||||
REMOVE_VERTEX, // vertex_id
|
||||
REMOVE_EDGE, // edge_id
|
||||
BUILD_INDEX // label, property
|
||||
BUILD_INDEX // label, label_name, property, property_name
|
||||
};
|
||||
|
||||
StateDelta() = default;
|
||||
StateDelta(const enum Type &type, tx::transaction_id_t tx_id)
|
||||
: type_(type), transaction_id_(tx_id) {}
|
||||
: type(type), transaction_id(tx_id) {}
|
||||
|
||||
/** Attempts to decode a StateDelta from the given decoder. Returns the
|
||||
* decoded value if successful, otherwise returns nullopt. */
|
||||
@ -48,9 +56,6 @@ class StateDelta {
|
||||
HashedFileWriter &writer,
|
||||
communication::bolt::PrimitiveEncoder<HashedFileWriter> &encoder) const;
|
||||
|
||||
tx::transaction_id_t transaction_id() const { return transaction_id_; }
|
||||
Type type() const { return type_; }
|
||||
|
||||
static StateDelta TxBegin(tx::transaction_id_t tx_id);
|
||||
static StateDelta TxCommit(tx::transaction_id_t tx_id);
|
||||
static StateDelta TxAbort(tx::transaction_id_t tx_id);
|
||||
@ -58,43 +63,49 @@ class StateDelta {
|
||||
gid::Gid vertex_id);
|
||||
static StateDelta CreateEdge(tx::transaction_id_t tx_id, gid::Gid edge_id,
|
||||
gid::Gid vertex_from_id, gid::Gid vertex_to_id,
|
||||
const std::string &edge_type);
|
||||
storage::EdgeType edge_type,
|
||||
const std::string &edge_type_name);
|
||||
static StateDelta PropsSetVertex(tx::transaction_id_t tx_id,
|
||||
gid::Gid vertex_id,
|
||||
const std::string &property,
|
||||
storage::Property property,
|
||||
const std::string &property_name,
|
||||
const PropertyValue &value);
|
||||
static StateDelta PropsSetEdge(tx::transaction_id_t tx_id, gid::Gid edge_id,
|
||||
const std::string &property,
|
||||
storage::Property property,
|
||||
const std::string &property_name,
|
||||
const PropertyValue &value);
|
||||
static StateDelta AddLabel(tx::transaction_id_t tx_id, gid::Gid vertex_id,
|
||||
const std::string &label);
|
||||
storage::Label label,
|
||||
const std::string &label_name);
|
||||
static StateDelta RemoveLabel(tx::transaction_id_t tx_id, gid::Gid vertex_id,
|
||||
const std::string &label);
|
||||
storage::Label label,
|
||||
const std::string &label_name);
|
||||
static StateDelta RemoveVertex(tx::transaction_id_t tx_id,
|
||||
gid::Gid vertex_id);
|
||||
static StateDelta RemoveEdge(tx::transaction_id_t tx_id, gid::Gid edge_id);
|
||||
static StateDelta BuildIndex(tx::transaction_id_t tx_id,
|
||||
const std::string &label,
|
||||
const std::string &property);
|
||||
|
||||
std::pair<std::string, std::string> IndexName() const;
|
||||
static StateDelta BuildIndex(tx::transaction_id_t tx_id, storage::Label label,
|
||||
const std::string &label_name,
|
||||
storage::Property property,
|
||||
const std::string &property_name);
|
||||
|
||||
/// Applies CRUD delta to database accessor. Fails on other types of deltas
|
||||
void Apply(GraphDbAccessor &dba) const;
|
||||
|
||||
private:
|
||||
// Members valid for every delta.
|
||||
enum Type type_;
|
||||
tx::transaction_id_t transaction_id_;
|
||||
enum Type type;
|
||||
tx::transaction_id_t transaction_id;
|
||||
|
||||
// Members valid only for some deltas, see StateDelta::Type comments above.
|
||||
gid::Gid vertex_id_;
|
||||
gid::Gid edge_id_;
|
||||
gid::Gid vertex_from_id_;
|
||||
gid::Gid vertex_to_id_;
|
||||
std::string edge_type_;
|
||||
std::string property_;
|
||||
PropertyValue value_ = PropertyValue::Null;
|
||||
std::string label_;
|
||||
gid::Gid vertex_id;
|
||||
gid::Gid edge_id;
|
||||
gid::Gid vertex_from_id;
|
||||
gid::Gid vertex_to_id;
|
||||
storage::EdgeType edge_type;
|
||||
std::string edge_type_name;
|
||||
storage::Property property;
|
||||
std::string property_name;
|
||||
PropertyValue value = PropertyValue::Null;
|
||||
storage::Label label;
|
||||
std::string label_name;
|
||||
};
|
||||
} // namespace database
|
||||
|
@ -272,27 +272,28 @@ bool RecoverWal(const fs::path &wal_dir, database::GraphDb &db,
|
||||
while (true) {
|
||||
auto delta = database::StateDelta::Decode(wal_reader, decoder);
|
||||
if (!delta) break;
|
||||
if (should_skip(delta->transaction_id())) continue;
|
||||
switch (delta->type()) {
|
||||
if (should_skip(delta->transaction_id)) continue;
|
||||
switch (delta->type) {
|
||||
case database::StateDelta::Type::TRANSACTION_BEGIN:
|
||||
DCHECK(accessors.find(delta->transaction_id()) == accessors.end())
|
||||
DCHECK(accessors.find(delta->transaction_id) == accessors.end())
|
||||
<< "Double transaction start";
|
||||
accessors.emplace(delta->transaction_id(), db);
|
||||
accessors.emplace(delta->transaction_id, db);
|
||||
break;
|
||||
case database::StateDelta::Type::TRANSACTION_ABORT:
|
||||
get_accessor(delta->transaction_id()).Abort();
|
||||
accessors.erase(accessors.find(delta->transaction_id()));
|
||||
get_accessor(delta->transaction_id).Abort();
|
||||
accessors.erase(accessors.find(delta->transaction_id));
|
||||
break;
|
||||
case database::StateDelta::Type::TRANSACTION_COMMIT:
|
||||
get_accessor(delta->transaction_id()).Commit();
|
||||
accessors.erase(accessors.find(delta->transaction_id()));
|
||||
get_accessor(delta->transaction_id).Commit();
|
||||
accessors.erase(accessors.find(delta->transaction_id));
|
||||
break;
|
||||
case database::StateDelta::Type::BUILD_INDEX:
|
||||
// TODO index building might still be problematic in HA
|
||||
recovery_data.indexes.emplace_back(delta->IndexName());
|
||||
recovery_data.indexes.emplace_back(delta->label_name,
|
||||
delta->property_name);
|
||||
break;
|
||||
default:
|
||||
delta->Apply(get_accessor(delta->transaction_id()));
|
||||
delta->Apply(get_accessor(delta->transaction_id));
|
||||
}
|
||||
} // reading all deltas in a single wal file
|
||||
} // reading all wal files
|
||||
|
@ -74,7 +74,7 @@ void WriteAheadLog::WalFile::Flush(RingBuffer<database::StateDelta> &buffer) {
|
||||
while (true) {
|
||||
auto delta = buffer.pop();
|
||||
if (!delta) break;
|
||||
latest_tx_ = std::max(latest_tx_, delta->transaction_id());
|
||||
latest_tx_ = std::max(latest_tx_, delta->transaction_id);
|
||||
delta->Encode(writer_, encoder_);
|
||||
if (++current_wal_file_delta_count_ >= FLAGS_wal_rotate_deltas_count)
|
||||
RotateFile();
|
||||
|
@ -25,7 +25,7 @@ void RecordAccessor<Vertex>::PropsSet(storage::Property key,
|
||||
vertex.properties_.set(key, value);
|
||||
auto &dba = db_accessor();
|
||||
// TODO use the delta for handling.
|
||||
dba.wal().Emplace(StateDelta::PropsSetVertex(dba.transaction_id(), gid(),
|
||||
dba.wal().Emplace(StateDelta::PropsSetVertex(dba.transaction_id(), gid(), key,
|
||||
dba.PropertyName(key), value));
|
||||
if (is_local()) {
|
||||
db_accessor().UpdatePropertyIndex(key, *this, &vertex);
|
||||
@ -38,7 +38,7 @@ void RecordAccessor<Edge>::PropsSet(storage::Property key,
|
||||
update().properties_.set(key, value);
|
||||
auto &dba = db_accessor();
|
||||
// TODO use the delta for handling.
|
||||
dba.wal().Emplace(StateDelta::PropsSetEdge(dba.transaction_id(), gid(),
|
||||
dba.wal().Emplace(StateDelta::PropsSetEdge(dba.transaction_id(), gid(), key,
|
||||
dba.PropertyName(key), value));
|
||||
}
|
||||
|
||||
@ -46,8 +46,9 @@ template <>
|
||||
size_t RecordAccessor<Vertex>::PropsErase(storage::Property key) {
|
||||
auto &dba = db_accessor();
|
||||
// TODO use the delta for handling.
|
||||
dba.wal().Emplace(StateDelta::PropsSetVertex(
|
||||
dba.transaction_id(), gid(), dba.PropertyName(key), PropertyValue::Null));
|
||||
dba.wal().Emplace(StateDelta::PropsSetVertex(dba.transaction_id(), gid(), key,
|
||||
dba.PropertyName(key),
|
||||
PropertyValue::Null));
|
||||
return update().properties_.erase(key);
|
||||
}
|
||||
|
||||
@ -55,8 +56,9 @@ template <>
|
||||
size_t RecordAccessor<Edge>::PropsErase(storage::Property key) {
|
||||
auto &dba = db_accessor();
|
||||
// TODO use the delta for handling.
|
||||
dba.wal().Emplace(StateDelta::PropsSetEdge(
|
||||
dba.transaction_id(), gid(), dba.PropertyName(key), PropertyValue::Null));
|
||||
dba.wal().Emplace(StateDelta::PropsSetEdge(dba.transaction_id(), gid(), key,
|
||||
dba.PropertyName(key),
|
||||
PropertyValue::Null));
|
||||
return update().properties_.erase(key);
|
||||
}
|
||||
|
||||
@ -66,9 +68,9 @@ void RecordAccessor<Vertex>::PropsClear() {
|
||||
// TODO use the delta for handling.
|
||||
auto &dba = db_accessor();
|
||||
for (const auto &kv : updated.properties_)
|
||||
dba.wal().Emplace(StateDelta::PropsSetVertex(dba.transaction_id(), gid(),
|
||||
dba.PropertyName(kv.first),
|
||||
PropertyValue::Null));
|
||||
dba.wal().Emplace(StateDelta::PropsSetVertex(
|
||||
dba.transaction_id(), gid(), kv.first, dba.PropertyName(kv.first),
|
||||
PropertyValue::Null));
|
||||
updated.properties_.clear();
|
||||
}
|
||||
|
||||
@ -78,9 +80,9 @@ void RecordAccessor<Edge>::PropsClear() {
|
||||
auto &dba = db_accessor();
|
||||
// TODO use the delta for handling.
|
||||
for (const auto &kv : updated.properties_)
|
||||
dba.wal().Emplace(StateDelta::PropsSetEdge(dba.transaction_id(), gid(),
|
||||
dba.PropertyName(kv.first),
|
||||
PropertyValue::Null));
|
||||
dba.wal().Emplace(StateDelta::PropsSetEdge(
|
||||
dba.transaction_id(), gid(), kv.first, dba.PropertyName(kv.first),
|
||||
PropertyValue::Null));
|
||||
updated.properties_.clear();
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,8 @@ bool VertexAccessor::add_label(storage::Label label) {
|
||||
auto &dba = db_accessor();
|
||||
dba.UpdateLabelIndices(label, *this, &vertex);
|
||||
// TODO support distributed.
|
||||
dba.wal().Emplace(database::StateDelta::AddLabel(dba.transaction_id(), gid(),
|
||||
dba.LabelName(label)));
|
||||
dba.wal().Emplace(database::StateDelta::AddLabel(
|
||||
dba.transaction_id(), gid(), label, dba.LabelName(label)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ size_t VertexAccessor::remove_label(storage::Label label) {
|
||||
auto &dba = db_accessor();
|
||||
// TODO support distributed.
|
||||
dba.wal().Emplace(database::StateDelta::RemoveLabel(
|
||||
dba.transaction_id(), gid(), dba.LabelName(label)));
|
||||
dba.transaction_id(), gid(), label, dba.LabelName(label)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -357,29 +357,28 @@ TEST_F(Durability, WalEncoding) {
|
||||
ASSERT_EQ(deltas.size(), 11);
|
||||
|
||||
using Type = enum database::StateDelta::Type;
|
||||
EXPECT_EQ(deltas[0].type(), Type::TRANSACTION_BEGIN);
|
||||
EXPECT_EQ(deltas[0].transaction_id(), 1);
|
||||
EXPECT_EQ(deltas[1].type(), Type::CREATE_VERTEX);
|
||||
EXPECT_EQ(deltas[1].transaction_id(), 1);
|
||||
EXPECT_EQ(deltas[2].type(), Type::ADD_LABEL);
|
||||
EXPECT_EQ(deltas[2].transaction_id(), 1);
|
||||
EXPECT_EQ(deltas[3].type(), Type::SET_PROPERTY_VERTEX);
|
||||
EXPECT_EQ(deltas[3].transaction_id(), 1);
|
||||
EXPECT_EQ(deltas[4].type(), Type::CREATE_VERTEX);
|
||||
EXPECT_EQ(deltas[4].transaction_id(), 1);
|
||||
EXPECT_EQ(deltas[5].type(), Type::CREATE_EDGE);
|
||||
EXPECT_EQ(deltas[5].transaction_id(), 1);
|
||||
EXPECT_EQ(deltas[6].type(), Type::SET_PROPERTY_EDGE);
|
||||
EXPECT_EQ(deltas[6].transaction_id(), 1);
|
||||
EXPECT_EQ(deltas[0].type, Type::TRANSACTION_BEGIN);
|
||||
EXPECT_EQ(deltas[0].transaction_id, 1);
|
||||
EXPECT_EQ(deltas[1].type, Type::CREATE_VERTEX);
|
||||
EXPECT_EQ(deltas[1].transaction_id, 1);
|
||||
EXPECT_EQ(deltas[2].type, Type::ADD_LABEL);
|
||||
EXPECT_EQ(deltas[2].transaction_id, 1);
|
||||
EXPECT_EQ(deltas[3].type, Type::SET_PROPERTY_VERTEX);
|
||||
EXPECT_EQ(deltas[3].transaction_id, 1);
|
||||
EXPECT_EQ(deltas[4].type, Type::CREATE_VERTEX);
|
||||
EXPECT_EQ(deltas[4].transaction_id, 1);
|
||||
EXPECT_EQ(deltas[5].type, Type::CREATE_EDGE);
|
||||
EXPECT_EQ(deltas[5].transaction_id, 1);
|
||||
EXPECT_EQ(deltas[6].type, Type::SET_PROPERTY_EDGE);
|
||||
EXPECT_EQ(deltas[6].transaction_id, 1);
|
||||
// The next two deltas are the BuildIndex internal transactions.
|
||||
EXPECT_EQ(deltas[7].type(), Type::TRANSACTION_BEGIN);
|
||||
EXPECT_EQ(deltas[8].type(), Type::BUILD_INDEX);
|
||||
auto index_name = deltas[8].IndexName();
|
||||
EXPECT_EQ(index_name.first, "l1");
|
||||
EXPECT_EQ(index_name.second, "p1");
|
||||
EXPECT_EQ(deltas[9].type(), Type::TRANSACTION_COMMIT);
|
||||
EXPECT_EQ(deltas[10].type(), Type::TRANSACTION_COMMIT);
|
||||
EXPECT_EQ(deltas[10].transaction_id(), 1);
|
||||
EXPECT_EQ(deltas[7].type, Type::TRANSACTION_BEGIN);
|
||||
EXPECT_EQ(deltas[8].type, Type::BUILD_INDEX);
|
||||
EXPECT_EQ(deltas[8].label_name, "l1");
|
||||
EXPECT_EQ(deltas[8].property_name, "p1");
|
||||
EXPECT_EQ(deltas[9].type, Type::TRANSACTION_COMMIT);
|
||||
EXPECT_EQ(deltas[10].type, Type::TRANSACTION_COMMIT);
|
||||
EXPECT_EQ(deltas[10].transaction_id, 1);
|
||||
}
|
||||
|
||||
TEST_F(Durability, SnapshotEncoding) {
|
||||
|
@ -57,8 +57,8 @@ TEST(StateDelta, CreateEdge) {
|
||||
}
|
||||
{
|
||||
database::GraphDbAccessor dba(db);
|
||||
auto delta = database::StateDelta::CreateEdge(dba.transaction_id(), gid2,
|
||||
gid0, gid1, "edge");
|
||||
auto delta = database::StateDelta::CreateEdge(
|
||||
dba.transaction_id(), gid2, gid0, gid1, dba.EdgeType("edge"), "edge");
|
||||
delta.Apply(dba);
|
||||
dba.Commit();
|
||||
}
|
||||
@ -106,8 +106,8 @@ TEST(StateDelta, AddLabel) {
|
||||
}
|
||||
{
|
||||
database::GraphDbAccessor dba(db);
|
||||
auto delta =
|
||||
database::StateDelta::AddLabel(dba.transaction_id(), gid0, "label");
|
||||
auto delta = database::StateDelta::AddLabel(dba.transaction_id(), gid0,
|
||||
dba.Label("label"), "label");
|
||||
delta.Apply(dba);
|
||||
dba.Commit();
|
||||
}
|
||||
@ -133,8 +133,8 @@ TEST(StateDelta, RemoveLabel) {
|
||||
}
|
||||
{
|
||||
database::GraphDbAccessor dba(db);
|
||||
auto delta =
|
||||
database::StateDelta::RemoveLabel(dba.transaction_id(), gid0, "label");
|
||||
auto delta = database::StateDelta::RemoveLabel(dba.transaction_id(), gid0,
|
||||
dba.Label("label"), "label");
|
||||
delta.Apply(dba);
|
||||
dba.Commit();
|
||||
}
|
||||
@ -159,7 +159,8 @@ TEST(StateDelta, SetPropertyVertex) {
|
||||
{
|
||||
database::GraphDbAccessor dba(db);
|
||||
auto delta = database::StateDelta::PropsSetVertex(
|
||||
dba.transaction_id(), gid0, "property", PropertyValue(2212));
|
||||
dba.transaction_id(), gid0, dba.Property("property"), "property",
|
||||
PropertyValue(2212));
|
||||
delta.Apply(dba);
|
||||
dba.Commit();
|
||||
}
|
||||
@ -188,7 +189,8 @@ TEST(StateDelta, SetPropertyEdge) {
|
||||
{
|
||||
database::GraphDbAccessor dba(db);
|
||||
auto delta = database::StateDelta::PropsSetEdge(
|
||||
dba.transaction_id(), gid2, "property", PropertyValue(2212));
|
||||
dba.transaction_id(), gid2, dba.Property("property"), "property",
|
||||
PropertyValue(2212));
|
||||
delta.Apply(dba);
|
||||
dba.Commit();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user