Skip to content

feat: add dynamic cache ABI crate#7828

Open
yanghua wants to merge 3 commits into
lance-format:mainfrom
yanghua:cache-abi-only
Open

feat: add dynamic cache ABI crate#7828
yanghua wants to merge 3 commits into
lance-format:mainfrom
yanghua:cache-abi-only

Conversation

@yanghua

@yanghua yanghua commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR adds a standalone lance-cache-abi crate for the dynamic cache backend C ABI.

The new crate contains only the ABI-facing definitions:

  • ABI version and exported init symbol
  • status codes
  • byte slice / owned bytes / cache key structs
  • backend vtable and function pointer types

lance-core depends on this crate and re-exports the ABI types from lance_core::cache, so future dynamic cache backend implementations can depend on
the ABI crate directly without depending on lance-core.

This PR intentionally does not add dynamic loading logic or any concrete cache backend implementation.

Testing

Not run locally after the latest rebase because the local environment stalled while syncing the Rust 1.97.0 toolchain components.

@github-actions github-actions Bot added the A-deps Dependency updates label Jul 17, 2026
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Dynamic cache ABI

Layer / File(s) Summary
Register the ABI crate
Cargo.toml, rust/lance-cache-abi/Cargo.toml, rust/lance-core/Cargo.toml
The new lance-cache-abi crate is added to the workspace and configured as a workspace dependency of lance-core.
Define ABI data contracts
rust/lance-cache-abi/src/lib.rs
ABI metadata, status codes, C-compatible byte views, owned buffers, cache keys, lookup results, and conversion tests are defined.
Define backend interface and exports
rust/lance-cache-abi/src/lib.rs, rust/lance-core/src/cache/mod.rs
Backend operation function types, the vtable, initialization entrypoint, layout validation, and public lance-core re-exports are added.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: wjones127

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a dynamic cache ABI crate.
Description check ✅ Passed The description matches the changeset and accurately summarizes the new ABI crate and its integration into lance-core.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the enhancement New feature or request label Jul 17, 2026
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 68.29268% with 65 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
rust/lance-cache-abi/src/lib.rs 68.29% 65 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions github-actions Bot added A-python Python bindings A-java Java bindings + JNI labels Jul 17, 2026
@yanghua
yanghua marked this pull request as ready for review July 17, 2026 08:11

@coderabbitai coderabbitai 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.

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (1)
rust/lance-cache-abi/src/lib.rs-29-43 (1)

29-43: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

from_slice doesn't null-normalize ptr when len == 0, violating the field doc.

