Skip to content

fix(vector): SQ8/TQ code-size mis-dispatch CPU error-storm (#73)#334

Merged
pilotspacex-byte merged 1 commit into
mainfrom
fix/sq8-tq-misdispatch-error-storm
Jul 15, 2026
Merged

fix(vector): SQ8/TQ code-size mis-dispatch CPU error-storm (#73)#334
pilotspacex-byte merged 1 commit into
mainfrom
fix/sq8-tq-misdispatch-error-storm

Conversation

@pilotspacex-byte

@pilotspacex-byte pilotspacex-byte commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Fix: SQ8/TQ code-size mis-dispatch CPU error-storm

The bug

SQ8's QuantizationConfig::bits() returns 8, which is outside TurboQuant's
supported 1..=4 range. The free helper code_bytes_per_vector(padded, bits) fell
through to its _ => arm, returned 0, and logged a tracing::error! on every
call
. Because that helper sits on the hot memory-accounting path (store.rs via
bytes_per_code_per_vector()), an SQ8 index produced:

  • a CPU-pegging error storm (one tracing::error! per accounting call), and
  • wrong resident-byte accounting (0 bytes/code → under-counted SQ8 memory).

This was the real cause of the leaked-process CPU spike originally mis-attributed to
the I/O busy-poller.

The fix

Dispatch now computes the true SQ8 layout directly instead of routing through the
TurboQuant bit-width path:

  • code_bytes_per_vector() — SQ8 ⇒ dim (true, unpadded) u8 codes; TQ4 ⇒ padded/4.
  • bytes_per_code_per_vector() — SQ8 ⇒ dim + SQ8_PARAMS_BYTES (8-byte affine
    (min,scale) trailer).
  • The free code_bytes_per_vector _ => arm now logs the unsupported-bit-width error
    at most once via an AtomicBool latch (defensive; no longer on any live SQ8 path).

Tests (red/green TDD)

New test_code_bytes_per_vector_sq8 asserts the real layout (dim 768 → 768/776;
dim 384 → 384/392). Full vector suite green on the VM: 970 passed, 0 failed.
cargo fmt --check clean; cargo clippy -- -D warnings clean on both default and
runtime-tokio,jemalloc feature sets.

Scope / risk

Memory-accounting + logging only — no change to SQ8 encode/decode/search/merge
correctness (compaction already guarded SQ8 at compaction.rs:1143). Additive
CHANGELOG entry under [Unreleased].

Closes #73.

Summary by CodeRabbit

  • Bug Fixes

    • Corrected SQ8 vector storage sizing and dispatch calculations.
    • Prevented repeated error logging when unsupported bit widths are encountered, reducing unnecessary log noise.
    • Improved accounting for SQ8 vector dimensions, padding, and metadata storage.
  • Documentation

    • Added the fix details to the unreleased changelog.

… memory accounting

SQ8's `QuantizationConfig::bits()` returns 8, which is OUTSIDE the TurboQuant
1..=4 range that the free `code_bytes_per_vector(padded, bits)` supports. On the
`_ =>` arm that function returned 0 and logged `tracing::error!` on EVERY call.

`CollectionMetadata::code_bytes_per_vector()` fell through to that free fn for
SQ8, so any unconditional caller hit the 0-return + per-call error log. The hot
memory-accounting paths (`store.rs` used_memory / eviction checks:
`live_count * bytes_per_code_per_vector()`) call it repeatedly, turning a benign
config into a CPU-pegging error storm and an under-count of SQ8 resident bytes
(reported ~4 B/vec instead of dim+8). Observed 2026-07 on a lunaris-backed SQ8
store (one moon instance pegged a core; log flooded with the codebook error).

Root cause is a size-dispatch gap, not io busy-poll. SQ8 stores `dim` u8 codes
(TRUE, unpadded dimension) + an 8-byte (min,scale) trailer — as `MutableSegment::new`
and `compaction.rs` already special-case inline. The collection-level helpers did
not.

Fix (comprehensive, host-tested):
- `CollectionMetadata::code_bytes_per_vector()`: SQ8 -> `dimension` (true dim),
  matching the segment/compaction inline branches; TQ paths unchanged.
- `CollectionMetadata::bytes_per_code_per_vector()`: SQ8 -> `dimension +
  SQ8_PARAMS_BYTES` (8-byte trailer), not `code_bytes()+4`. Corrects memory
  accounting (store.rs) and is consistent with the already-SQ8-guarded compaction
  slot sizing.
- Free `code_bytes_per_vector`: log the unsupported-width error ONCE (AtomicBool)
  instead of per-call, so any future stray caller can never re-create the storm.

Verified: FT.CREATE already rejects bogus quant strings (TQ8 etc.) at
ft_create.rs:704 — the bits=8 origin was legitimate SQ8, so no create-path change
needed. Compaction (compaction.rs:1143) already guards SQ8 explicitly, so it was
never corrupted; the live bug was purely the unguarded memory-accounting calls.

Tests: new `test_code_bytes_per_vector_sq8` (dim 768 -> 768/776; dim 384 ->
384/392). Pre-fix these returned 0/4. Existing TQ code-size tests unchanged.

Refs #73. Branch held for PR until v0.7.0 is tagged (24h replication soak owns the
CI VM).

author: Tin Dang <tindang.ht97@gmail.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 094f72a0-0869-49a5-8cee-784b1ecb0682

📥 Commits

Reviewing files that changed from the base of the PR and between 5dcfbd2 and 067982a.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/vector/turbo_quant/codebook.rs
  • src/vector/turbo_quant/collection.rs

📝 Walkthrough

Walkthrough

Changes

SQ8 TurboQuant corrections

Layer / File(s) Summary
SQ8 storage accounting
src/vector/turbo_quant/collection.rs, CHANGELOG.md
SQ8 code sizing now uses the true dimension, and per-vector storage includes SQ8_PARAMS_BYTES; tests cover padded and non-square dimensions.
Unsupported-width log guard
src/vector/turbo_quant/codebook.rs
Unsupported bit-width errors are logged once per process while the existing zero return value is preserved.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: tindang97

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is well written but does not follow the required template headings for Summary, Checklist, Performance Impact, and Notes. Rewrite the PR description using the repository template and include Summary, Checklist, Performance Impact, and Notes sections.
Linked Issues check ⚠️ Warning The PR addresses SQ8/TQ memory-accounting and logging, not the Moon Console UI, endpoints, or tests required by linked issue #73. Either link the correct issue for this bug fix or implement the Moon Console requirements from issue #73.
Out of Scope Changes check ⚠️ Warning The changes are unrelated to the Moon Console scope in #73 and appear to be a separate vector quantization bug fix. Remove or retarget these changes to a matching issue; if #73 is intended, the PR must cover the Moon Console objectives instead.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the actual change: an SQ8/TQ code-size misdispatch fix causing CPU error storms.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/sq8-tq-misdispatch-error-storm

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pilotspacex-byte
pilotspacex-byte merged commit f564170 into main Jul 15, 2026
9 checks passed
pilotspacex-byte added a commit that referenced this pull request Jul 15, 2026
Patch release folding in the two v0.7.0-tag-disclosed follow-ups (SQ8 #73/#334 + replica TTL #71/#335), both already on main. Version 0.7.0->0.7.1, CHANGELOG [0.7.1] roll-up, RELEASES.md ledger entry, clustering.md TTL note flipped to shipped. Author: Tin Dang <tindang.ht97@gmail.com>
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.

2 participants