Skip to content

Commit 9f0d3d7

Browse files
westonpaceclaude
andcommitted
refactor(index): break lance-table → lance-index-core dependency
Remove the unintended `lance-table → lance-index-core` dependency introduced in the previous commit. Key changes: - Restore `IndexFile` as a standalone struct in `lance-table` (duplicate of the one in `lance-index-core`), removing the re-export that forced the dep - Add `index_files_to_table()` / `table_files_to_index()` free functions in `lance-index` to convert between the two distinct `IndexFile` types - Introduce newtype wrappers `FragReuseIndexHandle` and `MemWalIndexHandle` in `lance-index` so that `Index` / `RowIdRemapper` (now in `lance-index-core`) can be implemented on the `lance-table` types without violating orphan rules - Remove the `lance-index-core` trait impls that were added directly on `FragReuseIndex` / `MemWalIndex` in `lance-table` - Update all call sites in `lance`, `lance-index`, and `lance-namespace-impls` to use the handle newtypes and conversion functions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d29d5d3 commit 9f0d3d7

24 files changed

Lines changed: 262 additions & 154 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

java/lance-jni/Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/lance-index/src/frag_reuse.rs

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,100 @@
55
//!
66
//! The data structures and table-format logic live in
77
//! [`lance_table::system_index::frag_reuse`]; this module re-exports them and
8-
//! the lance-table crate implements the [`Index`] and [`RowIdRemapper`] traits
9-
//! for [`FragReuseIndex`] via lance-index-core.
8+
//! provides newtype wrappers that implement the [`Index`] and [`RowIdRemapper`]
9+
//! traits.
10+
11+
use std::any::Any;
12+
use std::sync::Arc;
13+
14+
use arrow_array::RecordBatch;
15+
use async_trait::async_trait;
16+
use lance_core::deepsize::DeepSizeOf;
17+
use lance_core::Result;
18+
use lance_select::RowAddrTreeMap;
19+
use roaring::{RoaringBitmap, RoaringTreemap};
20+
use serde::Serialize;
1021

1122
pub use lance_table::system_index::frag_reuse::*;
23+
24+
use crate::scalar::RowIdRemapper;
25+
use crate::{Index, IndexType};
26+
27+
/// Newtype wrapping [`FragReuseIndex`] so that `lance-index` can implement
28+
/// the `Index` and `RowIdRemapper` traits (orphan rules prevent implementing
29+
/// them directly in `lance-table`).
30+
pub struct FragReuseIndexHandle(pub Arc<FragReuseIndex>);
31+
32+
impl std::fmt::Debug for FragReuseIndexHandle {
33+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34+
f.debug_tuple("FragReuseIndexHandle").field(&self.0).finish()
35+
}
36+
}
37+
38+
impl DeepSizeOf for FragReuseIndexHandle {
39+
fn deep_size_of_children(&self, context: &mut lance_core::deepsize::Context) -> usize {
40+
self.0.deep_size_of_children(context)
41+
}
42+
}
43+
44+
#[derive(Serialize)]
45+
struct FragReuseStatistics {
46+
num_versions: usize,
47+
}
48+
49+
#[async_trait]
50+
impl Index for FragReuseIndexHandle {
51+
fn as_any(&self) -> &dyn Any {
52+
self
53+
}
54+
55+
fn as_index(self: Arc<Self>) -> Arc<dyn Index> {
56+
self
57+
}
58+
59+
fn statistics(&self) -> Result<serde_json::Value> {
60+
let stats = FragReuseStatistics {
61+
num_versions: self.0.details.versions.len(),
62+
};
63+
serde_json::to_value(stats).map_err(|e| {
64+
lance_core::Error::internal(format!(
65+
"failed to serialize fragment reuse index statistics: {}",
66+
e
67+
))
68+
})
69+
}
70+
71+
async fn prewarm(&self) -> Result<()> {
72+
Ok(())
73+
}
74+
75+
fn index_type(&self) -> IndexType {
76+
IndexType::FragmentReuse
77+
}
78+
79+
async fn calculate_included_frags(&self) -> Result<RoaringBitmap> {
80+
unimplemented!()
81+
}
82+
}
83+
84+
impl RowIdRemapper for FragReuseIndexHandle {
85+
fn remap_row_id(&self, row_id: u64) -> Option<u64> {
86+
self.0.remap_row_id(row_id)
87+
}
88+
89+
fn remap_row_addrs_tree_map(&self, row_addrs: &RowAddrTreeMap) -> RowAddrTreeMap {
90+
self.0.remap_row_addrs_tree_map(row_addrs)
91+
}
92+
93+
fn remap_row_ids_roaring_tree_map(&self, row_ids: &RoaringTreemap) -> RoaringTreemap {
94+
self.0.remap_row_ids_roaring_tree_map(row_ids)
95+
}
96+
97+
fn remap_row_ids_record_batch(
98+
&self,
99+
batch: RecordBatch,
100+
row_id_idx: usize,
101+
) -> Result<RecordBatch> {
102+
self.0.remap_row_ids_record_batch(batch, row_id_idx)
103+
}
104+
}

