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:
florijan 2018-02-02 10:34:09 +01:00
parent 583f6f1794
commit 1d5d67aeac
9 changed files with 220 additions and 182 deletions

View File

@ -219,8 +219,8 @@ void GraphDbAccessor::EnableIndex(const LabelPropertyIndex::Key &key) {
// built at this point even if this DBA's transaction aborts for some // built at this point even if this DBA's transaction aborts for some
// reason. // reason.
auto wal_build_index_tx_id = transaction_id(); auto wal_build_index_tx_id = transaction_id();
wal().Emplace(database::StateDelta::BuildIndex(wal_build_index_tx_id, wal().Emplace(database::StateDelta::BuildIndex(
LabelName(key.label_), wal_build_index_tx_id, key.label_, LabelName(key.label_), key.property_,
PropertyName(key.property_))); PropertyName(key.property_)));
// After these two operations we are certain that everything is contained in // After these two operations we are certain that everything is contained in
@ -419,7 +419,7 @@ EdgeAccessor GraphDbAccessor::InsertEdge(
// outcomes are success or error (serialization, timeout). // outcomes are success or error (serialization, timeout).
} }
wal().Emplace(database::StateDelta::CreateEdge( 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))); EdgeTypeName(edge_type)));
return EdgeAccessor(edge_vlist, *this, from.address(), to.address(), return EdgeAccessor(edge_vlist, *this, from.address(), to.address(),
edge_type); edge_type);

View File

