mirror of
https://github.com/lancedb/lancedb.git
synced 2026-11-14 06:36:54 +00:00
fix(storage): preserve legacy direct store listing
Keep the parent probe only for untyped deprecated direct bindings while provider-resolved and capable stores remain target-bounded.
This commit is contained in:
+53
-27
@@ -183,6 +183,11 @@ async fn map_dataset_not_found(
|
||||
/// Object stores cannot represent empty directories: probe an exact key and then consume
|
||||
/// at most the first object under the table prefix. Neither path inspects sibling tables.
|
||||
async fn table_storage_exists(uri: &str, params: ReadParams) -> Result<bool> {
|
||||
#[allow(deprecated)]
|
||||
let uses_legacy_direct_store = params.store_options.as_ref().is_some_and(|options| {
|
||||
options.object_store.is_some() && options.native_directory_path_resolver.is_none()
|
||||
});
|
||||
|
||||
// Resolve the effective provider and wrapper for this exact table URI. The resolved
|
||||
// store remains authoritative even when a custom provider preserves a `file` scheme.
|
||||
let (object_store, path, _) = DatasetBuilder::from_uri(uri)
|
||||
@@ -195,6 +200,17 @@ async fn table_storage_exists(uri: &str, params: ReadParams) -> Result<bool> {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// The deprecated direct binding cannot identify native directory semantics unless its
|
||||
// caller supplies a resolver. Preserve its established list/open agreement without
|
||||
// widening this sibling-enumerating fallback to provider-resolved stores.
|
||||
if uses_legacy_direct_store {
|
||||
let (Some(parent), Some(dir_name)) = (path.parent(), path.filename()) else {
|
||||
return Ok(false);
|
||||
};
|
||||
let entries = object_store.read_dir(parent).await?;
|
||||
return Ok(entries.iter().any(|entry| entry.as_str() == dir_name));
|
||||
}
|
||||
|
||||
if let Some(native_path) = object_store.native_directory_path(&path) {
|
||||
// A native table URI intentionally grants access to this exact path; LanceDB does
|
||||
// not confine local databases beneath a separate filesystem root. nosemgrep
|
||||
@@ -4788,38 +4804,48 @@ mod tests {
|
||||
let table_path = tmp_dir.path().join(format!("{table_name}.lance"));
|
||||
std::fs::create_dir(&table_path).unwrap();
|
||||
let uri = url::Url::from_file_path(&table_path).unwrap();
|
||||
let read_params = ReadParams {
|
||||
store_options: Some(ObjectStoreParams {
|
||||
object_store: Some((
|
||||
Arc::new(object_store::local::LocalFileSystem::new()),
|
||||
uri.clone(),
|
||||
)),
|
||||
native_directory_path_resolver: Some(NativeDirectoryPathResolver::new(|path| {
|
||||
let cases = [
|
||||
("legacy", None),
|
||||
(
|
||||
"capable",
|
||||
Some(NativeDirectoryPathResolver::new(|path| {
|
||||
std::path::PathBuf::from(lance_io::local::to_local_path(path))
|
||||
})),
|
||||
),
|
||||
];
|
||||
|
||||
for (case, native_directory_path_resolver) in cases {
|
||||
let read_params = ReadParams {
|
||||
store_options: Some(ObjectStoreParams {
|
||||
object_store: Some((
|
||||
Arc::new(object_store::local::LocalFileSystem::new()),
|
||||
uri.clone(),
|
||||
)),
|
||||
native_directory_path_resolver,
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
};
|
||||
|
||||
let err = NativeTable::open_with_params(
|
||||
uri.as_ref(),
|
||||
table_name,
|
||||
Vec::new(),
|
||||
None,
|
||||
Some(read_params),
|
||||
None,
|
||||
None,
|
||||
HashSet::new(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
let err = NativeTable::open_with_params(
|
||||
uri.as_ref(),
|
||||
table_name,
|
||||
Vec::new(),
|
||||
None,
|
||||
Some(read_params),
|
||||
None,
|
||||
None,
|
||||
HashSet::new(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert!(
|
||||
matches!(&err, Error::TableCorrupted { name, .. } if name == table_name),
|
||||
"empty direct local directory must remain corrupt, got {err:?}"
|
||||
);
|
||||
assert!(
|
||||
matches!(&err, Error::TableCorrupted { name, .. } if name == table_name),
|
||||
"{case} empty direct local directory must remain corrupt, got {err:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// If a concurrent create commits after the first manifest lookup misses,
|
||||
|
||||
Reference in New Issue
Block a user