rust/lance-index/src/mem_wal.rs

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,76 @@
55
//!
66
//! The data structures and table-format logic live in
77
//! [`lance_table::system_index::mem_wal`]; this module re-exports them and
8-
//! the lance-table crate implements the [`Index`] trait for [`MemWalIndex`]
9-
//! via lance-index-core.
8+
//! provides a newtype wrapper that implements the [`Index`] trait.
9+
10+
use std::any::Any;
11+
use std::sync::Arc;
12+
13+
use async_trait::async_trait;
14+
use lance_core::deepsize::DeepSizeOf;
15+
use lance_core::Result;
16+
use roaring::RoaringBitmap;
17+
use serde::Serialize;
1018

1119
pub use lance_table::system_index::mem_wal::*;
20+
21+
use crate::{Index, IndexType};
22+
23+
/// Newtype wrapping [`MemWalIndex`] so that `lance-index` can implement
24+
/// the `Index` trait (orphan rules prevent implementing it directly in
25+
/// `lance-table`).
26+
pub struct MemWalIndexHandle(pub Arc<MemWalIndex>);
27+
28+
impl DeepSizeOf for MemWalIndexHandle {
29+
fn deep_size_of_children(&self, context: &mut lance_core::deepsize::Context) -> usize {
30+
self.0.deep_size_of_children(context)
31+
}
32+
}
33+
34+
#[derive(Serialize)]
35+
struct MemWalStatistics {
36+
num_shards: u32,
37+
num_merged_generations: usize,
38+
num_shard_specs: usize,
39+
num_maintained_indexes: usize,
40+
num_index_catchup_entries: usize,
41+
}
42+
43+
#[async_trait]
44+
impl Index for MemWalIndexHandle {
45+
fn as_any(&self) -> &dyn Any {
46+
self
47+
}
48+
49+
fn as_index(self: Arc<Self>) -> Arc<dyn Index> {
50+
self
51+
}
52+
53+
fn statistics(&self) -> Result<serde_json::Value> {
54+
let stats = MemWalStatistics {
55+
num_shards: self.0.details.num_shards,
56+
num_merged_generations: self.0.details.merged_generations.len(),
57+
num_shard_specs: self.0.details.sharding_specs.len(),
58+
num_maintained_indexes: self.0.details.maintained_indexes.len(),
59+
num_index_catchup_entries: self.0.details.index_catchup.len(),
60+
};
61+
serde_json::to_value(stats).map_err(|e| {
62+
lance_core::Error::internal(format!(
63+
"failed to serialize MemWAL index statistics: {}",
64+
e
65+
))
66+
})
67+
}
68+
69+
async fn prewarm(&self) -> Result<()> {
70+
Ok(())
71+
}
72+
73+
fn index_type(&self) -> IndexType {
74+
IndexType::MemWal
75+
}
76+
77+
async fn calculate_included_frags(&self) -> Result<RoaringBitmap> {
78+
Ok(RoaringBitmap::new())
79+
}
80+
}

rust/lance-index/src/scalar.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,40 @@ pub mod zonemap;
4848

4949
pub use inverted::tokenizer::InvertedIndexParams;
5050

