Summary:
Rare TSAN and valgrind failures are caused by unnecessary
reading of a field on the TaskLimiterToken::limiter_ for an assertion
after the token has been released and the limiter destroyed. To simplify
we can simply destroy the token before triggering DB shutdown
(potentially destroying the limiter). This makes the ReleaseOnce logic
unnecessary.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/8567
Test Plan: watch for more failures in CI
Reviewed By: ajkr
Differential Revision:
D29811795
Pulled By: pdillinger
fbshipit-source-id:
135549ebb98fe4f176d1542ed85d5bd6350a40b3
if (prepicked_compaction != nullptr &&
prepicked_compaction->task_token != nullptr) {
- // Releasing task tokens affects the DB state, so must be done before we
- // potentially signal the DB close process to proceed below.
- prepicked_compaction->task_token->ReleaseOnce();
+ // Releasing task tokens affects (and asserts on) the DB state, so
+ // must be done before we potentially signal the DB close process to
+ // proceed below.
+ prepicked_compaction->task_token.reset();
+ ;
}
if (made_progress ||
return new ConcurrentTaskLimiterImpl(name, limit);
}
-void TaskLimiterToken::ReleaseOnce() {
- if (!released_) {
- --limiter_->outstanding_tasks_;
- released_ = true;
- }
+TaskLimiterToken::~TaskLimiterToken() {
+ --limiter_->outstanding_tasks_;
assert(limiter_->outstanding_tasks_ >= 0);
}
-TaskLimiterToken::~TaskLimiterToken() { ReleaseOnce(); }
-
} // namespace ROCKSDB_NAMESPACE
class TaskLimiterToken {
public:
explicit TaskLimiterToken(ConcurrentTaskLimiterImpl* limiter)
- : limiter_(limiter), released_(false) {}
+ : limiter_(limiter) {}
~TaskLimiterToken();
- // Releases the token from the `ConcurrentTaskLimiterImpl` if not already
- // released.
- // Not thread-safe.
- void ReleaseOnce();
private:
ConcurrentTaskLimiterImpl* limiter_;
- bool released_;
// no copying allowed
TaskLimiterToken(const TaskLimiterToken&) = delete;