The field doc on line 30 states "or null when len == 0", but from_slice(&[]) produces a non-null dangling pointer (Rust's empty-slice as_ptr() is non-null). A C backend that checks ptr != NULL instead of len > 0 could dereference it. The same invariant gap exists on DynamicCacheOwnedBytes::from_vec (lines 86-97) when len == 0 but capacity > 0.

🛡️ Proposed fix for both constructors
     pub fn from_slice(bytes: &[u8]) -> Self {
         Self {
-            ptr: bytes.as_ptr(),
+            ptr: if bytes.is_empty() { std::ptr::null() } else { bytes.as_ptr() },
             len: bytes.len(),
         }
     }

And for DynamicCacheOwnedBytes::from_vec:

     pub fn from_vec(mut bytes: Vec<u8>) -> Self {
-        if bytes.capacity() == 0 {
+        if bytes.is_empty() {
             return Self::empty();
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-cache-abi/src/lib.rs` around lines 29 - 43, Update
DynamicCacheByteSlice::from_slice and DynamicCacheOwnedBytes::from_vec to set
ptr to null whenever the resulting len is zero, including empty vectors with
nonzero capacity; preserve the existing data pointer for non-empty values and
keep ownership metadata unchanged.
🧹 Nitpick comments (2)
rust/lance-cache-abi/src/lib.rs (2)

252-265: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add tests for DynamicCacheByteSlice round-trip and empty-slice handling.

The only test covers DynamicCacheOwnedBytes. DynamicCacheByteSlice::from_slice/as_slice and the empty-slice null-pointer edge case are untested. As per coding guidelines, every feature must have corresponding tests.

🧪 Suggested additional tests
     #[test]
     fn owned_bytes_round_trip_in_allocating_library() {
         let bytes = vec![1, 2, 3];
         let owned = DynamicCacheOwnedBytes::from_vec(bytes);
         // SAFETY: This test reconstructs the vector in the same crate that
         // allocated it, which mirrors a plugin's `free_bytes` implementation.
         let bytes = unsafe { owned.into_vec() };
         assert_eq!(bytes, vec![1, 2, 3]);
     }
+
+    #[test]
+    fn byte_slice_round_trip() {
+        let data = b"hello";
+        let slice = DynamicCacheByteSlice::from_slice(data);
+        // SAFETY: `data` outlives the call.
+        let borrowed = unsafe { slice.as_slice() };
+        assert_eq!(borrowed, b"hello");
+    }
+
+    #[test]
+    fn byte_slice_empty_is_safe() {
+        let slice = DynamicCacheByteSlice::from_slice(&[]);
+        assert_eq!(slice.len, 0);
+        // SAFETY: len == 0 returns an empty slice without dereferencing ptr.
+        let borrowed = unsafe { slice.as_slice() };
+        assert!(borrowed.is_empty());
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-cache-abi/src/lib.rs` around lines 252 - 265, Add tests in the
existing tests module covering DynamicCacheByteSlice::from_slice followed by
as_slice, asserting the original bytes are preserved, and separately covering an
empty slice to verify its null-pointer edge-case behavior. Keep the existing
DynamicCacheOwnedBytes test unchanged.

Source: Coding guidelines


14-15: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use &CStr instead of &[u8] for the init symbol.

&[u8] with an embedded null terminator is error-prone for FFI symbol lookup. A &CStr provides type safety and direct .as_ptr() access for dlsym/GetProcAddress. C string literals are const-constructible since Rust 1.77, which the project exceeds.

♻️ Proposed refactor
-use std::ffi::c_void;
+use std::ffi::{c_void, CStr};

-/// Exported symbol every dynamic cache backend must provide.
-pub const DYNAMIC_CACHE_BACKEND_INIT_SYMBOL: &[u8] = b"lance_cache_backend_init\0";
+/// Exported symbol every dynamic cache backend must provide.
+pub const DYNAMIC_CACHE_BACKEND_INIT_SYMBOL: &CStr = c"lance_cache_backend_init";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-cache-abi/src/lib.rs` around lines 14 - 15, Change
DYNAMIC_CACHE_BACKEND_INIT_SYMBOL from a byte slice to a const-constructible
&CStr using the existing null-terminated symbol value. Preserve the exported
symbol name and ensure callers use its direct pointer access for dynamic lookup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Other comments:
In `@rust/lance-cache-abi/src/lib.rs`:
- Around line 29-43: Update DynamicCacheByteSlice::from_slice and
DynamicCacheOwnedBytes::from_vec to set ptr to null whenever the resulting len
is zero, including empty vectors with nonzero capacity; preserve the existing
data pointer for non-empty values and keep ownership metadata unchanged.

---

Nitpick comments:
In `@rust/lance-cache-abi/src/lib.rs`:
- Around line 252-265: Add tests in the existing tests module covering
DynamicCacheByteSlice::from_slice followed by as_slice, asserting the original
bytes are preserved, and separately covering an empty slice to verify its
null-pointer edge-case behavior. Keep the existing DynamicCacheOwnedBytes test
unchanged.
- Around line 14-15: Change DYNAMIC_CACHE_BACKEND_INIT_SYMBOL from a byte slice
to a const-constructible &CStr using the existing null-terminated symbol value.
Preserve the exported symbol name and ensure callers use its direct pointer
access for dynamic lookup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 9dcd6ea4-9d7a-4d74-be47-bb2707b72275

📥 Commits

Reviewing files that changed from the base of the PR and between f23b8d6 and ddf1b07.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • java/lance-jni/Cargo.lock is excluded by !**/*.lock
  • python/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • Cargo.toml
  • rust/lance-cache-abi/Cargo.toml
  • rust/lance-cache-abi/src/lib.rs
  • rust/lance-core/Cargo.toml
  • rust/lance-core/src/cache/mod.rs

@yanghua
yanghua marked this pull request as draft July 17, 2026 09:09
@yanghua
yanghua marked this pull request as ready for review July 17, 2026 10:14

@coderabbitai coderabbitai 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.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rust/lance-cache-abi/src/lib.rs`:
- Around line 166-169: Define one canonical representation for empty owned
buffers in the buffer contract: require len == 0 to use a null ptr and capacity
== 0, and update the related documentation around the owned-buffer definition
and free_bytes behavior to match. Ensure the empty-buffer no-op semantics cannot
permit an allocated zero-length buffer to leak.
- Around line 67-120: Add compiling Rust doc examples across the public ABI APIs
in the affected sections, covering owned-byte lifecycle and unsafe ownership
rules, DynamicCacheStatus conversion, vtable construction, and the
initialization handshake. Attach each example to the relevant public structs,
enums, constants, and methods using intra-doc links, and ensure every snippet
matches the current function signatures and compiles as documentation tests.
- Around line 381-385: Make vtable initialization reject any host buffer smaller
than DYNAMIC_CACHE_BACKEND_VTABLE_SIZE before calling out_vtable.write, keeping
new() and the documented full-size protocol consistent. Preserve full-size
initialization behavior and add tests covering required-size rejection, exact
full-size success, and a canary buffer proving no out-of-bounds writes occur.
- Around line 423-449: Update the current-layout constructor
DynamicCacheVTable::new to stop accepting an abi_version argument and always
assign DYNAMIC_CACHE_ABI_VERSION internally. Keep the constructor’s other
callback parameters and current-layout metadata unchanged; add version-specific
constructors only if another layout is actually supported.

In `@rust/lance-core/src/cache/mod.rs`:
- Line 58: Update the cache module’s re-exports so the existing direct ABI
symbols, including DynamicCacheBackendVTable, remain publicly available. Add the
dynamic_cache_abi module alias alongside those direct re-exports, and apply the
project’s standard #[deprecated] compatibility treatment to the old paths only
after providing the replacement.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 0132d7ef-0fff-48d5-b0df-d9a3933da58c

📥 Commits

Reviewing files that changed from the base of the PR and between ddf1b07 and 9c79b34.

📒 Files selected for processing (2)
  • rust/lance-cache-abi/src/lib.rs
  • rust/lance-core/src/cache/mod.rs

Comment on lines +67 to +120
/// Dynamic cache operation status.
///
/// ABI function signatures use raw `u32` return values so hosts can handle
/// unknown future status codes without constructing an invalid Rust enum. This
/// enum is a Rust-side helper for known v1 status values.
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DynamicCacheStatus {
/// Operation completed successfully.
Ok = 0,
/// Lookup found a byte payload.
Hit = 1,
/// Lookup did not find a byte payload.
Miss = 2,
/// Operation failed inside the dynamic backend.
Error = 3,
}

impl DynamicCacheStatus {
/// Return the raw ABI status code.
pub const fn as_u32(self) -> u32 {
self as u32
}
}

impl TryFrom<u32> for DynamicCacheStatus {
type Error = UnknownDynamicCacheStatus;

fn try_from(value: u32) -> Result<Self, UnknownDynamicCacheStatus> {
match value {
DYNAMIC_CACHE_STATUS_OK => Ok(Self::Ok),
DYNAMIC_CACHE_STATUS_HIT => Ok(Self::Hit),
DYNAMIC_CACHE_STATUS_MISS => Ok(Self::Miss),
DYNAMIC_CACHE_STATUS_ERROR => Ok(Self::Error),
_ => Err(UnknownDynamicCacheStatus(value)),
}
}
}

/// Raw status code that is not known to this ABI crate.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct UnknownDynamicCacheStatus(pub u32);

/// Operation completed successfully.
pub const DYNAMIC_CACHE_STATUS_OK: u32 = DynamicCacheStatus::Ok as u32;
/// Lookup found a byte payload.
pub const DYNAMIC_CACHE_STATUS_HIT: u32 = DynamicCacheStatus::Hit as u32;
/// Lookup did not find a byte payload.
pub const DYNAMIC_CACHE_STATUS_MISS: u32 = DynamicCacheStatus::Miss as u32;
/// Operation failed inside the dynamic backend.
pub const DYNAMIC_CACHE_STATUS_ERROR: u32 = DynamicCacheStatus::Error as u32;

/// Number of pointer-sized slots reserved for future optional functions.
pub const DYNAMIC_CACHE_BACKEND_VTABLE_RESERVED_SLOTS: usize = 8;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Add compiling examples for the public ABI surface.

Document the owned-byte lifecycle, status conversion, vtable construction, and initialization handshake with examples linked to the relevant types. This is especially important for the unsafe ownership contracts.

As per coding guidelines, “Document all public APIs with examples and links to relevant structs and methods; keep examples synchronized with actual signatures.”

Also applies to: 122-220, 274-359, 368-477

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-cache-abi/src/lib.rs` around lines 67 - 120, Add compiling Rust
doc examples across the public ABI APIs in the affected sections, covering
owned-byte lifecycle and unsafe ownership rules, DynamicCacheStatus conversion,
vtable construction, and the initialization handshake. Attach each example to
the relevant public structs, enums, constants, and methods using intra-doc
links, and ensure every snippet matches the current function signatures and
compiles as documentation tests.

Source: Coding guidelines

Comment on lines +166 to +169
///
/// A non-empty buffer must have a non-null `ptr`, `capacity >= len`, and an
/// allocation that can be released by the backend's [`DynamicCacheFreeBytesFn`].
/// Empty buffers have no readable bytes; hosts must not read from `ptr`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Define canonical empty owned-buffer semantics.

The general contract permits len == 0 with nonzero capacity, but free_bytes says empty buffers should be no-ops. A backend returning an allocated empty buffer could therefore leak it. Either require ptr == null && capacity == 0 whenever len == 0, or require free_bytes to release nonzero-capacity empty allocations.

Also applies to: 360-366

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-cache-abi/src/lib.rs` around lines 166 - 169, Define one canonical
representation for empty owned buffers in the buffer contract: require len == 0
to use a null ptr and capacity == 0, and update the related documentation around
the owned-buffer definition and free_bytes behavior to match. Ensure the
empty-buffer no-op semantics cannot permit an allocated zero-length buffer to
leak.

Comment on lines +381 to +385
/// Size in bytes of the vtable filled by the backend.
///
/// Backends must set this to [`DYNAMIC_CACHE_BACKEND_VTABLE_SIZE`]. Hosts
/// must validate this before reading fields that may not exist in older
/// vtables.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Make bounded vtable initialization unambiguous and safe.

Initialization permits host_vtable_size < DYNAMIC_CACHE_BACKEND_VTABLE_SIZE, while the field documentation and new() produce a full-sized vtable. Writing that value with out_vtable.write(...) would overrun a smaller host buffer.

Define one safe protocol: reject undersized buffers, or provide prefix-writing logic that writes at most host_vtable_size and reports the exact bytes written. Add required-size, full-size, and canary-buffer tests.

As per coding guidelines, “Every bugfix and feature must have corresponding tests.”

Also applies to: 423-449, 465-477

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-cache-abi/src/lib.rs` around lines 381 - 385, Make vtable
initialization reject any host buffer smaller than
DYNAMIC_CACHE_BACKEND_VTABLE_SIZE before calling out_vtable.write, keeping new()
and the documented full-size protocol consistent. Preserve full-size
initialization behavior and add tests covering required-size rejection, exact
full-size success, and a canary buffer proving no out-of-bounds writes occur.

Source: Coding guidelines

Comment on lines +423 to +449
/// Create a vtable with current layout metadata and empty reserved slots.
#[allow(clippy::too_many_arguments)]
pub const fn new(
abi_version: u32,
create: DynamicCacheCreateFn,
destroy: DynamicCacheDestroyFn,
get: DynamicCacheGetFn,
insert: DynamicCacheInsertFn,
invalidate_prefix: DynamicCacheInvalidatePrefixFn,
clear: DynamicCacheClearFn,
measure: DynamicCacheMeasureFn,
free_bytes: DynamicCacheFreeBytesFn,
) -> Self {
Self {
struct_size: DYNAMIC_CACHE_BACKEND_VTABLE_SIZE,
abi_version,
create,
destroy,
get,
insert,
invalidate_prefix,
clear,
measure,
free_bytes,
reserved: [None; DYNAMIC_CACHE_BACKEND_VTABLE_RESERVED_SLOTS],
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not accept arbitrary ABI versions for the current-layout constructor.

new() always creates the current vtable layout, but callers can label it with any u32. Set abi_version to DYNAMIC_CACHE_ABI_VERSION internally; introduce explicit version-specific constructors only when another layout exists.

Proposed fix
 pub const fn new(
-    abi_version: u32,
     create: DynamicCacheCreateFn,
     destroy: DynamicCacheDestroyFn,
     get: DynamicCacheGetFn,
     insert: DynamicCacheInsertFn,
     invalidate_prefix: DynamicCacheInvalidatePrefixFn,
     clear: DynamicCacheClearFn,
     measure: DynamicCacheMeasureFn,
     free_bytes: DynamicCacheFreeBytesFn,
 ) -> Self {
     Self {
         struct_size: DYNAMIC_CACHE_BACKEND_VTABLE_SIZE,
-        abi_version,
+        abi_version: DYNAMIC_CACHE_ABI_VERSION,

As per coding guidelines, “Validate inputs at API boundaries and reject invalid values with descriptive errors; never silently clamp or adjust them.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Create a vtable with current layout metadata and empty reserved slots.
#[allow(clippy::too_many_arguments)]
pub const fn new(
abi_version: u32,
create: DynamicCacheCreateFn,
destroy: DynamicCacheDestroyFn,
get: DynamicCacheGetFn,
insert: DynamicCacheInsertFn,
invalidate_prefix: DynamicCacheInvalidatePrefixFn,
clear: DynamicCacheClearFn,
measure: DynamicCacheMeasureFn,
free_bytes: DynamicCacheFreeBytesFn,
) -> Self {
Self {
struct_size: DYNAMIC_CACHE_BACKEND_VTABLE_SIZE,
abi_version,
create,
destroy,
get,
insert,
invalidate_prefix,
clear,
measure,
free_bytes,
reserved: [None; DYNAMIC_CACHE_BACKEND_VTABLE_RESERVED_SLOTS],
}
}
/// Create a vtable with current layout metadata and empty reserved slots.
#[allow(clippy::too_many_arguments)]
pub const fn new(
create: DynamicCacheCreateFn,
destroy: DynamicCacheDestroyFn,
get: DynamicCacheGetFn,
insert: DynamicCacheInsertFn,
invalidate_prefix: DynamicCacheInvalidatePrefixFn,
clear: DynamicCacheClearFn,
measure: DynamicCacheMeasureFn,
free_bytes: DynamicCacheFreeBytesFn,
) -> Self {
Self {
struct_size: DYNAMIC_CACHE_BACKEND_VTABLE_SIZE,
abi_version: DYNAMIC_CACHE_ABI_VERSION,
create,
destroy,
get,
insert,
invalidate_prefix,
clear,
measure,
free_bytes,
reserved: [None; DYNAMIC_CACHE_BACKEND_VTABLE_RESERVED_SLOTS],
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-cache-abi/src/lib.rs` around lines 423 - 449, Update the
current-layout constructor DynamicCacheVTable::new to stop accepting an
abi_version argument and always assign DYNAMIC_CACHE_ABI_VERSION internally.
Keep the constructor’s other callback parameters and current-layout metadata
unchanged; add version-specific constructors only if another layout is actually
supported.

Source: Coding guidelines

CacheCodec, CacheCodecImpl, CacheDecode, CacheMissReason, MAGIC, has_cache_envelope,
};
pub use entry_io::{CacheEntryReader, CacheEntryWriter};
pub use lance_cache_abi as dynamic_cache_abi;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve the existing direct ABI re-exports.

Replacing the previous symbol re-exports breaks imports such as lance_core::cache::DynamicCacheBackendVTable. Add the module alias alongside the existing paths, then deprecate those paths through the normal compatibility process.

As per coding guidelines, “Do not break public API signatures; deprecate old APIs with #[deprecated] and add a replacement.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-core/src/cache/mod.rs` at line 58, Update the cache module’s
re-exports so the existing direct ABI symbols, including
DynamicCacheBackendVTable, remain publicly available. Add the dynamic_cache_abi
module alias alongside those direct re-exports, and apply the project’s standard
#[deprecated] compatibility treatment to the old paths only after providing the
replacement.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-deps Dependency updates A-java Java bindings + JNI A-python Python bindings enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant