summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandolph Tan <randolph@10gen.com>2015-06-15 16:07:15 -0400
committerRandolph Tan <randolph@10gen.com>2015-06-17 15:27:45 -0400
commit63b4dff0e2496b610de26d160b9288314795ced0 (patch)
treeb2625d43b5caa3b4b45d3c71cb49d38fbf7f6ee7
parente8dd921f644576193ffa6e7df65efbbf4a5a68f1 (diff)
downloadmongo-63b4dff0e2496b610de26d160b9288314795ced0.tar.gz
SERVER-18525 Mock out tick source in replset_dist_lock_manager_test
-rw-r--r--src/mongo/db/service_context.cpp8
-rw-r--r--src/mongo/db/service_context.h13
-rw-r--r--src/mongo/s/catalog/dist_lock_catalog_impl.h2
-rw-r--r--src/mongo/s/catalog/replset/SConscript6
-rw-r--r--src/mongo/s/catalog/replset/catalog_manager_replica_set_test_fixture.cpp11
-rw-r--r--src/mongo/s/catalog/replset/replset_dist_lock_manager.cpp13
-rw-r--r--src/mongo/s/catalog/replset/replset_dist_lock_manager.h10
-rw-r--r--src/mongo/s/catalog/replset/replset_dist_lock_manager_test.cpp38
-rw-r--r--src/mongo/util/SConscript7
-rw-r--r--src/mongo/util/tick_source_mock.cpp53
-rw-r--r--src/mongo/util/tick_source_mock.h59
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