Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
74da77a
refactor: use dlopen
richyreachy Jun 24, 2026
17a7fd5
refactor: use dlopen to load libaio
richyreachy Jun 25, 2026
1dd03d4
feat: add diskann windows
richyreachy Jun 25, 2026
82d08f6
fix: support io uring
richyreachy Jun 25, 2026
8ef5d2d
fix: log out the warning only once
richyreachy Jun 26, 2026
813f2ab
fix: warning
richyreachy Jun 26, 2026
50c6c8d
fix: add log
richyreachy Jun 26, 2026
0cf5cdd
fix: fix conflict
richyreachy Jun 26, 2026
ceee226
fix: add log
richyreachy Jun 26, 2026
5e77ee3
Merge branch 'refactor/diskann_dlopen' of github.com:richyreachy/zvec…
richyreachy Jun 26, 2026
34066a7
Merge branch 'refactor/diskann_dlopen' into feat/diskann_on_iouring
richyreachy Jun 26, 2026
29b59b9
fix: remove log
richyreachy Jun 26, 2026
6d774ed
refactor: merge main
richyreachy Jun 26, 2026
e2a2ede
Merge branch 'main' into refactor/diskann_dlopen
richyreachy Jun 30, 2026
a2524eb
fix: fix windows build
richyreachy Jul 1, 2026
ac109ae
Merge branch 'refactor/diskann_dlopen' of github.com:richyreachy/zvec…
richyreachy Jul 1, 2026
6688e1a
fix: remove libaio dependency
richyreachy Jul 1, 2026
837a39d
Merge branch 'refactor/diskann_dlopen' into feat/diskann_on_iouring
richyreachy Jul 2, 2026
5d63ac0
merge from io uring
richyreachy Jul 2, 2026
5d3b96a
fix: fix
richyreachy Jul 2, 2026
6cb054a
fix: fix makefile
richyreachy Jul 2, 2026
760fb7a
Merge branch 'main' into refactor/diskann_dlopen
richyreachy Jul 2, 2026
f2559b5
fix: remove no use code
richyreachy Jul 2, 2026
d753080
fix: fix makefile
richyreachy Jul 2, 2026
bc7b843
Merge branch 'refactor/diskann_dlopen' of github.com:richyreachy/zvec…
richyreachy Jul 2, 2026
c5ca726
fix: support windows
richyreachy Jul 3, 2026
c7f34c2
fix: fix windows
richyreachy Jul 3, 2026
77a7b4d
fix: fix windows
richyreachy Jul 3, 2026
292322c
fix: fix ut
richyreachy Jul 3, 2026
3f59037
fix: fix reader
richyreachy Jul 3, 2026
a0a9ce9
fix: remove export map
richyreachy Jul 3, 2026
37780e7
fix: foramt
richyreachy Jul 3, 2026
ba9be50
fix: fix unused
richyreachy Jul 3, 2026
69b1e23
fix: clean code
richyreachy Jul 3, 2026
081aee3
fix: add ci job to test libaio
richyreachy Jul 3, 2026
ad07197
fix: fix type
richyreachy Jul 3, 2026
ce93b16
fix: fix array
richyreachy Jul 3, 2026
ab8901a
fix: fix on comment
richyreachy Jul 6, 2026
63f5ff7
fix: remove diskann runtime
richyreachy Jul 6, 2026
0bb0a61
fix: fix read
richyreachy Jul 6, 2026
58e5f93
Merge branch 'feat/diskann_on_windows' of github.com:richyreachy/zvec…
richyreachy Jul 6, 2026
1954039
Merge branch 'refactor/diskann_dlopen' into feat/diskann_on_iouring
richyreachy Jul 7, 2026
5ffc23a
refactor: move libaio loader to ailego
richyreachy Jul 7, 2026
1c7ff60
fix: add io backend
richyreachy Jul 7, 2026
54eaa11
fix: add io backend
richyreachy Jul 7, 2026
9870923
Merge branch 'main' into refactor/diskann_dlopen
richyreachy Jul 7, 2026
f19defb
Merge branch 'main' into refactor/diskann_dlopen
richyreachy Jul 7, 2026
34ae23b
merge with dlopen via libaio
richyreachy Jul 8, 2026
4b4a00b
fix: fix
richyreachy Jul 8, 2026
241dd7a
Merge branch 'main' into refactor/diskann_dlopen
richyreachy Jul 8, 2026
e1048c0
fix: remove ci
richyreachy Jul 8, 2026
fde7813
fix: add ci
richyreachy Jul 8, 2026
6496a0b
Merge branch 'refactor/diskann_dlopen' of github.com:richyreachy/zvec…
richyreachy Jul 8, 2026
4567d99
Merge branch 'main' into refactor/diskann_dlopen
richyreachy Jul 8, 2026
ca89c30
fix: debug output
richyreachy Jul 8, 2026
d63cb21
Merge branch 'refactor/diskann_dlopen' into feat/diskann_on_iouring
richyreachy Jul 8, 2026
34a4cad
fix: fix merge
richyreachy Jul 8, 2026
0583231
fix: fix ut
richyreachy Jul 8, 2026
0afa1d5
fix: fix ut
richyreachy Jul 8, 2026
69f41bd
Merge branch 'feat/diskann_on_iouring' into feat/diskann_on_windows
richyreachy Jul 8, 2026
232e72a
fix: fix
richyreachy Jul 8, 2026
bf4f630
fix: fix ut
richyreachy Jul 8, 2026
31c0fe5
fix: schema
richyreachy Jul 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions .github/workflows/03-macos-linux-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,6 @@ jobs:
sudo apt-get install -y clang libomp-dev
shell: bash