@ -6,12 +6,6 @@
namespace database { 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) { StateDelta StateDelta::TxBegin(tx::transaction_id_t tx_id) {
return {StateDelta::Type::TRANSACTION_BEGIN, 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, StateDelta StateDelta::CreateVertex(tx::transaction_id_t tx_id,
gid::Gid vertex_id) { gid::Gid vertex_id) {
StateDelta op(StateDelta::Type::CREATE_VERTEX, tx_id); StateDelta op(StateDelta::Type::CREATE_VERTEX, tx_id);
op.vertex_id_ = vertex_id; op.vertex_id = vertex_id;
return op; return op;
} }
StateDelta StateDelta::CreateEdge(tx::transaction_id_t tx_id, gid::Gid edge_id, StateDelta StateDelta::CreateEdge(tx::transaction_id_t tx_id, gid::Gid edge_id,
gid::Gid vertex_from_id, gid::Gid vertex_from_id,
gid::Gid vertex_to_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); StateDelta op(StateDelta::Type::CREATE_EDGE, tx_id);
op.edge_id_ = edge_id; op.edge_id = edge_id;
op.vertex_from_id_ = vertex_from_id; op.vertex_from_id = vertex_from_id;
op.vertex_to_id_ = vertex_to_id; op.vertex_to_id = vertex_to_id;
op.edge_type_ = edge_type; op.edge_type = edge_type;
op.edge_type_name = edge_type_name;
return op; return op;
} }
StateDelta StateDelta::PropsSetVertex(tx::transaction_id_t tx_id, StateDelta StateDelta::PropsSetVertex(tx::transaction_id_t tx_id,
gid::Gid vertex_id, gid::Gid vertex_id,
const std::string &property, storage::Property property,
const std::string &property_name,
const PropertyValue &value) { const PropertyValue &value) {
StateDelta op(StateDelta::Type::SET_PROPERTY_VERTEX, tx_id); StateDelta op(StateDelta::Type::SET_PROPERTY_VERTEX, tx_id);
op.vertex_id_ = vertex_id; op.vertex_id = vertex_id;
op.property_ = property; op.property = property;
op.value_ = value; op.property_name = property_name;
op.value = value;
return op; return op;
} }
StateDelta StateDelta::PropsSetEdge(tx::transaction_id_t tx_id, StateDelta StateDelta::PropsSetEdge(tx::transaction_id_t tx_id,
gid::Gid edge_id, gid::Gid edge_id,
const std::string &property, storage::Property property,
const std::string &property_name,
const PropertyValue &value) { const PropertyValue &value) {
StateDelta op(StateDelta::Type::SET_PROPERTY_EDGE, tx_id); StateDelta op(StateDelta::Type::SET_PROPERTY_EDGE, tx_id);
op.edge_id_ = edge_id; op.edge_id = edge_id;
op.property_ = property; op.property = property;
op.value_ = value; op.property_name = property_name;
op.value = value;
return op; return op;
} }
StateDelta StateDelta::AddLabel(tx::transaction_id_t tx_id, gid::Gid vertex_id, 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); StateDelta op(StateDelta::Type::ADD_LABEL, tx_id);
op.vertex_id_ = vertex_id; op.vertex_id = vertex_id;
op.label_ = label; op.label = label;
op.label_name = label_name;
return op; return op;
} }
StateDelta StateDelta::RemoveLabel(tx::transaction_id_t tx_id, StateDelta StateDelta::RemoveLabel(tx::transaction_id_t tx_id,
gid::Gid vertex_id, gid::Gid vertex_id, storage::Label label,
const std::string &label) { const std::string &label_name) {
StateDelta op(StateDelta::Type::REMOVE_LABEL, tx_id); StateDelta op(StateDelta::Type::REMOVE_LABEL, tx_id);
op.vertex_id_ = vertex_id; op.vertex_id = vertex_id;
op.label_ = label; op.label = label;
op.label_name = label_name;
return op; return op;
} }
StateDelta StateDelta::RemoveVertex(tx::transaction_id_t tx_id, StateDelta StateDelta::RemoveVertex(tx::transaction_id_t tx_id,
gid::Gid vertex_id) { gid::Gid vertex_id) {
StateDelta op(StateDelta::Type::REMOVE_VERTEX, tx_id); StateDelta op(StateDelta::Type::REMOVE_VERTEX, tx_id);
op.vertex_id_ = vertex_id; op.vertex_id = vertex_id;
return op; return op;
} }
StateDelta StateDelta::RemoveEdge(tx::transaction_id_t tx_id, StateDelta StateDelta::RemoveEdge(tx::transaction_id_t tx_id,
gid::Gid edge_id) { gid::Gid edge_id) {
StateDelta op(StateDelta::Type::REMOVE_EDGE, tx_id); StateDelta op(StateDelta::Type::REMOVE_EDGE, tx_id);
op.edge_id_ = edge_id; op.edge_id = edge_id;
return op; return op;
} }
StateDelta StateDelta::BuildIndex(tx::transaction_id_t tx_id, StateDelta StateDelta::BuildIndex(tx::transaction_id_t tx_id,
const std::string &label, storage::Label label,
const std::string &property) { const std::string &label_name,
storage::Property property,
const std::string &property_name) {
StateDelta op(StateDelta::Type::BUILD_INDEX, tx_id); StateDelta op(StateDelta::Type::BUILD_INDEX, tx_id);
op.label_ = label; op.label = label;
op.property_ = property; op.label_name = label_name;
op.property = property;
op.property_name = property_name;
return op; return op;
} }
void StateDelta::Encode( void StateDelta::Encode(
HashedFileWriter &writer, HashedFileWriter &writer,
communication::bolt::PrimitiveEncoder<HashedFileWriter> &encoder) const { communication::bolt::PrimitiveEncoder<HashedFileWriter> &encoder) const {
encoder.WriteInt(static_cast<int64_t>(type_)); encoder.WriteInt(static_cast<int64_t>(type));
encoder.WriteInt(static_cast<int64_t>(transaction_id_)); encoder.WriteInt(static_cast<int64_t>(transaction_id));
switch (type_) { switch (type) {
case Type::TRANSACTION_BEGIN: case Type::TRANSACTION_BEGIN:
case Type::TRANSACTION_COMMIT: case Type::TRANSACTION_COMMIT:
case Type::TRANSACTION_ABORT: case Type::TRANSACTION_ABORT:
break; break;
case Type::CREATE_VERTEX: case Type::CREATE_VERTEX:
encoder.WriteInt(vertex_id_); encoder.WriteInt(vertex_id);
break; break;
case Type::CREATE_EDGE: case Type::CREATE_EDGE:
encoder.WriteInt(edge_id_); encoder.WriteInt(edge_id);
encoder.WriteInt(vertex_from_id_); encoder.WriteInt(vertex_from_id);
encoder.WriteInt(vertex_to_id_); encoder.WriteInt(vertex_to_id);
encoder.WriteString(edge_type_); encoder.WriteInt(edge_type.storage());
encoder.WriteString(edge_type_name);
break; break;
case Type::SET_PROPERTY_VERTEX: case Type::SET_PROPERTY_VERTEX:
encoder.WriteInt(vertex_id_); encoder.WriteInt(vertex_id);
encoder.WriteString(property_); encoder.WriteInt(property.storage());
encoder.WritePropertyValue(value_); encoder.WriteString(property_name);
encoder.WritePropertyValue(value);
break; break;
case Type::SET_PROPERTY_EDGE: case Type::SET_PROPERTY_EDGE:
encoder.WriteInt(edge_id_); encoder.WriteInt(edge_id);
encoder.WriteString(property_); encoder.WriteInt(property.storage());
encoder.WritePropertyValue(value_); encoder.WriteString(property_name);
encoder.WritePropertyValue(value);
break; break;
case Type::ADD_LABEL: case Type::ADD_LABEL:
case Type::REMOVE_LABEL: case Type::REMOVE_LABEL:
encoder.WriteInt(vertex_id_); encoder.WriteInt(vertex_id);
encoder.WriteString(label_); encoder.WriteInt(label.storage());
encoder.WriteString(label_name);
break; break;
case Type::REMOVE_VERTEX: case Type::REMOVE_VERTEX:
encoder.WriteInt(vertex_id_); encoder.WriteInt(vertex_id);
break; break;
case Type::REMOVE_EDGE: case Type::REMOVE_EDGE:
encoder.WriteInt(edge_id_); encoder.WriteInt(edge_id);
break; break;
case Type::BUILD_INDEX: case Type::BUILD_INDEX:
encoder.WriteString(label_); encoder.WriteInt(label.storage());
encoder.WriteString(property_); encoder.WriteString(label_name);
encoder.WriteInt(property.storage());
encoder.WriteString(property_name);
break; break;
} }
@ -159,6 +172,10 @@ void StateDelta::Encode(
if (!decoder.ReadValue(&dv)) return nullopt; \ if (!decoder.ReadValue(&dv)) return nullopt; \
r_val.member = dv.value_f(); 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( std::experimental::optional<StateDelta> StateDelta::Decode(
HashedFileReader &reader, HashedFileReader &reader,
communication::bolt::Decoder<HashedFileReader> &decoder) { communication::bolt::Decoder<HashedFileReader> &decoder) {
@ -170,49 +187,55 @@ std::experimental::optional<StateDelta> StateDelta::Decode(
try { try {
if (!decoder.ReadValue(&dv)) return nullopt; if (!decoder.ReadValue(&dv)) return nullopt;
r_val.type_ = static_cast<enum StateDelta::Type>(dv.ValueInt()); r_val.type = static_cast<enum StateDelta::Type>(dv.ValueInt());
DECODE_MEMBER(transaction_id_, ValueInt) DECODE_MEMBER(transaction_id, ValueInt)
switch (r_val.type_) { switch (r_val.type) {
case Type::TRANSACTION_BEGIN: case Type::TRANSACTION_BEGIN:
case Type::TRANSACTION_COMMIT: case Type::TRANSACTION_COMMIT:
case Type::TRANSACTION_ABORT: case Type::TRANSACTION_ABORT:
break; break;
case Type::CREATE_VERTEX: case Type::CREATE_VERTEX:
DECODE_MEMBER(vertex_id_, ValueInt) DECODE_MEMBER(vertex_id, ValueInt)
break; break;
case Type::CREATE_EDGE: case Type::CREATE_EDGE:
DECODE_MEMBER(edge_id_, ValueInt) DECODE_MEMBER(edge_id, ValueInt)
DECODE_MEMBER(vertex_from_id_, ValueInt) DECODE_MEMBER(vertex_from_id, ValueInt)
DECODE_MEMBER(vertex_to_id_, ValueInt) DECODE_MEMBER(vertex_to_id, ValueInt)
DECODE_MEMBER(edge_type_, ValueString) DECODE_MEMBER_CAST(edge_type, ValueInt, storage::EdgeType)
DECODE_MEMBER(edge_type_name, ValueString)
break; break;
case Type::SET_PROPERTY_VERTEX: case Type::SET_PROPERTY_VERTEX:
DECODE_MEMBER(vertex_id_, ValueInt) DECODE_MEMBER(vertex_id, ValueInt)
DECODE_MEMBER(property_, ValueString) DECODE_MEMBER_CAST(property, ValueInt, storage::Property)
DECODE_MEMBER(property_name, ValueString)
if (!decoder.ReadValue(&dv)) return nullopt; if (!decoder.ReadValue(&dv)) return nullopt;
r_val.value_ = static_cast<PropertyValue>(dv); r_val.value = static_cast<PropertyValue>(dv);
break; break;
case Type::SET_PROPERTY_EDGE: case Type::SET_PROPERTY_EDGE:
DECODE_MEMBER(edge_id_, ValueInt) DECODE_MEMBER(edge_id, ValueInt)
DECODE_MEMBER(property_, ValueString) DECODE_MEMBER_CAST(property, ValueInt, storage::Property)
DECODE_MEMBER(property_name, ValueString)
if (!decoder.ReadValue(&dv)) return nullopt; if (!decoder.ReadValue(&dv)) return nullopt;
r_val.value_ = static_cast<PropertyValue>(dv); r_val.value = static_cast<PropertyValue>(dv);
break; break;
case Type::ADD_LABEL: case Type::ADD_LABEL:
case Type::REMOVE_LABEL: case Type::REMOVE_LABEL:
DECODE_MEMBER(vertex_id_, ValueInt) DECODE_MEMBER(vertex_id, ValueInt)
DECODE_MEMBER(label_, ValueString) DECODE_MEMBER_CAST(label, ValueInt, storage::Label)
DECODE_MEMBER(label_name, ValueString)
break; break;
case Type::REMOVE_VERTEX: case Type::REMOVE_VERTEX:
DECODE_MEMBER(vertex_id_, ValueInt) DECODE_MEMBER(vertex_id, ValueInt)
break; break;
case Type::REMOVE_EDGE: case Type::REMOVE_EDGE:
DECODE_MEMBER(edge_id_, ValueInt) DECODE_MEMBER(edge_id, ValueInt)
break; break;
case Type::BUILD_INDEX: case Type::BUILD_INDEX:
DECODE_MEMBER(label_, ValueString) DECODE_MEMBER_CAST(label, ValueInt, storage::Label)
DECODE_MEMBER(property_, ValueString) DECODE_MEMBER(label_name, ValueString)
DECODE_MEMBER_CAST(property, ValueInt, storage::Property)
DECODE_MEMBER(property_name, ValueString)
break; break;
} }
@ -232,7 +255,7 @@ std::experimental::optional<StateDelta> StateDelta::Decode(
#undef DECODE_MEMBER #undef DECODE_MEMBER
void StateDelta::Apply(GraphDbAccessor &dba) const { void StateDelta::Apply(GraphDbAccessor &dba) const {
switch (type_) { switch (type) {
// Transactional state is not recovered. // Transactional state is not recovered.
case Type::TRANSACTION_BEGIN: case Type::TRANSACTION_BEGIN:
case Type::TRANSACTION_COMMIT: case Type::TRANSACTION_COMMIT:
@ -240,48 +263,48 @@ void StateDelta::Apply(GraphDbAccessor &dba) const {
LOG(FATAL) << "Transaction handling not handled in Apply"; LOG(FATAL) << "Transaction handling not handled in Apply";
break; break;
case Type::CREATE_VERTEX: case Type::CREATE_VERTEX:
dba.InsertVertex(vertex_id_); dba.InsertVertex(vertex_id);
break; break;
case Type::CREATE_EDGE: { case Type::CREATE_EDGE: {
auto from = dba.FindVertex(vertex_from_id_, true); auto from = dba.FindVertex(vertex_from_id, true);
auto to = dba.FindVertex(vertex_to_id_, true); auto to = dba.FindVertex(vertex_to_id, true);
DCHECK(from) << "Failed to find vertex."; DCHECK(from) << "Failed to find vertex.";
DCHECK(to) << "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; break;
} }
case Type::SET_PROPERTY_VERTEX: { 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."; DCHECK(vertex) << "Failed to find vertex.";
vertex->PropsSet(dba.Property(property_), value_); vertex->PropsSet(dba.Property(property_name), value);
break; break;
} }
case Type::SET_PROPERTY_EDGE: { 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."; DCHECK(edge) << "Failed to find edge.";
edge->PropsSet(dba.Property(property_), value_); edge->PropsSet(dba.Property(property_name), value);
break; break;
} }
case Type::ADD_LABEL: { case Type::ADD_LABEL: {
auto vertex = dba.FindVertex(vertex_id_, true); auto vertex = dba.FindVertex(vertex_id, true);
DCHECK(vertex) << "Failed to find vertex."; DCHECK(vertex) << "Failed to find vertex.";
vertex->add_label(dba.Label(label_)); vertex->add_label(dba.Label(label_name));
break; break;
} }
case Type::REMOVE_LABEL: { case Type::REMOVE_LABEL: {
auto vertex = dba.FindVertex(vertex_id_, true); auto vertex = dba.FindVertex(vertex_id, true);
DCHECK(vertex) << "Failed to find vertex."; DCHECK(vertex) << "Failed to find vertex.";
vertex->remove_label(dba.Label(label_)); vertex->remove_label(dba.Label(label_name));
break; break;
} }
case Type::REMOVE_VERTEX: { case Type::REMOVE_VERTEX: {
auto vertex = dba.FindVertex(vertex_id_, true); auto vertex = dba.FindVertex(vertex_id, true);
DCHECK(vertex) << "Failed to find vertex."; DCHECK(vertex) << "Failed to find vertex.";
dba.DetachRemoveVertex(*vertex); dba.DetachRemoveVertex(*vertex);
break; break;
} }
case Type::REMOVE_EDGE: { case Type::REMOVE_EDGE: {
auto edge = dba.FindEdge(edge_id_, true); auto edge = dba.FindEdge(edge_id, true);
DCHECK(edge) << "Failed to find edge."; DCHECK(edge) << "Failed to find edge.";
dba.RemoveEdge(*edge); dba.RemoveEdge(*edge);
break; break;

View File

@ -10,9 +10,16 @@
namespace database { namespace database {
/** Describes single change to the database state. Used for durability (WAL) and /** Describes single change to the database state. Used for durability (WAL) and
* state communication over network in HA and for distributed remote storage * state communication over network in HA and for distributed remote storage
* changes*/ * changes.
class StateDelta { *
public: * 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 /** 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 * need to be stored. All deltas have the transaction_id member, so that's
* omitted in the comment. */ * omitted in the comment. */
@ -21,20 +28,21 @@ class StateDelta {
TRANSACTION_COMMIT, TRANSACTION_COMMIT,
TRANSACTION_ABORT, TRANSACTION_ABORT,
CREATE_VERTEX, // vertex_id CREATE_VERTEX, // vertex_id
CREATE_EDGE, // edge_id, from_vertex_id, to_vertex_id, edge_type CREATE_EDGE, // edge_id, from_vertex_id, to_vertex_id, edge_type,
SET_PROPERTY_VERTEX, // vertex_id, property, property_value // edge_type_name
SET_PROPERTY_EDGE, // edge_id, property, property_value 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 // remove property is done by setting a PropertyValue::Null
ADD_LABEL, // vertex_id, label ADD_LABEL, // vertex_id, label, label_name
REMOVE_LABEL, // vertex_id, label REMOVE_LABEL, // vertex_id, label, label_name
REMOVE_VERTEX, // vertex_id REMOVE_VERTEX, // vertex_id
REMOVE_EDGE, // edge_id REMOVE_EDGE, // edge_id
BUILD_INDEX // label, property BUILD_INDEX // label, label_name, property, property_name
}; };
StateDelta() = default; StateDelta() = default;
StateDelta(const enum Type &type, tx::transaction_id_t tx_id) 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 /** Attempts to decode a StateDelta from the given decoder. Returns the
* decoded value if successful, otherwise returns nullopt. */ * decoded value if successful, otherwise returns nullopt. */
@ -48,9 +56,6 @@ class StateDelta {
HashedFileWriter &writer, HashedFileWriter &writer,
communication::bolt::PrimitiveEncoder<HashedFileWriter> &encoder) const; 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 TxBegin(tx::transaction_id_t tx_id);
static StateDelta TxCommit(tx::transaction_id_t tx_id); static StateDelta TxCommit(tx::transaction_id_t tx_id);
static StateDelta TxAbort(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); gid::Gid vertex_id);
static StateDelta CreateEdge(tx::transaction_id_t tx_id, gid::Gid edge_id, static StateDelta CreateEdge(tx::transaction_id_t tx_id, gid::Gid edge_id,
gid::Gid vertex_from_id, gid::Gid vertex_to_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, static StateDelta PropsSetVertex(tx::transaction_id_t tx_id,
gid::Gid vertex_id, gid::Gid vertex_id,
const std::string &property, storage::Property property,
const std::string &property_name,
const PropertyValue &value); const PropertyValue &value);
static StateDelta PropsSetEdge(tx::transaction_id_t tx_id, gid::Gid edge_id, 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); const PropertyValue &value);
static StateDelta AddLabel(tx::transaction_id_t tx_id, gid::Gid vertex_id, 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, 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, static StateDelta RemoveVertex(tx::transaction_id_t tx_id,
gid::Gid vertex_id); gid::Gid vertex_id);
static StateDelta RemoveEdge(tx::transaction_id_t tx_id, gid::Gid edge_id); static StateDelta RemoveEdge(tx::transaction_id_t tx_id, gid::Gid edge_id);
static StateDelta BuildIndex(tx::transaction_id_t tx_id, static StateDelta BuildIndex(tx::transaction_id_t tx_id, storage::Label label,
const std::string &label, const std::string &label_name,
const std::string &property); storage::Property property,
const std::string &property_name);
std::pair<std::string, std::string> IndexName() const;
/// Applies CRUD delta to database accessor. Fails on other types of deltas /// Applies CRUD delta to database accessor. Fails on other types of deltas
void Apply(GraphDbAccessor &dba) const; void Apply(GraphDbAccessor &dba) const;
private:
// Members valid for every delta. // Members valid for every delta.
enum Type type_; enum Type type;
tx::transaction_id_t transaction_id_; tx::transaction_id_t transaction_id;
// Members valid only for some deltas, see StateDelta::Type comments above. // Members valid only for some deltas, see StateDelta::Type comments above.
gid::Gid vertex_id_; gid::Gid vertex_id;
gid::Gid edge_id_; gid::Gid edge_id;
gid::Gid vertex_from_id_; gid::Gid vertex_from_id;
gid::Gid vertex_to_id_; gid::Gid vertex_to_id;
std::string edge_type_; storage::EdgeType edge_type;
std::string property_; std::string edge_type_name;
PropertyValue value_ = PropertyValue::Null; storage::Property property;
std::string label_; std::string property_name;
PropertyValue value = PropertyValue::Null;
storage::Label label;
std::string label_name;
}; };
} // namespace database } // namespace database

View File

@ -272,27 +272,28 @@ bool RecoverWal(const fs::path &wal_dir, database::GraphDb &db,
while (true) { while (true) {
auto delta = database::StateDelta::Decode(wal_reader, decoder); auto delta = database::StateDelta::Decode(wal_reader, decoder);
if (!delta) break; if (!delta) break;
if (should_skip(delta->transaction_id())) continue; if (should_skip(delta->transaction_id)) continue;
switch (delta->type()) { switch (delta->type) {
case database::StateDelta::Type::TRANSACTION_BEGIN: 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"; << "Double transaction start";
accessors.emplace(delta->transaction_id(), db); accessors.emplace(delta->transaction_id, db);
break; break;
case database::StateDelta::Type::TRANSACTION_ABORT: case database::StateDelta::Type::TRANSACTION_ABORT:
get_accessor(delta->transaction_id()).Abort(); get_accessor(delta->transaction_id).Abort();
accessors.erase(accessors.find(delta->transaction_id())); accessors.erase(accessors.find(delta->transaction_id));
break; break;
case database::StateDelta::Type::TRANSACTION_COMMIT: case database::StateDelta::Type::TRANSACTION_COMMIT:
get_accessor(delta->transaction_id()).Commit(); get_accessor(delta->transaction_id).Commit();
accessors.erase(accessors.find(delta->transaction_id())); accessors.erase(accessors.find(delta->transaction_id));
break; break;
case database::StateDelta::Type::BUILD_INDEX: case database::StateDelta::Type::BUILD_INDEX:
// TODO index building might still be problematic in HA // 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; break;
default: 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 deltas in a single wal file
} // reading all wal files } // reading all wal files

View File

@ -74,7 +74,7 @@ void WriteAheadLog::WalFile::Flush(RingBuffer<database::StateDelta> &buffer) {
while (true) { while (true) {
auto delta = buffer.pop(); auto delta = buffer.pop();
if (!delta) break; 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_); delta->Encode(writer_, encoder_);
if (++current_wal_file_delta_count_ >= FLAGS_wal_rotate_deltas_count) if (++current_wal_file_delta_count_ >= FLAGS_wal_rotate_deltas_count)
RotateFile(); RotateFile();

View File

@ -25,7 +25,7 @@ void RecordAccessor<Vertex>::PropsSet(storage::Property key,
vertex.properties_.set(key, value); vertex.properties_.set(key, value);
auto &dba = db_accessor(); auto &dba = db_accessor();
// TODO use the delta for handling. // 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)); dba.PropertyName(key), value));
if (is_local()) { if (is_local()) {
db_accessor().UpdatePropertyIndex(key, *this, &vertex); db_accessor().UpdatePropertyIndex(key, *this, &vertex);
@ -38,7 +38,7 @@ void RecordAccessor<Edge>::PropsSet(storage::Property key,
update().properties_.set(key, value); update().properties_.set(key, value);
auto &dba = db_accessor(); auto &dba = db_accessor();
// TODO use the delta for handling. // 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)); dba.PropertyName(key), value));
} }
@ -46,8 +46,9 @@ template <>
size_t RecordAccessor<Vertex>::PropsErase(storage::Property key) { size_t RecordAccessor<Vertex>::PropsErase(storage::Property key) {
auto &dba = db_accessor(); auto &dba = db_accessor();
// TODO use the delta for handling. // TODO use the delta for handling.
dba.wal().Emplace(StateDelta::PropsSetVertex( dba.wal().Emplace(StateDelta::PropsSetVertex(dba.transaction_id(), gid(), key,
dba.transaction_id(), gid(), dba.PropertyName(key), PropertyValue::Null)); dba.PropertyName(key),
PropertyValue::Null));
return update().properties_.erase(key); return update().properties_.erase(key);
} }
@ -55,8 +56,9 @@ template <>
size_t RecordAccessor<Edge>::PropsErase(storage::Property key) { size_t RecordAccessor<Edge>::PropsErase(storage::Property key) {
auto &dba = db_accessor(); auto &dba = db_accessor();
// TODO use the delta for handling. // TODO use the delta for handling.
dba.wal().Emplace(StateDelta::PropsSetEdge( dba.wal().Emplace(StateDelta::PropsSetEdge(dba.transaction_id(), gid(), key,
dba.transaction_id(), gid(), dba.PropertyName(key), PropertyValue::Null)); dba.PropertyName(key),
PropertyValue::Null));
return update().properties_.erase(key); return update().properties_.erase(key);
} }
@ -66,8 +68,8 @@ void RecordAccessor<Vertex>::PropsClear() {
// TODO use the delta for handling. // TODO use the delta for handling.
auto &dba = db_accessor(); auto &dba = db_accessor();
for (const auto &kv : updated.properties_) for (const auto &kv : updated.properties_)
dba.wal().Emplace(StateDelta::PropsSetVertex(dba.transaction_id(), gid(), dba.wal().Emplace(StateDelta::PropsSetVertex(
dba.PropertyName(kv.first), dba.transaction_id(), gid(), kv.first, dba.PropertyName(kv.first),
PropertyValue::Null)); PropertyValue::Null));
updated.properties_.clear(); updated.properties_.clear();
} }
@ -78,8 +80,8 @@ void RecordAccessor<Edge>::PropsClear() {
auto &dba = db_accessor(); auto &dba = db_accessor();
// TODO use the delta for handling. // TODO use the delta for handling.
for (const auto &kv : updated.properties_) for (const auto &kv : updated.properties_)
dba.wal().Emplace(StateDelta::PropsSetEdge(dba.transaction_id(), gid(), dba.wal().Emplace(StateDelta::PropsSetEdge(
dba.PropertyName(kv.first), dba.transaction_id(), gid(), kv.first, dba.PropertyName(kv.first),
PropertyValue::Null)); PropertyValue::Null));
updated.properties_.clear(); updated.properties_.clear();
} }

View File

@ -20,8 +20,8 @@ bool VertexAccessor::add_label(storage::Label label) {
auto &dba = db_accessor(); auto &dba = db_accessor();
dba.UpdateLabelIndices(label, *this, &vertex); dba.UpdateLabelIndices(label, *this, &vertex);
// TODO support distributed. // TODO support distributed.
dba.wal().Emplace(database::StateDelta::AddLabel(dba.transaction_id(), gid(), dba.wal().Emplace(database::StateDelta::AddLabel(
dba.LabelName(label))); dba.transaction_id(), gid(), label, dba.LabelName(label)));
return true; return true;
} }
@ -35,7 +35,7 @@ size_t VertexAccessor::remove_label(storage::Label label) {
auto &dba = db_accessor(); auto &dba = db_accessor();
// TODO support distributed. // TODO support distributed.
dba.wal().Emplace(database::StateDelta::RemoveLabel( dba.wal().Emplace(database::StateDelta::RemoveLabel(
dba.transaction_id(), gid(), dba.LabelName(label))); dba.transaction_id(), gid(), label, dba.LabelName(label)));
return 1; return 1;
} }

View File

@ -357,29 +357,28 @@ TEST_F(Durability, WalEncoding) {
ASSERT_EQ(deltas.size(), 11); ASSERT_EQ(deltas.size(), 11);
using Type = enum database::StateDelta::Type; using Type = enum database::StateDelta::Type;
EXPECT_EQ(deltas[0].type(), Type::TRANSACTION_BEGIN); EXPECT_EQ(deltas[0].type, Type::TRANSACTION_BEGIN);
EXPECT_EQ(deltas[0].transaction_id(), 1); EXPECT_EQ(deltas[0].transaction_id, 1);
EXPECT_EQ(deltas[1].type(), Type::CREATE_VERTEX); EXPECT_EQ(deltas[1].type, Type::CREATE_VERTEX);
EXPECT_EQ(deltas[1].transaction_id(), 1); EXPECT_EQ(deltas[1].transaction_id, 1);
EXPECT_EQ(deltas[2].type(), Type::ADD_LABEL); EXPECT_EQ(deltas[2].type, Type::ADD_LABEL);
EXPECT_EQ(deltas[2].transaction_id(), 1); EXPECT_EQ(deltas[2].transaction_id, 1);
EXPECT_EQ(deltas[3].type(), Type::SET_PROPERTY_VERTEX); EXPECT_EQ(deltas[3].type, Type::SET_PROPERTY_VERTEX);
EXPECT_EQ(deltas[3].transaction_id(), 1); EXPECT_EQ(deltas[3].transaction_id, 1);
EXPECT_EQ(deltas[4].type(), Type::CREATE_VERTEX); EXPECT_EQ(deltas[4].type, Type::CREATE_VERTEX);
EXPECT_EQ(deltas[4].transaction_id(), 1); EXPECT_EQ(deltas[4].transaction_id, 1);
EXPECT_EQ(deltas[5].type(), Type::CREATE_EDGE); EXPECT_EQ(deltas[5].type, Type::CREATE_EDGE);
EXPECT_EQ(deltas[5].transaction_id(), 1); EXPECT_EQ(deltas[5].transaction_id, 1);
EXPECT_EQ(deltas[6].type(), Type::SET_PROPERTY_EDGE); EXPECT_EQ(deltas[6].type, Type::SET_PROPERTY_EDGE);
EXPECT_EQ(deltas[6].transaction_id(), 1); EXPECT_EQ(deltas[6].transaction_id, 1);
// The next two deltas are the BuildIndex internal transactions. // The next two deltas are the BuildIndex internal transactions.
EXPECT_EQ(deltas[7].type(), Type::TRANSACTION_BEGIN); EXPECT_EQ(deltas[7].type, Type::TRANSACTION_BEGIN);
EXPECT_EQ(deltas[8].type(), Type::BUILD_INDEX); EXPECT_EQ(deltas[8].type, Type::BUILD_INDEX);
auto index_name = deltas[8].IndexName(); EXPECT_EQ(deltas[8].label_name, "l1");
EXPECT_EQ(index_name.first, "l1"); EXPECT_EQ(deltas[8].property_name, "p1");
EXPECT_EQ(index_name.second, "p1"); EXPECT_EQ(deltas[9].type, Type::TRANSACTION_COMMIT);
EXPECT_EQ(deltas[9].type(), Type::TRANSACTION_COMMIT); EXPECT_EQ(deltas[10].type, Type::TRANSACTION_COMMIT);
EXPECT_EQ(deltas[10].type(), Type::TRANSACTION_COMMIT); EXPECT_EQ(deltas[10].transaction_id, 1);
EXPECT_EQ(deltas[10].transaction_id(), 1);
} }
TEST_F(Durability, SnapshotEncoding) { TEST_F(Durability, SnapshotEncoding) {

View File

@ -57,8 +57,8 @@ TEST(StateDelta, CreateEdge) {
} }
{ {
database::GraphDbAccessor dba(db); database::GraphDbAccessor dba(db);
auto delta = database::StateDelta::CreateEdge(dba.transaction_id(), gid2, auto delta = database::StateDelta::CreateEdge(
gid0, gid1, "edge"); dba.transaction_id(), gid2, gid0, gid1, dba.EdgeType("edge"), "edge");
delta.Apply(dba); delta.Apply(dba);
dba.Commit(); dba.Commit();
} }
@ -106,8 +106,8 @@ TEST(StateDelta, AddLabel) {
} }
{ {
database::GraphDbAccessor dba(db); database::GraphDbAccessor dba(db);
auto delta = auto delta = database::StateDelta::AddLabel(dba.transaction_id(), gid0,
database::StateDelta::AddLabel(dba.transaction_id(), gid0, "label"); dba.Label("label"), "label");
delta.Apply(dba); delta.Apply(dba);
dba.Commit(); dba.Commit();
} }
@ -133,8 +133,8 @@ TEST(StateDelta, RemoveLabel) {
} }
{ {
database::GraphDbAccessor dba(db); database::GraphDbAccessor dba(db);
auto delta = auto delta = database::StateDelta::RemoveLabel(dba.transaction_id(), gid0,
database::StateDelta::RemoveLabel(dba.transaction_id(), gid0, "label"); dba.Label("label"), "label");
delta.Apply(dba); delta.Apply(dba);
dba.Commit(); dba.Commit();
} }
@ -159,7 +159,8 @@ TEST(StateDelta, SetPropertyVertex) {
{ {
database::GraphDbAccessor dba(db); database::GraphDbAccessor dba(db);
auto delta = database::StateDelta::PropsSetVertex( 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); delta.Apply(dba);
dba.Commit(); dba.Commit();
} }
@ -188,7 +189,8 @@ TEST(StateDelta, SetPropertyEdge) {
{ {
database::GraphDbAccessor dba(db); database::GraphDbAccessor dba(db);
auto delta = database::StateDelta::PropsSetEdge( 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); delta.Apply(dba);
dba.Commit(); dba.Commit();
} }