Prevent low-likelihood crash on shutdown (RIPD-1392):

The DatabaseImp has threads that asynchronously call JobQueue to
perform database reads.  Formerly these threads had the same
lifespan as Database, which was until the end-of-life of
ApplicationImp.  During shutdown these threads could call JobQueue
after JobQueue had already stopped.  Or, even worse, occasionally
call JobQueue after JobQueue's destructor had run.

To avoid these shutdown conditions, Database is made a Stoppable,
with JobQueue as its parent.  When Database stops, it shuts down
its asynchronous read threads.  This prevents Database from
accessing JobQueue after JobQueue has stopped, but allows
Database to perform stores for the remainder of shutdown.

During development it was noted that the Database::close()
method was never called.  So that method is removed from Database
and all derived classes.

Stoppable is also adjusted so it can be constructed using either
a char const* or a std::string.

For those files touched for other reasons, unneeded #includes
are removed.
This commit is contained in:
Scott Schurr
2017-03-07 10:13:14 -08:00
parent 9ff9fa0aea
commit 9d4500cf69
16 changed files with 107 additions and 171 deletions

View File

@@ -22,7 +22,6 @@
#include <ripple/nodestore/DummyScheduler.h>
#include <ripple/nodestore/Manager.h>
#include <ripple/beast/utility/temp_dir.h>
#include <algorithm>
namespace ripple {
namespace NodeStore {
@@ -34,6 +33,7 @@ public:
std::string const& srcBackendType, std::int64_t seedValue)
{
DummyScheduler scheduler;
RootStoppable parent ("TestRootStoppable");
beast::temp_dir node_db;
Section srcParams;
@@ -49,7 +49,7 @@ public:
// Write to source db
{
std::unique_ptr <Database> src = Manager::instance().make_Database (
"test", scheduler, j, 2, srcParams);
"test", scheduler, 2, parent, srcParams, j);
storeBatch (*src, batch);
}
@@ -58,7 +58,7 @@ public:
{
// Re-open the db
std::unique_ptr <Database> src = Manager::instance().make_Database (
"test", scheduler, j, 2, srcParams);
"test", scheduler, 2, parent, srcParams, j);
// Set up the destination database
beast::temp_dir dest_db;
@@ -67,7 +67,7 @@ public:
destParams.set ("path", dest_db.path());
std::unique_ptr <Database> dest = Manager::instance().make_Database (
"test", scheduler, j, 2, destParams);
"test", scheduler, 2, parent, destParams, j);
testcase ("import into '" + destBackendType +
"' from '" + srcBackendType + "'");
@@ -93,6 +93,7 @@ public:
int numObjectsToTest = 2000)
{
DummyScheduler scheduler;
RootStoppable parent ("TestRootStoppable");
std::string s = "NodeStore backend '" + type + "'";
@@ -114,7 +115,7 @@ public:
{
// Open the database
std::unique_ptr <Database> db = Manager::instance().make_Database (
"test", scheduler, j, 2, nodeParams);
"test", scheduler, 2, parent, nodeParams, j);
// Write the batch
storeBatch (*db, batch);
@@ -143,7 +144,7 @@ public:
{
// Re-open the database without the ephemeral DB
std::unique_ptr <Database> db = Manager::instance().make_Database (
"test", scheduler, j, 2, nodeParams);
"test", scheduler, 2, parent, nodeParams, j);
// Read it back in
Batch copy;