MOD-15579 Lazy initialization of the shared SVS thread pool#971
Open
dor-forer wants to merge 1 commit into
Open
MOD-15579 Lazy initialization of the shared SVS thread pool#971dor-forer wants to merge 1 commit into
dor-forer wants to merge 1 commit into
Conversation
🛡️ Jit Security Scan Results✅ No security findings were detected in this PR
Security scan by Jit
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #971 +/- ##
==========================================
- Coverage 97.11% 97.09% -0.02%
==========================================
Files 141 141
Lines 8144 8160 +16
==========================================
+ Hits 7909 7923 +14
- Misses 235 237 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
31c0e0a to
0adca87
Compare
6b4b160 to
8fe69ac
Compare
0adca87 to
9d082f0
Compare
8fe69ac to
760524d
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 760524d. Configure here.
75228a3 to
f278e8d
Compare
Open
4 tasks
f278e8d to
09d0e83
Compare
Base automatically changed from
dor-forer-MOD-15578-track-svs-thpool-memory
to
main
June 4, 2026 17:06
09d0e83 to
33f7564
Compare
Defer creation of the shared SVS thread pool's OS worker threads until the first SVS index is created, instead of spawning them eagerly on `VecSim_UpdateThreadPoolSize()` at module init. Today every Redis with `WORKERS=N` configured spawns N-1 SVS worker threads at startup even in deployments that never create an SVS index; this eliminates that cost. The change extends the existing deferred-resize protocol to a second safe point. `VecSimSVSThreadPoolImpl::resize()` now defers in two cases: * No SVS index attached yet -> record the requested size; apply it on the first `onIndexAttached()` call (lazy thread spawn). * Shrink while jobs are in flight (`pending_jobs_ > 0`) -> record; apply when `endScheduledJob()` drops the counter to 0 (existing behaviour). * Otherwise -> apply immediately via `resize_locked()`. The two deferral cases share `deferred_size_` and never overlap (no jobs can be in flight before the first index attaches). A new gate field `has_attached_index_` distinguishes the states; it is set on the first `onIndexAttached()` call from the per-index `VecSimSVSThreadPool` ctor. `VecSim_UpdateThreadPoolSize` still sets the write mode eagerly — only the SVS pool sizing is deferred. The C API surface is unchanged, and no RediSearch integration changes are required. Test-only `resetForTest()` (under BUILD_TESTS) restores the singleton to a clean baseline; it asserts `pending_jobs_ == 0` so misuse fails loudly instead of corrupting the deferred-protocol bookkeeping. Tests: * SVSTest.ThreadPoolLazyInit (new) — verifies UpdateThreadPoolSize does not allocate worker threads before any SVS index exists, and that the first index creation triggers the deferred spawn at the requested size. * SVSThreadPoolTest.UpdateThreadPoolSizeModeTransitions — validates the lazy -> eager transition (size stays 1 until an index attaches). * SVSThreadPoolTest fixture / SVSTest.NumThreadsParamIgnored / SVSTest.sharedMemoryTracksThreadPoolResize — call onIndexAttached() up front so resizes apply eagerly where the test needs it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
33f7564 to
6f073fb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Make initialization of the shared SVS thread pool lazy: OS worker threads are spawned only when the first SVS index is created, not when
VecSim_UpdateThreadPoolSizeis called. This eliminates the cost of pre-allocated SVS workers in deployments that configure RediSearch workers but never create an SVS index (today, every Redis withWORKERS=Nconfigured spawnsN-1SVS worker threads at module init regardless of whether SVS is ever used).The change extends the existing deferred-resize protocol to cover a second "safe point".
VecSimSVSThreadPoolImpl::resize()now defers application in two cases:onIndexAttached()(lazy thread spawn).pending_jobs_ > 0) → recorded; applied whenendScheduledJob()drops the counter to 0 (existing behaviour).resize_locked().The two deferral cases share
deferred_size_and never overlap (no jobs can be in flight before the first index attaches). One new gate field,has_attached_index_, distinguishes the two states. It is set on the firstonIndexAttached()call from the per-indexVecSimSVSThreadPoolctor.VecSim_UpdateThreadPoolSizecontinues to set the write mode (InPlace/Async) eagerly — only the SVS pool sizing is now deferred. The C API surface is unchanged.RediSearch integration impact: none required —
VecSim_UpdateThreadPoolSize(N)is still the single entry point for both module init andCONFIG SET search-workers M. Pre-index calls now just record the size; post-index calls behave exactly as before.Main objects this PR modified
VecSimSVSThreadPoolImpl::resize()— now lazy until the first index attaches.VecSimSVSThreadPoolImpl::onIndexAttached()— new entry point called from the per-indexVecSimSVSThreadPoolctor; flipshas_attached_index_and applies any deferred size.VecSimSVSThreadPoolImpl::has_attached_index_— new member field gating spawn vs. defer.VecSimSVSThreadPoolImpl::resetForTest()— newBUILD_TESTS-only hook that restores the singleton to a clean baseline. Assertspending_jobs_ == 0so misuse fails loudly instead of corrupting the deferred-protocol bookkeeping.VecSim_UpdateThreadPoolSize()— comment updated; behaviour now lazy via the newresize()semantics.Tests
SVSTest.ThreadPoolLazyInit(new) — verifiesVecSim_UpdateThreadPoolSizedoes not allocate worker threads before any SVS index exists, and that the first SVS index creation triggers the deferred spawn at the previously requested size. Post-VecSimIndex_Newchecks useASSERT_*so a regression in the lazy-spawn contract halts the test on the first failure.SVSThreadPoolTest.UpdateThreadPoolSizeModeTransitions— validates the lazy → eager transition (pool size stays at 1 until an index attaches; subsequent transitions apply immediately).SVSThreadPoolTestfixture —SetUp()callsonIndexAttached()so the pool-isolation tests retain eagerresize()semantics.SVSTest.NumThreadsParamIgnored— callsonIndexAttached()up front (resizes before constructing an index) and restores the singleton viaresetForTest()so it does not leakhas_attached_index_to later tests.SVSTest.sharedMemoryTracksThreadPoolResize— callsonIndexAttached()up front so the resize-without-index path applies eagerly and the grow/shrink memory deltas are observable.Mark if applicable
Supersedes #969 — ownership transferred to @dor-forer. Builds on #972 (MOD-15578), now merged to
main.Note
Medium Risk
Changes shared thread-pool lifecycle and when OS threads are created, but the public C API is unchanged and deferred-shrink while jobs are in flight is preserved; risk is mainly regressions in worker count or timing around module init vs first SVS index.
Overview
Lazy SVS thread pool sizing defers spawning OS worker threads until the first SVS index is created.
VecSim_UpdateThreadPoolSizestill switches write mode (InPlace/Async) immediately; only pool sizing is deferred.VecSimSVSThreadPoolImpl::resize()now records the requested size indeferred_size_when no index has attached (has_attached_index_is false) instead of callingresize_locked()right away. The first per-indexVecSimSVSThreadPoolconstruction callsonIndexAttached(), which sets the flag and applies any deferred size—this is where workers are created on the lazy path. After attach, resize behaves as before (immediate grow/shrink, with shrink still deferred whilepending_jobs_ > 0).A
BUILD_TESTS-onlyresetForTest()clears slots,deferred_size_, andhas_attached_index_so unit tests get a clean singleton. Tests addThreadPoolLazyInit, callonIndexAttached()where tests resize without a real index, and extendUpdateThreadPoolSizeModeTransitionsfor the lazy → eager transition.Reviewed by Cursor Bugbot for commit 6f073fb. Bugbot is set up for automated code reviews on this repo. Configure here.