Skip to content

perf(diskann): Yi-aligned update path, async I/O, and search hot-path optimizations - #103

Merged
huanglune merged 19 commits into
AlayaDB-AI:mainfrom
huanglune:dev/yi
Jul 7, 2026
Merged

perf(diskann): Yi-aligned update path, async I/O, and search hot-path optimizations#103
huanglune merged 19 commits into
AlayaDB-AI:mainfrom
huanglune:dev/yi

Conversation

@huanglune

Copy link
Copy Markdown
Contributor

Summary

Migrate Yi's DiskANN update/search performance optimizations into AlayaLite, covering build system modernization, update path alignment, coroutine-based async I/O, and search hot-path kernel optimizations.

  • Build system: Modular CMake rewrite + official Conan dependency provider replacing hand-rolled scripts
  • Python: Fix runtime dependencies and repair the rag subpackage
  • Update path: Align with Yi baseline semantics — mixed concurrency queue, node cache coherence, shard page pool
  • Async I/O: C++20 coroutine + io_uring reactor for the update I/O path
  • Search hot-path: Batched PQ kernel, dirty-word visited bitset, page cache node recycling, tombstone snapshot skip, query-level coroutine pipelining

Commit breakdown

Build & CI

Commit Description
2aa177e Rewrite build system into modular, presets-based CMake layout
d34692d Replace hand-rolled conan_install.py with official conan_provider.cmake
22d6491 Exempt vendored conan provider from content-mutating pre-commit hooks
01a8795 Build uring_reactor_test in the codecov CI job

Python

Commit Description
51208ed Correct runtime dependencies and repair the rag subpackage

DiskANN update path (Yi alignment)

Commit Description
7d1a14d Align update path with Yi baseline semantics
d952c17 Improve update path concurrency
1f41229 Add mixed update concurrency
cb43e21 Add shared mixed worker queue
3ee2c27 Align mixed benchmark semantics
2770385 Honor update workers in mixed queue
e24960e Keep node cache coherent during updates
80c6b4f Restore laser reader boundary

Async I/O & page pool

Commit Description
b401eca Coroutine async update I/O via cooperatively-polled io_uring
a143cb2 Unified page pool — searches peek and fill the shard cache

Search hot-path optimizations

Commit Description
f5fcdb0 Batched PQ kernel, dirty-word visited reset, query pipelining, and search profiling

Key changes

1. Batched PQ distance kernel

pq_distance_batch() gathers code rows into a contiguous stack tile with software prefetch, then accumulates chunk-major so the dist_table row stays L1-hot. Eliminates the per-neighbor dependent random 32B code fetch that dominated eval at 100M scale. Bit-identical to the scalar path.

2. Dirty-word visited bitset

clear() now costs O(words set) via a dirty-word tracking list instead of a full-array memset. Removes the ~12MB per-query DRAM bandwidth wall at 100M slot counts.

3. Page cache node recycling

At steady-state capacity, write() splices the LRU victim's map node and 4KB buffer in-place instead of erase+alloc, cutting per-fill heap traffic under concurrent shard search.

4. Tombstone snapshot skip

make_search_snapshot() skips the full-capacity bitmap copy when count()==0 — zero overhead on the common post-compaction no-tombstone path.

5. search_pipelined() — query-level coroutine pipelining

num_threads pool threads drive pipeline concurrent query coroutines over the shared io_uring reactor. Each query suspends on its beam-wave reads instead of parking a thread; throughput follows Little's law. Requires update_io=uring.

6. Coroutine async update I/O

The update path uses a cooperatively-polled io_uring reactor for asynchronous disk I/O, avoiding blocking threads during page reads/writes.

7. Unified page pool

Searches peek and fill the shard page cache, so hot pages written by updates are visible to subsequent searches without cold reads.

Test plan

  • test_diskann_update_e2e::PipelinedSearchMatchesBatchSearch — validates recall parity between pipelined and sync paths (within ±3%)
  • bench_diskann_sift_update --eval_pipeline — end-to-end throughput/latency with per-query IO breakdown
  • All existing diskann e2e / PQ / tombstone tests pass
  • CI codecov job builds and runs uring_reactor_test

huanglune added 17 commits July 1, 2026 15:14
Restructure the monolithic root CMakeLists into cmake/ modules with a
thin orchestrator, keeping the external contract intact (option names,
target names, ctest names/labels, install destinations, plain-cmake CI
configure, scikit-build/cibuildwheel wheel pipeline). ctest inventory
is byte-identical before/after (85 tests, same labels).

