diff options
| author | Randolph Tan <randolph@10gen.com> | 2015-06-15 16:07:15 -0400 |
|---|---|---|
| committer | Randolph Tan <randolph@10gen.com> | 2015-06-17 15:27:45 -0400 |
| commit | 63b4dff0e2496b610de26d160b9288314795ced0 (patch) | |
| tree | b2625d43b5caa3b4b45d3c71cb49d38fbf7f6ee7 | |
| parent | e8dd921f644576193ffa6e7df65efbbf4a5a68f1 (diff) | |
| download | mongo-63b4dff0e2496b610de26d160b9288314795ced0.tar.gz | |
SERVER-18525 Mock out tick source in replset_dist_lock_manager_test
| -rw-r--r-- | src/mongo/db/service_context.cpp | 8 | ||||
| -rw-r--r-- | src/mongo/db/service_context.h | 13 | ||||
| -rw-r--r-- | src/mongo/s/catalog/dist_lock_catalog_impl.h | 2 | ||||
| -rw-r--r-- | src/mongo/s/catalog/replset/SConscript | 6 | ||||
| -rw-r--r-- | src/mongo/s/catalog/replset/catalog_manager_replica_set_test_fixture.cpp | 11 | ||||
| -rw-r--r-- | src/mongo/s/catalog/replset/replset_dist_lock_manager.cpp | 13 | ||||
| -rw-r--r-- | src/mongo/s/catalog/replset/replset_dist_lock_manager.h | 10 | ||||
| -rw-r--r-- | src/mongo/s/catalog/replset/replset_dist_lock_manager_test.cpp | 38 | ||||
| -rw-r--r-- | src/mongo/util/SConscript | 7 | ||||
| -rw-r--r-- | src/mongo/util/tick_source_mock.cpp | 53 | ||||
| -rw-r--r-- | src/mongo/util/tick_source_mock.h | 59 |
11 files changed, 200 insertions, 20 deletions
diff --git a/src/mongo/db/service_context.cpp b/src/mongo/db/service_context.cpp index feb28ceadb6..745cb2f9d76 100644 --- a/src/mongo/db/service_context.cpp +++ b/src/mongo/db/service_context.cpp @@ -142,6 +142,14 @@ namespace mongo { return UniqueClient(client.release()); } + TickSource* ServiceContext::getTickSource() const { + return _tickSource.get(); + } + + void ServiceContext::setTickSource(std::unique_ptr<TickSource> newSource) { + _tickSource = std::move(newSource); + } + void ServiceContext::ClientDeleter::operator()(Client* client) const { ServiceContext* const service = client->getServiceContext(); { diff --git a/src/mongo/db/service_context.h b/src/mongo/db/service_context.h index accd9232947..7cf48b9861f 100644 --- a/src/mongo/db/service_context.h +++ b/src/mongo/db/service_context.h @@ -36,6 +36,7 @@ #include "mongo/platform/unordered_set.h" #include "mongo/stdx/functional.h" #include "mongo/util/decorable.h" +#include "mongo/util/tick_source.h" namespace mongo { @@ -303,6 +304,16 @@ namespace mongo { */ virtual OpObserver* getOpObserver() = 0; + /** + * Returns the tick source set in this context. + */ + TickSource* getTickSource() const; + + /** + * Replaces the current tick source with a new one. + */ + void setTickSource(std::unique_ptr<TickSource> newSource); + protected: ServiceContext() = default; @@ -323,6 +334,8 @@ namespace mongo { */ std::vector<std::unique_ptr<ClientObserver>> _clientObservers; ClientSet _clients; + + std::unique_ptr<TickSource> _tickSource; }; /** diff --git a/src/mongo/s/catalog/dist_lock_catalog_impl.h b/src/mongo/s/catalog/dist_lock_catalog_impl.h index 7494a8bdb06..4ec349cbfb8 100644 --- a/src/mongo/s/catalog/dist_lock_catalog_impl.h +++ b/src/mongo/s/catalog/dist_lock_catalog_impl.h @@ -40,7 +40,7 @@ namespace mongo { class RemoteCommandRunner; class RemoteCommandTargeter; - class DistLockCatalogImpl: public DistLockCatalog { + class DistLockCatalogImpl final : public DistLockCatalog { public: DistLockCatalogImpl(RemoteCommandTargeter* targeter, RemoteCommandRunner* executor, diff --git a/src/mongo/s/catalog/replset/SConscript b/src/mongo/s/catalog/replset/SConscript index 327aba314d7..15cadcc96d2 100644 --- a/src/mongo/s/catalog/replset/SConscript +++ b/src/mongo/s/catalog/replset/SConscript @@ -19,7 +19,10 @@ env.CppUnitTest( 'replset_dist_lock_manager_test.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/service_context', '$BUILD_DIR/mongo/s/catalog/dist_lock_catalog_mock', + '$BUILD_DIR/mongo/util/foundation', + '$BUILD_DIR/mongo/util/tick_source_mock', 'replset_dist_lock_manager' ] ) @@ -47,7 +50,6 @@ env.CppUnitTest( ], LIBDEPS=[ 'catalog_manager_replica_set', - 'replset_dist_lock_manager', '$BUILD_DIR/mongo/client/remote_command_runner_mock', '$BUILD_DIR/mongo/client/remote_command_targeter_mock', '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init', @@ -55,7 +57,7 @@ env.CppUnitTest( '$BUILD_DIR/mongo/db/repl/replication_executor', '$BUILD_DIR/mongo/dbtests/mocklib', '$BUILD_DIR/mongo/executor/network_interface_mock', - '$BUILD_DIR/mongo/s/catalog/dist_lock_catalog_mock', + '$BUILD_DIR/mongo/s/catalog/dist_lock_manager_mock', '$BUILD_DIR/mongo/s/coreshard', '$BUILD_DIR/mongo/s/mongoscore', ] diff --git a/src/mongo/s/catalog/replset/catalog_manager_replica_set_test_fixture.cpp b/src/mongo/s/catalog/replset/catalog_manager_replica_set_test_fixture.cpp index 9e8108288ba..4b7ebba5adf 100644 --- a/src/mongo/s/catalog/replset/catalog_manager_replica_set_test_fixture.cpp +++ b/src/mongo/s/catalog/replset/catalog_manager_replica_set_test_fixture.cpp @@ -40,9 +40,8 @@ #include "mongo/db/repl/replication_executor.h" #include "mongo/executor/network_interface_mock.h" #include "mongo/executor/task_executor.h" -#include "mongo/s/catalog/dist_lock_catalog_mock.h" +#include "mongo/s/catalog/dist_lock_manager_mock.h" #include "mongo/s/catalog/replset/catalog_manager_replica_set.h" -#include "mongo/s/catalog/replset/replset_dist_lock_manager.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/grid.h" #include "mongo/stdx/memory.h" @@ -74,19 +73,13 @@ namespace mongo { }, executor.get())); - std::unique_ptr<ReplSetDistLockManager> distLockMgr( - stdx::make_unique<ReplSetDistLockManager>("Test", - stdx::make_unique<DistLockCatalogMock>(), - Milliseconds(2), - Seconds(10))); - std::unique_ptr<CatalogManagerReplicaSet> cm( stdx::make_unique<CatalogManagerReplicaSet>()); ASSERT_OK(cm->init(ConnectionString::forReplicaSet("CatalogManagerReplSetTest", { HostAndPort{ "TestHost1" }, HostAndPort{ "TestHost2" } }), - std::move(distLockMgr))); + std::move(stdx::make_unique<DistLockManagerMock>()))); std::unique_ptr<ShardRegistry> shardRegistry( stdx::make_unique<ShardRegistry>(stdx::make_unique<RemoteCommandTargeterFactoryMock>(), diff --git a/src/mongo/s/catalog/replset/replset_dist_lock_manager.cpp b/src/mongo/s/catalog/replset/replset_dist_lock_manager.cpp index 0e29a37c6e9..f756fe9238b 100644 --- a/src/mongo/s/catalog/replset/replset_dist_lock_manager.cpp +++ b/src/mongo/s/catalog/replset/replset_dist_lock_manager.cpp @@ -36,6 +36,7 @@ #include "mongo/base/status.h" #include "mongo/base/status_with.h" +#include "mongo/db/service_context.h" #include "mongo/s/catalog/dist_lock_catalog.h" #include "mongo/s/type_lockpings.h" #include "mongo/s/type_locks.h" @@ -52,10 +53,12 @@ namespace mongo { using stdx::chrono::milliseconds; using std::chrono::duration_cast; - ReplSetDistLockManager::ReplSetDistLockManager(StringData processID, + ReplSetDistLockManager::ReplSetDistLockManager(ServiceContext* globalContext, + StringData processID, unique_ptr<DistLockCatalog> catalog, milliseconds pingInterval, milliseconds lockExpiration): + _serviceContext(globalContext), _processID(processID.toString()), _catalog(std::move(catalog)), _pingInterval(pingInterval), @@ -99,7 +102,7 @@ namespace mongo { << " (sleeping for " << duration_cast<milliseconds>(_pingInterval).count() << " ms)"; - Timer elapsedSincelastPing; + Timer elapsedSincelastPing(_serviceContext->getTickSource()); while (!isShutDown()) { auto pingStatus = _catalog->ping(_processID, Date_t::now()); @@ -158,7 +161,7 @@ namespace mongo { << ": " << errMsg}; } - Timer timer; + Timer timer(_serviceContext->getTickSource()); auto serverInfoStatus = _catalog->getServerInfo(); if (!serverInfoStatus.isOK()) { return serverInfoStatus.getStatus(); @@ -243,8 +246,8 @@ namespace mongo { StringData whyMessage, milliseconds waitFor, milliseconds lockTryInterval) { - Timer timer; - Timer msgTimer; + Timer timer(_serviceContext->getTickSource()); + Timer msgTimer(_serviceContext->getTickSource()); while (waitFor <= milliseconds::zero() || milliseconds(timer.millis()) < waitFor) { OID lockSessionID = OID::gen(); diff --git a/src/mongo/s/catalog/replset/replset_dist_lock_manager.h b/src/mongo/s/catalog/replset/replset_dist_lock_manager.h index 4389c580bd0..4e042e2fa41 100644 --- a/src/mongo/s/catalog/replset/replset_dist_lock_manager.h +++ b/src/mongo/s/catalog/replset/replset_dist_lock_manager.h @@ -43,9 +43,12 @@ namespace mongo { - class ReplSetDistLockManager: public DistLockManager { + class ServiceContext; + + class ReplSetDistLockManager final : public DistLockManager { public: - ReplSetDistLockManager(StringData processID, + ReplSetDistLockManager(ServiceContext* globalContext, + StringData processID, std::unique_ptr<DistLockCatalog> catalog, stdx::chrono::milliseconds pingInterval, stdx::chrono::milliseconds lockExpiration); @@ -94,11 +97,14 @@ namespace mongo { // All member variables are labeled with one of the following codes indicating the // synchronization rules for accessing them. // + // (F) Self synchronizing. // (M) Must hold _mutex for access. // (I) Immutable, no synchronization needed. // (S) Can only be called inside startUp/shutDown. // + ServiceContext* const _serviceContext; // (F) + const std::string _processID; // (I) const std::unique_ptr<DistLockCatalog> _catalog; // (I) const stdx::chrono::milliseconds _pingInterval; // (I) diff --git a/src/mongo/s/catalog/replset/replset_dist_lock_manager_test.cpp b/src/mongo/s/catalog/replset/replset_dist_lock_manager_test.cpp index 36a1f2bc5af..6ad0034beb3 100644 --- a/src/mongo/s/catalog/replset/replset_dist_lock_manager_test.cpp +++ b/src/mongo/s/catalog/replset/replset_dist_lock_manager_test.cpp @@ -40,6 +40,7 @@ #include "mongo/bson/json.h" #include "mongo/bson/util/builder.h" #include "mongo/db/jsobj.h" +#include "mongo/db/service_context_noop.h" #include "mongo/s/catalog/dist_lock_catalog_mock.h" #include "mongo/s/type_lockpings.h" #include "mongo/s/type_locks.h" @@ -47,6 +48,8 @@ #include "mongo/stdx/memory.h" #include "mongo/stdx/mutex.h" #include "mongo/unittest/unittest.h" +#include "mongo/util/system_tick_source.h" +#include "mongo/util/tick_source_mock.h" #include "mongo/util/time_support.h" /** @@ -76,7 +79,11 @@ namespace { _dummyDoNotUse(stdx::make_unique<DistLockCatalogMock>()), _mockCatalog(_dummyDoNotUse.get()), _processID("test"), - _mgr(_processID, std::move(_dummyDoNotUse), kPingInterval, kLockExpiration) { + _mgr(&_context, + _processID, + std::move(_dummyDoNotUse), + kPingInterval, + kLockExpiration) { } /** @@ -100,8 +107,23 @@ namespace { return _processID; } + /** + * Make the mock catalog use the mock tick source. Not thread-safe. + */ + void useMockTickSource() { + _context.setTickSource(stdx::make_unique<TickSourceMock>()); + } + + /** + * Returns the mock tick source. Valid only if useMockTickSource was called. + */ + TickSourceMock* getMockTickSource() { + return dynamic_cast<TickSourceMock*>(_context.getTickSource()); + } + protected: void setUp() override { + _context.setTickSource(stdx::make_unique<SystemTickSource>()); _mgr.startUp(); } @@ -112,9 +134,11 @@ namespace { } private: + TickSourceMock _tickSource; std::unique_ptr<DistLockCatalogMock> _dummyDoNotUse; // dummy placeholder DistLockCatalogMock* _mockCatalog; string _processID; + ServiceContextNoop _context; ReplSetDistLockManager _mgr; }; @@ -217,6 +241,8 @@ namespace { int retryAttempt = 0; const int kMaxRetryAttempt = 3; + useMockTickSource(); + LocksType goodLockDoc; goodLockDoc.setName(lockName); goodLockDoc.setState(LocksType::LOCKED); @@ -251,6 +277,8 @@ namespace { lastTS = lockSessionID; lastTime = time; + getMockTickSource()->advance(Milliseconds(1)); + if (++retryAttempt >= kMaxRetryAttempt) { getMockCatalog()->expectGrabLock([this, &lockName, @@ -350,6 +378,8 @@ namespace { int retryAttempt = 0; const int kMaxRetryAttempt = 3; + useMockTickSource(); + getMockCatalog()->expectGrabLock( [this, &lockName, @@ -375,6 +405,8 @@ namespace { lastTS = lockSessionID; lastTime = time; + getMockTickSource()->advance(Milliseconds(1)); + if (++retryAttempt >= kMaxRetryAttempt) { getMockCatalog()->expectGrabLock([this, &lockName, @@ -480,6 +512,8 @@ namespace { int retryAttempt = 0; + useMockTickSource(); + getMockCatalog()->expectGrabLock( [this, &lockName, @@ -504,6 +538,8 @@ namespace { lastTS = lockSessionID; lastTime = time; retryAttempt++; + + getMockTickSource()->advance(Milliseconds(1)); }, {ErrorCodes::LockStateChangeFailed, "nMod 0"}); // Make mock return lock not found to skip lock overtaking. diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index 6a7705f46b8..bc6e9b0d9bd 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -126,6 +126,13 @@ env.Library( ], ) +env.Library( + target='tick_source_mock', + source=[ + 'tick_source_mock.cpp', + ], +) + env.CppUnitTest( target='text_test', source=[ diff --git a/src/mongo/util/tick_source_mock.cpp b/src/mongo/util/tick_source_mock.cpp new file mode 100644 index 00000000000..63227156d2c --- /dev/null +++ b/src/mongo/util/tick_source_mock.cpp @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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 "mongo/util/tick_source_mock.h" + +namespace mongo { + +namespace { + const TickSource::Tick kTicksPerSecond = 1000; +} // unnamed namespace + + TickSource::Tick TickSourceMock::getTicks() { + return _currentTicks; + } + + TickSource::Tick TickSourceMock::getTicksPerSecond() { + return kTicksPerSecond; + } + + void TickSourceMock::advance(const stdx::chrono::milliseconds& ms) { + _currentTicks += ms.count(); + } + + void TickSourceMock::reset(TickSource::Tick tick) { + _currentTicks = std::move(tick); + } + +} // namespace mongo diff --git a/src/mongo/util/tick_source_mock.h b/src/mongo/util/tick_source_mock.h new file mode 100644 index 00000000000..0ee743f7b3f --- /dev/null +++ b/src/mongo/util/tick_source_mock.h @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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. + */ + +#pragma once + +#include "mongo/stdx/chrono.h" +#include "mongo/util/tick_source.h" + +namespace mongo { + + /** + * Mock tick source with millisecond resolution that doesn't gives a fixed tick count + * until the advance method is called. + */ + class TickSourceMock final : public TickSource { + public: + TickSource::Tick getTicks() override; + + TickSource::Tick getTicksPerSecond() override; + + /** + * Advance the ticks by the given amount of milliseconds. + */ + void advance(const stdx::chrono::milliseconds& ms); + + /** + * Resets the tick count to the give value. + */ + void reset(TickSource::Tick tick); + + private: + TickSource::Tick _currentTicks = 0; + }; +} // namespace mongo |
