diff options
author | Waley Chen <waleycz@gmail.com> | 2016-04-15 02:58:33 -0400 |
---|---|---|
committer | Waley Chen <waleycz@gmail.com> | 2016-04-15 02:58:33 -0400 |
commit | c2041cd99ea8ff1aa8bfba2d4bcb3bbd2ea7932c (patch) | |
tree | 1a7b9828a9883d470c5f85322371eff738279731 /src/mongo | |
parent | 7850673c0303b740ecdd2b8718d8c745e25884b3 (diff) | |
download | mongo-c2041cd99ea8ff1aa8bfba2d4bcb3bbd2ea7932c.tar.gz |
SERVER-23243 Extract time-keeping from Listener
BackgroundThreadClockSource & FastClockSourceFactory
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/service_context.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/service_context.h | 28 | ||||
-rw-r--r-- | src/mongo/util/SConscript | 22 | ||||
-rw-r--r-- | src/mongo/util/background_thread_clock_source.cpp | 80 | ||||
-rw-r--r-- | src/mongo/util/background_thread_clock_source.h | 73 | ||||
-rw-r--r-- | src/mongo/util/background_thread_clock_source_test.cpp | 67 | ||||
-rw-r--r-- | src/mongo/util/fast_clock_source_factory.cpp | 49 | ||||
-rw-r--r-- | src/mongo/util/fast_clock_source_factory.h | 50 |
9 files changed, 377 insertions, 1 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 0b65fb199a5..4dfa9e23441 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -250,6 +250,7 @@ mongodLibDeps = [ "db/repl/storage_interface_impl", "executor/network_interface_factory", 's/commands/shared_cluster_commands', + "util/clock_sources", "util/ntservice", ] diff --git a/src/mongo/db/service_context.cpp b/src/mongo/db/service_context.cpp index 075fafd7360..5bcf655cb93 100644 --- a/src/mongo/db/service_context.cpp +++ b/src/mongo/db/service_context.cpp @@ -147,6 +147,10 @@ TickSource* ServiceContext::getTickSource() const { return _tickSource.get(); } +ClockSource* ServiceContext::getFastClockSource() const { + return _fastClockSource.get(); +} + ClockSource* ServiceContext::getPreciseClockSource() const { return _preciseClockSource.get(); } @@ -155,6 +159,10 @@ void ServiceContext::setTickSource(std::unique_ptr<TickSource> newSource) { _tickSource = std::move(newSource); } +void ServiceContext::setFastClockSource(std::unique_ptr<ClockSource> newSource) { + _fastClockSource = std::move(newSource); +} + void ServiceContext::setPreciseClockSource(std::unique_ptr<ClockSource> newSource) { _preciseClockSource = std::move(newSource); } diff --git a/src/mongo/db/service_context.h b/src/mongo/db/service_context.h index 4a5b54bb6c7..6bf652eec43 100644 --- a/src/mongo/db/service_context.h +++ b/src/mongo/db/service_context.h @@ -35,8 +35,8 @@ #include "mongo/db/storage/storage_engine.h" #include "mongo/platform/unordered_set.h" #include "mongo/stdx/functional.h" -#include "mongo/util/decorable.h" #include "mongo/util/clock_source.h" +#include "mongo/util/decorable.h" #include "mongo/util/tick_source.h" namespace mongo { @@ -312,6 +312,16 @@ public: * Returns the tick/clock source set in this context. */ TickSource* getTickSource() const; + + /** + * Get a ClockSource implementation that may be less precise than the _preciseClockSource but + * may be cheaper to call. + */ + ClockSource* getFastClockSource() const; + + /** + * Get a ClockSource implementation that is very precise but may be expensive to call. + */ ClockSource* getPreciseClockSource() const; /** @@ -321,6 +331,12 @@ public: void setTickSource(std::unique_ptr<TickSource> newSource); /** + * Call this method with a ClockSource implementation that may be less precise than + * the _preciseClockSource but may be cheaper to call. + */ + void setFastClockSource(std::unique_ptr<ClockSource> newSource); + + /** * Call this method with a ClockSource implementation that is very precise but * may be expensive to call. */ @@ -348,6 +364,16 @@ private: ClientSet _clients; std::unique_ptr<TickSource> _tickSource; + + /** + * A ClockSource implementation that may be less precise than the _preciseClockSource but + * may be cheaper to call. + */ + std::unique_ptr<ClockSource> _fastClockSource; + + /** + * A ClockSource implementation that is very precise but may be expensive to call. + */ std::unique_ptr<ClockSource> _preciseClockSource; }; diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index 60cf152be60..e03426cfdb3 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -293,6 +293,28 @@ env.Library( ], ) +env.Library( + target='clock_sources', + source=[ + 'background_thread_clock_source.cpp', + 'fast_clock_source_factory.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + ], +) + +env.CppUnitTest( + target='background_thread_clock_source_test', + source=[ + 'background_thread_clock_source_test.cpp', + ], + LIBDEPS=[ + 'clock_source_mock', + 'clock_sources', + ], +) + if env.TargetOSIs('windows'): env.CppUnitTest( target='ntservice_test', diff --git a/src/mongo/util/background_thread_clock_source.cpp b/src/mongo/util/background_thread_clock_source.cpp new file mode 100644 index 00000000000..96dececff9c --- /dev/null +++ b/src/mongo/util/background_thread_clock_source.cpp @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2016 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/platform/basic.h" + +#include "mongo/util/background_thread_clock_source.h" + +#include <chrono> +#include <thread> + +#include "mongo/stdx/memory.h" +#include "mongo/stdx/thread.h" +#include "mongo/util/time_support.h" + +namespace mongo { + +BackgroundThreadClockSource::BackgroundThreadClockSource(std::unique_ptr<ClockSource> clockSource, + Milliseconds granularity) + : _clockSource(std::move(clockSource)), _granularity(granularity), _shutdownTimer(false) { + _updateCurrent(); + _startTimerThread(); +} + +BackgroundThreadClockSource::~BackgroundThreadClockSource() { + { + stdx::unique_lock<stdx::mutex> lock(_mutex); + _shutdownTimer = true; + _condition.notify_one(); + } + + _timer.join(); +} + +Date_t BackgroundThreadClockSource::now() { + return Date_t::fromMillisSinceEpoch(_current.load()); +} + +void BackgroundThreadClockSource::_startTimerThread() { + // Start the background thread that repeatedly sleeps for the specified duration of milliseconds + // and wakes up to store the current time. + _timer = stdx::thread([&]() { + stdx::unique_lock<stdx::mutex> lock(_mutex); + while (!_shutdownTimer) { + if (_condition.wait_for(lock, _granularity) == stdx::cv_status::timeout) { + _updateCurrent(); + } + } + }); +} + +void BackgroundThreadClockSource::_updateCurrent() { + _current.store(_clockSource->now().toMillisSinceEpoch()); +} + +} // namespace mongo diff --git a/src/mongo/util/background_thread_clock_source.h b/src/mongo/util/background_thread_clock_source.h new file mode 100644 index 00000000000..eecd75c0f4c --- /dev/null +++ b/src/mongo/util/background_thread_clock_source.h @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2016 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 <chrono> +#include <thread> + +#include "mongo/base/disallow_copying.h" +#include "mongo/platform/atomic_word.h" +#include "mongo/util/clock_source.h" +#include "mongo/util/time_support.h" +#include "mongo/stdx/condition_variable.h" +#include "mongo/stdx/memory.h" +#include "mongo/stdx/mutex.h" +#include "mongo/stdx/thread.h" + +namespace mongo { + +/** + * A clock source that uses a periodic timer to build a low-resolution, fast-to-read clock. + * Essentially uses a background thread that repeatedly sleeps for X amount of milliseconds + * and wakes up to store the current time. + */ +class BackgroundThreadClockSource final : public ClockSource { + MONGO_DISALLOW_COPYING(BackgroundThreadClockSource); + +public: + BackgroundThreadClockSource(std::unique_ptr<ClockSource> clockSource, Milliseconds granularity); + ~BackgroundThreadClockSource() override; + Date_t now() override; + +private: + void _startTimerThread(); + void _updateCurrent(); + + const std::unique_ptr<ClockSource> _clockSource; + AtomicInt64 _current; + + const Milliseconds _granularity; + + stdx::mutex _mutex; + stdx::condition_variable _condition; + bool _shutdownTimer; + stdx::thread _timer; +}; + +} // namespace mongo diff --git a/src/mongo/util/background_thread_clock_source_test.cpp b/src/mongo/util/background_thread_clock_source_test.cpp new file mode 100644 index 00000000000..5bd82e4186e --- /dev/null +++ b/src/mongo/util/background_thread_clock_source_test.cpp @@ -0,0 +1,67 @@ +/** + * Copyright (C) 2016 10gen 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/platform/basic.h" + +#include "mongo/stdx/memory.h" +#include "mongo/unittest/unittest.h" +#include "mongo/util/background_thread_clock_source.h" +#include "mongo/util/clock_source.h" +#include "mongo/util/clock_source_mock.h" +#include "mongo/util/time_support.h" + +namespace { + +using namespace mongo; + +TEST(BackgroundThreadClockSource, CreateAndTerminate) { + auto clockSource = stdx::make_unique<ClockSourceMock>(); + auto btClockSource = + stdx::make_unique<BackgroundThreadClockSource>(std::move(clockSource), Milliseconds(1)); + btClockSource.reset(); // destroys the clock source + + clockSource = stdx::make_unique<ClockSourceMock>(); + btClockSource = + stdx::make_unique<BackgroundThreadClockSource>(std::move(clockSource), Hours(48)); + btClockSource.reset(); // destroys the clock source +} + +TEST(BackgroundThreadClockSource, TimeKeeping) { + auto clockSource = stdx::make_unique<ClockSourceMock>(); + ClockSourceMock* clockSourceMock = clockSource.get(); + + auto btClockSource = + stdx::make_unique<BackgroundThreadClockSource>(std::move(clockSource), Milliseconds(1)); + ASSERT_EQUALS(btClockSource->now(), clockSourceMock->now()); + + clockSourceMock->advance(Milliseconds(100)); + sleepFor(Milliseconds(10)); // give the btClockSource opportunity to read the new time + ASSERT_EQUALS(btClockSource->now(), clockSourceMock->now()); +} + +} // namespace diff --git a/src/mongo/util/fast_clock_source_factory.cpp b/src/mongo/util/fast_clock_source_factory.cpp new file mode 100644 index 00000000000..f0b7da62c09 --- /dev/null +++ b/src/mongo/util/fast_clock_source_factory.cpp @@ -0,0 +1,49 @@ +/** + * Copyright (C) 2016 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/platform/basic.h" + +#include "mongo/util/fast_clock_source_factory.h" + +#include <memory> + +#include "mongo/stdx/memory.h" +#include "mongo/util/background_thread_clock_source.h" +#include "mongo/util/system_clock_source.h" + +namespace mongo { + +std::unique_ptr<ClockSource> FastClockSourceFactory::create(Milliseconds granularity) { + // TODO: Create the fastest to read wall clock available on the system. + // For now, assume there is no built-in fast wall clock so instead + // create a background-thread-based timer. + return stdx::make_unique<BackgroundThreadClockSource>( + std::move(stdx::make_unique<SystemClockSource>()), granularity); +} + +} // namespace mongo diff --git a/src/mongo/util/fast_clock_source_factory.h b/src/mongo/util/fast_clock_source_factory.h new file mode 100644 index 00000000000..6d6de15d47f --- /dev/null +++ b/src/mongo/util/fast_clock_source_factory.h @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2016 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 <memory> + +#include "mongo/util/time_support.h" + +namespace mongo { + +class ClockSource; + +// Factory that creates the fastest to read wall clock available on the system. +class FastClockSourceFactory { +public: + /** + * Creates the fastest to read wall clock available on the system. + * However, on systems with no built-in fast wall clock, + * creates a background-thread-based clock implementation. + */ + static std::unique_ptr<ClockSource> create(Milliseconds granularity); +}; + +} // namespace mongo |