Skip to content

Commit 6233d97

Browse files
committed
fix: url parsing inconsistencies
Signed-off-by: Robert Pack <[email protected]>
1 parent a878029 commit 6233d97

File tree

5 files changed

+30
-44
lines changed

5 files changed

+30
-44
lines changed

crates/core/src/logstore/config.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::HashMap;
22

33
use ::object_store::RetryConfig;
4-
use object_store::{path::Path, prefix::PrefixStore, ObjectStore};
4+
use object_store::{path::Path, prefix::PrefixStore, ObjectStore, ObjectStoreScheme};
55
use tokio::runtime::Handle;
66

77
#[cfg(feature = "delta-cache")]
@@ -141,18 +141,14 @@ impl StorageConfig {
141141
Ok(inner)
142142
}
143143

144-
fn decorate_prefix<T: ObjectStore>(
144+
pub(crate) fn decorate_prefix<T: ObjectStore>(
145145
store: T,
146146
table_root: &url::Url,
147147
) -> DeltaResult<Box<dyn ObjectStore>> {
148-
let prefix = if table_root.scheme() == "file" {
149-
Path::from_filesystem_path(
150-
table_root
151-
.to_file_path()
152-
.map_err(|_| DeltaTableError::generic("failed to convert fs"))?,
153-
)?
154-
} else {
155-
Path::parse(table_root.path())?
148+
let prefix = match ObjectStoreScheme::parse(table_root) {
149+
Ok((ObjectStoreScheme::AmazonS3, _)) => Path::parse(table_root.path())?,
150+
Ok((_, path)) => path,
151+
_ => Path::parse(table_root.path())?,
156152
};
157153
Ok(if prefix != Path::from("/") {
158154
Box::new(PrefixStore::new(store, prefix)) as Box<dyn ObjectStore>

crates/gcp/tests/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ pub mod gs_cli {
129129
.wait()
130130
}
131131

132+
#[allow(unused)]
132133
pub fn delete_bucket(container_name: impl AsRef<str>) -> std::io::Result<ExitStatus> {
133134
let endpoint = std::env::var("GOOGLE_ENDPOINT_URL")
134135
.expect("variable GOOGLE_ENDPOINT_URL must be set to connect to GCS Emulator");

crates/mount/src/file.rs

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -108,42 +108,20 @@ impl From<LocalFileSystemError> for ObjectStoreError {
108108
#[derive(Debug)]
109109
pub struct MountFileStorageBackend {
110110
inner: Arc<LocalFileSystem>,
111-
root_url: Arc<Url>,
112111
}
113112

114113
impl MountFileStorageBackend {
115114
/// Creates a new MountFileStorageBackend.
116-
pub fn try_new(path: impl AsRef<std::path::Path>) -> ObjectStoreResult<Self> {
115+
pub fn try_new() -> ObjectStoreResult<Self> {
117116
Ok(Self {
118-
root_url: Arc::new(Self::path_to_root_url(path.as_ref())?),
119-
inner: Arc::new(LocalFileSystem::new_with_prefix(path)?),
120-
})
121-
}
122-
123-
fn path_to_root_url(path: &std::path::Path) -> ObjectStoreResult<Url> {
124-
let root_path =
125-
std::fs::canonicalize(path).map_err(|e| object_store::Error::InvalidPath {
126-
source: object_store::path::Error::Canonicalize {
127-
path: path.into(),
128-
source: e,
129-
},
130-
})?;
131-
132-
Url::from_file_path(root_path).map_err(|_| object_store::Error::InvalidPath {
133-
source: object_store::path::Error::InvalidPath { path: path.into() },
117+
inner: Arc::new(LocalFileSystem::new()),
134118
})
135119
}
136120

137121
/// Return an absolute filesystem path of the given location
138122
fn path_to_filesystem(&self, location: &ObjectStorePath) -> String {
139-
let mut url = self.root_url.as_ref().clone();
140-
url.path_segments_mut()
141-
.expect("url path")
142-
// technically not necessary as Path ignores empty segments
143-
// but avoids creating paths with "//" which look odd in error messages.
144-
.pop_if_empty()
145-
.extend(location.parts());
146-
123+
let mut url = url::Url::parse("file:///").unwrap();
124+
url.set_path(location.as_ref());
147125
url.to_file_path().unwrap().to_str().unwrap().to_owned()
148126
}
149127
}
@@ -264,6 +242,19 @@ impl ObjectStore for MountFileStorageBackend {
264242
}
265243
}
266244

245+
fn path_to_root_url(path: &std::path::Path) -> ObjectStoreResult<Url> {
246+
let root_path = std::fs::canonicalize(path).map_err(|e| object_store::Error::InvalidPath {
247+
source: object_store::path::Error::Canonicalize {
248+
path: path.into(),
249+
source: e,
250+
},
251+
})?;
252+
253+
Url::from_file_path(root_path).map_err(|_| object_store::Error::InvalidPath {
254+
source: object_store::path::Error::InvalidPath { path: path.into() },
255+
})
256+
}
257+
267258
/// Regular renames `from` to `to`.
268259
/// `from` has to exist, but `to` is not, otherwise the operation will fail.
269260
/// It's not atomic and cannot be called in parallel with other operations on the same file.

crates/mount/src/lib.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,15 @@ impl ObjectStoreFactory for MountFactory {
6060
}
6161
// We need to convert the dbfs url to a file url
6262
let new_url = Url::parse(&format!("file:///dbfs{}", url.path())).unwrap();
63-
let store = Arc::new(file::MountFileStorageBackend::try_new(
64-
new_url.to_file_path().unwrap(),
65-
)?) as ObjectStoreRef;
63+
let store = Arc::new(file::MountFileStorageBackend::try_new()?) as ObjectStoreRef;
6664
Ok((store, Path::from("/")))
6765
}
6866
"file" => {
6967
if allow_unsafe_rename {
70-
let store = Arc::new(file::MountFileStorageBackend::try_new(
71-
url.to_file_path().unwrap(),
72-
)?) as ObjectStoreRef;
73-
Ok((store, Path::from("/")))
68+
let store =
69+
Arc::new(file::MountFileStorageBackend::try_new()?) as ObjectStoreRef;
70+
let prefix = Path::from_filesystem_path(url.to_file_path().unwrap())?;
71+
Ok((store, prefix))
7472
} else {
7573
let store = Arc::new(LocalFileSystem::new()) as ObjectStoreRef;
7674
let prefix = Path::from_filesystem_path(url.to_file_path().unwrap())?;

crates/mount/tests/integration.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ static TEST_PREFIXES: &[&str] = &["my table", "你好/😊"];
1111

1212
#[tokio::test]
1313
#[serial]
14-
async fn test_integration_local() -> TestResult {
14+
async fn test_integration_mount() -> TestResult {
1515
let context = IntegrationContext::new(Box::<MountIntegration>::default())?;
1616

1717
test_read_tables(&context).await?;

0 commit comments

Comments
 (0)