Skip to content

fix(reprocess): drop Lance tables before full-reprocess (99% hang)#394

Merged
HumanBean17 merged 1 commit into
masterfrom
fix/reprocess-drop-before-full-reprocess
Jul 6, 2026
Merged

fix(reprocess): drop Lance tables before full-reprocess (99% hang)#394
HumanBean17 merged 1 commit into
masterfrom
fix/reprocess-drop-before-full-reprocess

Conversation

@HumanBean17

Copy link
Copy Markdown
Owner

Bug

reprocess hangs at 99% for many minutes (15+ on a large repo), every run, even after a clean reinit. erase → init works fine.

Root cause

reprocess = cocoindex update --full-reprocess against an existing table → the in-place bulk-update merge_insert path. cocoindex implements that as ~one deletion-vector + version commit per matched row — O(rows) of tiny file IO, not a batched operation. It spins at 99% CPU in native _lancedb.abi3.so (main thread parked in kevent), and the deletion files accumulate without cleanup, so it worsens each run.

Measured on Shopizer (3475 chunks), with a process sample during the hang confirming native lancedb + heavy libsystem_malloc/libsystem_kernel:

path _versions _deletions files sys time wall
init (insert, fresh table) 3 0 11 4.5s 34s
reprocess (bulk-update) 3481 3474 10450 83s 105s → hangs
drop+reprocess (insert) 2 0 5 3.6s 28s

LANCE_MEM_POOL_SIZE=4GiB does not help (still 105s) — this is file-IO amplification, not memory. So independent of #392 (concurrency) and #393 (mem-pool/PK-index); neither causes nor addresses it.

Fix

A full reprocess rebuilds every row, so drop the Lance target tables first and let cocoindex recreate them via the fast INSERT path. Drop+recreate is semantically identical to a full rebuild — all rows are recomputed either way; only the write path differs. Drop only touches the 3 vector tables, not the graph, so reprocess's graph phase is unaffected.

Applied at both --full-reprocess sites:

  • pipeline.run_cocoindex_updatereprocess --vectors-only
  • server.run_refresh_pipeline → default reprocess (vectors+graph) — the path users hit

Drop failure is non-fatal: a non-preflight failure logs and falls back to the slow in-place path; a 127/126 preflight stub (graph-only installs) stays silent.

Validation

End-to-end on Shopizer via the real CLI (default reprocess):

before after
wall 105s → hangs 2:42+ 48s (≈ init)
sys time 83s 4.9s
_deletions 3474 0
_versions 3481 3

The child log confirms the drop cleared the tables ("No existing dataset ... it will be created" ×3) and vectors ticked 25→1150 with no stall. 1130 tests pass (+4 new in tests/test_pipeline.py: full_reprocess drops once; increment does not drop; drop failure falls back; preflight stub silent).

Workaround until merged

erase → init instead of reprocess (same fast insert path, identical rebuild).

🤖 Generated with Claude Code

…row-delete hang

reprocess (cocoindex ``update --full-reprocess`` against an EXISTING table) took
the in-place bulk-update merge_insert path, which cocoindex implements as ~one
deletion-vector + version commit PER matched row — O(rows) of tiny file IO.
Measured on Shopizer (3475 chunks): 3481 versions / 3474 deletion files / 83s
sys time, degrading to a multi-minute 99%-CPU hang (native ``_lancedb.abi3.so``,
main thread parked in ``kevent``) that reproduces every run and worsens with repo
size — a larger repo hung 15+ min at "99%".

init (insert into a fresh table) is unaffected: 3 versions / 0 deletions / 4.5s
sys. drop+recreate is semantically identical to a full rebuild (all rows are
recomputed either way), so make reprocess DROP the Lance target tables first and
let cocoindex recreate them via the fast INSERT path.

Applied at both ``--full-reprocess`` sites:
- ``pipeline.run_cocoindex_update``  → covers ``reprocess --vectors-only``
- ``server.run_refresh_pipeline``    → covers the default ``reprocess`` (vectors+graph)

Drop failure is non-fatal: a non-preflight failure logs and falls back to the
slow in-place path; a 127/126 preflight stub (graph-only installs) stays silent.

Validated on Shopizer: reprocess 105s→hang → 48s (≈ init), sys 83s→4.9s,
deletions 3474→0, versions 3481→3. Independent of #392 (concurrency) and #393
(mem-pool/PK-index): ``LANCE_MEM_POOL_SIZE=4GiB`` did not help — this is file-IO
amplification, not memory.

Tests: ``tests/test_pipeline.py`` — full_reprocess drops exactly once; increment
does not drop (would lose the table); drop failure falls back to in-place; a
preflight drop stub is silent.

Co-Authored-By: Claude <noreply@anthropic.com>
@HumanBean17 HumanBean17 merged commit 96f3658 into master Jul 6, 2026
3 checks passed
@HumanBean17 HumanBean17 deleted the fix/reprocess-drop-before-full-reprocess branch July 6, 2026 20:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant