summaryrefslogtreecommitdiff
path: root/src/mongo/db/client_out_of_line_executor_test.cpp
diff options
context:
space:
mode:
authorAmirsaman Memaripour <amirsaman.memaripour@mongodb.com>2020-03-20 15:55:07 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-04-16 19:08:39 +0000
commit6ad41d820bc3827aa295c37f14ef0420f44d3f8a (patch)
tree4072cc81814410fe0f99389801c602a43ae8ab34 /src/mongo/db/client_out_of_line_executor_test.cpp
parent54488c22e2ce672a8bdbb2dac68941b958e69b5c (diff)
downloadmongo-6ad41d820bc3827aa295c37f14ef0420f44d3f8a.tar.gz
SERVER-46514 Allow mirroring maestro to leave GC for the client thread
Diffstat (limited to 'src/mongo/db/client_out_of_line_executor_test.cpp')
-rw-r--r--src/mongo/db/client_out_of_line_executor_test.cpp171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/mongo/db/client_out_of_line_executor_test.cpp b/src/mongo/db/client_out_of_line_executor_test.cpp
new file mode 100644
index 00000000000..cffeb633c87
--- /dev/null
+++ b/src/mongo/db/client_out_of_line_executor_test.cpp
@@ -0,0 +1,171 @@
+/**
+ * Copyright (C) 2020-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include <memory>
+
+#include "mongo/db/client.h"
+#include "mongo/db/client_out_of_line_executor.h"
+#include "mongo/db/service_context.h"
+#include "mongo/platform/atomic_word.h"
+#include "mongo/stdx/thread.h"
+#include "mongo/unittest/barrier.h"
+#include "mongo/unittest/unittest.h"
+
+namespace mongo {
+namespace {
+
+/**
+ * The following implements a pseudo garbage collector to test client's out-of-line executor.
+ */
+class ClientOutOfLineExecutorTest : public unittest::Test {
+public:
+ class DummyInstance {
+ public:
+ DummyInstance() = delete;
+
+ DummyInstance(ClientOutOfLineExecutorTest* parent) : _parent(parent) {
+ _parent->_instanceCount.fetchAndAdd(1);
+ }
+
+ DummyInstance(DummyInstance&& other) : _parent(std::move(other._parent)) {
+ _parent->_instanceCount.fetchAndAdd(1);
+ }
+
+ DummyInstance(const DummyInstance& other) {
+ MONGO_UNREACHABLE;
+ }
+
+ ~DummyInstance() {
+ _parent->_instanceCount.fetchAndAdd(-1);
+ }
+
+ private:
+ ClientOutOfLineExecutorTest* _parent;
+ };
+
+ void setUp() override {
+ setGlobalServiceContext(ServiceContext::make());
+ Client::initThread(kClientThreadName);
+ _instanceCount.store(0);
+ }
+
+ void tearDown() override {
+ auto client = Client::releaseCurrent();
+ client.reset(nullptr);
+ }
+
+ auto getDecoration() noexcept {
+ return ClientOutOfLineExecutor::get(Client::getCurrent());
+ }
+
+ int countDummies() const noexcept {
+ return _instanceCount.load();
+ }
+
+ static constexpr auto kClientThreadName = "ClientOutOfLineExecutorTest"_sd;
+
+private:
+ friend class DummyInstance;
+
+ AtomicWord<int> _instanceCount;
+};
+
+TEST_F(ClientOutOfLineExecutorTest, CheckDecoration) {
+ auto decoration = getDecoration();
+ ASSERT(decoration);
+}
+
+TEST_F(ClientOutOfLineExecutorTest, ScheduleAndExecute) {
+ auto thread = stdx::thread([this, handle = getDecoration()->getHandle()]() mutable {
+ DummyInstance dummy(this);
+ handle.schedule([dummy = std::move(dummy)](const Status& status) {
+ ASSERT_OK(status);
+ ASSERT_EQ(getThreadName(), ClientOutOfLineExecutorTest::kClientThreadName);
+ });
+ });
+ thread.join();
+ ASSERT_EQ(countDummies(), 1);
+
+ getDecoration()->consumeAllTasks();
+ ASSERT_EQ(countDummies(), 0);
+}
+
+TEST_F(ClientOutOfLineExecutorTest, DestructorExecutesLeftovers) {
+ const auto kDummiesCount = 8;
+ unittest::Barrier b1(2), b2(2);
+
+ auto thread = stdx::thread([this, kDummiesCount, b1 = &b1, b2 = &b2]() {
+ Client::initThread("ThreadWithLeftovers"_sd);
+
+ auto handle = ClientOutOfLineExecutor::get(Client::getCurrent())->getHandle();
+ for (auto i = 0; i < kDummiesCount; i++) {
+ DummyInstance dummy(this);
+ handle.schedule([dummy = std::move(dummy),
+ threadId = stdx::this_thread::get_id()](const Status& status) {
+ ASSERT(status == ErrorCodes::ClientDisconnect);
+ // Avoid using `getThreadName()` here as it'll cause read-after-delete errors.
+ ASSERT_EQ(threadId, stdx::this_thread::get_id());
+ });
+ }
+
+ b1->countDownAndWait();
+ // Wait for the main thread to count dummies.
+ b2->countDownAndWait();
+ });
+
+ b1.countDownAndWait();
+ ASSERT_EQ(countDummies(), kDummiesCount);
+ b2.countDownAndWait();
+
+ thread.join();
+ ASSERT_EQ(countDummies(), 0);
+}
+
+TEST_F(ClientOutOfLineExecutorTest, ScheduleAfterClientThreadReturns) {
+ ClientOutOfLineExecutor::QueueHandle handle;
+
+ auto thread = stdx::thread([&handle]() mutable {
+ Client::initThread("ClientThread"_sd);
+ handle = ClientOutOfLineExecutor::get(Client::getCurrent())->getHandle();
+ // Return to destroy the client, and close the task queue.
+ });
+
+ thread.join();
+
+ bool taskCalled = false;
+ handle.schedule([&taskCalled, threadName = getThreadName()](const Status& status) {
+ ASSERT(status == ErrorCodes::CallbackCanceled);
+ ASSERT_EQ(getThreadName(), threadName);
+ taskCalled = true;
+ });
+ ASSERT(taskCalled);
+}
+
+} // namespace
+} // namespace mongo