diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2022-12-19 11:04:48 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-19 11:04:48 +0100 |
commit | 7b265f56441a2c6107e01e78082d3f1f26883b0b (patch) | |
tree | 6bbc252e42a81b1bcae2423855d98155947d776a /searchcore/src/tests | |
parent | ce50369c437611db07c923f0f78adb0d9a0b9e3f (diff) | |
parent | 6e4cd90b0b3f77577e6c3366872f8a7bc02a061f (diff) |
Merge pull request #25282 from vespa-engine/geirst/avoid-flushing-components-more-than-necessary
Avoid flushing components in proton more than necessary.
Diffstat (limited to 'searchcore/src/tests')
3 files changed, 93 insertions, 50 deletions
diff --git a/searchcore/src/tests/proton/flushengine/flushengine_test.cpp b/searchcore/src/tests/proton/flushengine/flushengine_test.cpp index 4595ce12229..d795ed95550 100644 --- a/searchcore/src/tests/proton/flushengine/flushengine_test.cpp +++ b/searchcore/src/tests/proton/flushengine/flushengine_test.cpp @@ -1,5 +1,6 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/searchcore/proton/flushengine/active_flush_stats.h> #include <vespa/searchcore/proton/flushengine/cachedflushtarget.h> #include <vespa/searchcore/proton/flushengine/flush_engine_explorer.h> #include <vespa/searchcore/proton/flushengine/flushengine.h> @@ -19,13 +20,8 @@ #include <vespa/log/log.h> LOG_SETUP("flushengine_test"); -// -------------------------------------------------------------------------------- -// -// Setup. -// -// -------------------------------------------------------------------------------- - using namespace proton; +using namespace proton::flushengine; using namespace vespalib::slime; using searchcorespi::IFlushTarget; using searchcorespi::FlushTask; @@ -335,8 +331,9 @@ public: const SimpleStrategy &_flush; }; - FlushContext::List getFlushTargets(const FlushContext::List &targetList, - const flushengine::TlsStatsMap &) const override { + FlushContext::List getFlushTargets(const FlushContext::List& targetList, + const flushengine::TlsStatsMap&, + const flushengine::ActiveFlushStats&) const override { FlushContext::List fv(targetList); std::sort(fv.begin(), fv.end(), CompareTarget(*this)); return fv; @@ -380,8 +377,8 @@ public: class NoFlushStrategy : public SimpleStrategy { - FlushContext::List getFlushTargets(const FlushContext::List &, const flushengine::TlsStatsMap &) const override { - return FlushContext::List(); + FlushContext::List getFlushTargets(const FlushContext::List &, const flushengine::TlsStatsMap &, const flushengine::ActiveFlushStats&) const override { + return {}; } }; @@ -771,6 +768,28 @@ TEST_F("require that oldest serial is updated when finishing priority flush stra EXPECT_EQUAL(20u, handler->_oldestSerial); } +TEST("the oldest start time is tracked per flush handler in ActiveFlushStats") +{ + using seconds = std::chrono::seconds; + using vespalib::system_time; + system_time now = vespalib::system_clock::now(); + system_time t1 = now + seconds(1); + system_time t2 = now + seconds(2); + system_time t3 = now + seconds(3); + system_time t4 = now + seconds(4); + ActiveFlushStats stats; + EXPECT_FALSE(stats.oldest_start_time("h1").has_value()); + stats.set_start_time("h1", t2); + stats.set_start_time("h2", t4); + EXPECT_EQUAL(t2, stats.oldest_start_time("h1").value()); + EXPECT_EQUAL(t4, stats.oldest_start_time("h2").value()); + + stats.set_start_time("h1", t1); + EXPECT_EQUAL(t1, stats.oldest_start_time("h1").value()); + stats.set_start_time("h1", t3); + EXPECT_EQUAL(t1, stats.oldest_start_time("h1").value()); +} + TEST_MAIN() { diff --git a/searchcore/src/tests/proton/flushengine/prepare_restart_flush_strategy/prepare_restart_flush_strategy_test.cpp b/searchcore/src/tests/proton/flushengine/prepare_restart_flush_strategy/prepare_restart_flush_strategy_test.cpp index 40c4c491940..6aa17151942 100644 --- a/searchcore/src/tests/proton/flushengine/prepare_restart_flush_strategy/prepare_restart_flush_strategy_test.cpp +++ b/searchcore/src/tests/proton/flushengine/prepare_restart_flush_strategy/prepare_restart_flush_strategy_test.cpp @@ -1,9 +1,10 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/testkit/testapp.h> -#include <vespa/searchcore/proton/flushengine/prepare_restart_flush_strategy.h> -#include <vespa/searchcore/proton/flushengine/flush_target_candidates.h> +#include <vespa/searchcore/proton/flushengine/active_flush_stats.h> #include <vespa/searchcore/proton/flushengine/flush_target_candidate.h> +#include <vespa/searchcore/proton/flushengine/flush_target_candidates.h> +#include <vespa/searchcore/proton/flushengine/prepare_restart_flush_strategy.h> #include <vespa/searchcore/proton/flushengine/tls_stats_map.h> #include <vespa/searchcore/proton/test/dummy_flush_handler.h> #include <vespa/searchcore/proton/test/dummy_flush_target.h> @@ -220,7 +221,8 @@ struct FlushStrategyFixture {} FlushContext::List getFlushTargets(const FlushContext::List &targetList, const flushengine::TlsStatsMap &tlsStatsMap) const { - return strategy.getFlushTargets(targetList, tlsStatsMap); + flushengine::ActiveFlushStats active_flushes; + return strategy.getFlushTargets(targetList, tlsStatsMap, active_flushes); } }; diff --git a/searchcore/src/tests/proton/server/memoryflush/memoryflush_test.cpp b/searchcore/src/tests/proton/server/memoryflush/memoryflush_test.cpp index 8a9b119bcbb..8c017184a7b 100644 --- a/searchcore/src/tests/proton/server/memoryflush/memoryflush_test.cpp +++ b/searchcore/src/tests/proton/server/memoryflush/memoryflush_test.cpp @@ -1,5 +1,6 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/searchcore/proton/flushengine/active_flush_stats.h> #include <vespa/searchcore/proton/flushengine/flushcontext.h> #include <vespa/searchcore/proton/flushengine/tls_stats_map.h> #include <vespa/searchcore/proton/server/memoryflush.h> @@ -52,19 +53,15 @@ public: bool needUrgentFlush() const override { return _urgentFlush; } }; -struct StringList : public std::vector<vespalib::string> { - StringList() : std::vector<vespalib::string>() {} - StringList &add(const vespalib::string &str) { - push_back(str); - return *this; - } -}; +using StringList = std::vector<vespalib::string>; class ContextBuilder { private: FlushContext::List _list; IFlushHandler::SP _handler; flushengine::TlsStatsMap::Map _map; + flushengine::ActiveFlushStats _active_flushes; + void fixupMap(const vespalib::string &name, SerialNum lastSerial) { @@ -92,25 +89,32 @@ public: FlushContext::SP ctx(new FlushContext(_handler, target, lastSerial)); return add(ctx); } + ContextBuilder& active_flush(const vespalib::string& handler_name, vespalib::system_time start_time) { + _active_flushes.set_start_time(handler_name, start_time); + return *this; + } const FlushContext::List &list() const { return _list; } flushengine::TlsStatsMap tlsStats() const { flushengine::TlsStatsMap::Map map(_map); return flushengine::TlsStatsMap(std::move(map)); } + FlushContext::List flush_targets(const IFlushStrategy& strategy) const { + return strategy.getFlushTargets(list(), tlsStats(), _active_flushes); + } }; using minutes = std::chrono::minutes; using seconds = std::chrono::seconds; ContextBuilder::ContextBuilder() - : _list(), _handler(new MyFlushHandler("myhandler")) + : _list(), _handler(new MyFlushHandler("myhandler")), _map(), _active_flushes() {} ContextBuilder::~ContextBuilder() = default; MyFlushTarget::SP createTargetM(const vespalib::string &name, MemoryGain memoryGain) { - return std::make_shared<MyFlushTarget>(name, memoryGain, DiskGain(),SerialNum(), system_time(), false); + return std::make_shared<MyFlushTarget>(name, memoryGain, DiskGain(), SerialNum(), system_time(), false); } MyFlushTarget::SP @@ -155,13 +159,11 @@ TEST(MemoryFlushTest, can_order_by_memory_gain) .add(createTargetM("t3", MemoryGain(15, 0))); { // target t4 has memoryGain >= maxMemoryGain MemoryFlush flush({1000, 20_Gi, 1.0, 20, 1.0, minutes(1)}); - assertOrder(StringList().add("t4").add("t3").add("t2").add("t1"), - flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t4", "t3", "t2", "t1"}, cb.flush_targets(flush)); } { // trigger totalMemoryGain >= globalMaxMemory MemoryFlush flush({50, 20_Gi, 1.0, 1000, 1.0, minutes(1)}); - assertOrder(StringList().add("t4").add("t3").add("t2").add("t1"), - flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t4", "t3", "t2", "t1"}, cb.flush_targets(flush)); } } @@ -178,14 +180,12 @@ TEST(MemoryFlushTest, can_order_by_disk_gain_with_large_values) { // target t4 has diskGain > bloatValue // t4 gain: 55M / 100M = 0.55 -> bloat factor 0.54 to trigger MemoryFlush flush({1000, 20_Gi, 10.0, 1000, 0.54, minutes(1)}); - assertOrder(StringList().add("t4").add("t3").add("t2").add("t1"), - flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t4", "t3", "t2", "t1"}, cb.flush_targets(flush)); } { // trigger totalDiskGain > totalBloatValue // total gain: 160M / 4 * 100M = 0.4 -> bloat factor 0.39 to trigger MemoryFlush flush({1000, 20_Gi, 0.39, 1000, 10.0, minutes(1)}); - assertOrder(StringList().add("t4").add("t3").add("t2").add("t1"), - flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t4", "t3", "t2", "t1"}, cb.flush_targets(flush)); } } @@ -201,14 +201,12 @@ TEST(MemoryFlushTest, can_order_by_disk_gain_with_small_values) { // target t4 has diskGain > bloatValue // t4 gain: 55 / 100M = 0.0000055 -> bloat factor 0.0000054 to trigger MemoryFlush flush({1000, 20_Gi, 10.0, 1000, 0.00000054, minutes(1)}); - assertOrder(StringList().add("t4").add("t3").add("t2").add("t1"), - flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t4", "t3", "t2", "t1"}, cb.flush_targets(flush)); } { // trigger totalDiskGain > totalBloatValue // total gain: 160 / 100M = 0.0000016 -> bloat factor 0.0000015 to trigger MemoryFlush flush({1000, 20_Gi, 0.0000015, 1000, 10.0, minutes(1)}); - assertOrder(StringList().add("t4").add("t3").add("t2").add("t1"), - flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t4", "t3", "t2", "t1"}, cb.flush_targets(flush)); } } @@ -224,12 +222,11 @@ TEST(MemoryFlushTest, can_order_by_age) { // all targets have timeDiff >= maxTimeGain MemoryFlush flush({1000, 20_Gi, 1.0, 1000, 1.0, seconds(2)}, start); - assertOrder(StringList().add("t4").add("t3").add("t2").add("t1"), - flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t4", "t3", "t2", "t1"}, cb.flush_targets(flush)); } { // no targets have timeDiff >= maxTimeGain MemoryFlush flush({1000, 20_Gi, 1.0, 1000, 1.0, seconds(30)}, start); - assertOrder(StringList(), flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({}, cb.flush_targets(flush)); } } @@ -238,8 +235,8 @@ TEST(MemoryFlushTest, can_order_by_tls_size) system_time now(vespalib::system_clock::now()); system_time start = now - seconds(20); ContextBuilder cb; - IFlushHandler::SP handler1(std::make_shared<MyFlushHandler>("handler1")); - IFlushHandler::SP handler2(std::make_shared<MyFlushHandler>("handler2")); + auto handler1 = std::make_shared<MyFlushHandler>("handler1"); + auto handler2 = std::make_shared<MyFlushHandler>("handler2"); cb.addTls("handler1", {20_Gi, 1001, 2000 }); cb.addTls("handler2", { 5_Gi, 1001, 2000 }); cb.add(std::make_shared<FlushContext>(handler1, createTargetT("t2", now - seconds(10), 1900), 2000)). @@ -248,27 +245,52 @@ TEST(MemoryFlushTest, can_order_by_tls_size) add(std::make_shared<FlushContext>(handler2, createTargetT("t3", now - seconds(15), 1900), 2000)); { // sum of tls sizes above limit, trigger sort order based on tls size MemoryFlush flush({1000, 3_Gi, 1.0, 1000, 1.0, seconds(2)}, start); - assertOrder(StringList().add("t4").add("t1").add("t2").add("t3"), - flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t4", "t1", "t2", "t3"}, cb.flush_targets(flush)); } { // sum of tls sizes below limit MemoryFlush flush({1000, 30_Gi, 1.0, 1000, 1.0, seconds(30)}, start); - assertOrder(StringList(), flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({}, cb.flush_targets(flush)); } } +TEST(MemoryFlushTest, order_by_tls_size_not_always_selected_when_active_flushes) +{ + system_time now = vespalib::system_clock::now(); + system_time start = now - seconds(20); + ContextBuilder cb; + auto h1 = std::make_shared<MyFlushHandler>("h1"); + constexpr uint64_t first_serial = 1001; + constexpr uint64_t last_serial = 2000; + cb.addTls("h1", {5_Gi, first_serial, last_serial}); + cb.add(std::make_shared<FlushContext>(h1, createTargetT("t1", now - seconds(10), 1300), last_serial)). + add(std::make_shared<FlushContext>(h1, createTargetT("t2", now - seconds(5), 1500), last_serial)); + MemoryFlush flush({1000, 4_Gi, 1.0, 1000, 1.0, seconds(60)}, start); + + // Last flush time of both t1 and t2 are older than start of active flush -> triggers TLSSIZE. + cb.active_flush("h1", now - seconds(4)); + assertOrder({"t1", "t2"}, cb.flush_targets(flush)); + + // Last flush time of only t1 is older than start of active flush -> triggers TLSSIZE. + cb.active_flush("h1", now - seconds(9)); + assertOrder({"t1", "t2"}, cb.flush_targets(flush)); + + // Last flush time both t1 and t2 is newer than start of active flush -> don't use TLSSIZE. + cb.active_flush("h1", now - seconds(11)); + assertOrder({}, cb.flush_targets(flush)); +} + TEST(MemoryFlushTest, can_handle_large_serial_numbers_when_ordering_by_tls_size) { uint64_t uint32_max = std::numeric_limits<uint32_t>::max(); - ContextBuilder builder; + ContextBuilder cb; SerialNum firstSerial = 10; SerialNum lastSerial = uint32_max + 10; - builder.addTls("myhandler", {uint32_max, firstSerial, lastSerial}); - builder.add(createTargetT("t1", system_time(), uint32_max + 5), lastSerial); - builder.add(createTargetT("t2", system_time(), uint32_max - 5), lastSerial); + cb.addTls("myhandler", {uint32_max, firstSerial, lastSerial}); + cb.add(createTargetT("t1", system_time(), uint32_max + 5), lastSerial); + cb.add(createTargetT("t2", system_time(), uint32_max - 5), lastSerial); uint64_t maxMemoryGain = 10; MemoryFlush flush({maxMemoryGain, 1000, 0, maxMemoryGain, 0, vespalib::duration(0)}, system_time()); - assertOrder(StringList().add("t2").add("t1"), flush.getFlushTargets(builder.list(), builder.tlsStats())); + assertOrder({"t2", "t1"}, cb.flush_targets(flush)); } TEST(MemoryFlushTest, order_type_is_preserved) @@ -281,21 +303,21 @@ TEST(MemoryFlushTest, order_type_is_preserved) cb.add(createTargetT("t2", ts2, 5), 14) .add(createTargetD("t1", DiskGain(100 * milli, 80 * milli), 5)); MemoryFlush flush({1000, 20_Gi, 1.0, 1000, 0.19, seconds(30)}); - assertOrder(StringList().add("t1").add("t2"), flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t1", "t2"}, cb.flush_targets(flush)); } { // DISKBLOAT VS MEMORY ContextBuilder cb; cb.add(createTargetD("t2", DiskGain(100 * milli, 80 * milli))) .add(createTargetM("t1", MemoryGain(100, 80))); MemoryFlush flush({1000, 20_Gi, 1.0, 20, 0.19, seconds(30)}); - assertOrder(StringList().add("t1").add("t2"), flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t1", "t2"}, cb.flush_targets(flush)); } { // urgent flush ContextBuilder cb; cb.add(createTargetF("t2", false)) .add(createTargetF("t1", true)); MemoryFlush flush({1000, 20_Gi, 1.0, 1000, 1.0, seconds(30)}); - assertOrder(StringList().add("t1").add("t2"), flush.getFlushTargets(cb.list(), cb.tlsStats())); + assertOrder({"t1", "t2"}, cb.flush_targets(flush)); } } |