Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 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
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
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
292322c
fix: fix ut
richyreachy Jul 3, 2026
a0a9ce9
fix: remove export map
richyreachy Jul 3, 2026
69b1e23
fix: clean code
richyreachy Jul 3, 2026
081aee3
fix: add ci job to test libaio
richyreachy Jul 3, 2026
ab8901a
fix: fix on comment
richyreachy Jul 6, 2026
63f5ff7
fix: remove diskann runtime
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
0583231
fix: fix ut
richyreachy Jul 8, 2026
0afa1d5
fix: fix ut
richyreachy Jul 8, 2026
ddbec83
Merge branch 'main' into feat/diskann_on_iouring
richyreachy Jul 9, 2026
f1465b2
Merge branch 'main' into feat/diskann_on_iouring
richyreachy Jul 17, 2026
06714c8
fix: merge
richyreachy Jul 17, 2026
a5a8bec
fix: merge main
richyreachy Jul 17, 2026
d63c0d1
fix: merge main
richyreachy Jul 17, 2026
0c84e01
fix: remove old func
richyreachy Jul 17, 2026
83e537d
revert: ut
richyreachy Jul 17, 2026
4e4b57a
revert: ut
richyreachy Jul 17, 2026
878d7d0
revert: header
richyreachy Jul 17, 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
64 changes: 45 additions & 19 deletions src/ailego/io/io_backend_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// Abstract I/O backend selector.
// Abstract I/O backend selector — internal header.
//
// Wraps the low-level loaders (LibAioLoader for libaio) and provides a uniform
// way to initialize, query, and report the active I/O backend. The actual I/O
// operations are still performed by the underlying loaders; this class is
// responsible only for backend initialization and reporting.
// Wraps the low-level backends (io_uring via raw syscalls, LibAioLoader for
// libaio) and provides a uniform way to initialize, query, and report the
// active I/O backend. The actual I/O operations are still performed by the
// underlying backends; this class is responsible only for backend
// initialization and reporting.
//
// When no async backend is available, the caller should fall back to
// synchronous pread().
//
// This header pulls in libaio_loader and the io_uring kernel ABI; the
// dependency-free enum and IOBackendTypeName() live in the public header
// zvec/ailego/io/io_backend.h, which this header includes.
//
// Usage:
// auto& backend = ailego::IOBackend::Instance();
// if (!backend.is_pread()) { ... }
Expand All @@ -32,24 +37,25 @@
#include <ailego/io/libaio_loader.h>
#include <zvec/ailego/io/io_backend.h>

#if defined(__linux) || defined(__linux__)
#include <unistd.h> // ::syscall(), ::close() — POSIX only
#include <cstring> // std::memset
#include <ailego/io/iouring_def.h> // io_uring_params, __NR_io_uring_setup
#endif

