summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/client_out_of_line_executor.cpp4
-rw-r--r--src/mongo/db/client_out_of_line_executor.h11
-rw-r--r--src/mongo/db/client_out_of_line_executor_test.cpp15
3 files changed, 29 insertions, 1 deletions
diff --git a/src/mongo/db/client_out_of_line_executor.cpp b/src/mongo/db/client_out_of_line_executor.cpp
index e2fe618165f..f82612266ba 100644
--- a/src/mongo/db/client_out_of_line_executor.cpp
+++ b/src/mongo/db/client_out_of_line_executor.cpp
@@ -55,6 +55,8 @@ ClientOutOfLineExecutor::ClientOutOfLineExecutor() noexcept
: _impl{std::make_unique<Impl>()}, _taskQueue{std::make_shared<QueueType>()} {}
ClientOutOfLineExecutor::~ClientOutOfLineExecutor() noexcept {
+ if (!_requireShutdown.load())
+ return;
invariant(_isShutdown);
}
@@ -83,7 +85,7 @@ ClientOutOfLineExecutor* ClientOutOfLineExecutor::get(const Client* client) noex
}
void ClientOutOfLineExecutor::schedule(Task task) {
- _taskQueue->push(std::move(task));
+ getHandle().schedule(std::move(task));
}
void ClientOutOfLineExecutor::consumeAllTasks() noexcept {
diff --git a/src/mongo/db/client_out_of_line_executor.h b/src/mongo/db/client_out_of_line_executor.h
index 08a9a734d82..b0a9e9874c1 100644
--- a/src/mongo/db/client_out_of_line_executor.h
+++ b/src/mongo/db/client_out_of_line_executor.h
@@ -33,6 +33,8 @@
#include <memory>
#include "mongo/db/client.h"
+#include "mongo/platform/atomic_word.h"
+#include "mongo/platform/compiler.h"
#include "mongo/util/out_of_line_executor.h"
#include "mongo/util/producer_consumer_queue.h"
@@ -78,10 +80,19 @@ public:
};
auto getHandle() noexcept {
+ // We always acquire a handle before scheduling tasks on the executor. The following ensures
+ // that acquiring a handle, thus exposing the executor to the outside world, always requires
+ // shutdown. A combination of load/store is preferred over using CAS due to performance
+ // considerations, and considering the fact that overwriting `_requireShutdown` is safe.
+ if (MONGO_unlikely(!_requireShutdown.load()))
+ _requireShutdown.store(true);
return QueueHandle(_taskQueue);
}
private:
+ // Shutdown is not required so long as the executor is not exposed to the outside world.
+ AtomicWord<bool> _requireShutdown{false};
+
class Impl;
std::unique_ptr<Impl> _impl;
diff --git a/src/mongo/db/client_out_of_line_executor_test.cpp b/src/mongo/db/client_out_of_line_executor_test.cpp
index cffeb633c87..a72b3450c66 100644
--- a/src/mongo/db/client_out_of_line_executor_test.cpp
+++ b/src/mongo/db/client_out_of_line_executor_test.cpp
@@ -35,6 +35,7 @@
#include "mongo/platform/atomic_word.h"
#include "mongo/stdx/thread.h"
#include "mongo/unittest/barrier.h"
+#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -167,5 +168,19 @@ TEST_F(ClientOutOfLineExecutorTest, ScheduleAfterClientThreadReturns) {
ASSERT(taskCalled);
}
+TEST_F(ClientOutOfLineExecutorTest, SkipShutdownWhenNoTaskIsScheduled) {
+ ClientOutOfLineExecutor executor;
+}
+
+DEATH_TEST_F(ClientOutOfLineExecutorTest, RequireShutdownAfterAcquiringHandles, "invariant") {
+ ClientOutOfLineExecutor executor;
+ executor.getHandle();
+}
+
+DEATH_TEST_F(ClientOutOfLineExecutorTest, RequireShutdownAfterSchedulingTasks, "invariant") {
+ ClientOutOfLineExecutor executor;
+ executor.schedule([](Status) {});
+}
+
} // namespace
} // namespace mongo