Repository navigation
Add optional bounded file-backed vector loading and batched access - #744
Merged
Merged
Conversation
Contributor
|
Before you submit for review:
If you did not complete any of these, then please explain below. |
tlwillke
marked this pull request as ready for review
October 10, 2026 01:43
tlwillke
requested review from
MarkWolters,
ashkrisk and
jshook
as code owners
October 10, 2026 01:43
This was referenced Oct 10, 2026
MarkWolters
requested changes
Oct 10, 2026
MarkWolters
left a comment
Contributor
There was a problem hiding this comment.
Left some comments requesting changes.
Full regression run in progress, will add results when it finishes.
Contributor
|
pr744.tar.gz |
MarkWolters
approved these changes
Oct 12, 2026
MarkWolters
left a comment
Contributor
There was a problem hiding this comment.
Looks good, thanks for addressing my comments.
Merged
tlwillke
added this pull request to stack #749
October 12, 2026 21:02
jshook
approved these changes
Oct 12, 2026
jshook
left a comment
Contributor
There was a problem hiding this comment.
Concerns addressed on sub-branch. LGTM!
forBenchmark(MultiConfig) now returns an explicitly set jvector.dataset_loader as-is, so buffered applies even to uncompressed-construction and exact-search configurations, matching the documented explicit override. Routing still applies when buffered input comes from the YAML useDatasetPrefetching flag. Fixes TestDatasetLoaderOverride.
randomAccessScoreProvider's value-shared path re-read node1 on every comparison, doubling source reads in full-precision builds from a file-backed source. The anchor is now copied on first use and kept by the score function: creation still reads nothing, the copy can't be overwritten by later reads through the same views, and each comparison reads only node2. Fixes TestBuildScoreProviderAnchorReads.
Storage.close() cleared each point reader's channel and buffer without taking its lease, so a concurrent point read could hit a null buffer or reopen a channel that was never closed. close() now takes each reader's lease before closing its channel, and readPointInto checks for closure after taking a lease, so later point reads fail with IllegalStateException. Fixes TestFvecCloseDuringPointReads.
tlwillke
force-pushed
the
batched-vector-access
branch
from
October 12, 2026 21:51
ed5f016 to
4dcfe91
Compare
jshook
approved these changes
Oct 12, 2026
jshook
left a comment
Contributor
There was a problem hiding this comment.
Reapproving after merge fixes
Closed
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.
This PR supersedes the dataset-loading approaches proposed in #737 and #721.
Purpose of this PR
Enable quantizer-independent, bounded access to input vector files without requiring the original base dataset to be fully resident in memory.
Buffered prefetching supports:
It is not intended for repeated raw-vector comparisons during full-precision graph construction. Encoded vectors, trained models and graph structures retain their existing memory requirements.
Bounded file-backed input vector loading
This PR allows quantization and construction to consume file-backed vectors without preloading the complete base dataset into Java heap.
BatchedVectorValuesoptionally supports ranges and arbitrary selections.VectorAccessuses batching when available and preserves ordinaryRandomAccessVectorValuesfallback.useDatasetPrefetching: trueto opt into buffered input where supported. Queries and ground truth remain resident.I/O workers follow JVector’s compute sizing. The shared input payload budget defaults to at most 1% of file size or 64 MiB, with one record as the minimum. Reads use ordinary positional file I/O and the OS page cache.
The loader supports immutable, seekable files on local or network-attached filesystems. Storage performance affects throughput. Buffering is bounded, but training samples, encoded vectors, graph state and JVM overhead still require memory.
No machine-specific heap limits, cgroup configuration or IntelliJ launch settings are included in this PR.
The flag is optional and defaults to false. Full-precision construction and
raw-input comparison workloads retain resident input. Grid uses resident quantized
vectors for construction peer scoring; each original insertion vector is supplied
from a bounded input batch. Query algorithms and scorer semantics remain unchanged.
AutoBenchYAML's existing exact compaction validation retains its resident input.
Benchmark results
The following tables contain only the three large datasets requested for final
validation. Times are seconds; memory is GiB. Measurements are copied from the
completed raw evidence without changing phase definitions or substituting estimates.
Ample memory: latest main versus this PR, both using main's existing
V6 writer. Limited memory: This PR plus the deferred complete-record batch writer, a separate follow-up PR (#747). That writer is not included in #744.
It retains V6 and batches complete records containing NVQ, FP or other fixed-size
feature payloads. The limited-memory timings shown require that additional writer
change; standalone #744 also completed under these limits with higher writing cost.
The follow-up writer implementation is on the
deferred-batch-writerbranch.Its PR number will be linked here when opened.
Memory configurations: ample = 128 GiB maximum Java heap, uncapped total
memory on the approximately 354 GiB host, zero swap; limited = 32 GiB total cgroup memory,
20 GiB maximum heap, zero swap. These are experimental settings, not library defaults.
All input datasets exceed the limited heap; Cohere and CAP also exceed the total cap.
Both configurations use JDK23, native Highway automatic
avx3_sprdispatch,preferred512, 48 insertion/cleanup workers, DOT_PRODUCT, PQ width8/K256/no centering/
anisotropic−1, NVQ2, M32/efConstruction100/overflow1.2, hierarchy and refinement
enabled, fused PQ, pruning disabled. Input files started cold, with verified
file-specific eviction. Every successful run trained fresh independent codebooks
and built a fresh graph. No query benchmark is included in this construction study.
Main source:
056d93c2; #744 source:1bab1881(the subsequent0b7c24e5changeonly fixes a documentation link); combined writer source:
9194992f.The table values remain the measurements of those frozen sources. Subsequent audit
commits
7b5d8c7eandb5761f33fix JDK test compatibility, bound scan ordinal metadata anddemand-read progress, correct mapped-input diagnostic validation, and make test subprocess logs UTF-8
across platforms; no table
values were changed or extrapolated to the later commits.
OOM† is the recorded preload failure from earlier tests with the same
32 GiB/20 GiB/zero-swap limits, before graph construction or writer execution.
Those failures were not rerun in the final study. A dash means no completed-run
metric is available. The reported ample MPNet pair is the final counterbalanced
repeat; prior runs remain archived. Independent training and parallel graph
topology introduce variability, so these tables do not establish universal speedups.
Total process time summary
Cohere 10M
Base input: 10,000,000 vectors × 1,024 dimensions; 38.184 GiB fvecs, including record headers. Memory limits are specified above.
MPNet 10M
Base input: 9,997,697 vectors × 768 dimensions; 28.641 GiB fvecs, including record headers. Memory limits are specified above.
CAP 6M
Base input: 6,070,488 vectors × 1,536 dimensions; 34.758 GiB fvecs, including record headers. Memory limits are specified above.
Preparation includes upfront base-vector loading for main; #744 opens the file
and reads vectors during the pipeline. Avoiding preload explains essentially all
of the ample MPNet total-time saving (its pipeline is 1.949 s slower). Cohere and
CAP also show faster pipelines, principally insertion; these measurements do not
isolate the cause of those additional gains, especially CAP's large difference.
Pipeline is the sum of training, encoding, NVQ setup, insertion, cleanup and
writing. Process time also includes preparation, JVM startup, logging and cache
bookkeeping. Deferred NVQ encoding occurs during final writing rather than insertion.
RSS is a separate process resident peak, not heap plus buffer pool. Buffer pool
includes mapped address ranges and is not resident memory; it excludes other native
memory. GC reclaimed is cumulative. The constrained cgroup limit includes charged
file cache and kernel memory; all three combined runs completed without OOM or swap.
Reproduction
fvecs files,
NO_SCRUBmetadata and the construction settings listed above.backend, V6 writer, storage placement, concurrency and resource limits. Enable
useDatasetPrefetching: trueonly in Add optional bounded file-backed vector loading and batched access #744's index-parameter YAML.integration branch, retain V6, enable its existing parallel writer with 48
workers and the default 64-record batches, and apply the recorded 32 GiB cgroup /
20 GiB heap / zero-swap limits. The ordinary Add optional bounded file-backed vector loading and batched access #744 branch does not contain this writer.
file-specific cold input cache before each run; allow natural warming during it.
Preserve failures and outliers. Do not overlap benchmark workloads.
separately. Record total child-process time and peak RSS; sample heap/buffer pool
at 100 ms; collect GC logs and in-run cgroup high-water under the limited protocol.
The recorded construction-only study used external phase markers and a return
before queries; those measurement adapters are not committed library features.
Choose heap and worker counts for the machine; no machine-specific limits are
committed. For a standard BenchYAML invocation, use caller-supplied runtime values:
The existing
-Djvector.dataset_loader=preload|bufferedremains an explicit override.Full-precision construction and raw-input exact comparisons keep their resident
source. Production applications can continue supplying ordinary RAVVs without
implementing the optional bulk hooks.
Documentation and validation
docs/batched-vector-access.mdcovers public-dataset hello-world examples, arbitrary selections, sequential scans,
borrowed-vector ownership, resource limits, fallback behavior and the benchmark opt-in.
The required 4.0.2 release note
is included.
The post-audit focused suite completed 127 tests on Java 11 and 127 tests
on Java 23 with native Highway enabled, with zero failures. The FFM cold-cache test
is skipped on Java 11. Coverage includes the AutoBenchYAML configuration-error
regression, a 1,000,003-ordinal bounded mapped scan, array-free PQ identity scans,
prefix/tail encoding parity, mapped ordering/duplicates with debug validation,
and demand-read zero-progress/EOF handling. Added coverage exercises concurrent reads,
buffer bounds, cancellation/closure, zero-progress reads, ordinary-source fallback,
sampling order/duplicates, quantizer encoding parity, and borrowed-vector ownership.
The quantization algorithms, distance metrics, stored V6 layout and query semantics
are preserved. The deferred-writer follow-up has its own serialization validation.