51+
/// Convert a `Vec<`[`lance_index_core::scalar::IndexFile`]`>` to a
52+
/// `Vec<`[`lance_table::format::IndexFile`]`>`.
53+
///
54+
/// These two structs have identical fields; this helper bridges the crate
55+
/// boundary without relying on orphan-rule–violating `From` impls.
56+
pub fn index_files_to_table(
57+
files: Vec<lance_index_core::scalar::IndexFile>,
58+
) -> Vec<lance_table::format::IndexFile> {
59+
files
60+
.into_iter()
61+
.map(|f| lance_table::format::IndexFile {
62+
path: f.path,
63+
size_bytes: f.size_bytes,
64+
})
65+
.collect()
66+
}
67+
68+
/// Convert a `Vec<`[`lance_table::format::IndexFile`]`>` to a
69+
/// `Vec<`[`lance_index_core::scalar::IndexFile`]`>`.
70+
///
71+
/// These two structs have identical fields; this helper bridges the crate
72+
/// boundary without relying on orphan-rule–violating `From` impls.
73+
pub fn table_files_to_index(
74+
files: Vec<lance_table::format::IndexFile>,
75+
) -> Vec<lance_index_core::scalar::IndexFile> {
76+
files
77+
.into_iter()
78+
.map(|f| lance_index_core::scalar::IndexFile {
79+
path: f.path,
80+
size_bytes: f.size_bytes,
81+
})
82+
.collect()
83+
}
84+
5185
impl IndexParams for InvertedIndexParams {
5286
fn as_any(&self) -> &dyn std::any::Any {
5387
self

rust/lance-index/src/scalar/btree.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6287,7 +6287,7 @@ mod tests {
62876287

62886288
#[tokio::test]
62896289
async fn test_btree_index_state_reconstruct_applies_frag_reuse_index() {
6290-
use crate::frag_reuse::{FragReuseIndex, FragReuseIndexDetails};
6290+
use crate::frag_reuse::{FragReuseIndex, FragReuseIndexDetails, FragReuseIndexHandle};
62916291
use std::collections::HashMap;
62926292
use uuid::Uuid;
62936293

@@ -6320,11 +6320,11 @@ mod tests {
63206320
// Querying for value == 0 should now return row 5000, confirming reconstruct threaded
63216321
// the FragReuseIndex through to the rebuilt BTreeIndex.
63226322
let frag_reuse_index: Arc<dyn crate::scalar::RowIdRemapper> =
6323-
Arc::new(FragReuseIndex::new(
6323+
Arc::new(FragReuseIndexHandle(Arc::new(FragReuseIndex::new(
63246324
Uuid::new_v4(),
63256325
vec![HashMap::from([(0u64, Some(5000u64))])],
63266326
FragReuseIndexDetails { versions: vec![] },
6327-
));
6327+
))));
63286328
let reconstructed = state
63296329
.reconstruct(
63306330
test_store.clone(),

rust/lance-index/src/scalar/lance_format.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,14 @@ impl IndexStore for LanceIndexStore {
537537
}
538538

539539
async fn list_files_with_sizes(&self) -> Result<Vec<IndexFile>> {
540-
list_index_files_with_sizes(&self.object_store, &self.index_dir).await
540+
let files = list_index_files_with_sizes(&self.object_store, &self.index_dir).await?;
541+
Ok(files
542+
.into_iter()
543+
.map(|f| IndexFile {
544+
path: f.path,
545+
size_bytes: f.size_bytes,
546+
})
547+
.collect())
541548
}
542549
}
543550

rust/lance-namespace-impls/src/dir/manifest.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use lance_index::progress::noop_progress;
3636
use lance_index::registry::IndexPluginRegistry;
3737
use lance_index::scalar::lance_format::LanceIndexStore;
3838
use lance_index::scalar::registry::VALUE_COLUMN_NAME;
39-
use lance_index::scalar::{BuiltinIndexType, CreatedIndex, ScalarIndexParams};
39+
use lance_index::scalar::{BuiltinIndexType, CreatedIndex, ScalarIndexParams, index_files_to_table};
4040
use lance_io::object_store::{ObjectStore, ObjectStoreParams};
4141
use lance_io::stream::RecordBatchStream as LanceRecordBatchStream;
4242
use lance_namespace::LanceNamespace;
@@ -1279,7 +1279,7 @@ impl ManifestNamespace {
12791279
index_version: trained_index.created_index.index_version as i32,
12801280
created_at: None,
12811281
base_id: None,
1282-
files: Some(trained_index.created_index.files),
1282+
files: Some(index_files_to_table(trained_index.created_index.files)),
12831283
})
12841284
}
12851285

rust/lance-table/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ rust-version.workspace = true
1414
[dependencies]
1515
lance-arrow.workspace = true
1616
lance-core.workspace = true
17-
lance-index-core.workspace = true
1817
lance-file.workspace = true
1918
lance-select.workspace = true
2019
lance-io.workspace = true

0 commit comments

Comments
 (0)