GraphDb - index garbage collection fix
Summary: A single line (graph_db.cpp:109 in the new code) was missing. This should have been done in D355 (made by DGleich, approved by Flor AND Buda AND Mislav :D). Converted a lambda to a method for convenience. Reviewers: buda, dgleich, mislav.bradac Reviewed By: buda Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D665
This commit is contained in:
parent
23652fee15
commit
71d8062af1
@ -33,33 +33,8 @@ GraphDb::GraphDb(const std::string &name, const fs::path &snapshot_db_dir)
|
|||||||
gc_edges_(edges_, edge_record_deleter_, edge_version_list_deleter_) {
|
gc_edges_(edges_, edge_record_deleter_, edge_version_list_deleter_) {
|
||||||
// Pause of -1 means we shouldn't run the GC.
|
// Pause of -1 means we shouldn't run the GC.
|
||||||
if (FLAGS_gc_cycle_sec != -1) {
|
if (FLAGS_gc_cycle_sec != -1) {
|
||||||
gc_scheduler_.Run(std::chrono::seconds(FLAGS_gc_cycle_sec), [this]() {
|
gc_scheduler_.Run(std::chrono::seconds(FLAGS_gc_cycle_sec),
|
||||||
// main garbage collection logic
|
[this]() { CollectGarbage(); });
|
||||||
// see wiki documentation for logic explanation
|
|
||||||
const auto snapshot = this->tx_engine_.GcSnapshot();
|
|
||||||
{
|
|
||||||
// This can be run concurrently
|
|
||||||
this->gc_vertices_.Run(snapshot, this->tx_engine_);
|
|
||||||
this->gc_edges_.Run(snapshot, this->tx_engine_);
|
|
||||||
}
|
|
||||||
// This has to be run sequentially after gc because gc modifies
|
|
||||||
// version_lists and changes the oldest visible record, on which Refresh
|
|
||||||
// depends.
|
|
||||||
{
|
|
||||||
// This can be run concurrently
|
|
||||||
this->labels_index_.Refresh(snapshot, this->tx_engine_);
|
|
||||||
this->edge_types_index_.Refresh(snapshot, this->tx_engine_);
|
|
||||||
}
|
|
||||||
// we free expired objects with snapshot.back(), which is
|
|
||||||
// the ID of the oldest active transaction (or next active, if there
|
|
||||||
// are no currently active). that's legal because that was the
|
|
||||||
// last possible transaction that could have obtained pointers
|
|
||||||
// to those records
|
|
||||||
this->edge_record_deleter_.FreeExpiredObjects(snapshot.back());
|
|
||||||
this->vertex_record_deleter_.FreeExpiredObjects(snapshot.back());
|
|
||||||
this->edge_version_list_deleter_.FreeExpiredObjects(snapshot.back());
|
|
||||||
this->vertex_version_list_deleter_.FreeExpiredObjects(snapshot.back());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RecoverDatabase(snapshot_db_dir);
|
RecoverDatabase(snapshot_db_dir);
|
||||||
@ -115,6 +90,35 @@ void GraphDb::RecoverDatabase(const fs::path &snapshot_db_dir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphDb::CollectGarbage() {
|
||||||
|
// main garbage collection logic
|
||||||
|
// see wiki documentation for logic explanation
|
||||||
|
const auto snapshot = this->tx_engine_.GcSnapshot();
|
||||||
|
{
|
||||||
|
// This can be run concurrently
|
||||||
|
this->gc_vertices_.Run(snapshot, this->tx_engine_);
|
||||||
|
this->gc_edges_.Run(snapshot, this->tx_engine_);
|
||||||
|
}
|
||||||
|
// This has to be run sequentially after gc because gc modifies
|
||||||
|
// version_lists and changes the oldest visible record, on which Refresh
|
||||||
|
// depends.
|
||||||
|
{
|
||||||
|
// This can be run concurrently
|
||||||
|
this->labels_index_.Refresh(snapshot, this->tx_engine_);
|
||||||
|
this->edge_types_index_.Refresh(snapshot, this->tx_engine_);
|
||||||
|
this->label_property_index_.Refresh(snapshot, this->tx_engine_);
|
||||||
|
}
|
||||||
|
// we free expired objects with snapshot.back(), which is
|
||||||
|
// the ID of the oldest active transaction (or next active, if there
|
||||||
|
// are no currently active). that's legal because that was the
|
||||||
|
// last possible transaction that could have obtained pointers
|
||||||
|
// to those records
|
||||||
|
this->edge_record_deleter_.FreeExpiredObjects(snapshot.back());
|
||||||
|
this->vertex_record_deleter_.FreeExpiredObjects(snapshot.back());
|
||||||
|
this->edge_version_list_deleter_.FreeExpiredObjects(snapshot.back());
|
||||||
|
this->vertex_version_list_deleter_.FreeExpiredObjects(snapshot.back());
|
||||||
|
}
|
||||||
|
|
||||||
GraphDb::~GraphDb() {
|
GraphDb::~GraphDb() {
|
||||||
// Stop the gc scheduler to not run into race conditions for deletions.
|
// Stop the gc scheduler to not run into race conditions for deletions.
|
||||||
gc_scheduler_.Stop();
|
gc_scheduler_.Stop();
|
||||||
|
@ -67,6 +67,11 @@ class GraphDb {
|
|||||||
*/
|
*/
|
||||||
void RecoverDatabase(const fs::path &snapshot_db_path);
|
void RecoverDatabase(const fs::path &snapshot_db_path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects garbage.
|
||||||
|
*/
|
||||||
|
void CollectGarbage();
|
||||||
|
|
||||||
/** transaction engine related to this database */
|
/** transaction engine related to this database */
|
||||||
tx::Engine tx_engine_;
|
tx::Engine tx_engine_;
|
||||||
|
|
||||||
|
43
tests/unit/graph_db.cpp
Normal file
43
tests/unit/graph_db.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "database/graph_db.hpp"
|
||||||
|
#include "database/graph_db_accessor.hpp"
|
||||||
|
#include "database/graph_db_datatypes.hpp"
|
||||||
|
#include "database/indexes/label_property_index.hpp"
|
||||||
|
|
||||||
|
class GraphDbTest : public testing::Test {
|
||||||
|
protected:
|
||||||
|
GraphDb graph_db{"default", fs::path()};
|
||||||
|
std::unique_ptr<GraphDbAccessor> dba =
|
||||||
|
std::make_unique<GraphDbAccessor>(graph_db);
|
||||||
|
|
||||||
|
void Commit() {
|
||||||
|
dba->Commit();
|
||||||
|
auto dba2 = std::make_unique<GraphDbAccessor>(graph_db);
|
||||||
|
dba.swap(dba2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(GraphDbTest, GarbageCollectIndices) {
|
||||||
|
auto label = dba->Label("label");
|
||||||
|
auto property = dba->Property("property");
|
||||||
|
dba->BuildIndex(label, property);
|
||||||
|
Commit();
|
||||||
|
|
||||||
|
auto vertex = dba->InsertVertex();
|
||||||
|
vertex.add_label(label);
|
||||||
|
vertex.PropsSet(property, 42);
|
||||||
|
Commit();
|
||||||
|
|
||||||
|
EXPECT_EQ(dba->VerticesCount(label, property), 1);
|
||||||
|
auto vertex_transferred = dba->Transfer(vertex);
|
||||||
|
dba->RemoveVertex(vertex_transferred.value());
|
||||||
|
EXPECT_EQ(dba->VerticesCount(label, property), 1);
|
||||||
|
Commit();
|
||||||
|
EXPECT_EQ(dba->VerticesCount(label, property), 1);
|
||||||
|
graph_db.CollectGarbage();
|
||||||
|
EXPECT_EQ(dba->VerticesCount(label, property), 0);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user