Fix unique constraint recovery
Summary: See https://app.asana.com/0/743890251333732/888297761596047/f for more details. # BEFORE ``` Note: Google Test filter = *UniqueConstraintRecovery* [==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from Durability [ RUN ] Durability.UniqueConstraintRecovery unknown file: Failure C++ exception with description "Index couldn't be created due to constraint violation!" thrown in the test body. [ FAILED ] Durability.UniqueConstraintRecovery (3 ms) [----------] 1 test from Durability (3 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. (3 ms total) [ PASSED ] 0 tests. [ FAILED ] 1 test, listed below: [ FAILED ] Durability.UniqueConstraintRecovery 1 FAILED TEST ``` # AFTER ``` [==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from Durability [ RUN ] Durability.UniqueConstraintRecovery [ OK ] Durability.UniqueConstraintRecovery (4 ms) [----------] 1 test from Durability (4 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. (4 ms total) [ PASSED ] 1 test. ``` Reviewers: ipaljak, vkasljevic Reviewed By: ipaljak Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1714
This commit is contained in:
parent
0493470f98
commit
4f0a7df4bb
@ -402,17 +402,47 @@ void RecoverWal(const fs::path &durability_dir, database::GraphDb *db,
|
||||
case database::StateDelta::Type::TRANSACTION_COMMIT:
|
||||
transactions->Commit(delta.transaction_id);
|
||||
break;
|
||||
case database::StateDelta::Type::BUILD_INDEX:
|
||||
case database::StateDelta::Type::BUILD_INDEX: {
|
||||
// TODO index building might still be problematic in HA
|
||||
recovery_data->indexes.emplace_back(
|
||||
IndexRecoveryData{delta.label_name, delta.property_name,
|
||||
/*create = */ true, delta.unique});
|
||||
auto drop_it = std::find_if(
|
||||
recovery_data->indexes.begin(), recovery_data->indexes.end(),
|
||||
[label = delta.label_name, property = delta.property_name](
|
||||
const IndexRecoveryData &other) {
|
||||
return other.label == label && other.property == property &&
|
||||
other.create == false;
|
||||
});
|
||||
|
||||
// If we already have a drop index in the recovery data, just erase
|
||||
// the drop index action. Otherwise add the build index action.
|
||||
if (drop_it != recovery_data->indexes.end()) {
|
||||
recovery_data->indexes.erase(drop_it);
|
||||
} else {
|
||||
recovery_data->indexes.emplace_back(
|
||||
IndexRecoveryData{delta.label_name, delta.property_name,
|
||||
/*create = */ true, delta.unique});
|
||||
}
|
||||
break;
|
||||
case database::StateDelta::Type::DROP_INDEX:
|
||||
recovery_data->indexes.emplace_back(
|
||||
IndexRecoveryData{delta.label_name, delta.property_name,
|
||||
/*create = */ false});
|
||||
}
|
||||
case database::StateDelta::Type::DROP_INDEX: {
|
||||
auto build_it = std::find_if(
|
||||
recovery_data->indexes.begin(), recovery_data->indexes.end(),
|
||||
[label = delta.label_name, property = delta.property_name](
|
||||
const IndexRecoveryData &other) {
|
||||
return other.label == label && other.property == property &&
|
||||
other.create == true;
|
||||
});
|
||||
|
||||
// If we already have a build index in the recovery data, just erase
|
||||
// the build index action. Otherwise add the drop index action.
|
||||
if (build_it != recovery_data->indexes.end()) {
|
||||
recovery_data->indexes.erase(build_it);
|
||||
} else {
|
||||
recovery_data->indexes.emplace_back(
|
||||
IndexRecoveryData{delta.label_name, delta.property_name,
|
||||
/*create = */ false});
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
transactions->Apply(delta);
|
||||
}
|
||||
|
@ -402,17 +402,47 @@ void RecoverWal(const fs::path &durability_dir, database::GraphDb *db,
|
||||
case database::StateDelta::Type::TRANSACTION_COMMIT:
|
||||
transactions->Commit(delta.transaction_id);
|
||||
break;
|
||||
case database::StateDelta::Type::BUILD_INDEX:
|
||||
case database::StateDelta::Type::BUILD_INDEX: {
|
||||
// TODO index building might still be problematic in HA
|
||||
recovery_data->indexes.emplace_back(
|
||||
IndexRecoveryData{delta.label_name, delta.property_name,
|
||||
/*create = */ true, delta.unique});
|
||||
auto drop_it = std::find_if(
|
||||
recovery_data->indexes.begin(), recovery_data->indexes.end(),
|
||||
[label = delta.label_name, property = delta.property_name](
|
||||
const IndexRecoveryData &other) {
|
||||
return other.label == label && other.property == property &&
|
||||
other.create == false;
|
||||
});
|
||||
|
||||
// If we already have a drop index in the recovery data, just erase
|
||||
// the drop index action. Otherwise add the build index action.
|
||||
if (drop_it != recovery_data->indexes.end()) {
|
||||
recovery_data->indexes.erase(drop_it);
|
||||
} else {
|
||||
recovery_data->indexes.emplace_back(
|
||||
IndexRecoveryData{delta.label_name, delta.property_name,
|
||||
/*create = */ true, delta.unique});
|
||||
}
|
||||
break;
|
||||
case database::StateDelta::Type::DROP_INDEX:
|
||||
recovery_data->indexes.emplace_back(
|
||||
IndexRecoveryData{delta.label_name, delta.property_name,
|
||||
/*create = */ false});
|
||||
}
|
||||
case database::StateDelta::Type::DROP_INDEX: {
|
||||
auto build_it = std::find_if(
|
||||
recovery_data->indexes.begin(), recovery_data->indexes.end(),
|
||||
[label = delta.label_name, property = delta.property_name](
|
||||
const IndexRecoveryData &other) {
|
||||
return other.label == label && other.property == property &&
|
||||
other.create == true;
|
||||
});
|
||||
|
||||
// If we already have a build index in the recovery data, just erase
|
||||
// the build index action. Otherwise add the drop index action.
|
||||
if (build_it != recovery_data->indexes.end()) {
|
||||
recovery_data->indexes.erase(build_it);
|
||||
} else {
|
||||
recovery_data->indexes.emplace_back(
|
||||
IndexRecoveryData{delta.label_name, delta.property_name,
|
||||
/*create = */ false});
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
transactions->Apply(delta);
|
||||
}
|
||||
|
@ -811,8 +811,9 @@ TEST_F(Durability, SequentialRecovery) {
|
||||
return threads;
|
||||
};
|
||||
|
||||
auto make_updates = [&run_updates, this](
|
||||
database::GraphDb &db, bool snapshot_during, bool snapshot_after) {
|
||||
auto make_updates = [&run_updates, this](database::GraphDb &db,
|
||||
bool snapshot_during,
|
||||
bool snapshot_after) {
|
||||
std::atomic<bool> keep_running{true};
|
||||
auto update_theads = run_updates(db, keep_running);
|
||||
std::this_thread::sleep_for(25ms);
|
||||
@ -907,6 +908,82 @@ TEST_F(Durability, MoveToBackupWal) {
|
||||
ASSERT_TRUE(durability::ContainsDurabilityFiles(backup_dir_));
|
||||
}
|
||||
|
||||
TEST_F(Durability, UniqueConstraintRecoverySnapshotAndWal) {
|
||||
auto config = DbConfig();
|
||||
config.durability_enabled = true;
|
||||
database::GraphDb db{config};
|
||||
{
|
||||
auto dba = db.Access();
|
||||
auto label = dba->Label("A");
|
||||
auto property = dba->Property("x");
|
||||
|
||||
dba->BuildIndex(label, property, true);
|
||||
|
||||
auto v0 = dba->InsertVertex();
|
||||
v0.add_label(label);
|
||||
v0.PropsSet(property, 5);
|
||||
|
||||
dba->Commit();
|
||||
}
|
||||
// create snapshot with build index and vertex
|
||||
MakeSnapshot(db);
|
||||
|
||||
{
|
||||
auto dba = db.Access();
|
||||
auto label = dba->Label("A");
|
||||
auto property = dba->Property("x");
|
||||
|
||||
dba->DeleteIndex(label, property);
|
||||
|
||||
auto v0 = dba->InsertVertex();
|
||||
v0.add_label(label);
|
||||
v0.PropsSet(property, 5);
|
||||
|
||||
dba->Commit();
|
||||
}
|
||||
// create wal with drop index and vertex
|
||||
db.wal().Flush();
|
||||
|
||||
{
|
||||
auto recovered_config = DbConfig();
|
||||
recovered_config.db_recover_on_startup = true;
|
||||
database::GraphDb recovered{recovered_config};
|
||||
CompareDbs(db, recovered);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Durability, UniqueConstraintRecoveryWal) {
|
||||
auto config = DbConfig();
|
||||
config.durability_enabled = true;
|
||||
database::GraphDb db{config};
|
||||
{
|
||||
auto dba = db.Access();
|
||||
auto label = dba->Label("A");
|
||||
auto property = dba->Property("x");
|
||||
|
||||
dba->BuildIndex(label, property, true);
|
||||
|
||||
auto v0 = dba->InsertVertex();
|
||||
v0.add_label(label);
|
||||
v0.PropsSet(property, 5);
|
||||
|
||||
dba->DeleteIndex(label, property);
|
||||
|
||||
auto v1 = dba->InsertVertex();
|
||||
v1.add_label(label);
|
||||
v1.PropsSet(property, 5);
|
||||
|
||||
dba->Commit();
|
||||
}
|
||||
db.wal().Flush();
|
||||
{
|
||||
auto recovered_config = DbConfig();
|
||||
recovered_config.db_recover_on_startup = true;
|
||||
database::GraphDb recovered{recovered_config};
|
||||
CompareDbs(db, recovered);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
Loading…
Reference in New Issue
Block a user