-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: Change recursive_mutex to mutex in DatabaseRotatingImp #5276
base: develop
Are you sure you want to change the base?
Changes from all commits
ce650ad
b8413ae
063e881
9f564bc
d912b50
3f7fb66
4de9be2
3b6984c
52b68da
b90f65f
925c311
217bc1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
|
||
#include <xrpld/nodestore/detail/DatabaseRotatingImp.h> | ||
#include <xrpl/protocol/HashPrefix.h> | ||
#include <boost/thread/locks.hpp> | ||
|
||
namespace ripple { | ||
namespace NodeStore { | ||
|
@@ -33,45 +34,68 @@ DatabaseRotatingImp::DatabaseRotatingImp( | |
: DatabaseRotating(scheduler, readThreads, config, j) | ||
, writableBackend_(std::move(writableBackend)) | ||
, archiveBackend_(std::move(archiveBackend)) | ||
, unitTest_(get<bool>(config, unitTestFlag, false)) | ||
{ | ||
if (writableBackend_) | ||
fdRequired_ += writableBackend_->fdRequired(); | ||
if (archiveBackend_) | ||
fdRequired_ += archiveBackend_->fdRequired(); | ||
} | ||
|
||
void | ||
[[nodiscard]] bool | ||
DatabaseRotatingImp::rotateWithLock( | ||
std::function<std::unique_ptr<NodeStore::Backend>( | ||
std::string const& writableBackendName)> const& f) | ||
{ | ||
std::lock_guard lock(mutex_); | ||
// This function should be the only one taking any kind of unique/write | ||
// lock, and should only be called once at a time by its syncronous caller. | ||
Comment on lines
+50
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are the consequences if the synchronous caller calls it multiple times? Can we protect against that, or at least detect it, and would it make sense to do so? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If it calls them sequentially, then it'll just rotate multiple times, which would be dumb. If it calls them in parallel, all but one will fail. If it calls it recursively through the callback, the recursive call will fail. I've added test cases that demonstrate all three of those possibilities, though the focus is on the latter two. |
||
|
||
// The upgradable lock will NOT block shared locks, but will block other | ||
// upgrade locks and unique/exclusive locks. | ||
boost::upgrade_lock upgradeableLock(mutex_, boost::defer_lock); | ||
if (!upgradeableLock.try_lock()) | ||
{ | ||
// If anything other than a unit test gets here, something has gone very | ||
// wrong | ||
XRPL_ASSERT( | ||
unitTest_, | ||
"ripple::NodeStore::DatabaseRotatingImp::rotateWithLock " | ||
"unit testing"); | ||
return false; | ||
} | ||
auto newBackend = f(writableBackend_->getName()); | ||
|
||
// boost::upgrade_mutex guarantees that only one thread can have "upgrade | ||
// ownership" at a time, so this is 100% safe, and guaranteed to avoid | ||
// deadlock. | ||
boost::upgrade_to_unique_lock writeLock(upgradeableLock); | ||
|
||
archiveBackend_->setDeletePath(); | ||
archiveBackend_ = std::move(writableBackend_); | ||
writableBackend_ = std::move(newBackend); | ||
|
||
return true; | ||
} | ||
|
||
std::string | ||
DatabaseRotatingImp::getName() const | ||
{ | ||
std::lock_guard lock(mutex_); | ||
boost::shared_lock lock(mutex_); | ||
return writableBackend_->getName(); | ||
} | ||
|
||
std::int32_t | ||
DatabaseRotatingImp::getWriteLoad() const | ||
{ | ||
std::lock_guard lock(mutex_); | ||
boost::shared_lock lock(mutex_); | ||
return writableBackend_->getWriteLoad(); | ||
} | ||
|
||
void | ||
DatabaseRotatingImp::importDatabase(Database& source) | ||
{ | ||
auto const backend = [&] { | ||
std::lock_guard lock(mutex_); | ||
boost::shared_lock lock(mutex_); | ||
return writableBackend_; | ||
}(); | ||
|
||
|
@@ -81,7 +105,7 @@ DatabaseRotatingImp::importDatabase(Database& source) | |
void | ||
DatabaseRotatingImp::sync() | ||
{ | ||
std::lock_guard lock(mutex_); | ||
boost::shared_lock lock(mutex_); | ||
writableBackend_->sync(); | ||
} | ||
|
||
|
@@ -95,7 +119,7 @@ DatabaseRotatingImp::store( | |
auto nObj = NodeObject::createObject(type, std::move(data), hash); | ||
|
||
auto const backend = [&] { | ||
std::lock_guard lock(mutex_); | ||
boost::shared_lock lock(mutex_); | ||
return writableBackend_; | ||
}(); | ||
|
||
|
@@ -149,7 +173,7 @@ DatabaseRotatingImp::fetchNodeObject( | |
std::shared_ptr<NodeObject> nodeObject; | ||
|
||
auto [writable, archive] = [&] { | ||
std::lock_guard lock(mutex_); | ||
boost::shared_lock lock(mutex_); | ||
return std::make_pair(writableBackend_, archiveBackend_); | ||
}(); | ||
|
||
|
@@ -163,7 +187,7 @@ DatabaseRotatingImp::fetchNodeObject( | |
{ | ||
{ | ||
// Refresh the writable backend pointer | ||
std::lock_guard lock(mutex_); | ||
boost::shared_lock lock(mutex_); | ||
writable = writableBackend_; | ||
} | ||
|
||
|
@@ -184,7 +208,7 @@ DatabaseRotatingImp::for_each( | |
std::function<void(std::shared_ptr<NodeObject>)> f) | ||
{ | ||
auto [writable, archive] = [&] { | ||
std::lock_guard lock(mutex_); | ||
boost::shared_lock lock(mutex_); | ||
return std::make_pair(writableBackend_, archiveBackend_); | ||
}(); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In line 363 the
clearCaches(validatedSeq)
is already called - is calling it here again needed?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe so because some time could have passed between the two calls, and this helps clear out any entries that were added in that time.