Commit dd26859
fix(master): stop MergeWal starving Compact in the scheduler (#239)
## Problem
`Compact` tasks could sit queued indefinitely whenever `MergeWal` load
was present. In production the 600s auto-sweep kept ~50–80 MergeWal
tasks queued/running, fragments grew to **1,085,065** (1–10 rows each),
and because every worker's open `Dataset` handle keeps the full manifest
resident, **18 of 20 workers were OOMKilled**. Scaling the master 3→8
replicas did not help — every added slot was consumed the same way.
## Root cause: admission, not concurrency
`MERGE_WAL_CONCURRENCY` already gave merge its own semaphore, but a
single dispatch loop called one **unfiltered** `claim_next()` and only
chose a pool *after* the claim.
Claiming is destructive — it deletes the queue key, grants a lease, and
takes the per-experiment target lock. So a claim made because the
*general* pool had permits could return a `MergeWal`, then park it on
the saturated merge semaphore **while holding its target lock**. With
MergeWal numerically dominant, nearly every claim returned one, and the
loop's `while` guard stayed true only because the general pool was idle.
The dispatcher spun claiming work it could not run while a lone
`Compact` sat queued behind it.
### One correction to the issue's diagnosis
The issue lists "single shared queue, interleaved only by queue key
order" as root cause #1. That part is not accurate: task ids are
**UUIDv7** (`lance-context-core/src/id.rs`), so the queue is genuinely
time-ordered FIFO — ordering was never arbitrary.
This matters, because plain FIFO turns out to be sufficient once
admission is fixed. **No priority, fairness policy, or reserved capacity
was added** — those would solve a problem that isn't there.
## Fix
Add `TaskKinds`, a small kind set threaded into `claim_next`, and run
**one poller per pool** — `GENERAL` (Compact + IndexId) and `MERGE_WAL`
— each claiming only the kinds it can actually run. The filter is
applied *before* the dependency probe, so skipped kinds cost nothing.
FIFO order within a kind is unchanged, and **no new config knob** is
introduced.
One caveat, now documented in the config docs rather than left implicit:
`MERGE_WAL_CONCURRENCY=0` shares a single pool, which necessarily
reinstates single-poller behavior. Prefer a non-zero value when both
kinds are in play.
## Tests
Both etcd-backed, and **both verified to fail with the fix reverted**:
- `filtered_claim_reaches_compact_behind_merge_wal_backlog` — 30
MergeWal enqueued *ahead* of one Compact (worst case for FIFO). Asserts
an unfiltered claim still returns MergeWal, so the test cannot silently
stop exercising the scenario; that `GENERAL` reaches the trailing
Compact; that `GENERAL` never returns MergeWal; and that the merge pool
still drains its own backlog.
- `compact_runs_while_merge_wal_pool_is_saturated` — end-to-end through
the dispatcher against a stub worker that accepts and never responds.
Asserts the Compact reaches `Done` **and** that MergeWal work is still
outstanding, so it cannot pass merely because the backlog drained.
**Negative verification:** with the kind filter removed, the first fails
on the kind assertion and the second hangs to timeout — the production
symptom exactly.
Full suite green: 22/22 etcd-backed master tests, 222 core, 68 server,
`fmt` + `clippy -D warnings` clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>1 parent 7e39d92 commit dd26859
3 files changed
Lines changed: 324 additions & 23 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
152 | 152 | | |
153 | 153 | | |
154 | 154 | | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
155 | 163 | | |
156 | | - | |
| 164 | + | |
| 165 | + | |
157 | 166 | | |
158 | 167 | | |
159 | 168 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
| 37 | + | |
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| |||
447 | 447 | | |
448 | 448 | | |
449 | 449 | | |
450 | | - | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
451 | 458 | | |
452 | 459 | | |
453 | 460 | | |
| |||
494 | 501 | | |
495 | 502 | | |
496 | 503 | | |
497 | | - | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
498 | 553 | | |
499 | 554 | | |
500 | | - | |
501 | | - | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
502 | 559 | | |
503 | | - | |
504 | | - | |
505 | | - | |
506 | | - | |
507 | | - | |
508 | | - | |
509 | | - | |
| 560 | + | |
510 | 561 | | |
511 | | - | |
| 562 | + | |
512 | 563 | | |
513 | 564 | | |
514 | 565 | | |
515 | 566 | | |
516 | 567 | | |
517 | | - | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
518 | 571 | | |
519 | | - | |
520 | | - | |
521 | | - | |
522 | | - | |
523 | | - | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
524 | 577 | | |
525 | 578 | | |
526 | 579 | | |
527 | 580 | | |
528 | | - | |
| 581 | + | |
529 | 582 | | |
530 | 583 | | |
531 | 584 | | |
| |||
756 | 809 | | |
757 | 810 | | |
758 | 811 | | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
759 | 904 | | |
760 | 905 | | |
761 | 906 | | |
| |||
0 commit comments