namespace zvec {
namespace ailego {

// Returns a human-readable name for the given backend type.
inline const char *IOBackendTypeName(IOBackendType type) {
switch (type) {
case IOBackendType::kLibAio:
return "libaio";
case IOBackendType::kPread:
return "pread";
}
return "unknown";
}
// IOBackendTypeName() is defined in the public header
// zvec/ailego/io/io_backend.h.

// Returns a human-readable description for the given backend type.
// When the backend is kPread, includes installation guidance for libaio.
inline const char *IOBackendDescription(IOBackendType type) {
switch (type) {
case IOBackendType::kIoUring:
return "io_uring async I/O backend (raw kernel syscalls, zero "
"dependency).";
case IOBackendType::kLibAio:
return "libaio async I/O backend loaded at runtime via dlopen().";
case IOBackendType::kPread:
Expand All @@ -63,8 +69,8 @@ inline const char *IOBackendDescription(IOBackendType type) {

// Singleton that loads and queries an I/O backend on demand.
//
// available() (no arg) tries the best backend with priority (libaio > pread)
// and returns the loaded backend type.
// available() (no arg) tries the best backend with priority
// (io_uring > libaio > pread) and returns the loaded backend type.
// available(IOBackendType) tries a specific backend.
// Use type() / name() to query the loaded backend without triggering a load.
class IOBackend {
Expand All @@ -74,14 +80,18 @@ class IOBackend {
return instance;
}

// Try to load the best available backend (libaio > pread).
// Try to load the best available backend (io_uring > libaio > pread).
// Returns the loaded backend type.
// Idempotent — if already loaded, returns immediately.
IOBackendType available() {
if (type_ != IOBackendType::kPread) {
return type_;
}
return available(IOBackendType::kLibAio);
IOBackendType t = available(IOBackendType::kIoUring);
if (t == IOBackendType::kPread) {
t = available(IOBackendType::kLibAio);
}
return t;
}

// Try to load the requested backend. Returns the loaded backend type
Expand All @@ -92,6 +102,18 @@ class IOBackend {
return type_;
}
#if defined(__linux) || defined(__linux__)
if (requested == IOBackendType::kIoUring) {
// Probe io_uring availability with a minimal ring setup using only
// raw syscalls — no dependency on liburing.
struct io_uring_params params;
std::memset(&params, 0, sizeof(params));
int fd = static_cast<int>(::syscall(__NR_io_uring_setup, 1, &params));
if (fd >= 0) {
::close(fd);
type_ = IOBackendType::kIoUring;
return type_;
}
}
if (requested == IOBackendType::kLibAio) {
if (LibAioLoader::Instance().load() &&
LibAioLoader::Instance().is_available()) {
Expand All @@ -112,6 +134,10 @@ class IOBackend {
return available() == IOBackendType::kLibAio;
}

bool is_io_uring() {
return available() == IOBackendType::kIoUring;
}

// Returns the loaded backend type.
IOBackendType type() const {
return type_;
Expand Down
199 changes: 199 additions & 0 deletions src/ailego/io/iouring_def.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// Copyright 2025-present the zvec project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Private header defining the io_uring kernel ABI structures and constants.
//
// This header is the io_uring analogue of libaio_def.h: it declares *only*
// the types, constants, and inline helpers that zvec needs from the io_uring
// kernel interface. By defining these structures ourselves we avoid any
// build-time dependency on <linux/io_uring.h> or liburing-dev, mirroring the
// project's zero-dependency philosophy established by the libaio dlopen
// approach.
//
// The struct layouts (io_uring_sqe, io_uring_cqe, io_uring_params,
// io_sqring_offsets, io_cqring_offsets) are part of the Linux kernel ABI
// and are copied verbatim from <linux/io_uring.h>.

#pragma once

#include <cstdint>

#if defined(__linux) || defined(__linux__)

// ---------------------------------------------------------------------------
// Syscall numbers
// ---------------------------------------------------------------------------
// io_uring was introduced in Linux 5.1 (2019). The three syscalls share the
// same numbers across all supported architectures. We prefer the values
// from <sys/syscall.h> when available and fall back to hardcoded numbers.
#include <sys/syscall.h>

#ifndef __NR_io_uring_setup
#define __NR_io_uring_setup 425
#endif

#ifndef __NR_io_uring_enter
#define __NR_io_uring_enter 426
#endif

#ifndef __NR_io_uring_register
#define __NR_io_uring_register 427
#endif

// ---------------------------------------------------------------------------
// Constants (from <linux/io_uring.h>)
// ---------------------------------------------------------------------------

// mmap offsets for the three shared regions.
#define IORING_OFF_SQ_RING 0ULL
#define IORING_OFF_CQ_RING 0x8000000ULL
#define IORING_OFF_SQES 0x10000000ULL

// io_uring_enter flags.
#define IORING_ENTER_GETEVENTS (1U << 0)

// io_uring_setup flags (none used by default).
// IORING_SETUP_IOPOLL (1U << 0)
// IORING_SETUP_SQPOLL (1U << 1)
// IORING_SETUP_SQ_AFF (1U << 2)

// SQE opcode values.
#define IORING_OP_NOP 0
#define IORING_OP_READV 1
#define IORING_OP_WRITEV 2
#define IORING_OP_FSYNC 3
#define IORING_OP_READ_FIXED 4
#define IORING_OP_WRITE_FIXED 5
#define IORING_OP_POLL_ADD 6
#define IORING_OP_POLL_REMOVE 7
#define IORING_OP_SYNC_FILE_RANGE 8
#define IORING_OP_SENDMSG 9
#define IORING_OP_RECVMSG 10
#define IORING_OP_TIMEOUT 11
#define IORING_OP_TIMEOUT_REMOVE 12
#define IORING_OP_ACCEPT 13
#define IORING_OP_ASYNC_CANCEL 14
#define IORING_OP_LINK_TIMEOUT 15
#define IORING_OP_CONNECT 16
#define IORING_OP_FALLOCATE 17
#define IORING_OP_OPENAT 18
#define IORING_OP_CLOSE 19
#define IORING_OP_FILES_UPDATE 20
#define IORING_OP_STATX 21
#define IORING_OP_READ 22
#define IORING_OP_WRITE 23

// ---------------------------------------------------------------------------
// Struct definitions (copied verbatim from <linux/io_uring.h>)
// ---------------------------------------------------------------------------

// Submission queue entry — 64 bytes.
struct io_uring_sqe {
uint8_t opcode; // type of operation for this sqe
uint8_t flags; // IOSQE_ flags
uint16_t ioprio; // ioprio for the request
int32_t fd; // file descriptor to do IO on
union {
uint64_t off; // offset into file
uint64_t addr2;
};
union {
uint64_t addr; // buffer or iovecs
uint64_t splice_off_in;
};
uint32_t len; // buffer size or number of iovecs
union {
uint32_t rw_flags; // read/write flags (union of all flag types)
};
uint64_t user_data; // data to be passed back at completion time
union {
struct {
uint16_t buf_index; // index into fixed buffers, if used
uint16_t personality;
} buf;
uint64_t __pad2[3];
};
};

// Completion queue entry — 16 bytes.
struct io_uring_cqe {
uint64_t user_data; // sqe->user_data
int32_t res; // result code for this event
uint32_t flags;
};

// SQ ring offsets — returned by io_uring_setup in io_uring_params.
struct io_sqring_offsets {
uint32_t head;
uint32_t tail;
uint32_t ring_mask;
uint32_t ring_entries;
uint32_t flags;
uint32_t dropped;
uint32_t array;
uint32_t resv1;
uint64_t resv2;
};

// CQ ring offsets — returned by io_uring_setup in io_uring_params.
struct io_cqring_offsets {
uint32_t head;
uint32_t tail;
uint32_t ring_mask;
uint32_t ring_entries;
uint32_t overflow;
uint32_t cqes;
uint32_t flags;
uint32_t resv1;
uint64_t resv2;
};

// Parameters passed to io_uring_setup().
struct io_uring_params {
uint32_t sq_entries;
uint32_t cq_entries;
uint32_t flags;
uint32_t sq_thread_cpu;
uint32_t sq_thread_idle;
uint32_t features;
uint32_t wq_fd;
uint32_t resv[3];
struct io_sqring_offsets sq_off;
struct io_cqring_offsets cq_off;
};

// ---------------------------------------------------------------------------
// Inline helper — prepare an SQE for a read operation.
// ---------------------------------------------------------------------------
static inline void io_uring_prep_read(struct io_uring_sqe *sqe, int fd,
void *buf, uint32_t nbytes,
uint64_t offset) {
sqe->opcode = IORING_OP_READ;
sqe->flags = 0;
sqe->ioprio = 0;
sqe->fd = fd;
sqe->off = offset;
sqe->addr = reinterpret_cast<uint64_t>(buf);
sqe->len = nbytes;
sqe->rw_flags = 0;
sqe->user_data = 0;
sqe->buf.buf_index = 0;
sqe->buf.personality = 0;
}

// ---------------------------------------------------------------------------
// End: struct and constant definitions from <linux/io_uring.h>
// ---------------------------------------------------------------------------

#endif // __linux__
Loading
Loading