From 4a61ccee0097605bf00575cad474f916cc48d34d Mon Sep 17 00:00:00 2001 From: jolavillette Date: Wed, 5 Aug 2026 13:53:52 +0200 Subject: [PATCH] gxs: adapt the warm-up slice size to a fixed per-slice time budget A fixed 4096-row slice held mDbMutex for ~10 s on a cold large-row database (23492 forum metas warmed in 6 slices of ~10 s each), stalling single-group readers for that long -- the very stall the background scan exists to avoid. Start at 256 rows and rescale each slice towards a 250 ms target, clamped to [64, 4096] rows. Co-Authored-By: Claude Fable 5 --- src/gxs/rsdataservice.cc | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/gxs/rsdataservice.cc b/src/gxs/rsdataservice.cc index 0504831f2..db6f12c6e 100644 --- a/src/gxs/rsdataservice.cc +++ b/src/gxs/rsdataservice.cc @@ -1328,7 +1328,15 @@ void RsDataService::msgMetaWarmupThreadBody() // a deletion) are covered; until the scan completes, cold groups keep // being served by the indexed per-group query. - static const uint32_t WARMUP_SLICE_ROWS = 4096; + // The slice size adapts so that one slice -- hence one mDbMutex hold -- + // stays around WARMUP_SLICE_TARGET_MS. With a fixed row count, a cold + // slice of a large-row database was measured at ~10 s, which is exactly + // the reader stall this thread exists to avoid. + static const int64_t WARMUP_SLICE_TARGET_MS = 250; + static const uint32_t WARMUP_SLICE_MIN_ROWS = 64; + static const uint32_t WARMUP_SLICE_MAX_ROWS = 4096; + + uint32_t slice_rows = 256; std::list columns(mMsgMetaColumns); columns.push_front("rowid"); @@ -1341,6 +1349,8 @@ void RsDataService::msgMetaWarmupThreadBody() while(!done && !mMsgMetaWarmupStop) { + auto slice_t0 = std::chrono::steady_clock::now(); + { RsStackMutex stack(mDbMutex); @@ -1349,7 +1359,7 @@ void RsDataService::msgMetaWarmupThreadBody() RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, columns, "rowid > " + std::to_string(last_rowid), - "rowid LIMIT " + std::to_string(WARMUP_SLICE_ROWS)); + "rowid LIMIT " + std::to_string(slice_rows)); if(!c) { @@ -1378,7 +1388,7 @@ void RsDataService::msgMetaWarmupThreadBody() total_rows += n_rows; ++n_slices; - if(n_rows < WARMUP_SLICE_ROWS) + if(n_rows < slice_rows) { // Last slice. Every group of this database now holds all its // metas, including the ones that have no message at all and @@ -1391,9 +1401,24 @@ void RsDataService::msgMetaWarmupThreadBody() } } - // Let the readers waiting on mDbMutex in between two slices. if(!done) + { + // Rescale the next slice towards the per-slice time target. + int64_t slice_ms = std::chrono::duration_cast( + std::chrono::steady_clock::now() - slice_t0).count(); + + if(slice_ms > 0) + { + uint64_t next = (uint64_t)slice_rows * WARMUP_SLICE_TARGET_MS / slice_ms; + slice_rows = (uint32_t)std::min(WARMUP_SLICE_MAX_ROWS, + std::max(WARMUP_SLICE_MIN_ROWS, next)); + } + else + slice_rows = WARMUP_SLICE_MAX_ROWS; + + // Let the readers waiting on mDbMutex in between two slices. std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } } if(done)