diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2022-03-01 05:42:38 +0000 |
---|---|---|
committer | Henning Baldersheim <balder@yahoo-inc.com> | 2022-03-03 11:39:52 +0000 |
commit | 64c08801e0ac5094fb111c5fe3ea63cc7597506d (patch) | |
tree | a34f000d2743b864e22e322d9ce94b655c86ac97 | |
parent | 6f78fdc9750ad3ac03b14166b6838c628487458c (diff) |
Let the InvocationService drive the clock instead of having its own ticking loop.
Also use sleep_until to get intervals indendant of invoke cost as long as cost is within interval.
This also also saves a clock sample and simplifies implementation.
36 files changed, 131 insertions, 151 deletions
diff --git a/searchcore/src/apps/tests/persistenceconformance_test.cpp b/searchcore/src/apps/tests/persistenceconformance_test.cpp index fd0ace21955..4369666591f 100644 --- a/searchcore/src/apps/tests/persistenceconformance_test.cpp +++ b/searchcore/src/apps/tests/persistenceconformance_test.cpp @@ -171,7 +171,6 @@ private: DummyFileHeaderContext _fileHeaderContext; vespalib::string _tlsSpec; matching::QueryLimiter _queryLimiter; - vespalib::Clock _clock; mutable DummyWireService _metricsWireService; mutable MemoryConfigStores _config_stores; vespalib::ThreadStackExecutor _summaryExecutor; @@ -209,7 +208,7 @@ public: tuneFileDocDB, HwInfo()); mgr.forwardConfig(b); mgr.nextGeneration(_shared_service.transport(), 0ms); - return DocumentDB::create(_baseDir, mgr.getConfig(), _tlsSpec, _queryLimiter, _clock, docType, bucketSpace, + return DocumentDB::create(_baseDir, mgr.getConfig(), _tlsSpec, _queryLimiter, docType, bucketSpace, *b->getProtonConfigSP(), const_cast<DocumentDBFactory &>(*this), _shared_service, _bucketExecutor, _tls, _metricsWireService, _fileHeaderContext, _config_stores.getConfigStore(docType.toString()), @@ -223,7 +222,6 @@ DocumentDBFactory::DocumentDBFactory(const vespalib::string &baseDir, int tlsLis _fileHeaderContext(), _tlsSpec(vespalib::make_string("tcp/localhost:%d", tlsListenPort)), _queryLimiter(), - _clock(), _metricsWireService(), _summaryExecutor(8, 128_Ki), _shared_service(_summaryExecutor, _summaryExecutor), diff --git a/searchcore/src/tests/grouping/grouping.cpp b/searchcore/src/tests/grouping/grouping.cpp index 65c7361953e..a08d4703814 100644 --- a/searchcore/src/tests/grouping/grouping.cpp +++ b/searchcore/src/tests/grouping/grouping.cpp @@ -10,6 +10,7 @@ #include <vespa/searchcore/grouping/groupingsession.h> #include <vespa/searchcore/proton/matching/sessionmanager.h> #include <vespa/searchlib/test/mock_attribute_context.h> +#include <vespa/vespalib/util/testclock.h> #include <iostream> #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/log/log.h> @@ -111,7 +112,7 @@ private: }; struct DoomFixture { - vespalib::Clock clock; + vespalib::TestClock clock; steady_time timeOfDoom; DoomFixture() : clock(), timeOfDoom(steady_time::max()) {} }; @@ -168,7 +169,7 @@ TEST_F("testGroupingContextInitialization", DoomFixture()) { nos << (uint32_t)1; baseRequest.serialize(nos); - GroupingContext context(f1.clock, f1.timeOfDoom, os.data(), os.size()); + GroupingContext context(f1.clock.clock(), f1.timeOfDoom, os.data(), os.size()); ASSERT_TRUE(!context.empty()); GroupingContext::GroupingList list = context.getGroupingList(); ASSERT_TRUE(list.size() == 1); @@ -198,7 +199,7 @@ TEST_F("testGroupingContextUsage", DoomFixture()) { GroupingContext::GroupingPtr r1(new Grouping(request1)); GroupingContext::GroupingPtr r2(new Grouping(request2)); - GroupingContext context(f1.clock, f1.timeOfDoom); + GroupingContext context(f1.clock.clock(), f1.timeOfDoom); ASSERT_TRUE(context.empty()); context.addGrouping(r1); ASSERT_TRUE(context.getGroupingList().size() == 1); @@ -220,7 +221,7 @@ TEST_F("testGroupingContextSerializing", DoomFixture()) { nos << (uint32_t)1; baseRequest.serialize(nos); - GroupingContext context(f1.clock, f1.timeOfDoom); + GroupingContext context(f1.clock.clock(), f1.timeOfDoom); GroupingContext::GroupingPtr bp(new Grouping(baseRequest)); context.addGrouping(bp); context.serialize(); @@ -238,7 +239,7 @@ TEST_F("testGroupingManager", DoomFixture()) { .addLevel(createGL(MU<AttributeNode>("attr1"), MU<AttributeNode>("attr2"))) .addLevel(createGL(MU<AttributeNode>("attr2"), MU<AttributeNode>("attr3"))); - GroupingContext context(f1.clock, f1.timeOfDoom); + GroupingContext context(f1.clock.clock(), f1.timeOfDoom); GroupingContext::GroupingPtr bp(new Grouping(request1)); context.addGrouping(bp); GroupingManager manager(context); @@ -273,7 +274,7 @@ TEST_F("testGroupingSession", DoomFixture()) { GroupingContext::GroupingPtr r1(new Grouping(request1)); GroupingContext::GroupingPtr r2(new Grouping(request2)); - GroupingContext initContext(f1.clock, f1.timeOfDoom); + GroupingContext initContext(f1.clock.clock(), f1.timeOfDoom); initContext.addGrouping(r1); initContext.addGrouping(r2); SessionId id("foo"); @@ -305,7 +306,7 @@ TEST_F("testGroupingSession", DoomFixture()) { } // Test second pass { - GroupingContext context(f1.clock, f1.timeOfDoom); + GroupingContext context(f1.clock.clock(), f1.timeOfDoom); GroupingContext::GroupingPtr r(new Grouping(request1)); r->setFirstLevel(1); r->setLastLevel(1); @@ -316,7 +317,7 @@ TEST_F("testGroupingSession", DoomFixture()) { } // Test last pass. Session should be marked as finished { - GroupingContext context(f1.clock, f1.timeOfDoom); + GroupingContext context(f1.clock.clock(), f1.timeOfDoom); GroupingContext::GroupingPtr r(new Grouping(request1)); r->setFirstLevel(2); r->setLastLevel(2); @@ -340,7 +341,7 @@ TEST_F("testEmptySessionId", DoomFixture()) { .addLevel(createGL(MU<AttributeNode>("attr2"), MU<AttributeNode>("attr3"))); GroupingContext::GroupingPtr r1(new Grouping(request1)); - GroupingContext initContext(f1.clock, f1.timeOfDoom); + GroupingContext initContext(f1.clock.clock(), f1.timeOfDoom); initContext.addGrouping(r1); SessionId id; @@ -373,7 +374,7 @@ TEST_F("testSessionManager", DoomFixture()) { .setResult(Int64ResultNode(0)))); GroupingContext::GroupingPtr r1(new Grouping(request1)); - GroupingContext initContext(f1.clock, f1.timeOfDoom); + GroupingContext initContext(f1.clock.clock(), f1.timeOfDoom); initContext.addGrouping(r1); SessionManager mgr(2); @@ -431,7 +432,7 @@ TEST_F("test grouping fork/join", DoomFixture()) { .setLastLevel(1); GroupingContext::GroupingPtr g1(new Grouping(request)); - GroupingContext context(f1.clock, f1.timeOfDoom); + GroupingContext context(f1.clock.clock(), f1.timeOfDoom); context.addGrouping(g1); GroupingSession session(SessionId(), context, world.attributeContext); session.prepareThreadContextCreation(4); @@ -473,8 +474,8 @@ TEST_F("test session timeout", DoomFixture()) { SessionId id1("foo"); SessionId id2("bar"); - GroupingContext initContext1(f1.clock, steady_time(duration(10))); - GroupingContext initContext2(f1.clock, steady_time(duration(20))); + GroupingContext initContext1(f1.clock.clock(), steady_time(duration(10))); + GroupingContext initContext2(f1.clock.clock(), steady_time(duration(20))); GroupingSession::UP s1(new GroupingSession(id1, initContext1, world.attributeContext)); GroupingSession::UP s2(new GroupingSession(id2, initContext2, world.attributeContext)); mgr.insert(std::move(s1)); diff --git a/searchcore/src/tests/proton/docsummary/docsummary.cpp b/searchcore/src/tests/proton/docsummary/docsummary.cpp index faea1cc8b7c..ef8dc17dc0e 100644 --- a/searchcore/src/tests/proton/docsummary/docsummary.cpp +++ b/searchcore/src/tests/proton/docsummary/docsummary.cpp @@ -183,7 +183,6 @@ public: storage::spi::dummy::DummyBucketExecutor _bucketExecutor; bool _mkdirOk; matching::QueryLimiter _queryLimiter; - vespalib::Clock _clock; DummyWireService _dummy; ::config::DirSpec _spec; DocumentDBConfigHelper _configMgr; @@ -204,7 +203,6 @@ public: _bucketExecutor(2), _mkdirOk(FastOS_File::MakeDirectory("tmpdb")), _queryLimiter(), - _clock(), _dummy(), _spec(TEST_PATH("")), _configMgr(_spec, getDocTypeName()), @@ -227,7 +225,7 @@ public: if (! FastOS_File::MakeDirectory((std::string("tmpdb/") + docTypeName).c_str())) { LOG_ABORT("should not be reached"); } - _ddb = DocumentDB::create("tmpdb", _configMgr.getConfig(), "tcp/localhost:9013", _queryLimiter, _clock, + _ddb = DocumentDB::create("tmpdb", _configMgr.getConfig(), "tcp/localhost:9013", _queryLimiter, DocTypeName(docTypeName), makeBucketSpace(), *b->getProtonConfigSP(), *this, _shared_service, _bucketExecutor, _tls, _dummy, _fileHeaderContext, std::make_unique<MemoryConfigStore>(), diff --git a/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp b/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp index 0e9eb926514..9e77047e578 100644 --- a/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp +++ b/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp @@ -28,6 +28,7 @@ #include <vespa/vespalib/io/fileutil.h> #include <vespa/vespalib/util/size_literals.h> #include <vespa/vespalib/util/threadstackexecutor.h> +#include <vespa/vespalib/util/testclock.h> using namespace config; using namespace document; @@ -146,7 +147,7 @@ struct MyDocumentDBReferenceResolver : public IDocumentDBReferenceResolver { struct Fixture { - vespalib::Clock _clock; + vespalib::TestClock _clock; matching::QueryLimiter _queryLimiter; EmptyConstantValueFactory _constantValueFactory; ConstantValueRepo _constantValueRepo; @@ -175,7 +176,7 @@ Fixture::Fixture() vespalib::mkdir(BASE_DIR); initViewSet(_views); _configurer = std::make_unique<Configurer>(_views._summaryMgr, _views.searchView, _views.feedView, _queryLimiter, - _constantValueRepo, _clock, "test", 0); + _constantValueRepo, _clock.clock(), "test", 0); } Fixture::~Fixture() = default; @@ -184,7 +185,7 @@ Fixture::initViewSet(ViewSet &views) { using IndexManager = proton::index::IndexManager; using IndexConfig = proton::index::IndexConfig; - auto matchers = std::make_shared<Matchers>(_clock, _queryLimiter, _constantValueRepo); + auto matchers = std::make_shared<Matchers>(_clock.clock(), _queryLimiter, _constantValueRepo); auto indexMgr = make_shared<IndexManager>(BASE_DIR, IndexConfig(searchcorespi::index::WarmupConfig(), 2, 0), Schema(), 1, views._reconfigurer, views._service.write(), _summaryExecutor, TuneFileIndexManager(), TuneFileAttributes(), views._fileHeaderContext); diff --git a/searchcore/src/tests/proton/documentdb/document_subdbs/document_subdbs_test.cpp b/searchcore/src/tests/proton/documentdb/document_subdbs/document_subdbs_test.cpp index 27636324835..68a92c73b44 100644 --- a/searchcore/src/tests/proton/documentdb/document_subdbs/document_subdbs_test.cpp +++ b/searchcore/src/tests/proton/documentdb/document_subdbs/document_subdbs_test.cpp @@ -35,6 +35,7 @@ #include <vespa/vespalib/util/size_literals.h> #include <vespa/vespalib/util/threadstackexecutor.h> #include <vespa/vespalib/util/destructor_callbacks.h> +#include <vespa/vespalib/util/testclock.h> #include <vespa/config/subscription/sourcespec.h> using namespace cloud::config::filedistribution; @@ -215,9 +216,9 @@ struct MySearchableConfig struct MySearchableContext { MyFastAccessContext _fastUpdCtx; - QueryLimiter _queryLimiter; - vespalib::Clock _clock; - SearchableContext _ctx; + QueryLimiter _queryLimiter; + vespalib::TestClock _clock; + SearchableContext _ctx; MySearchableContext(IThreadingService &writeService, std::shared_ptr<bucketdb::BucketDBOwner> bucketDB, IBucketDBHandlerInitializer & bucketDBHandlerInitializer); @@ -236,7 +237,7 @@ MySearchableContext::MySearchableContext(IThreadingService &writeService, IBucketDBHandlerInitializer & bucketDBHandlerInitializer) : _fastUpdCtx(writeService, bucketDB, bucketDBHandlerInitializer), _queryLimiter(), _clock(), - _ctx(_fastUpdCtx._ctx, _queryLimiter, _clock, writeService.shared()) + _ctx(_fastUpdCtx._ctx, _queryLimiter, _clock.clock(), writeService.shared()) {} MySearchableContext::~MySearchableContext() = default; diff --git a/searchcore/src/tests/proton/documentdb/documentdb_test.cpp b/searchcore/src/tests/proton/documentdb/documentdb_test.cpp index c6a8df79a5e..1f3be7511da 100644 --- a/searchcore/src/tests/proton/documentdb/documentdb_test.cpp +++ b/searchcore/src/tests/proton/documentdb/documentdb_test.cpp @@ -127,7 +127,6 @@ struct Fixture : public FixtureBase { DummyFileHeaderContext _fileHeaderContext; TransLogServer _tls; matching::QueryLimiter _queryLimiter; - vespalib::Clock _clock; std::unique_ptr<ConfigStore> make_config_store(); Fixture(); @@ -151,8 +150,7 @@ Fixture::Fixture(bool file_config) _db(), _fileHeaderContext(), _tls(_shared_service.transport(), "tmp", 9014, ".", _fileHeaderContext), - _queryLimiter(), - _clock() + _queryLimiter() { auto documenttypesConfig = std::make_shared<DocumenttypesConfig>(); DocumentType docType("typea", 0); @@ -167,7 +165,7 @@ Fixture::Fixture(bool file_config) tuneFileDocumentDB, HwInfo()); mgr.forwardConfig(b); mgr.nextGeneration(_shared_service.transport(), 0ms); - _db = DocumentDB::create(".", mgr.getConfig(), "tcp/localhost:9014", _queryLimiter, _clock, DocTypeName("typea"), + _db = DocumentDB::create(".", mgr.getConfig(), "tcp/localhost:9014", _queryLimiter, DocTypeName("typea"), makeBucketSpace(), *b->getProtonConfigSP(), _myDBOwner, _shared_service, _bucketExecutor, _tls, _dummy, _fileHeaderContext, make_config_store(), diff --git a/searchcore/src/tests/proton/matching/matching_test.cpp b/searchcore/src/tests/proton/matching/matching_test.cpp index 09bb67dbac9..187c0463da3 100644 --- a/searchcore/src/tests/proton/matching/matching_test.cpp +++ b/searchcore/src/tests/proton/matching/matching_test.cpp @@ -8,7 +8,6 @@ #include <vespa/searchcore/proton/documentmetastore/documentmetastore.h> #include <vespa/searchcore/proton/matching/fakesearchcontext.h> #include <vespa/searchcore/proton/matching/i_constant_value_repo.h> -#include <vespa/searchcore/proton/matching/isearchcontext.h> #include <vespa/searchcore/proton/matching/matcher.h> #include <vespa/searchcore/proton/matching/querynodes.h> #include <vespa/searchcore/proton/matching/sessionmanager.h> @@ -37,6 +36,7 @@ #include <vespa/eval/eval/tensor_spec.h> #include <vespa/eval/eval/value_codec.h> #include <vespa/vespalib/objects/nbostream.h> +#include <vespa/vespalib/util/testclock.h> #include <vespa/log/log.h> LOG_SETUP("matching_test"); @@ -120,7 +120,7 @@ struct MyWorld { SessionManager::SP sessionManager; DocumentMetaStore metaStore; MatchingStats matchingStats; - vespalib::Clock clock; + vespalib::TestClock clock; QueryLimiter queryLimiter; EmptyConstantValueRepo constantValueRepo; @@ -344,7 +344,7 @@ struct MyWorld { } Matcher::SP createMatcher() { - return std::make_shared<Matcher>(schema, config, clock, queryLimiter, constantValueRepo, RankingExpressions(), OnnxModels(), 0); + return std::make_shared<Matcher>(schema, config, clock.clock(), queryLimiter, constantValueRepo, RankingExpressions(), OnnxModels(), 0); } struct MySearchHandler : ISearchHandler { diff --git a/searchcore/src/tests/proton/matching/request_context/request_context_test.cpp b/searchcore/src/tests/proton/matching/request_context/request_context_test.cpp index 8ede5277d71..191c1718f61 100644 --- a/searchcore/src/tests/proton/matching/request_context/request_context_test.cpp +++ b/searchcore/src/tests/proton/matching/request_context/request_context_test.cpp @@ -6,6 +6,7 @@ #include <vespa/searchcore/proton/matching/requestcontext.h> #include <vespa/searchlib/attribute/attribute_blueprint_params.h> #include <vespa/searchlib/fef/properties.h> +#include <vespa/vespalib/util/testclock.h> #include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/objects/nbostream.h> @@ -29,7 +30,7 @@ public: class RequestContextTest : public ::testing::Test { private: - vespalib::Clock _clock; + vespalib::TestClock _clock; vespalib::Doom _doom; MyAttributeContext _attr_ctx; Properties _props; @@ -45,7 +46,7 @@ private: public: RequestContextTest() : _clock(), - _doom(_clock, vespalib::steady_time(), vespalib::steady_time(), false), + _doom(_clock.clock(), vespalib::steady_time(), vespalib::steady_time(), false), _attr_ctx(), _props(), _request_ctx(_doom, _attr_ctx, _props, AttributeBlueprintParams()), diff --git a/searchcore/src/vespa/searchcore/bmcluster/bm_node.cpp b/searchcore/src/vespa/searchcore/bmcluster/bm_node.cpp index 85fd304f395..86dc38159e8 100644 --- a/searchcore/src/vespa/searchcore/bmcluster/bm_node.cpp +++ b/searchcore/src/vespa/searchcore/bmcluster/bm_node.cpp @@ -451,7 +451,6 @@ class MyBmNode : public BmNode int _distributor_status_port; vespalib::string _tls_spec; proton::matching::QueryLimiter _query_limiter; - vespalib::Clock _clock; proton::DummyWireService _metrics_wire_service; proton::MemoryConfigStores _config_stores; vespalib::ThreadStackExecutor _summary_executor; @@ -516,7 +515,6 @@ MyBmNode::MyBmNode(const vespalib::string& base_dir, int base_port, uint32_t nod _distributor_status_port(port_number(base_port, PortBias::DISTRIBUTOR_STATUS_PORT)), _tls_spec(vespalib::make_string("tcp/localhost:%d", _tls_listen_port)), _query_limiter(), - _clock(), _metrics_wire_service(), _config_stores(), _summary_executor(8, 128_Ki), @@ -591,7 +589,7 @@ MyBmNode::create_document_db(const BmClusterParams& params) tuneFileDocDB, HwInfo()); mgr.forwardConfig(bootstrap_config); mgr.nextGeneration(_shared_service.transport(), 0ms); - _document_db = DocumentDB::create(_base_dir, mgr.getConfig(), _tls_spec, _query_limiter, _clock, _doc_type_name, + _document_db = DocumentDB::create(_base_dir, mgr.getConfig(), _tls_spec, _query_limiter, _doc_type_name, _bucket_space, *bootstrap_config->getProtonConfigSP(), _document_db_owner, _shared_service, *_persistence_engine, _tls, _metrics_wire_service, _file_header_context, diff --git a/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.cpp b/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.cpp index 435b6f718c7..56c3a1c761b 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.cpp +++ b/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.cpp @@ -1,12 +1,14 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "fakesearchcontext.h" +#include <vespa/vespalib/util/testclock.h> + namespace proton::matching { FakeSearchContext::FakeSearchContext(size_t initialNumDocs) - : _clock(), - _doom(_clock, vespalib::steady_time()), + : _clock(std::make_unique<vespalib::TestClock>()), + _doom(_clock->clock(), vespalib::steady_time()), _selector(std::make_shared<search::FixedSourceSelector>(0, "fs", initialNumDocs)), _indexes(std::make_shared<IndexCollection>(_selector)), _attrSearchable(), diff --git a/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.h b/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.h index 254f473c4ae..659bfc6c6d8 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.h +++ b/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.h @@ -11,6 +11,7 @@ #include <map> #include <vector> +namespace vespalib { class TestClock; } namespace proton::matching { using searchcorespi::FakeIndexSearchable; @@ -23,7 +24,7 @@ public: typedef search::queryeval::FakeSearchable FakeSearchable; private: - vespalib::Clock _clock; + std::unique_ptr<vespalib::TestClock> _clock; vespalib::Doom _doom; search::queryeval::ISourceSelector::SP _selector; IndexCollection::SP _indexes; diff --git a/searchcore/src/vespa/searchcore/proton/matching/matcher.cpp b/searchcore/src/vespa/searchcore/proton/matching/matcher.cpp index 4d94d2629fe..e945bbb850b 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/matcher.cpp +++ b/searchcore/src/vespa/searchcore/proton/matching/matcher.cpp @@ -150,7 +150,7 @@ Matcher::create_match_tools_factory(const search::engine::Request &request, ISea : _stats.softDoomFactor()) : 0.95; vespalib::duration safeLeft = std::chrono::duration_cast<vespalib::duration>(request.getTimeLeft() * factor); - vespalib::steady_time safeDoom(_clock.getTimeNSAssumeRunning() + safeLeft); + vespalib::steady_time safeDoom(_clock.getTimeNS() + safeLeft); if (softTimeoutEnabled) { LOG(debug, "Soft-timeout computed factor=%1.3f, used factor=%1.3f, userSupplied=%d, softTimeout=%" PRId64, _stats.softDoomFactor(), factor, hasFactorOverride, vespalib::count_ns(safeLeft)); diff --git a/searchcore/src/vespa/searchcore/proton/server/documentdb.cpp b/searchcore/src/vespa/searchcore/proton/server/documentdb.cpp index cf6193555e5..37a17fecfc1 100644 --- a/searchcore/src/vespa/searchcore/proton/server/documentdb.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/documentdb.cpp @@ -140,7 +140,6 @@ DocumentDB::create(const vespalib::string &baseDir, DocumentDBConfig::SP currentSnapshot, const vespalib::string &tlsSpec, matching::QueryLimiter &queryLimiter, - const vespalib::Clock &clock, const DocTypeName &docTypeName, document::BucketSpace bucketSpace, const ProtonConfig &protonCfg, @@ -155,7 +154,7 @@ DocumentDB::create(const vespalib::string &baseDir, const HwInfo &hwInfo) { return DocumentDB::SP( - new DocumentDB(baseDir, std::move(currentSnapshot), tlsSpec, queryLimiter, clock, docTypeName, bucketSpace, + new DocumentDB(baseDir, std::move(currentSnapshot), tlsSpec, queryLimiter, docTypeName, bucketSpace, protonCfg, owner, shared_service, bucketExecutor, tlsWriterFactory, metricsWireService, fileHeaderContext, std::move(config_store), initializeThreads, hwInfo)); } @@ -163,7 +162,6 @@ DocumentDB::DocumentDB(const vespalib::string &baseDir, DocumentDBConfig::SP configSnapshot, const vespalib::string &tlsSpec, matching::QueryLimiter &queryLimiter, - const vespalib::Clock &clock, const DocTypeName &docTypeName, document::BucketSpace bucketSpace, const ProtonConfig &protonCfg, @@ -219,7 +217,7 @@ DocumentDB::DocumentDB(const vespalib::string &baseDir, _transient_usage_provider(std::make_shared<DocumentDBResourceUsageProvider>(*this)), _feedHandler(std::make_unique<FeedHandler>(_writeService, tlsSpec, docTypeName, *this, _writeFilter, *this, tlsWriterFactory)), _subDBs(*this, *this, *_feedHandler, _docTypeName, _writeService, shared_service.warmup(), fileHeaderContext, - metricsWireService, getMetrics(), queryLimiter, clock, _configMutex, _baseDir, hwInfo), + metricsWireService, getMetrics(), queryLimiter, shared_service.clock(), _configMutex, _baseDir, hwInfo), _maintenanceController(shared_service.transport(), _writeService.master(), shared_service.shared(), _refCount, _docTypeName), _jobTrackers(), _calc(), diff --git a/searchcore/src/vespa/searchcore/proton/server/documentdb.h b/searchcore/src/vespa/searchcore/proton/server/documentdb.h index 2030e6ffac9..e3d467fc3c1 100644 --- a/searchcore/src/vespa/searchcore/proton/server/documentdb.h +++ b/searchcore/src/vespa/searchcore/proton/server/documentdb.h @@ -197,7 +197,6 @@ private: DocumentDBConfig::SP currentSnapshot, const vespalib::string &tlsSpec, matching::QueryLimiter &queryLimiter, - const vespalib::Clock &clock, const DocTypeName &docTypeName, document::BucketSpace bucketSpace, const ProtonConfig &protonCfg, @@ -228,7 +227,6 @@ public: DocumentDBConfig::SP currentSnapshot, const vespalib::string &tlsSpec, matching::QueryLimiter &queryLimiter, - const vespalib::Clock &clock, const DocTypeName &docTypeName, document::BucketSpace bucketSpace, const ProtonConfig &protonCfg, diff --git a/searchcore/src/vespa/searchcore/proton/server/executorthreadingservice.cpp b/searchcore/src/vespa/searchcore/proton/server/executorthreadingservice.cpp index a268a6eac87..d6ecc6dd2d3 100644 --- a/searchcore/src/vespa/searchcore/proton/server/executorthreadingservice.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/executorthreadingservice.cpp @@ -13,6 +13,7 @@ using vespalib::CpuUsage; using vespalib::SequencedTaskExecutor; using vespalib::SingleExecutor; using vespalib::SyncableThreadExecutor; +using vespalib::steady_time; using OptimizeFor = vespalib::Executor::OptimizeFor; using SharedFieldWriterExecutor = proton::ThreadingServiceConfig::SharedFieldWriterExecutor; diff --git a/searchcore/src/vespa/searchcore/proton/server/i_shared_threading_service.h b/searchcore/src/vespa/searchcore/proton/server/i_shared_threading_service.h index a467f9bc320..12377fd25e0 100644 --- a/searchcore/src/vespa/searchcore/proton/server/i_shared_threading_service.h +++ b/searchcore/src/vespa/searchcore/proton/server/i_shared_threading_service.h @@ -7,6 +7,7 @@ namespace vespalib { class ISequencedTaskExecutor; class ThreadExecutor; class InvokeService; +class Clock; } namespace proton { @@ -51,6 +52,11 @@ public: * Returns a shared transport object that can be utilized by multiple services. */ virtual FNET_Transport & transport() = 0; + + /** + * Return a very cheap clock. + */ + virtual const vespalib::Clock & clock() const = 0; }; } diff --git a/searchcore/src/vespa/searchcore/proton/server/proton.cpp b/searchcore/src/vespa/searchcore/proton/server/proton.cpp index 974c2522565..9bf6d19231e 100644 --- a/searchcore/src/vespa/searchcore/proton/server/proton.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/proton.cpp @@ -241,7 +241,6 @@ Proton::Proton(FastOS_ThreadPool & threadPool, FNET_Transport & transport, const _shared_service(), _compile_cache_executor_binding(), _queryLimiter(), - _clock(), _distributionKey(-1), _isInitializing(true), _abortInit(false), @@ -278,7 +277,6 @@ Proton::init(const BootstrapConfig::SP & configSnapshot) setBucketCheckSumType(protonConfig); setFS4Compression(protonConfig); _shared_service = std::make_unique<SharedThreadingService>(SharedThreadingServiceConfig::make(protonConfig, hwInfo.cpu()), _transport); - _clock.start(_shared_service->invokeService()); _diskMemUsageSampler = std::make_unique<DiskMemUsageSampler>(_shared_service->transport(), protonConfig.basedir, diskMemUsageSamplerConfig(protonConfig, hwInfo)); @@ -473,7 +471,6 @@ Proton::~Proton() _persistenceEngine.reset(); _tls.reset(); _compile_cache_executor_binding.reset(); - _clock.stop(); _shared_service.reset(); LOG(debug, "Explicit destructor done"); } @@ -610,7 +607,6 @@ Proton::addDocumentDB(const document::DocumentType &docType, documentDBConfig, config.tlsspec, _queryLimiter, - _clock, docTypeName, bucketSpace, config, diff --git a/searchcore/src/vespa/searchcore/proton/server/proton.h b/searchcore/src/vespa/searchcore/proton/server/proton.h index 73b8ae83ef2..58c9a8bda3e 100644 --- a/searchcore/src/vespa/searchcore/proton/server/proton.h +++ b/searchcore/src/vespa/searchcore/proton/server/proton.h @@ -111,7 +111,6 @@ private: std::unique_ptr<SharedThreadingService> _shared_service; vespalib::eval::CompileCache::ExecutorBinding::UP _compile_cache_executor_binding; matching::QueryLimiter _queryLimiter; - vespalib::Clock _clock; uint32_t _distributionKey; bool _isInitializing; bool _abortInit; diff --git a/searchcore/src/vespa/searchcore/proton/server/shared_threading_service.cpp b/searchcore/src/vespa/searchcore/proton/server/shared_threading_service.cpp index b36dce23e28..cba2c1d458f 100644 --- a/searchcore/src/vespa/searchcore/proton/server/shared_threading_service.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/shared_threading_service.cpp @@ -3,13 +3,11 @@ #include "shared_threading_service.h" #include <vespa/vespalib/util/blockingthreadstackexecutor.h> #include <vespa/vespalib/util/cpu_usage.h> -#include <vespa/vespalib/util/isequencedtaskexecutor.h> #include <vespa/vespalib/util/sequencedtaskexecutor.h> #include <vespa/vespalib/util/size_literals.h> -#include <vespa/fnet/transport.h> -#include <vespa/fastos/thread.h> using vespalib::CpuUsage; +using vespalib::steady_time; VESPA_THREAD_STACK_TAG(proton_field_writer_executor) VESPA_THREAD_STACK_TAG(proton_shared_executor) @@ -28,7 +26,8 @@ SharedThreadingService::SharedThreadingService(const SharedThreadingServiceConfi _field_writer(), _invokeService(std::max(vespalib::adjustTimeoutByDetectedHz(1ms), cfg.field_writer_config().reactionTime())), - _invokeRegistrations() + _invokeRegistrations(), + _clock(_invokeService.nowPtr()) { const auto& fw_cfg = cfg.field_writer_config(); if (fw_cfg.shared_field_writer() == SharedFieldWriterExecutor::DOCUMENT_DB) { diff --git a/searchcore/src/vespa/searchcore/proton/server/shared_threading_service.h b/searchcore/src/vespa/searchcore/proton/server/shared_threading_service.h index 349dcc2d0ce..463823f10cb 100644 --- a/searchcore/src/vespa/searchcore/proton/server/shared_threading_service.h +++ b/searchcore/src/vespa/searchcore/proton/server/shared_threading_service.h @@ -5,6 +5,7 @@ #include "shared_threading_service_config.h" #include <vespa/vespalib/util/threadstackexecutor.h> #include <vespa/vespalib/util/syncable.h> +#include <vespa/vespalib/util/clock.h> #include <vespa/vespalib/util/invokeserviceimpl.h> #include <memory> @@ -22,7 +23,7 @@ private: std::unique_ptr<vespalib::ISequencedTaskExecutor> _field_writer; vespalib::InvokeServiceImpl _invokeService; std::vector<Registration> _invokeRegistrations; - + vespalib::Clock _clock; public: SharedThreadingService(const SharedThreadingServiceConfig& cfg, FNET_Transport & transport); ~SharedThreadingService() override; @@ -35,6 +36,7 @@ public: vespalib::ISequencedTaskExecutor* field_writer() override { return _field_writer.get(); } vespalib::InvokeService & invokeService() override { return _invokeService; } FNET_Transport & transport() override { return _transport; } + const vespalib::Clock & clock() const override { return _clock; } }; } diff --git a/searchcore/src/vespa/searchcore/proton/test/mock_shared_threading_service.cpp b/searchcore/src/vespa/searchcore/proton/test/mock_shared_threading_service.cpp index d695f4d8dc7..55f77ff41ea 100644 --- a/searchcore/src/vespa/searchcore/proton/test/mock_shared_threading_service.cpp +++ b/searchcore/src/vespa/searchcore/proton/test/mock_shared_threading_service.cpp @@ -8,7 +8,8 @@ MockSharedThreadingService::MockSharedThreadingService(ThreadExecutor& warmup_in : _warmup(warmup_in), _shared(shared_in), _invokeService(10ms), - _transport() + _transport(), + _clock(_invokeService.nowPtr()) { } diff --git a/searchcore/src/vespa/searchcore/proton/test/mock_shared_threading_service.h b/searchcore/src/vespa/searchcore/proton/test/mock_shared_threading_service.h index 7db208fa3ef..35c8ee46de5 100644 --- a/searchcore/src/vespa/searchcore/proton/test/mock_shared_threading_service.h +++ b/searchcore/src/vespa/searchcore/proton/test/mock_shared_threading_service.h @@ -4,6 +4,7 @@ #include "transport_helper.h" #include <vespa/searchcore/proton/server/i_shared_threading_service.h> #include <vespa/vespalib/util/invokeserviceimpl.h> +#include <vespa/vespalib/util/clock.h> namespace proton { @@ -14,7 +15,7 @@ private: ThreadExecutor & _shared; vespalib::InvokeServiceImpl _invokeService; Transport _transport; - + vespalib::Clock _clock; public: MockSharedThreadingService(ThreadExecutor& warmup_in, ThreadExecutor& shared_in); @@ -24,6 +25,7 @@ public: vespalib::ISequencedTaskExecutor* field_writer() override { return nullptr; } vespalib::InvokeService & invokeService() override { return _invokeService; } FNET_Transport & transport() override { return _transport.transport(); } + const vespalib::Clock & clock() const override { return _clock; } }; } diff --git a/searchlib/src/tests/queryeval/simple_phrase/simple_phrase_test.cpp b/searchlib/src/tests/queryeval/simple_phrase/simple_phrase_test.cpp index 8879d591f5a..4877072eacd 100644 --- a/searchlib/src/tests/queryeval/simple_phrase/simple_phrase_test.cpp +++ b/searchlib/src/tests/queryeval/simple_phrase/simple_phrase_test.cpp @@ -9,6 +9,7 @@ #include <vespa/searchlib/fef/matchdatalayout.h> #include <vespa/searchlib/query/tree/simplequery.h> #include <vespa/searchlib/query/weight.h> +#include <vespa/vespalib/util/testclock.h> #include <vespa/vespalib/testkit/testapp.h> #include <vespa/log/log.h> @@ -211,8 +212,8 @@ void Test::requireThatIteratorHonorsFutureDoom() { test.addTerm("foo", 0).addTerm("bar", 1); test.fetchPostings(false); - vespalib::Clock clock; - vespalib::Doom futureDoom(clock, vespalib::steady_time::max()); + vespalib::TestClock clock; + vespalib::Doom futureDoom(clock.clock(), vespalib::steady_time::max()); unique_ptr<SearchIterator> search(test.createSearch(false)); static_cast<SimplePhraseSearch &>(*search).setDoom(&futureDoom); EXPECT_TRUE(!search->seek(1u)); @@ -225,8 +226,8 @@ void Test::requireThatIteratorHonorsDoom() { test.addTerm("foo", 0).addTerm("bar", 1); test.fetchPostings(false); - vespalib::Clock clock; - vespalib::Doom futureDoom(clock, vespalib::steady_time()); + vespalib::TestClock clock; + vespalib::Doom futureDoom(clock.clock(), vespalib::steady_time()); unique_ptr<SearchIterator> search(test.createSearch(false)); static_cast<SimplePhraseSearch &>(*search).setDoom(&futureDoom); EXPECT_TRUE(!search->seek(1u)); diff --git a/searchlib/src/tests/sortspec/multilevelsort.cpp b/searchlib/src/tests/sortspec/multilevelsort.cpp index 576e1d1336c..88b105ec80c 100644 --- a/searchlib/src/tests/sortspec/multilevelsort.cpp +++ b/searchlib/src/tests/sortspec/multilevelsort.cpp @@ -7,6 +7,7 @@ #include <vespa/searchlib/attribute/attributecontext.h> #include <vespa/searchlib/attribute/attributemanager.h> #include <vespa/searchlib/uca/ucaconverter.h> +#include <vespa/vespalib/util/testclock.h> #include <vespa/vespalib/testkit/testapp.h> #include <vespa/log/log.h> LOG_SETUP("multilevelsort_test"); @@ -14,13 +15,9 @@ LOG_SETUP("multilevelsort_test"); using namespace search; typedef FastS_SortSpec::VectorRef VectorRef; -typedef IntegerAttributeTemplate<uint8_t> Uint8; typedef IntegerAttributeTemplate<int8_t> Int8; -typedef IntegerAttributeTemplate<uint16_t> Uint16; typedef IntegerAttributeTemplate<int16_t> Int16; -typedef IntegerAttributeTemplate<uint32_t> Uint32; typedef IntegerAttributeTemplate<int32_t> Int32; -typedef IntegerAttributeTemplate<uint64_t> Uint64; typedef IntegerAttributeTemplate<int64_t> Int64; typedef FloatingPointAttributeTemplate<float> Float; typedef FloatingPointAttributeTemplate<double> Double; @@ -239,8 +236,8 @@ MultilevelSortTest::sortAndCheck(const std::vector<Spec> &spec, uint32_t num, hits[i]._rankValue = getRandomValue<uint32_t>(); } - vespalib::Clock clock; - vespalib::Doom doom(clock, vespalib::steady_time::max()); + vespalib::TestClock clock; + vespalib::Doom doom(clock.clock(), vespalib::steady_time::max()); search::uca::UcaConverterFactory ucaFactory; FastS_SortSpec sorter(7, doom, ucaFactory, _sortMethod); // init sorter with sort data @@ -396,8 +393,8 @@ TEST("require that all sort methods behave the same") } TEST("test that [docid] translates to [lid][paritionid]") { - vespalib::Clock clock; - vespalib::Doom doom(clock, vespalib::steady_time::max()); + vespalib::TestClock clock; + vespalib::Doom doom(clock.clock(), vespalib::steady_time::max()); search::uca::UcaConverterFactory ucaFactory; FastS_SortSpec asc(7, doom, ucaFactory); RankedHit hits[2] = {RankedHit(91, 0.0), RankedHit(3, 2.0)}; diff --git a/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.cpp b/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.cpp index ea4cbf84550..a123d3f6cd1 100644 --- a/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.cpp @@ -1,12 +1,14 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "fake_requestcontext.h" +#include <vespa/vespalib/util/testclock.h> + namespace search::queryeval { FakeRequestContext::FakeRequestContext(attribute::IAttributeContext * context, vespalib::steady_time softDoom, vespalib::steady_time hardDoom) - : _clock(), - _doom(_clock, softDoom, hardDoom, false), + : _clock(std::make_unique<vespalib::TestClock>()), + _doom(_clock->clock(), softDoom, hardDoom, false), _attributeContext(context), _query_tensor_name(), _query_tensor(), diff --git a/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.h b/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.h index 25a4fa559e0..a492f055cdb 100644 --- a/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.h +++ b/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.h @@ -13,6 +13,7 @@ #include <vespa/vespalib/util/doom.h> #include <limits> +namespace vespalib { class TestClock; } namespace search::queryeval { class FakeRequestContext : public IRequestContext @@ -47,7 +48,7 @@ public: const search::attribute::AttributeBlueprintParams& get_attribute_blueprint_params() const override; private: - vespalib::Clock _clock; + std::unique_ptr<vespalib::TestClock> _clock; const vespalib::Doom _doom; attribute::IAttributeContext *_attributeContext; vespalib::string _query_tensor_name; diff --git a/staging_vespalib/src/tests/clock/clock_benchmark.cpp b/staging_vespalib/src/tests/clock/clock_benchmark.cpp index c8d3e2a5aff..a51d83ae4dc 100644 --- a/staging_vespalib/src/tests/clock/clock_benchmark.cpp +++ b/staging_vespalib/src/tests/clock/clock_benchmark.cpp @@ -139,17 +139,16 @@ main(int , char *argv[]) NSVolatile nsVolatile; NSAtomic nsAtomic; vespalib::InvokeServiceImpl invoker(vespalib::from_s(1.0/frequency)); - Clock clock; + Clock clock(invoker.nowPtr()); TestClock nsClock(nsValue, 1.0/frequency); TestClock nsVolatileClock(nsVolatile, 1.0/frequency); TestClock nsAtomicClock(nsAtomic, 1.0/frequency); - clock.start(invoker); assert(pool.NewThread(&nsClock, nullptr) != nullptr); assert(pool.NewThread(&nsVolatileClock, nullptr) != nullptr); assert(pool.NewThread(&nsAtomicClock, nullptr) != nullptr); benchmark("vespalib::Clock", pool, samples, numThreads, [&clock]() { - return clock.getTimeNSAssumeRunning(); + return clock.getTimeNS(); }); benchmark("uint64_t", pool, samples, numThreads, [&nsValue]() { return steady_time (duration(nsValue._value)); @@ -175,6 +174,5 @@ main(int , char *argv[]) }); pool.Close(); - clock.stop(); return 0; } diff --git a/staging_vespalib/src/tests/clock/clock_test.cpp b/staging_vespalib/src/tests/clock/clock_test.cpp index 2c6cbc0c876..b8ee4d7cc64 100644 --- a/staging_vespalib/src/tests/clock/clock_test.cpp +++ b/staging_vespalib/src/tests/clock/clock_test.cpp @@ -19,19 +19,11 @@ void waitForMovement(steady_time start, Clock & clock, vespalib::duration timeou TEST("Test that clock is ticking forward") { vespalib::InvokeServiceImpl invoker(50ms); - Clock clock; - clock.start(invoker); + Clock clock(invoker.nowPtr()); steady_time start = clock.getTimeNS(); waitForMovement(start, clock, 10s); steady_time stop = clock.getTimeNS(); EXPECT_TRUE(stop > start); - std::this_thread::sleep_for(1s); - start = clock.getTimeNS(); - waitForMovement(start, clock, 10s); - clock.stop(); - steady_time stop2 = clock.getTimeNS(); - EXPECT_TRUE(stop2 > stop); - EXPECT_TRUE(vespalib::count_ms(stop2 - stop) > 1000); } TEST_MAIN() { TEST_RUN_ALL(); }
\ No newline at end of file diff --git a/staging_vespalib/src/vespa/vespalib/util/CMakeLists.txt b/staging_vespalib/src/vespa/vespalib/util/CMakeLists.txt index e69dd36d6f5..2912ac2397b 100644 --- a/staging_vespalib/src/vespa/vespalib/util/CMakeLists.txt +++ b/staging_vespalib/src/vespa/vespalib/util/CMakeLists.txt @@ -23,6 +23,7 @@ vespa_add_library(staging_vespalib_vespalib_util OBJECT shutdownguard.cpp scheduledexecutor.cpp singleexecutor.cpp + testclock.cpp xmlserializable.cpp xmlstream.cpp DEPENDS diff --git a/staging_vespalib/src/vespa/vespalib/util/clock.cpp b/staging_vespalib/src/vespa/vespalib/util/clock.cpp index a4b9ed0fd5d..ad9d6d534f9 100644 --- a/staging_vespalib/src/vespa/vespalib/util/clock.cpp +++ b/staging_vespalib/src/vespa/vespalib/util/clock.cpp @@ -1,37 +1,16 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "clock.h" -#include <vespa/vespalib/util/invokeservice.h> - +#include <cassert> namespace vespalib { -Clock::Clock() : - _timeNS(0u), - _running(false), - _invokeRegistration() +Clock::Clock(const std::atomic<steady_time> * source) noexcept + : _timeNS(source) { - setTime(); + assert(_timeNS != nullptr); + static_assert(std::atomic<steady_time>::is_always_lock_free); } Clock::~Clock() = default; -void Clock::setTime() const -{ - _timeNS.store(count_ns(steady_clock::now().time_since_epoch()), std::memory_order_relaxed); -} - -void -Clock::start(InvokeService & invoker) -{ - _running.store(true, std::memory_order_relaxed); - _invokeRegistration = invoker.registerInvoke([this]() { setTime(); }); -} - -void -Clock::stop() -{ - _running.store(false, std::memory_order_relaxed); - _invokeRegistration.reset(); -} - } diff --git a/staging_vespalib/src/vespa/vespalib/util/clock.h b/staging_vespalib/src/vespa/vespalib/util/clock.h index d4cffc200fe..0d160a98654 100644 --- a/staging_vespalib/src/vespa/vespalib/util/clock.h +++ b/staging_vespalib/src/vespa/vespalib/util/clock.h @@ -7,9 +7,6 @@ namespace vespalib { -class IDestructorCallback; -class InvokeService; - /** * Clock is a clock that updates the time at defined intervals. * It is intended used where you want to check the time with low cost, but where @@ -19,28 +16,18 @@ class InvokeService; class Clock { private: - mutable std::atomic<int64_t> _timeNS; - std::atomic<bool> _running; - std::unique_ptr<IDestructorCallback> _invokeRegistration; - - void setTime() const; + const std::atomic<steady_time> *_timeNS; public: - Clock(); + Clock(const std::atomic<steady_time> * source) noexcept; + Clock(const Clock &) = delete; + Clock & operator =(const Clock &) = delete; + Clock(Clock &&) = delete; + Clock & operator =(Clock &&) = delete; ~Clock(); - vespalib::steady_time getTimeNS() const { - if (!_running) { - setTime(); - } - return getTimeNSAssumeRunning(); - } - vespalib::steady_time getTimeNSAssumeRunning() const { - return vespalib::steady_time(std::chrono::nanoseconds(_timeNS.load(std::memory_order_relaxed))); + vespalib::steady_time getTimeNS() const noexcept { + return vespalib::steady_time(_timeNS->load(std::memory_order_relaxed)); } - - void start(InvokeService & invoker); - void stop(); }; } - diff --git a/staging_vespalib/src/vespa/vespalib/util/doom.h b/staging_vespalib/src/vespa/vespalib/util/doom.h index b9a7e76b8af..e7db0795fb7 100644 --- a/staging_vespalib/src/vespa/vespalib/util/doom.h +++ b/staging_vespalib/src/vespa/vespalib/util/doom.h @@ -14,8 +14,8 @@ public: Doom(const Clock &clock, steady_time softDoom, steady_time hardDoom, bool explicitSoftDoom); - bool soft_doom() const { return (_clock.getTimeNSAssumeRunning() > _softDoom); } - bool hard_doom() const { return (_clock.getTimeNSAssumeRunning() > _hardDoom); } + bool soft_doom() const { return (_clock.getTimeNS() > _softDoom); } + bool hard_doom() const { return (_clock.getTimeNS() > _hardDoom); } duration soft_left() const { return _softDoom - _clock.getTimeNS(); } duration hard_left() const { return _hardDoom - _clock.getTimeNS(); } bool isExplicitSoftDoom() const { return _isExplicitSoftDoom; } diff --git a/vespalib/src/tests/invokeservice/invokeservice_test.cpp b/vespalib/src/tests/invokeservice/invokeservice_test.cpp index 1d4791f4a33..d56eb28e6c7 100644 --- a/vespalib/src/tests/invokeservice/invokeservice_test.cpp +++ b/vespalib/src/tests/invokeservice/invokeservice_test.cpp @@ -29,6 +29,25 @@ TEST("require that wakeup is called") { EXPECT_EQUAL(countAtStop, a._count); } +TEST("require that now is moving forward") { + InvokeCounter a; + InvokeServiceImpl service(1ms); + EXPECT_EQUAL(0u, a._count); + steady_time prev = steady_clock::now(); + auto ra = service.registerInvoke([&prev, &a, now=service.nowPtr() ]() noexcept { + EXPECT_GREATER(now->load(), prev); + prev = now->load(); + a.inc(); + }); + EXPECT_TRUE(ra); + a.wait_for_atleast(100); + ra.reset(); + EXPECT_GREATER_EQUAL(a._count, 100u); + steady_time now = steady_clock::now(); + EXPECT_GREATER(now, prev); + EXPECT_LESS(now - prev, 5s); +} + TEST("require that same wakeup can be registered multiple times.") { InvokeCounter a; InvokeCounter b; diff --git a/vespalib/src/vespa/vespalib/util/invokeservice.h b/vespalib/src/vespa/vespalib/util/invokeservice.h index 3e3973234d1..22bee0d4526 100644 --- a/vespalib/src/vespa/vespalib/util/invokeservice.h +++ b/vespalib/src/vespa/vespalib/util/invokeservice.h @@ -3,6 +3,7 @@ #pragma once #include "idestructorcallback.h" +#include "time.h" #include <functional> namespace vespalib { @@ -13,8 +14,9 @@ namespace vespalib { **/ class InvokeService { public: + using InvokeFunc = std::function<void()>; virtual ~InvokeService() = default; - virtual std::unique_ptr<IDestructorCallback> registerInvoke(std::function<void()> func) = 0; + virtual std::unique_ptr<IDestructorCallback> registerInvoke(InvokeFunc func) = 0; }; } diff --git a/vespalib/src/vespa/vespalib/util/invokeserviceimpl.cpp b/vespalib/src/vespa/vespalib/util/invokeserviceimpl.cpp index ffa0825c950..eac84568ec2 100644 --- a/vespalib/src/vespa/vespalib/util/invokeserviceimpl.cpp +++ b/vespalib/src/vespa/vespalib/util/invokeserviceimpl.cpp @@ -7,11 +7,12 @@ namespace vespalib { InvokeServiceImpl::InvokeServiceImpl(duration napTime) : _naptime(napTime), + _now(steady_clock::now()), _lock(), _currId(0), _closed(false), _toInvoke(), - _thread() + _thread(std::make_unique<std::thread>([this]() { runLoop(); })) { } @@ -22,9 +23,7 @@ InvokeServiceImpl::~InvokeServiceImpl() assert(_toInvoke.empty()); _closed = true; } - if (_thread) { - _thread->join(); - } + _thread->join(); } class InvokeServiceImpl::Registration : public IDestructorCallback { @@ -44,20 +43,17 @@ private: }; std::unique_ptr<IDestructorCallback> -InvokeServiceImpl::registerInvoke(VoidFunc func) { +InvokeServiceImpl::registerInvoke(InvokeFunc func) { std::lock_guard guard(_lock); uint64_t id = _currId++; _toInvoke.emplace_back(id, std::move(func)); - if ( ! _thread) { - _thread = std::make_unique<std::thread>([this]() { runLoop(); }); - } return std::make_unique<Registration>(this, id); } void InvokeServiceImpl::unregister(uint64_t id) { std::lock_guard guard(_lock); - auto found = std::find_if(_toInvoke.begin(), _toInvoke.end(), [id](const std::pair<uint64_t, VoidFunc> & a) { + auto found = std::find_if(_toInvoke.begin(), _toInvoke.end(), [id](const IdAndFunc & a) { return id == a.first; }); assert (found != _toInvoke.end()); @@ -68,6 +64,8 @@ void InvokeServiceImpl::runLoop() { bool done = false; while ( ! done ) { + const steady_time now = steady_clock::now(); + _now.store(now, std::memory_order_relaxed); { std::lock_guard guard(_lock); for (auto & func: _toInvoke) { @@ -76,7 +74,7 @@ InvokeServiceImpl::runLoop() { done = _closed; } if ( ! done) { - std::this_thread::sleep_for(_naptime); + std::this_thread::sleep_until(now + _naptime); } } diff --git a/vespalib/src/vespa/vespalib/util/invokeserviceimpl.h b/vespalib/src/vespa/vespalib/util/invokeserviceimpl.h index 3b0c7690731..2448e381610 100644 --- a/vespalib/src/vespa/vespalib/util/invokeserviceimpl.h +++ b/vespalib/src/vespa/vespalib/util/invokeserviceimpl.h @@ -14,22 +14,24 @@ namespace vespalib { * An invoke service what will invoke the given function with at specified frequency. */ class InvokeServiceImpl : public InvokeService { - using VoidFunc = std::function<void()>; public: InvokeServiceImpl(duration napTime); InvokeServiceImpl(const InvokeServiceImpl &) = delete; InvokeServiceImpl & operator=(const InvokeServiceImpl &) = delete; ~InvokeServiceImpl() override; - std::unique_ptr<IDestructorCallback> registerInvoke(VoidFunc func) override; + std::unique_ptr<IDestructorCallback> registerInvoke(InvokeFunc func) override; + const std::atomic<steady_time> * nowPtr() const { return &_now; } private: + using IdAndFunc = std::pair<uint64_t, InvokeFunc>; class Registration; void unregister(uint64_t id); void runLoop(); duration _naptime; + std::atomic<steady_time> _now; std::mutex _lock; uint64_t _currId; bool _closed; - std::vector<std::pair<uint64_t, VoidFunc>> _toInvoke; + std::vector<IdAndFunc> _toInvoke; std::unique_ptr<std::thread> _thread; }; |