lance_io/object_store/providers/
local.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4use std::sync::Arc;
5
6use object_store::{local::LocalFileSystem, path::Path};
7use url::Url;
8
9use crate::object_store::{
10    ObjectStore, ObjectStoreParams, ObjectStoreProvider, StorageOptions, DEFAULT_LOCAL_BLOCK_SIZE,
11    DEFAULT_LOCAL_IO_PARALLELISM, DEFAULT_MAX_IOP_SIZE,
12};
13use lance_core::error::Result;
14
15#[derive(Default, Debug)]
16pub struct FileStoreProvider;
17
18#[async_trait::async_trait]
19impl ObjectStoreProvider for FileStoreProvider {
20    async fn new_store(&self, base_path: Url, params: &ObjectStoreParams) -> Result<ObjectStore> {
21        let block_size = params.block_size.unwrap_or(DEFAULT_LOCAL_BLOCK_SIZE);
22        let storage_options = StorageOptions(params.storage_options.clone().unwrap_or_default());
23        let download_retry_count = storage_options.download_retry_count();
24        Ok(ObjectStore {
25            inner: Arc::new(LocalFileSystem::new()),
26            scheme: base_path.scheme().to_owned(),
27            block_size,
28            max_iop_size: *DEFAULT_MAX_IOP_SIZE,
29            use_constant_size_upload_parts: false,
30            list_is_lexically_ordered: false,
31            io_parallelism: DEFAULT_LOCAL_IO_PARALLELISM,
32            download_retry_count,
33        })
34    }
35
36    fn extract_path(&self, url: &Url) -> object_store::path::Path {
37        url.to_file_path()
38            .ok()
39            .and_then(|p| Path::from_absolute_path(p).ok())
40            .unwrap_or_else(|| Path::from(url.path()))
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use crate::object_store::uri_to_url;
47
48    use super::*;
49
50    #[test]
51    fn test_file_store_path() {
52        let provider = FileStoreProvider;
53
54        let cases = [
55            ("file:///", ""),
56            ("file:///usr/local/bin", "usr/local/bin"),
57            ("file-object-store:///path/to/file", "path/to/file"),
58            ("file:///path/to/foo/../bar", "path/to/bar"),
59        ];
60
61        for (uri, expected_path) in cases {
62            let url = uri_to_url(uri).unwrap();
63            let path = provider.extract_path(&url);
64            assert_eq!(path.as_ref(), expected_path, "uri: '{}'", uri);
65        }
66    }
67
68    #[test]
69    #[cfg(windows)]
70    fn test_file_store_path_windows() {
71        let provider = FileStoreProvider;
72
73        let cases = [
74            (
75                "C:\\Users\\ADMINI~1\\AppData\\Local\\",
76                "C:/Users/ADMINI~1/AppData/Local",
77            ),
78            (
79                "C:\\Users\\ADMINI~1\\AppData\\Local\\..\\",
80                "C:/Users/ADMINI~1/AppData",
81            ),
82        ];
83
84        for (uri, expected_path) in cases {
85            let url = uri_to_url(uri).unwrap();
86            let path = provider.extract_path(&url);
87            assert_eq!(path.as_ref(), expected_path);
88        }
89    }
90}