diff options
author | Amirsaman Memaripour <amirsaman.memaripour@mongodb.com> | 2020-03-20 15:55:07 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-04-16 19:08:39 +0000 |
commit | 6ad41d820bc3827aa295c37f14ef0420f44d3f8a (patch) | |
tree | 4072cc81814410fe0f99389801c602a43ae8ab34 /src/mongo/db/client_out_of_line_executor_test.cpp | |
parent | 54488c22e2ce672a8bdbb2dac68941b958e69b5c (diff) | |
download | mongo-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.cpp | 171 |
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 |