- name: Install AIO
if: runner.os == 'Linux' && runner.arch == 'X64'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libaio-dev
shell: bash

- name: Print CPU info
if: runner.os == 'Linux'
run: lscpu
Expand Down Expand Up @@ -183,3 +175,31 @@ jobs:
./c_api_index_example
./c_api_optimized_example
shell: bash

# ------------------------------------------------------------------ #
# DiskAnn libaio round: install libaio and re-run tests
# ------------------------------------------------------------------ #
- name: Install libaio runtime
if: matrix.platform == 'linux-x64'
run: |
sudo apt-get update -y
# libaio1t64 on Ubuntu 24.04+ (t64 transition), libaio1 on older
sudo apt-get install -y libaio1t64 || sudo apt-get install -y libaio1
echo "=== libaio status (should be present) ==="
dpkg -l | grep -i libaio || true
ldconfig -p | grep libaio || true
shell: bash

- name: Run C++ Tests (w/ libaio)
if: matrix.platform == 'linux-x64'
run: |
cd "$GITHUB_WORKSPACE/build"
cmake --build . --target unittest --parallel $NPROC
shell: bash

- name: Run Python Tests (w/ libaio)
if: matrix.platform == 'linux-x64'
run: |
cd "$GITHUB_WORKSPACE"
python -m pytest python/tests/
shell: bash
7 changes: 0 additions & 7 deletions .github/workflows/08-cmake-subproject-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ jobs:
cache: 'pip'
cache-dependency-path: 'pyproject.toml'

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libaio-dev
shell: bash

- name: Set up environment variables
run: |
NPROC=$(nproc 2>/dev/null || echo 2)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/clang_tidy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
if: steps.changed_files.outputs.any_changed == 'true'
run: |
sudo apt-get update
sudo apt-get install -y clang-tidy=1:18.0-59~exp2 cmake ninja-build libomp-dev libaio-dev
sudo apt-get install -y clang-tidy=1:18.0-59~exp2 cmake ninja-build libomp-dev
- name: Setup ccache
if: steps.changed_files.outputs.any_changed == 'true'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/nightly_coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
lcov libaio-dev
lcov libaio-dev
shell: bash

- name: Install dependencies
Expand Down
28 changes: 7 additions & 21 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,15 @@ else()
endif()
message(STATUS "RABITQ_ARCH_FLAG: ${RABITQ_ARCH_FLAG}")

