[package] name = "pg_turbovec" description = "PostgreSQL extension: vector index backed by the TurboQuant quantizer (turbovec)" version = "2.11.0" edition = "2024" rust-version = "1.96.0" authors = ["Greg Burd "] license = "Apache-2.0" repository = "https://codeberg.org/gregburd/pg_turbovec" homepage = "https://codeberg.org/gregburd/pg_turbovec" documentation = "https://codeberg.org/gregburd/pg_turbovec/src/branch/main/docs" readme = "README.md" keywords = ["postgresql", "pgrx", "vector", "ann", "quantization"] # crates.io categories must be from https://crates.io/category_slugs categories = ["database-implementations", "science", "algorithms"] exclude = [ "benches/results/", "fixtures/", "target/", "tests/snapshots/", "docs/RECALL.md.tmp", ] [lib] crate-type = ["cdylib", "lib"] [features] default = ["pg16"] pg13 = ["pgrx/pg13", "pgrx-tests/pg13"] pg14 = ["pgrx/pg14", "pgrx-tests/pg14"] pg15 = ["pgrx/pg15", "pgrx-tests/pg15"] pg16 = ["pgrx/pg16", "pgrx-tests/pg16"] pg17 = ["pgrx/pg17", "pgrx-tests/pg17"] pg18 = ["pgrx/pg18", "pgrx-tests/pg18"] pg19 = ["pgrx/pg19", "pgrx-tests/pg19"] pg_test = [] # v1.3.0 (Phase Q) retired the `experimental_index_am` and # `relfile_storage` Cargo feature flags. The `turbovec` index # access method has been default-on since v0.9 and the # relfile-resident storage path (Phase L preview, Phase P # persisted layout) is now the only storage strategy. There is # no longer a side-table fallback to disable. Build flags reduce # to just `pg`. [dependencies] pgrx = "=0.19.1" turbovec = { git = "https://github.com/gburd/turbovec.git", rev = "455549fa6a2ffb128527d282b6dc87fad258f7f3", features = ["mask-skip-counter"] } # ^ turbovec 1.1.1 (upstream 60efd4d: staged 2/4-bit planes search) + FOUR # additive fork carries (the first three cherry-picked unchanged) on branch # gburd/turbovec@pgtv-2.11.0-port: `pub fn repack` (3ed5708), the # re-exposed IdMapIndex parts API (be133b8), the parallel cold-open # repack (9638651), and NEW carry #4, the parallel planes cold-open # repack (455549f) — both byte-identical to serial, pinned by turbovec's # `parallel_{,planes_}repack_is_byte_identical_to_serial`. Upstream # issues #545/#546/#547. We persist only packed codes, never turbovec's v8 file # container, so 1.1's v8 *file* format does not touch our wire format. # Pinned by git rev so the port builds anywhere. parking_lot = "0.12" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "2.0" rand = "0.8" # Seeded deterministic RNG for IVF k-means (IVF_SEED), mirroring # turbovec's ChaCha8Rng rotation precedent. Already in the tree # transitively via rand 0.8; pinned to 0.3 to match. rand_chacha = "0.3" libc = "0.2" half = { version = "2.4", features = ["serde"] } # Already in the tree transitively (faer/gemm stack pulls it in via # turbovec); declared directly so ambuild can size a bounded rayon # thread pool from `turbovec.build_parallelism`. v1.12.0 is the # version already resolved in Cargo.lock — no new graph edge. rayon = "1.10" # Already in the tree transitively (faer pulls the whole gemm stack); # declared directly so the IVF build can batch the corpus rotation # (corpus @ R^T) and the cell-assignment cross term (V @ C^T) as one # GEMM each instead of per-vector scalar loops (~10^12 scalar FLOPs # at 1M x 1024-d). v0.18.2 is already resolved in Cargo.lock — no new # graph edge. `Parallelism::None` gives a fixed reduction order, so # the GEMM is bit-deterministic; we use it for the IVF build to keep # the on-disk bytes identical to the scalar path. gemm = "0.18" [dev-dependencies] pgrx-tests = "=0.19.1" criterion = { version = "0.5", default-features = false, features = ["cargo_bench_support", "plotters"] } hegeltest = "0.25" [[bench]] name = "distance" harness = false [[bench]] name = "recall" harness = false [[bench]] name = "concurrent_knn" harness = false [[bench]] name = "recall_vs_pgvector" harness = false [[bench]] name = "allowlist_crossover" harness = false [profile.dev] panic = "unwind" [profile.release] panic = "unwind" opt-level = 3 lto = "fat" codegen-units = 1 [lints.clippy] pedantic = { level = "warn", priority = -1 } # Project-wide allows. The intent is that pedantic stays warn-by-default, # but a small set of lints are silenced because they conflict with idioms # we deliberately use: # # * pgrx's `#[pg_extern]` macro generates wrappers that take owned # values and never `#[must_use]` themselves; we cannot fix the lint # at the call site. # * pg_sys FFI uses `as` casts and raw-pointer-to-raw-pointer # conversions everywhere. # * Many docstrings reference SQL identifiers and numbers that are # not Rust paths. module_name_repetitions = "allow" similar_names = "allow" missing_safety_doc = "allow" missing_panics_doc = "allow" missing_errors_doc = "allow" unsafe_derive_deserialize = "allow" cast_possible_truncation = "allow" cast_possible_wrap = "allow" cast_lossless = "allow" cast_precision_loss = "allow" cast_sign_loss = "allow" needless_pass_by_value = "allow" # pg_extern arity uninlined_format_args = "allow" # style preference doc_markdown = "allow" # SQL identifiers in docstrings single_char_pattern = "allow" # test convenience must_use_candidate = "allow" # pgrx wrappers ptr_as_ptr = "allow" # pg_sys FFI ptr_cast_constness = "allow" # pg_sys FFI borrow_as_ptr = "allow" # pg_sys FFI too_many_arguments = "allow" # pg_extern signatures type_complexity = "allow" # pgrx-generated TableIterator types unnecessary_cast = "allow" # pg_sys FFI cast_ptr_alignment = "allow" # varlena layout non_std_lazy_statics = "allow" # once_cell::Lazy used intentionally manual_let_else = "allow" # readability of explicit match single_match_else = "allow" # readability ref_as_ptr = "allow" # pg_sys FFI nonminimal_bool = "allow" # `!is_null()` reads more naturally if_not_else = "allow" # FFI null-check chains read better as `!is_null()`