feat(rust): port vectorlite to Rust (vtab in Rust; FFI only to hnswlib + ops) - #56
Open
1yefuwang1 wants to merge 4 commits into
Open
feat(rust): port vectorlite to Rust (vtab in Rust; FFI only to hnswlib + ops)#561yefuwang1 wants to merge 4 commits into
1yefuwang1 wants to merge 4 commits into
Conversation
Add a Rust port of vectorlite's SQLite virtual-table glue and scalar functions under rust/. The numeric core (hnswlib + Highway `ops` + quantization) is not ported: it is wrapped behind a small C ABI (cpp/core_shim) and linked as a static library, keeping unsafe confined to the FFI boundary. - Ports vtab (BestIndex/Filter/Update/Column/Rename/FindFunction/...), scalar functions, constraint handling, per-connection index registry, vector-space/index-option parsing and JSON/blob serde to safe Rust. - SQLite extension-API bindings are pre-generated and committed in a vendored vectorlite-sqlite-sys crate, so normal builds need no libclang. - Statically embeds the full SQLite amalgamation, mirroring the C++ build. - build.rs is cross-platform (Linux/macOS/Windows): triplet-agnostic vcpkg discovery, platform-correct lib names, system libs and linker flags. - Passes the existing Python integration suite (112 tests). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously core_shim.cpp carried virtual-table policy (space/metric
selection, quantization + normalization dispatch, the rowid filter
predicate, ef handling, save/load orchestration and the load data-size
check). Move all of that into Rust so the C++/FFI surface exposes ONLY
hnswlib and ops.
- cpp/core_shim.{h,cpp}: now a generic, policy-free C ABI — a SpaceInterface
adapter around a Rust distance callback, a BaseFilterFunctor adapter around
a Rust predicate, thin HierarchicalNSW wrappers, and forwarders to ops.
- src/ops.rs: safe ops FFI wrappers + the six hnswlib distance callbacks
(l2/ip x f32/bf16/f16) that read dim from the space param and call ops.
- src/hnsw.rs: safe hnswlib FFI wrappers + a Rust rowid-filter trampoline.
- src/core.rs: owns quantization/normalization, per-query ef save/restore,
the rowid filter, the load data-size mismatch check and save/load
orchestration, plus the scalar distance — all in Rust.
- Only vectorlite/ops/ops.cpp and core_shim.cpp are compiled; no C++ vtab
sources are used.
All 112 Python integration tests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix clippy::mut_from_ref: drop the `&self -> &mut Registry` helper and deref the raw registry pointer directly at the rename call site. - Inline variables into format! strings (clippy::uninlined_format_args, 42x). - Data-drive scalar-function registration in sqlite3_extension_init instead of six near-identical blocks. - Use `len().is_multiple_of(..)` for the blob-size check. - Remove now-dead code (NamedVectorSpace::normalize, IndexEntry's unused allow_replace_deleted field, a stale allow(dead_code) on element_size). - Silence clippy on the machine-generated sqlite bindings. - Apply rustfmt across the crate. cargo clippy and cargo fmt --check are clean; all 112 Python integration tests still pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address the code-quality review of the Rust port: Safety / soundness - Set panic="abort" (dev+release) so a Rust panic can never unwind across an extern "C" boundary into SQLite/hnswlib (UB). Replace the .expect/ assert! on live callback paths with graceful SQLITE_ERROR returns (VTab::entry now returns Option; Space::new returns Result). - Guard the C shim: wrap vl_hnsw_space_create and vl_hnsw_contains in try/catch so no C++ exception crosses the C ABI. - Replace `static mut API` with an AtomicPtr (Acquire/Release). - Fetch value_blob/value_text before value_bytes, per SQLite's ordering. Correctness / DoS - Cap the requested k at the current element count before allocating result buffers (new vl_hnsw_current_count), preventing an attacker-controlled k (e.g. knn_param(v, 2e9)) from forcing a multi-GB allocation/abort. Read k/ef via value_int64 to avoid 32-bit truncation. - vector_to_json now errors on non-finite values instead of emitting `null` (which no longer round-trips). - Decouple idxStr from idxNum: x_filter reads idxStr via CStr. Build / packaging - Stop force-embedding SQLite. A loadable extension has no undefined SQLite symbols (all calls go through sqlite3_api_routines), so drop the whole-archive link plus /OPT:NOREF and --no-gc-sections. The artifact is now ~0.6 MB and identical across Linux/macOS/Windows. Tooling / tests - Add rust-version, fix error-string typos, remove is_multiple_of. - Add unit tests for vector, vector_space and index_options. - Add a matrix (ubuntu + windows) rust_port CI job running fmt/clippy/tests, the build, and the Python integration suite against the Rust extension. Verified on macOS: cargo fmt/clippy clean, 19 unit tests and 112 Python integration tests pass. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38b9cda2-a92d-4682-a15c-aaa8fe6cf5fb
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.
Summary
Adds a Rust port of the vectorlite SQLite extension under
rust/. All virtual-table logic lives in Rust; C++ is reached only via FFI, and only for two things: hnswlib and the SIMDops(Google Highway). The port is a drop-in replacement for the C++ extension and passes the existing Python integration suite (112 tests) unchanged.What is in Rust vs C++
Rust (this crate) — the entire virtual table + all policy:
xCreate/xConnect/xBestIndex/xFilter/xUpdate/xColumn/xRowid/xRename/xFindFunction/...vector_distance,vector_from_json,vector_to_json,knn_search,knn_param,vectorlite_inforowid IN (...)pushdown (sqlite3_vtab_in)float32/bfloat16/float16, the rowid filter predicate, per-queryefsave/restore, the load data-size mismatch check, and save/load orchestrationC++ (reached only through the C ABI) — nothing but hnswlib + ops:
cpp/core_shim.cppis generic, policy-free glue: aSpaceInterfaceadapter around a Rust distance callback, aBaseFilterFunctoradapter around a Rust predicate, thinHierarchicalNSWwrappers, and forwarders toops.vectorlite/ops/ops.cpp— the existing, un-ported Highway SIMD kernels..cppfiles are compiled; no C++ virtual-table sources are used.The distance function hnswlib calls is a Rust
extern "C"callback that forwards toops; the rowid filter is a Rust predicate invoked via a trampoline. So the only C++ is hnswlib itself, theopskernels, and the minimal adapters required to expose those through a C ABI.Highlights
ef/rowid filters,knn_parampointer passing, persistence with the data-size check, quantization/normalization across all element types andl2/ip/cosine, and the registry that keeps the index alive across schema reparses.vectorlite-sqlite-syscrate (thelibsqlite3-syspattern). Refresh withcargo build -p vectorlite-sqlite-sys --features regenerate.build.rsdiscovers the vcpkg triplet by scanningbuild/*/vcpkg_installed/*/, picks the right static-archive names (.a/.lib), system libs, and per-linker flags, so it builds on Linux, macOS and Windows. Onlyhwy+sqlite3are linked.Testing
Notes
rust/tree; no existing C++ sources or build files are modified.Cargo.lockis committed for reproducible builds;target/,.libclang/are git-ignored.