Repository navigation
Skip search slots until a database has an index - #103
Conversation
A newly enrolled database parked its full set of search slots before it had any index to search. Those slots are parallel workers, so they count against max_parallel_workers, and the first CREATE INDEX in that database could not register its build workers. The build silently ran on one thread. - The launcher now computes a search claim of zero for a database with no vamana index, so no slots are parked until the first index commits. A standby keeps its current behavior because it does not maintain the index count. - The worker parks exactly the published grant, so a live database granted zero holds zero slots. Searches still get at least one thread. - Committing the first index, or dropping the last one, wakes the launcher so slots are parked or released promptly instead of after the launcher's naptime. - The worker kicks the launcher again after its startup transaction seeds the index count, so a restart does not leave a database with indexes at zero slots until the next naptime. The earlier kick stays, because that reconcile completes memory admission, which the startup residency seed needs. - A build that starts fewer parallel workers than it was granted now emits a WARNING with the counts, the thread count it will use, and the session's max_parallel_workers. - svs_cpu_budget_test takes an optional per-database has-indexes array. A new TAP test covers the first build, the slot lifecycle around the first and last index, and the warning. - Existing tests that expected grants in databases with no index now create one in setup. docs/RESOURCE_SIZING.md and docs/USER_GUIDE.md describe the new behavior. Signed-off-by: Matt Welch <matt.welch@intel.com>
asonje
left a comment
There was a problem hiding this comment.
Reviewed the diff and tested on a scratch cluster. it matches the stated design; hasIndexes gate on the search claim, prompt launcher kicks on both the commit-time transition and the post-restart seed, and the shortfall WARNING. Sum-and-split apportionment is correctly left untouched.
I also ran it with an end-to-end test and the search slots no longer starve the build threads. confirmed the fix holds under a real workload, not just the TAP suite.
LGTM, approving.
After cpu_governance runs, the regression server keeps 8 search threads parked in contrib_regression, and ci/test_server.conf capped max_parallel_workers at 8. Every later CREATE INDEX or REINDEX in that database (in dynamic and halfvec) therefore got 0 or 1 of its 2 granted build workers. That was already happening silently, but builds now warn when they start fewer workers than granted, and because the count depends on launcher timing the warnings made those two files fail with output that differs from run to run. - Raise max_parallel_workers from 8 to 10 in ci/test_server.conf, so the pool covers the 8 parked search threads plus a build's max_parallel_maintenance_workers of 2. Under the CI config, 9 failed in 3 of 3 full installcheck runs and 10 passed in 8 of 8, with no warnings. - Leave the warning unfiltered, so a build that comes up short in any regression file still fails the diff. - Update the comment above the setting to say why the pool needs that room. Signed-off-by: Matt Welch <matt.welch@intel.com>
The failure artifact for build-and-test only kept the regression logs and the shared server log, so a TAP test that failed or stalled left nothing to explain why. Each TAP test writes its server log and regress_log to log/ at the repo root, so add that directory to the artifact paths. The upload still runs only on failure, and assert-build.yml already collects log/ the same way. Signed-off-by: Matt Welch <matt.welch@intel.com>
asonje
left a comment
There was a problem hiding this comment.
Also checked the two follow-up commits (bb25b32, b5cf7d1) — CI-only, no change to the fix itself: one adds TAP log uploads on failure, the other bumps the CI pool to max_parallel_workers = 10 since cpu_governance.sql's own seed index now leaves slots parked into later test files. Makes sense given the earlier change, no concerns.
Description
Enrolling a database parked its full set of search slots immediately, before the database had any index. The slots are parallel workers, so they count against
max_parallel_workersfor the backend that registers them. When the session running the firstCREATE INDEXhad amax_parallel_workersno larger than the parked slot count, every build worker registration failed and the build silently ran on one thread. A per-role or per-session setting made this easy to hit, because it overrides the server value.This PR makes two changes, and leaves the way the search and build threads are split between databases alone.
max_parallel_workers. The hint does not name a single cause, because the registration failure does not say why it failed. A build granted zero threads stays silent.The worker also kicks the launcher a second time, after its startup transaction seeds the index count. Without it, a restart leaves the launcher reading a count of zero for a database that has indexes, and its slots stay unparked until the next naptime. The earlier kick stays where it was, because the reconcile it triggers completes memory admission, which the startup residency seed depends on. Moving that kick instead of adding a second one broke the residency accounting test.
Several existing tests expected grants or parked slots in databases with no index, which is no longer true. They now create an index in setup where the test is not about the no-index state.
docs/RESOURCE_SIZING.mdanddocs/USER_GUIDE.mddescribe the new behavior and the new warning.The regression CI config also changes:
max_parallel_workersinci/test_server.confgoes from 8 to 10. Under the old value,cpu_governanceleaves 8 search threads parked incontrib_regression, so later builds indynamicandhalfvecgot 0 or 1 of their 2 granted workers. That was already happening, but silently. With the new warning it showed up in the expected output, and the count varied from run to run. The pool now covers the 8 search threads plus a build'smax_parallel_maintenance_workersof 2. The warning is not suppressed anywhere, so any build that comes up short in a regression file still fails the diff. The starved-build case itself is covered deterministically by the new TAP test and bycpu_governance.The failure artifact in
.github/workflows/build-and-test.ymlnow also uploadslog/, where each TAP test writes its server log andregress_log. Until now a TAP failure left only the regression logs, which gave no way to see why a test failed or stalled. The step still runs only on failure.Related Issues
Type of Change
Pre-Merge Checklist
Build
makecompletes without errors or warningsmake installcompletes successfullyTests
make installcheck) and TAP tests (test/t/) pass with no failurestest/sql/and/ortest/t/test/modules/: it builds and passes (make -C test/modules/<module> installcheck)Documentation
docs/updated if architecture or usage changedTesting Notes
The full TAP suite passes (72 files, 1529 tests; only
18_build_offset_overflow.plskips, since it needsenable_slow_tests=yes), as do the hardware-dependent TAP tests (2 files, 55 tests). The SQL regression suite passes (10 of 10), as do the hardware-dependent SQL tests (2 of 2).svs_cpu_budget_testpasses with two new cases for a database with no index. The new TAP test75_search_slots_no_index_build.plcovers the first build, slots appearing within 30 seconds of the first index committing, the warning with and without room in the pool, and slots being released after the last index is dropped.I checked that the new tests can fail by reversing each change with
git apply -Rand confirming the matching cases fail: the no-index gate, the raw-grant resize, the commit-time launcher kick, the warning, and the second startup kick (51_worker_crash_scope.pltest 21).I also ran the original reproduction on a scratch cluster with 16 search and build threads and a 20k by 768 table, smaller than the original 50k. Right after enrolling, the database showed 0 granted and 0 registered slots. The first build with a session limit of 16 got all 16 workers with no warning. Once the index was live and 16 slots were parked, the same limit started 0 of 16 workers and printed the warning, a limit of 24 started 8 of 16 and printed it, and a limit of 32 started 16 and printed nothing.
For the CI config change, I started a scratch server with
ci/test_server.confand ranmake installcheckrepeatedly with different pool sizes. With 8,dynamicfailed with the shortfall warnings. With 9, all 3 runs failed with 2 or 3 warnings. With 10, all 8 runs passed with no warnings, and 12 also passed in 3 of 3 runs.On CI, the SQL regression step now passes on both legs, and the 22.04 leg has passed on every run since the pool change. The 24.04 leg, which also runs the TAP suite with
-j2, passed once (72 files, 1529 tests) and failed on several other runs, in a few different places (two of them ended withpg_ctl start failedfor which I have no logs). Test 58 stalled in a 12,000-row rollback in two runs before TAP logs were being uploaded, so I have no log of that and its cause is not established. It passed in the later runs.73_primary_slot_catchup_scale.plfailed in two runs with logs: once when a 60-row insert hit the test's 1000 ms worker timeout while the worker was saving the index, and once when the test's SIGKILL and immediate restart raced the old worker's exit and the new server refused to start because the shared memory was still in use. Neither mechanism involves search slot parking, and I have not compared the failure rate againstmain. Thelog/upload ran on those failures and the artifacts contained the TAP and server logs.The first checklist item under Tests is left unchecked because this PR does change behavior, and a number of existing tests were edited to match it, so "no failures with no changes" would not be accurate.