# DiskAnn support (Linux x86_64 only, requires libaio)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|i686|i386" AND NOT ANDROID AND NOT IOS)
# DiskAnn support (Linux x86_64 with libaio/io_uring, or Windows x86_64 with IOCP)
if((CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|i686|i386" AND NOT ANDROID AND NOT IOS)
OR (WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64|i686|i386"))
set(DISKANN_SUPPORTED ON)
add_definitions(-DDISKANN_SUPPORTED=1)
else()
set(DISKANN_SUPPORTED OFF)
add_definitions(-DDISKANN_SUPPORTED=0)
message(STATUS "DiskAnn support disabled - only supported on Linux x86_64")
message(STATUS "DiskAnn support disabled - only supported on Linux x86_64 or Windows")
endif()
message(STATUS "DISKANN_SUPPORTED: ${DISKANN_SUPPORTED}")

Expand Down Expand Up @@ -180,24 +181,9 @@ if(BUILD_PYTHON_BINDINGS)
install(TARGETS _zvec LIBRARY DESTINATION ${ZVEC_PY_INSTALL_DIR}/zvec
COMPONENT python)

# DiskAnn ships as a runtime-loaded shared module
# (libzvec_diskann_plugin.so) that is brought online implicitly the
# first time a DiskAnn index is created — users never call any load
# function. The Python extension resolves the module next to _zvec.so
# (see the $ORIGIN rpath in src/binding/python/CMakeLists.txt); the
# module must therefore be installed alongside _zvec.so, i.e. inside the
# zvec package directory as well.
#
# Gate on DISKANN_SUPPORTED, not on the target's existence: on unsupported
# platforms (e.g. macOS / ARM64) the core_knn_diskann target is still
# defined, but built from an empty stub (src/core/algorithm/CMakeLists.txt)
# with zero exported symbols and a runtime load path compiled out
# (#if DISKANN_SUPPORTED). Shipping that stub is pure dead weight, so it is
# only packaged where DiskAnn is real — currently Linux x86_64 with libaio.
if(DISKANN_SUPPORTED)
install(TARGETS core_knn_diskann LIBRARY DESTINATION ${ZVEC_PY_INSTALL_DIR}/zvec
COMPONENT python)
endif()
# DiskAnn is statically linked into _zvec.so via --whole-archive
# (see src/binding/python/CMakeLists.txt -> core_knn_diskann_static),
# so no separate runtime .so needs to be installed in the wheel.
# Bundle cppjieba's dictionary files so the `jieba` FTS tokenizer works
# out of the box. python/zvec/__init__.py resolves this directory via
# importlib.resources and registers it with set_default_jieba_dict_dir().
Expand Down
4 changes: 3 additions & 1 deletion examples/c++/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ set(ZVEC_INCLUDE_DIR ${ZVEC_ROOT_DIR}/src/include)
set(ZVEC_LIB_DIR ${ZVEC_ROOT_DIR}/${HOST_BUILD_DIR}/lib)

# Add include and library search paths
include_directories(${ZVEC_INCLUDE_DIR})
# ${ZVEC_ROOT_DIR}/src is needed because public headers under src/include/
# reference ailego/ headers (e.g. <ailego/io/io_backend.h>) that live in src/.
include_directories(${ZVEC_INCLUDE_DIR} ${ZVEC_ROOT_DIR}/src)
set(ZVEC_LIB_SEARCH_DIRS ${ZVEC_LIB_DIR})

# Support multi-config builds (MSVC puts libs in Debug/Release subdirectories)
Expand Down
5 changes: 0 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,6 @@ test-command = "cd {project} && pytest python/tests -v --tb=short"
build-verbosity = 1

[tool.cibuildwheel.linux]
# libaio is required by the C++ backend; install it inside the manylinux
# container (manylinux_2_28 is AlmaLinux 8 based, so use dnf/libaio-devel).
# libaio-devel lives in BaseOS; disable EPEL so a flaky EPEL mirror cannot
# break metadata refresh.
before-all = "dnf install -y --disablerepo=epel libaio-devel"
archs = ["auto"]
environment = { CMAKE_GENERATOR = "Unix Makefiles", CMAKE_BUILD_PARALLEL_LEVEL = "16" }
manylinux-x86_64-image = "manylinux_2_28"
Expand Down
30 changes: 4 additions & 26 deletions python/tests/detail/fixture_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,14 @@
from zvec.typing import DataType, StatusCode, MetricType, QuantizeType
import zvec


# Cache the DiskAnn plugin preload status so we pay the load cost once per
# test session. The plugin normally auto-loads on first DiskAnn use, but we
# preload it explicitly here so a missing libaio / misplaced plugin .so
# surfaces as a clear pytest skip instead of a confusing
# "Create vector column indexer failed" deep inside the collection code path.
_DISKANN_PRELOAD_REASON: str | None = None
_DISKANN_PRELOAD_DONE: bool = False


def _ensure_diskann_runtime_or_reason() -> str | None:
"""Preload the DiskAnn plugin and return None on success or a human-readable
skip reason on failure. Idempotent across calls."""
"""Check whether DiskAnn is available on this platform and return None
on success or a human-readable skip reason on failure. Idempotent across
calls."""
global _DISKANN_PRELOAD_DONE, _DISKANN_PRELOAD_REASON
if _DISKANN_PRELOAD_DONE:
return _DISKANN_PRELOAD_REASON
Expand All @@ -35,22 +30,6 @@ def _ensure_diskann_runtime_or_reason() -> str | None:
_DISKANN_PRELOAD_REASON = "DiskAnn only supported on Linux x86_64"
return _DISKANN_PRELOAD_REASON

if not zvec.is_libaio_available():
_DISKANN_PRELOAD_REASON = (
"libaio is not available on this host; DiskAnn cannot run. "
"Install libaio1 (or libaio1t64 on Ubuntu 24.04+) and retry."
)
return _DISKANN_PRELOAD_REASON

status = zvec.load_diskann_plugin()
if status != zvec.DISKANN_PLUGIN_OK:
_DISKANN_PRELOAD_REASON = (
f"Failed to load DiskAnn plugin (status={status}); "
"check that libzvec_diskann_plugin.so is installed alongside "
"_zvec.so in the Python site-packages directory."
)
return _DISKANN_PRELOAD_REASON

_DISKANN_PRELOAD_REASON = None
return None

Expand Down Expand Up @@ -148,8 +127,7 @@ def full_schema_new(request) -> CollectionSchema:
else:
nullable, has_index, vector_index = True, False, HnswIndexParam()

# Skip DiskAnn tests on unsupported platforms or when the runtime cannot
# be brought up (missing libaio, plugin .so not installed, etc.).
# Skip DiskAnn tests on unsupported platforms.
from zvec.model.param import DiskAnnIndexParam

if isinstance(vector_index, DiskAnnIndexParam):
Expand Down
18 changes: 4 additions & 14 deletions python/tests/test_collection_diskann.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,15 @@
# limitations under the License.
"""End-to-end collection tests for the DiskAnn index.
Mirrors ``test_collection_hnsw_rabitq.py`` but targets the DiskAnn plugin.
Mirrors ``test_collection_hnsw_rabitq.py`` but targets the DiskAnn index.
Two platform-level prerequisites are enforced at module import time:
1. DiskAnn is currently built only for Linux x86_64 — other platforms are
skipped wholesale.
2. The DiskAnn backend lives in a *runtime-loaded* plugin
(``libzvec_diskann_plugin.so``). It must be loaded with ``RTLD_GLOBAL |
RTLD_NOW`` BEFORE ``import zvec`` so that the plugin's ``IndexFactory``
singleton is unified with the one inside ``_zvec.so``. After ``import
zvec`` we must also call ``zvec.load_diskann_plugin()`` exactly once.
2. libaio is loaded eagerly (via dlopen) inside DiskAnnBuilder::init() /
DiskAnnStreamer::init(). If libaio is missing, DiskAnn falls back to
synchronous pread() — the tests still run but with degraded performance.
If either prerequisite fails the whole module is skipped so the rest of the
test-suite is not affected.
Expand All @@ -32,7 +30,6 @@
from __future__ import annotations

import math
import os
import platform
import sys

Expand All @@ -46,13 +43,6 @@
reason="DiskAnn plugin is only supported on Linux x86_64",
)

# Promote all symbols in subsequently-loaded DSOs to the global namespace and
# resolve relocations eagerly. This is REQUIRED so the DiskAnn plugin can see
# the ``IndexFactory`` singleton that lives in ``_zvec.so`` and vice versa.
# See: DiskAnn RTLD_GLOBAL + RTLD_NOW Requirement.
if sys.platform == "linux":
sys.setdlopenflags(sys.getdlopenflags() | os.RTLD_GLOBAL | os.RTLD_NOW)

import zvec # noqa: E402

from zvec import ( # noqa: E402
Expand Down
25 changes: 2 additions & 23 deletions python/zvec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

from zvec._zvec import (
get_default_jieba_dict_dir,
io_backend_type,
set_default_jieba_dict_dir,
)

Expand All @@ -43,21 +44,6 @@
# Public API — grouped by category
# ==============================

# —— DiskAnn runtime plugin ——
# Re-export the plugin management entry points defined by the C++ extension.
# DiskAnn normally auto-loads on first use; these APIs let tests and
# diagnostic tools preload the plugin and get a clear error if libaio is
# missing or the plugin shared object cannot be located.
from zvec._zvec import (
DISKANN_PLUGIN_DLOPEN_FAILED,
DISKANN_PLUGIN_LIBAIO_MISSING,
DISKANN_PLUGIN_OK,
DISKANN_PLUGIN_UNSUPPORTED_PLATFORM,
is_diskann_plugin_loaded,
is_libaio_available,
load_diskann_plugin,
)

from . import model as model

# —— Extensions ——
Expand Down Expand Up @@ -142,6 +128,7 @@
"open",
"set_default_jieba_dict_dir",
"get_default_jieba_dict_dir",
"io_backend_type",
# Core classes
"Collection",
"Doc",
Expand Down Expand Up @@ -203,14 +190,6 @@
"StatusCode",
# Tools
"require_module",
# DiskAnn plugin
"load_diskann_plugin",
"is_diskann_plugin_loaded",
"is_libaio_available",
"DISKANN_PLUGIN_OK",
"DISKANN_PLUGIN_UNSUPPORTED_PLATFORM",
"DISKANN_PLUGIN_LIBAIO_MISSING",
"DISKANN_PLUGIN_DLOPEN_FAILED",
]

# ==============================
Expand Down
Loading