Layout:
- cmake/AlayaOptions.cmake     all user-facing switches + validation
- cmake/AlayaPreflight.cmake   early actionable env checks (compiler
                               floor, Python C API headers)
- cmake/AlayaToolchain.cmake   std/ccache/fast-linker/sanitizer detect
- cmake/AlayaFlags.cmake       flags as linkable alaya_build_flags
                               INTERFACE target (no directory-global
                               add_compile_options)
- cmake/AlayaDependencies.cmake conan bootstrap + find_package
- cmake/AlayaLaser.cmake       LASER backend wiring (alaya_laser)
- cmake/AlayaTesting.cmake     alaya_cc_target/alaya_add_test helpers;
                               tests/* shrink to declarative lists
- CMakePresets.json            release/debug/asan/coverage presets;
                               Makefile now wraps presets

Fixes baked in:
- laser fixture rule: depend on the _alayalitepy target instead of
  running a nested `cmake --build` inside the build graph; the nested
  build raced the outer ninja on the same pybind objects/PCH and
  produced cc1plus ICEs plus corrupted .ninja_deps on fresh parallel
  builds
- rename custom target codegen -> alaya_codegen ("codegen" is reserved
  from CMake 3.31, policy CMP0171; configuring with 3.31 used to fail)
- unify Python discovery on FindPython incl. pybind11
  (PYBIND11_FINDPYTHON): one interpreter for conan bootstrap, module
  and fixtures; prefers the uv-managed .venv, accepts legacy
  -DPython3_EXECUTABLE, and rejects header-less interpreters at
  configure time with instructions
- Makefile conan-install: uv run --no-project breaks the fresh-machine
  bootstrap cycle (editable build needing the deps being installed)
- conanfile: stop generating CMakeUserPresets.json (stale includes
  broke `cmake --preset` after make clean); clean removes leftovers
- -Ofast/-funroll-loops now Release-only, sanitizer builds pin -O1
  (Debug builds are actually debuggable; MSVC no longer forces /O2
  into Debug)

Verified: clean-tree 96-way parallel bootstrap (conan -> configure ->
192 targets) with zero ICEs and single fixture run; ctest 83/83
(-LE performance); asan preset build + subset green; codecov-style
BUILD_PYTHON=OFF coverage path green; uv sync editable rebuild +
pytest 356 passed; pre-commit (cmake-format/lint, cpplint, reuse)
all green. cmake_minimum_required is now 3.23...3.31.
Dependency metadata told the wrong story: pandas was the only declared
runtime dependency yet nothing in the SDK imports it, while numpy is
imported by 15 modules and arrived only transitively through pandas.
Declare numpy>=1.24 as the sole runtime dependency and move pandas to
the laser dev group (examples/laser and scripts/laser_alignment are
its only users).

alayalite.rag shipped in every wheel but could not be imported: the
chunker modules used top-level `from rag.chunker...` imports (wrong
package root, wrong module casing) plus sys.path hacks, and pulled
sentence-transformers/FlagEmbedding/torch/langchain at module import.
Fix the imports to proper relative form, drop the path hacks, make all
heavy dependencies lazy with an ImportError pointing at the new
`alayalite[rag]` extra, add the missing rag/__init__.py, replace the
sklearn two-vector cosine with numpy, and remove a stray debug print.
SentenceChunker now works dependency-free.

Housekeeping: drop the unused `api` dependency group (fastapi/uvicorn/
httpx are referenced nowhere) and the vestigial fastapi/httpx wheel
test-requires; remove setuptools/wheel from build-system requires
(scikit-build-core is the backend); add classifiers and repo URLs;
document why __init__ silences numpy's subnormal warnings (FTZ from
the -Ofast-built extension module).

Verified: uv lock/sync; pytest 356 passed; pre-commit all green;
uv build wheel; fresh-venv install smoke (numpy-only env): import,
Client/create_collection, alayalite.rag import, SentenceChunker
end-to-end, lazy ImportError messages for all model-backed classes.
…dency provider

The previous integration was bolted on: cmake/ConanSetup.cmake ran a
450-line wrapper script (scripts/conan_build/conan_install.py, invoking
conan through uvx) via execute_process inside the configure, then
include()d conan_toolchain.cmake AFTER project() — where the *_INIT
toolchain variables silently do nothing — and anchored the generator
output to a magic source-tree path (build/<type>/generators) that every
build tree had to share.

Now dependencies resolve through the official cmake-conan dependency
provider (cmake/vendor/conan_provider.cmake, pinned from
conan-io/cmake-conan @ b1593849dd84, MIT):

- cmake/AlayaConan.cmake registers it via CMAKE_PROJECT_TOP_LEVEL_INCLUDES
  before project(); the first intercepted find_package() runs
  `conan install` with a host profile derived from the real toolchain
  state (compiler, version, arch, build_type, CMAKE_CXX_STANDARD->cppstd)
- generators land per build tree (<binary dir>/conan); no toolchain
  file include, no wrapper script, no source-tree anchoring
- Python discovery (FindPython) uses BYPASS_PROVIDER so the first
  intercepted package is a real C++ dependency, after the C++ standard
  is configured — otherwise the derived profile says cppstd=gnu17 and
  libcoro's >=20 validation rejects it
- `conan` is now an explicit prerequisite on PATH for interactive
  builds (uv tool install conan; preflight prints exactly that when
  missing). PEP 517 builds (uv sync / uv build / cibuildwheel) already
  carry the CLI via [build-system].requires, so wheel lanes need no
  provisioning; gnu_codecoverage.sh self-provisions on CI runners
- deleted: cmake/ConanSetup.cmake, scripts/conan_build/ (installer
  script + per-arch profile files); Makefile conan-install targets
  (any reconfigure re-resolves); cibuildwheel before-build conan step
- conan cache action keys track conanfile.py + the vendored provider
  (conan-v3); codecov workflow paths/ccache keys updated accordingly
- cmake_minimum_required 3.24 (CMAKE_PROJECT_TOP_LEVEL_INCLUDES floor);
  scikit-build cmake.version >=3.24; vendored file exempt from
  cmake-format/lint and REUSE-annotated as MIT (JFrog)

Verified locally: cold-cache new-machine bootstrap (empty ~/.conan2 ->
configure in 84s, 8 packages source-built); warm configure 2.5s; full
build 192/192 + ctest 83/83 (-LE performance); make/asan/coverage+
BUILD_PYTHON=OFF paths; uv sync editable rebuild + pytest 356 passed
(incl. updated CI guard tests); uv build wheel + fresh-venv smoke;
pre-commit all green. cibuildwheel/codecov workflow changes need a CI
run upstream for final validation.
cmake/vendor/conan_provider.cmake must stay byte-identical to upstream,
but upstream carries a 'supress' typo and trailing whitespace that the
repo-wide typos and trailing-whitespace checks flag. Exclude the vendor
directory from both (typos needs --force-exclude because pre-commit
passes filenames explicitly), and fence the opt-out example comment in
AlayaConan.cmake so cmake-format keeps it verbatim.
Semantic audit of the migrated update path against Yi (verified line-by-line
on both sides) found the port was approximate; this change makes the
algorithms match and removes the scaling walls the benchmark exposed.

Correctness:
- SlotAllocator: alloc() now keeps the slot tombstoned; publish() clears it
  after the record bytes + PQ code exist. Reused slots were search-visible
  through stale in-edges before their data landed (mixed-search race).
- NodeCache: reconnect results now mirror unconditionally into override
  records (update_neighbors silently no-oped for uncached nodes, so
  searches read stale on-disk adjacency between flushes).
- TombstoneBitmap: storage is now a fixed table of atomically published
  8 KiB chunks instead of a flat vector. The reconnect path queries
  is_deleted() lock-free while allocs tombstone fresh slots, and a fresh
  slot beyond capacity grew the vector -- relocating it under those readers
  (TSan-confirmed use-after-free window; also word-level read/write races
  and a non-atomic tombstone count). Chunks never move, words and the
  count are atomic, and searches now take a flat TombstoneSnapshot copy
  under the update lock instead of copying the whole bitmap object.

Yi-parity algorithm alignment (all defaults, knobs to restore old behavior):
- Insert links the top max_degree candidates by symmetric-PQ order with an
  optional exact-L2 rerank (update_rerank, default on = Yi trace bench);
  alpha-prune of the insert pool is now opt-in (update_insert_prune).
- Insert search L defaults to max_degree+32 (Yi build_k; update_search_l=0).
- Two-hop repair candidates capped at 5 live nodes per deleted neighbor.
- Reconnect keeps pools <= max_degree verbatim (no scoring); overflow heap-
  caps to max_degree+32 nearest before alpha-prune.
- Flush moved out of the update path: per-op/per-batch page writeback is
  gone; flush_pages() (dirty pages + override drop) is the light checkpoint
  and the benchmark calls it outside the timed section, like Yi's
  background writeback.
- DiskANNBuildParams::record_capacity: on-disk neighbor slots per record
  (0 => R). Building R=64 graphs in capacity-96 records reproduces Yi's
  MAX_NEIGHBOURS=96 headroom, where reconnects almost never overflow.

Scaling (found via thread-scaling probes on SIFT1M):
- DiskPageIO: single io_mutex_ -> 64 page-offset shards (own mutex, LRU
  cache and version map per shard); atomic file size; batch neighbor reads
  consult the shard cache before raw pread (also fixes a stale-read hole).
- NodeCache: single shared_mutex -> lock-free immutable base after load +
  64-way sharded override map.
- batch_insert: replaced the 4-phase barrier pipeline with Yi-style
  end-to-end insert coroutines (search -> alloc -> write -> publish ->
  stage edges -> reconnect) and striped edge staging; one when_all per
  chunk.

Benchmark protocol (bench_diskann_sift_update):
- --mixed gets a round-0 no-update baseline like Yi's UpdateRunner;
  flush time is reported as its own flush_ms CSV column outside update_ms;
  new flags: --no_flush_rounds, --no_update_rerank, --update_insert_prune,
  --no_mixed_round0, --capacity.

SIFT1M 900k-init, 10x10k yi_sequential trace, R=64/cap96, pq32, eval L=25:
- trace parity: 2820 -> 11526 qps steady-state (4.1x), recall 0.900->0.907
- mixed (8t):   3189+3190 -> 8581 update + 4291 sustained search qps
- Yi itself on the same machine/graph/trace (uring backend): 2851-4094 qps
  parity, recall within 0.2pp of ours -- semantics independently validated.

Tests: publish-semantics unit tests updated; new RecordCapacity e2e tests
(build R<capacity, reload, self-search) and BuildRejectsCapacityBelowR.
TSan (build/Tsan, setarch -R): update-path runtime clean; remaining
reports are the pre-existing vamana OMP build races.
…_uring

Make every disk read on the DiskANN update path awaitable so pool threads
suspend instead of blocking — Yi's tasklet behavior at plain pool sizes —
and deliver completions by cooperative polling rather than a reaper thread.

Infrastructure:
- storage/io/uring_reactor.hpp: shared-ring reactor. read()/read_batch()
  are coro::tasks: one io_uring_submit per wave, then the waiting
  coroutine reaps the CQ from user space (try-locked peek, no syscall)
  and yields through its pool between polls. A reaper-thread design was
  measured first: its per-wave cross-thread wake chain cost ~230K
  voluntary context switches/s (41% kernel time) and capped utilization
  at 57%. Polling removes the chain and the resume handoff entirely.
  Submission hard-failures poison the reactor with exact in-kernel
  accounting so a failed wave drains before its frame unwinds.
  liburing is prebuilt/uninstrumented — TSan cannot see the
  submit -> kernel -> CQE handoff — so the ring handoff is annotated
  (__tsan_release at SQE prep, __tsan_acquire at CQE dispatch; TSan
  builds only). The C++-visible ordering is already carried by the
  wave counter's acq_rel chain.
- storage/io/{io_engine,io_uring_engine}.hpp, utils/macros.hpp: recovered
  from archive/dev-diskann-2026-04-19 (Apache -> AGPL headers); the
  reactor adopts its poll-don't-sleep philosophy.
- utils/coro_gate.hpp: AsyncGate<T>, a suspending object pool. Reactor-
  mode searches hold a ThreadData across waves; a thread-blocking pool
  would deadlock (all threads parked in acquire while every td is held
  by a suspended coroutine — no thread left to run the release).
  release() hands the object to the oldest waiter and reschedules it
  through its pool, never inline.

Update path:
- beam_search_async.hpp: disk_greedy_search_async (No-PQ) and
  pq_beam_search_async (PQ, no-rerank) — the update search suspends on
  reactor waves through the reader's O_DIRECT fd. Cache hits are served
  inline (Lookup guards never cross a suspension); misses land in
  neighbor-list/popped order, byte-identical to the sync deterministic
  scheduler on a cache-free index (tested). Both consult the update
  shard cache (DiskPageIO::try_read_cached_page) before issuing device
  reads — the unified-cache view Yi's buffer pool gives its tasklets.
  No pq_mutex_ across suspension: encode_pq_slot only writes still-dark
  slots, all masked by the search's tombstone snapshot.
- diskann_index.hpp: run_update_search_async behind an AsyncGate td set
  (update_search_concurrency load param, default 4x insert threads; gate
  tds skip libaio registration — no fs.aio-max-nr cost). insert_one
  warms the slot page plus every selected neighbor's page in ONE wave;
  per-edge reconnect prefetches collapse (reconnect stage: 11.3ms ->
  0.9ms per insert — the per-edge waves were the dominant queue load).
  UpdateStageStats instrumentation (wall-us per stage, take-and-reset).
- search_scratch.hpp: ThreadData::wave_scratch, a separate wave buffer so
  the sync pipelines' depth (== sector slot count) is untouched.
- aligned_file_reader.hpp: get_fd() accessor; io_getevents_exact drain
  loops at all three wait sites — io_uring completion task_work
  (TWA_SIGNAL) legally interrupts blocking io_getevents elsewhere in the
  process with a partial batch that the kernel cannot restart.

Benchmarks (SIFT 900k cap96+pq32, trace-yi-seq, 10 rounds, 8-core pinned,
R1-9 means; Yi on the same machine = 3154):
- disk-bound 20% cache, 8 threads: 1584 (blocking) -> 2988 (+89%), tail
  rounds 3146/3349 exceed Yi; beats 64-thread blocking oversubscription
  (2958) at 1/8 the threads and no aio-quota pressure.
- disk-bound 2% cache, 8 threads: 1379 -> 2533 (+84%); Yi livelocks (DNF)
  at the matched buffer budget.
- full-cache regression: 10575 vs parity 10757 (98%, unchanged).
- recall trajectories unchanged or slightly better in late rounds.

Verification: reactor/gate unit tests (deadlock-shaped oversubscription,
async==deterministic byte-equality for both search variants), page IO
19/19, update e2e 19/19 in uring and blocking modes, ctest suite green,
TSan (setarch -R) zero runtime warnings in both modes. The e2e
reused-slot probe now checks masking + monotonicity invariants while
the batch runs instead of assuming the first insert publishes slower
than a fixed sleep — async inserts broke that timing assumption.
storage_test_uring_reactor carries the storage label, so the coverage
ctest invocation selects it, but the job builds a hardcoded target list
that did not include the new binary — the test reported Not Run and
failed the job. liburing already reaches CI through the Conan
dependency provider; on runners where io_uring itself is unavailable
the fixture skips via UringReactor::is_available().
…ache

Yi's unified buffer pool serves search and update tasklets from one
dynamic LRU over data pages; our shard page cache was write-only from
the searches' point of view (update searches peeked it, nothing put
read pages back). Close the gap: with DiskANNLoadParams::
search_page_cache (default on), every search — the query-path
cached_beam_search/disk_greedy_search and both async update searches —
peeks the shard cache before each device read and offers the pages it
reads back through a versioned fill, so the cache converges to the hot
set of the whole workload instead of its write traffic.

- DiskPageIO::search_peek_page / search_fill_page: the public half of
  the wave-reconcile protocol. Fill runs BEFORE the page is parsed: on
  a version conflict the caller's buffer is refreshed from cache/disk
  instead of the pool taking stale bytes (reconcile_wave_page now
  delegates to it). Never-written pages report version 0.
- SearchContext::page_io carries the pool handle; the async searches'
  page_peek parameter folds into it. SearchStats::n_page_cache_hits.
- Pipelined schedulers serve pool hits inline via a one-page peek
  scratch (ThreadData::peek_scratch — process/absorb consume the record
  immediately); barrier schedulers let hits borrow sector slots, with
  the batch bounded by the slot count (never binds without a pool).
- bench: --search_page_cache toggle; per-round eval_qps/eval_mean_us.

Benchmarks (SIFT 900k cap96+pq32, trace-yi-seq, 10 rounds, 8-core
pinned, serial; the unified config moves the static BFS node cache's
90 MB into the pool — total data-memory budget unchanged at ~184 MB =
Yi's 20%; Yi on the same machine = 3154):
- disk-bound 20% updates: 2988 -> 3811 mean (+28%), every round after
  warm-up above Yi (R9 = 4285 = 136%). The win is update searches
  hitting pages that earlier searches read — the write-only cache
  could never serve those.
- disk-bound 2%: 2533 -> 3082 (+22%), near Yi's 20% figure at a tenth
  of the budget; Yi DNFs at this point.
- blocking mode gets the same medicine: 1584 -> ~1950 (+20%).
- full-cache (16T): 11175 R1-9 mean = 104% of the historical parity
  10757 — the fills cover freshly-inserted nodes, which the static
  BFS cache by construction never contains.
- eval-phase search ~11.1k vs 11.8k baseline (within the round noise
  band); recall trajectory 0.9246 -> 0.9157 vs baseline 0.9241 ->
  0.9196. A hybrid BFS+pool split (pool-c) adds nothing over the pure
  pool; --search_page_cache 0 reproduces the previous numbers.

Tests: peek/fill protocol units (install-for-later-peeks, stale offer
refused after write+eviction, cache-wins-when-present), repeat-search-
served-from-pool integration (zero device reads when warm), page IO
23/23, update e2e 19/19 in both IO modes, TSan (setarch -R) zero
runtime warnings in both modes.
…elining, and search profiling

Five hot-path optimizations for large-scale (100M+) search and a new
query-level pipelined search API:

1. pq_distance_batch — gather codes into a contiguous stack tile with
   software prefetch, then accumulate chunk-major so the dist_table row
   stays L1-hot; eliminates the per-neighbor dependent random 32 B code
   fetch that dominated eval at 100M scale.

2. Dirty-word visited bitset — clear() now costs O(words set) via a
   recorded dirty list instead of a full-array memset, removing the
   O(N/64) per-query DRAM bandwidth wall at large slot counts.

3. Page cache node recycling — at steady-state capacity, write() splices
   the LRU victim's map node and 4 KB buffer in-place instead of
   erase+alloc, cutting the per-fill heap traffic under concurrent
   shard search.

4. Tombstone snapshot skip — make_search_snapshot() avoids the
   full-capacity bitmap copy when count()==0 (the common no-tombstone
   case after compaction rounds).

5. search_pipelined() — Yi-style query-level coroutine pipelining:
   num_threads pool threads drive `pipeline` concurrent query coroutines
   over the shared io_uring reactor, each suspending on its beam-wave
   reads. Throughput follows Little's law instead of threads/latency.

Bench: --eval_pipeline flag and per-query IO/timing breakdown.
Test:  PipelinedSearchMatchesBatchSearch validates recall parity.
Copilot AI review requested due to automatic review settings July 7, 2026 08:46

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request modularizes the CMake build system, integrates the official Conan dependency provider, and migrates the Python build backend to scikit-build-core. It also introduces high-performance, coroutine-based asynchronous updates and searches for the DiskANN index on Linux using an io_uring reactor, supported by a sharded page cache and a deadlock-free coroutine gate. Feedback on these changes suggests optimizing the io_getevents_exact helper in the file reader to use non-blocking polling instead of blocking waits, thereby avoiding kernel-level sleep overhead in latency-sensitive asynchronous I/O pipelines.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread include/index/graph/laser/utils/aligned_file_reader.hpp

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR ports Yi’s DiskANN performance work into AlayaLite, spanning build/CI modernization (CMake presets + Conan provider), DiskANN update/search optimizations (tombstone semantics, visited-bitset clearing, PQ hot-path kernels, cache coherence), and Python packaging fixes (optional RAG extras with lazy imports).

Changes:

  • Reworks the build + CI surface around modular CMake, CMakePresets, and the Conan dependency provider (removing the custom conan_install script/profiles).
  • Adds/updates DiskANN runtime pieces and tests for update-path semantics, tombstones/snapshots, cache overrides, and PQ encode/distance behavior.
  • Repairs Python RAG subpackage imports and makes heavy ML dependencies optional via extras + lazy imports.

Reviewed changes

Copilot reviewed 84 out of 87 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/vamana/CMakeLists.txt Migrates Vamana tests to alaya_cc_target / alaya_add_test helpers.
tests/utils/CMakeLists.txt Migrates utils tests to the new CMake test helpers and label wiring.
tests/storage/uring_reactor_test.cpp Adds io_uring reactor coroutine tests and concurrency stress coverage.
tests/storage/CMakeLists.txt Registers storage tests via helpers and adds uring_reactor_test.
tests/space/CMakeLists.txt Migrates space tests to helper macros and labeled ctest entries.
tests/simd/CMakeLists.txt Migrates SIMD tests; documents manual-only micro-bench targets.
tests/recovery/CMakeLists.txt Migrates recovery tests and registers per-suite filters via helper.
tests/laser/CMakeLists.txt Refactors LASER test targets to BARE/helper style with explicit link sets.
tests/index/CMakeLists.txt Migrates index tests to helpers; keeps benchmark/manual target behavior.
tests/executor/CMakeLists.txt Migrates executor tests; registers multiple filtered suites per binary.
tests/diskann/test_diskann_update_trace.cpp Adds tests for Yi-format update trace generation.
tests/diskann/test_diskann_tombstone_slot.cpp Updates slot allocator tests for “dark until publish” semantics.
tests/diskann/test_diskann_tombstone_search.cpp Switches tombstone search tests to snapshot-based tombstone view.
tests/diskann/test_diskann_pq.cpp Adjusts PQ tests (smaller sizes/iters) and adds encode_one / symmetric distance tests.
tests/diskann/test_diskann_node_cache.cpp Adds test for update-time neighbor override behavior in node cache.
tests/diskann/test_diskann_e2e.cpp Scales down DiskANN e2e test and aligns PQ training parameters.
tests/diskann/sift_update_trace.hpp Implements update trace config/validation + generators + manifest writing.
tests/diskann/make_diskann_sift_update_trace.cpp Adds CLI tool to generate traces from SIFT/GIST FBIN headers.
tests/diskann/CMakeLists.txt Refactors DiskANN tests/benches into helper targets with LASER gating.
tests/disk/test_disk_collection_laser.cpp Makes LASER fixture availability a boolean + skips per-test.
scripts/conan_build/conan_profile.x86_64 Removes legacy Conan profile (superseded by provider flow).
scripts/conan_build/conan_profile.aarch64 Removes legacy Conan profile (superseded by provider flow).
scripts/conan_build/conan_profile_win.x86_64 Removes legacy Conan profile (superseded by provider flow).
scripts/conan_build/conan_profile_mac.x86_64 Removes legacy Conan profile (superseded by provider flow).
scripts/conan_build/conan_profile_mac.aarch64 Removes legacy Conan profile (superseded by provider flow).
scripts/conan_build/conan_install.py Removes legacy Conan install script (replaced by provider).
scripts/ci/codecov/gnu_codecoverage.sh Ensures Conan CLI exists on CI; adds uring_reactor_test to coverage targets.
REUSE.toml Adds license annotation for vendored Conan provider.
python/tests/ci/test_workflow_caching.py Updates CI assertions for new CMake module layout and cache keys.
python/src/alayalite/rag/embedder/multilingual_embedder.py Makes transformers/torch optional with lazy import + clearer error.
python/src/alayalite/rag/embedder/m3e_embedder.py Makes sentence-transformers optional with lazy import + clearer error.
python/src/alayalite/rag/embedder/jina_embedder.py Makes sentence-transformers optional with lazy import + clearer error.
python/src/alayalite/rag/embedder/bge_embedder.py Makes FlagEmbedding optional with lazy import + clearer error.
python/src/alayalite/rag/chunker/sentence_chunker.py Fixes imports to be package-relative; removes sys.path mutation.
python/src/alayalite/rag/chunker/semantic_chunker.py Lazy-imports sentence-transformers; removes sklearn dependency by inline cosine sim.
python/src/alayalite/rag/chunker/fix_size_chunker.py Lazy-imports langchain splitter; removes sys.path mutation.
python/src/alayalite/rag/chunker/chunker.py Fixes relative imports; removes debug printing.
python/src/alayalite/rag/init.py Adds dependency-free package init + public exports.
python/src/alayalite/init.py Documents/suppresses numpy FTZ/DAZ warnings triggered by fast-math extension.
python/CMakeLists.txt Renames codegen target, uses FindPython interpreter, applies shared build flags.
pyproject.toml Switches runtime deps to numpy-only; adds rag extras; updates cibuildwheel flow.
Makefile Moves build flavors to CMake presets; removes manual Conan install targets.
include/utils/macros.hpp Adds shared macros for copy/move special-member declarations.
include/utils/coro_gate.hpp Adds AsyncGate<T> coroutine-suspending object pool utility.
include/storage/io/uring_reactor.hpp Adds shared-ring, cooperatively-polled io_uring reactor for libcoro.
include/storage/io/io_engine.hpp Introduces IOEngine abstraction + SyncEngine fallback (pread/pwrite).
include/index/graph/laser/utils/aligned_file_reader.hpp Exposes fd for O_DIRECT reuse; hardens libaio io_getevents against EINTR/partials.
include/index/graph/diskann/visited_bitset.hpp Implements dirty-word tracking for O(words-set) clear.
include/index/graph/diskann/tombstone_bitmap.hpp Makes tombstones chunked/atomic + adds snapshot type for lock-free searches.
include/index/graph/diskann/slot_allocator.hpp Introduces “dark until publish” slot lifecycle semantics.
include/index/graph/diskann/search_scratch.hpp Extends scratch buffers for update/search pipelining and wave I/O.
include/index/graph/diskann/pq_table.hpp Refactors residual encode helpers; adds batch distance, encode_one, symmetric distance table.
include/index/graph/diskann/node_cache.hpp Adds update-time override records with shard locks + save/load behavior changes.
include/index/graph/diskann/disk_update_context.hpp Simplifies update context to removed-neighbor caching only.
include/index/graph/diskann/disk_page_cache.hpp Adds LRU page cache with node/buffer recycling on steady-state fills.
conanfile.py Disables generating CMakeUserPresets.json to avoid stale presets after clean.
CMakePresets.json Adds standard build/test presets (release/debug/asan/coverage).
cmake/PrintSummary.cmake Modernizes build summary output + reports Python executable + LASER option.
cmake/ConanSetup.cmake Removes legacy Conan setup module.
cmake/AlayaToolchain.cmake Centralizes C++20/toolchain behavior (sanitizers, ccache, fast linker).
cmake/AlayaTesting.cmake Introduces alaya_cc_target / alaya_add_test helpers.
cmake/AlayaPython.cmake Centralizes Python discovery + hints (FindPython / Python_EXECUTABLE).
cmake/AlayaPreflight.cmake Adds early toolchain/Python validation with actionable diagnostics.
cmake/AlayaOptions.cmake Consolidates and validates all user-facing CMake options (incl. LASER gating).
cmake/AlayaLaser.cmake Defines LASER backend wiring + alaya_laser consumer surface.
cmake/AlayaFlags.cmake Moves compile flags into alaya_build_flags INTERFACE target.
cmake/AlayaDependencies.cmake Centralizes third-party package discovery and aggregates THIRD_PARTY_LIBS.
cmake/AlayaConan.cmake Registers the vendored Conan dependency provider + enforces conan availability.
BUILDING.md Adds build instructions aligned with presets + Conan provider flow.
.typo.toml Excludes vendored cmake/vendor files from typo checks.
.pre-commit-config.yaml Excludes cmake/vendor from content-mutating hooks; forces typos exclude honoring.
.gitignore Adds build directory ignore entry.
.github/workflows/codecov.yaml Updates workflow triggers/cache key inputs for new Conan/CMake layout.
.github/actions/cache-restore/action.yaml Updates Conan cache key to track provider-based dependency drivers.
.cmake-format.py Teaches cmake-format about new helper commands and variable naming allowances.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread include/index/graph/diskann/pq_table.hpp
Comment thread tests/storage/uring_reactor_test.cpp
Comment thread tests/storage/CMakeLists.txt Outdated
Comment thread include/storage/io/io_engine.hpp
@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.04348% with 11 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
include/utils/coro_gate.hpp 74.19% 8 Missing ⚠️
include/storage/io/uring_reactor.hpp 94.82% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

… formatting

- pq_table.hpp: replace __builtin_prefetch with portable alaya::prefetch_l3
- io_engine.hpp: add <io.h> and ssize_t typedef for MSVC on Windows
- uring_reactor_test.cpp: add missing <cstring> for std::memcmp
- CMakeLists.txt: gate uring_reactor_test behind Linux platform check
- uring_reactor.hpp, coro_gate.hpp: LCOV_EXCL markers on defensive paths
- clang-format pass on all touched files
Route `make format` through `uvx pre-commit run` so it uses the same
clang-format and ruff-format versions as CI, preventing version-drift
formatting mismatches.
@huanglune
huanglune merged commit 91b166b into AlayaDB-AI:main Jul 7, 2026
12 checks passed
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