Skip to content

Commit 905910a

Browse files
Update errors
1 parent d6d90e9 commit 905910a

6 files changed

Lines changed: 72 additions & 28 deletions

File tree

datafusion/src/datasource/listing/helpers.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use futures::{
3535
use log::debug;
3636

3737
use crate::{
38-
error::Result,
38+
error::{DataFusionError, Result},
3939
execution::context::ExecutionContext,
4040
logical_plan::{self, Expr, ExpressionVisitor, Recursion},
4141
physical_plan::functions::Volatility,
@@ -191,12 +191,13 @@ pub async fn pruned_partition_list(
191191
Ok(Box::pin(
192192
store
193193
.list_file_with_suffix(table_path, file_extension)
194+
// .map_err(DataFusionError::from)
194195
.await?
195196
.filter_map(move |f| {
196197
let stream_path = stream_path.clone();
197198
let table_partition_cols_stream = table_partition_cols_stream.clone();
198199
async move {
199-
let file_meta = match f {
200+
let file_meta = match f.map_err(DataFusionError::from) {
200201
Ok(fm) => fm,
201202
Err(err) => return Some(Err(err)),
202203
};
@@ -230,6 +231,7 @@ pub async fn pruned_partition_list(
230231
// all the files anyway. This number will need to be adjusted according to the object
231232
// store if we switch to a streaming-stlye pruning of the files. For instance S3 lists
232233
// 1000 items at a time so batches of 1000 would be ideal with S3 as store.
234+
.map_err(DataFusionError::from)
233235
.chunks(1024)
234236
.map(|v| v.into_iter().collect::<Result<Vec<_>>>())
235237
.map(move |metas| paths_to_batch(table_partition_cols, &stream_path, &metas?))

datafusion/src/datasource/object_store/local.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
//! Object store that represents the Local File System.
1919
20+
use std::error::Error;
2021
use std::fs::{self, File, Metadata};
2122
use std::io::{BufReader, Read, Seek, SeekFrom};
2223
use std::sync::Arc;
@@ -28,8 +29,7 @@ use crate::datasource::object_store::{
2829
FileMeta, FileMetaStream, ListEntryStream, ObjectReader, ObjectStore,
2930
};
3031
use crate::datasource::PartitionedFile;
31-
use crate::error::DataFusionError;
32-
use crate::error::Result;
32+
use crate::error::{DataFusionError, Result as DataFusionResult};
3333

3434
use super::{ObjectReaderStream, SizedFile};
3535

@@ -39,19 +39,25 @@ pub struct LocalFileSystem;
3939

4040
#[async_trait]
4141
impl ObjectStore for LocalFileSystem {
42-
async fn list_file(&self, prefix: &str) -> Result<FileMetaStream> {
42+
async fn list_file(
43+
&self,
44+
prefix: &str,
45+
) -> Result<FileMetaStream, Box<dyn Error + Send + Sync>> {
4346
list_all(prefix.to_owned()).await
4447
}
4548

4649
async fn list_dir(
4750
&self,
4851
_prefix: &str,
4952
_delimiter: Option<String>,
50-
) -> Result<ListEntryStream> {
53+
) -> Result<ListEntryStream, Box<dyn Error + Send + Sync>> {
5154
todo!()
5255
}
5356

54-
fn file_reader(&self, file: SizedFile) -> Result<Arc<dyn ObjectReader>> {
57+
fn file_reader(
58+
&self,
59+
file: SizedFile,
60+
) -> Result<Arc<dyn ObjectReader>, Box<dyn Error + Send + Sync>> {
5561
Ok(Arc::new(LocalFileReader::new(file)?))
5662
}
5763
}
@@ -61,7 +67,7 @@ struct LocalFileReader {
6167
}
6268

6369
impl LocalFileReader {
64-
fn new(file: SizedFile) -> Result<Self> {
70+
fn new(file: SizedFile) -> DataFusionResult<Self> {
6571
Ok(Self { file })
6672
}
6773
}
@@ -72,7 +78,7 @@ impl ObjectReader for LocalFileReader {
7278
&self,
7379
_start: u64,
7480
_length: usize,
75-
) -> Result<Box<dyn AsyncRead>> {
81+
) -> Result<Box<dyn AsyncRead>, Box<dyn Error + Send + Sync>> {
7682
todo!(
7783
"implement once async file readers are available (arrow-rs#78, arrow-rs#111)"
7884
)
@@ -82,7 +88,7 @@ impl ObjectReader for LocalFileReader {
8288
&self,
8389
start: u64,
8490
length: usize,
85-
) -> Result<Box<dyn Read + Send + Sync>> {
91+
) -> Result<Box<dyn Read + Send + Sync>, Box<dyn Error + Send + Sync>> {
8692
// A new file descriptor is opened for each chunk reader.
8793
// This okay because chunks are usually fairly large.
8894
let mut file = File::open(&self.file.path)?;
@@ -98,7 +104,9 @@ impl ObjectReader for LocalFileReader {
98104
}
99105
}
100106

101-
async fn list_all(prefix: String) -> Result<FileMetaStream> {
107+
async fn list_all(
108+
prefix: String,
109+
) -> Result<FileMetaStream, Box<dyn Error + Send + Sync>> {
102110
fn get_meta(path: String, metadata: Metadata) -> FileMeta {
103111
FileMeta {
104112
sized_file: SizedFile {
@@ -112,7 +120,7 @@ async fn list_all(prefix: String) -> Result<FileMetaStream> {
112120
async fn find_files_in_dir(
113121
path: String,
114122
to_visit: &mut Vec<String>,
115-
) -> Result<Vec<FileMeta>> {
123+
) -> DataFusionResult<Vec<FileMeta>> {
116124
let mut dir = tokio::fs::read_dir(path).await?;
117125
let mut files = Vec::new();
118126

@@ -194,7 +202,7 @@ mod tests {
194202
use tempfile::tempdir;
195203

196204
#[tokio::test]
197-
async fn test_recursive_listing() -> Result<()> {
205+
async fn test_recursive_listing() -> DataFusionResult<()> {
198206
// tmp/a.txt
199207
// tmp/x/b.txt
200208
// tmp/y/c.txt

datafusion/src/datasource/object_store/mod.rs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
pub mod local;
2121

2222
use std::collections::HashMap;
23+
use std::error::Error;
2324
use std::fmt::{self, Debug};
2425
use std::io::Read;
2526
use std::pin::Pin;
@@ -31,7 +32,7 @@ use futures::{AsyncRead, Stream, StreamExt};
3132

3233
use local::LocalFileSystem;
3334

34-
use crate::error::{DataFusionError, Result};
35+
use crate::error::{DataFusionError, Result as DataFusionResult};
3536

3637
/// Object Reader for one file in an object store.
3738
///
@@ -40,18 +41,23 @@ use crate::error::{DataFusionError, Result};
4041
#[async_trait]
4142
pub trait ObjectReader: Send + Sync {
4243
/// Get reader for a part [start, start + length] in the file asynchronously
43-
async fn chunk_reader(&self, start: u64, length: usize)
44-
-> Result<Box<dyn AsyncRead>>;
44+
async fn chunk_reader(
45+
&self,
46+
start: u64,
47+
length: usize,
48+
) -> Result<Box<dyn AsyncRead>, Box<dyn Error + Send + Sync>>;
4549

4650
/// Get reader for a part [start, start + length] in the file
4751
fn sync_chunk_reader(
4852
&self,
4953
start: u64,
5054
length: usize,
51-
) -> Result<Box<dyn Read + Send + Sync>>;
55+
) -> Result<Box<dyn Read + Send + Sync>, Box<dyn Error + Send + Sync>>;
5256

5357
/// Get reader for the entire file
54-
fn sync_reader(&self) -> Result<Box<dyn Read + Send + Sync>> {
58+
fn sync_reader(
59+
&self,
60+
) -> Result<Box<dyn Read + Send + Sync>, Box<dyn Error + Send + Sync>> {
5561
self.sync_chunk_reader(0, self.length() as usize)
5662
}
5763

@@ -114,29 +120,38 @@ impl std::fmt::Display for FileMeta {
114120

115121
/// Stream of files listed from object store
116122
pub type FileMetaStream =
117-
Pin<Box<dyn Stream<Item = Result<FileMeta>> + Send + Sync + 'static>>;
123+
Pin<Box<dyn Stream<Item = DataFusionResult<FileMeta>> + Send + Sync + 'static>>;
118124

119125
/// Stream of list entries obtained from object store
120126
pub type ListEntryStream =
121-
Pin<Box<dyn Stream<Item = Result<ListEntry>> + Send + Sync + 'static>>;
127+
Pin<Box<dyn Stream<Item = DataFusionResult<ListEntry>> + Send + Sync + 'static>>;
122128

123129
/// Stream readers opened on a given object store
124-
pub type ObjectReaderStream =
125-
Pin<Box<dyn Stream<Item = Result<Arc<dyn ObjectReader>>> + Send + Sync + 'static>>;
130+
pub type ObjectReaderStream = Pin<
131+
Box<
132+
dyn Stream<Item = Result<Arc<dyn ObjectReader>, Box<dyn Error + Send + Sync>>>
133+
+ Send
134+
+ Sync
135+
+ 'static,
136+
>,
137+
>;
126138

127139
/// A ObjectStore abstracts access to an underlying file/object storage.
128140
/// It maps strings (e.g. URLs, filesystem paths, etc) to sources of bytes
129141
#[async_trait]
130142
pub trait ObjectStore: Sync + Send + Debug {
131143
/// Returns all the files in path `prefix`
132-
async fn list_file(&self, prefix: &str) -> Result<FileMetaStream>;
144+
async fn list_file(
145+
&self,
146+
prefix: &str,
147+
) -> Result<FileMetaStream, Box<dyn Error + Send + Sync>>;
133148

134149
/// Calls `list_file` with a suffix filter
135150
async fn list_file_with_suffix(
136151
&self,
137152
prefix: &str,
138153
suffix: &str,
139-
) -> Result<FileMetaStream> {
154+
) -> Result<FileMetaStream, Box<dyn Error + Send + Sync>> {
140155
let file_stream = self.list_file(prefix).await?;
141156
let suffix = suffix.to_owned();
142157
Ok(Box::pin(file_stream.filter(move |fr| {
@@ -154,10 +169,13 @@ pub trait ObjectStore: Sync + Send + Debug {
154169
&self,
155170
prefix: &str,
156171
delimiter: Option<String>,
157-
) -> Result<ListEntryStream>;
172+
) -> Result<ListEntryStream, Box<dyn Error + Send + Sync>>;
158173

159174
/// Get object reader for one file
160-
fn file_reader(&self, file: SizedFile) -> Result<Arc<dyn ObjectReader>>;
175+
fn file_reader(
176+
&self,
177+
file: SizedFile,
178+
) -> Result<Arc<dyn ObjectReader>, Box<dyn Error + Send + Sync>>;
161179
}
162180

163181
static LOCAL_SCHEME: &str = "file";
@@ -223,7 +241,7 @@ impl ObjectStoreRegistry {
223241
pub fn get_by_uri<'a>(
224242
&self,
225243
uri: &'a str,
226-
) -> Result<(Arc<dyn ObjectStore>, &'a str)> {
244+
) -> Result<(Arc<dyn ObjectStore>, &'a str), Box<dyn Error + Send + Sync>> {
227245
if let Some((scheme, path)) = uri.split_once("://") {
228246
let stores = self.object_stores.read().unwrap();
229247
let store = stores

datafusion/src/error.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ pub enum DataFusionError {
6161
/// Error returned during execution of the query.
6262
/// Examples include files not found, errors in parsing certain types.
6363
Execution(String),
64+
/// Errors originating from outside DataFusion's core codebase.
65+
/// For example, a custom S3Error from the crate datafusion-objectstore-s3
66+
External(Box<dyn error::Error + Send + Sync>),
6467
}
6568

6669
impl DataFusionError {
@@ -101,6 +104,12 @@ impl From<ParserError> for DataFusionError {
101104
}
102105
}
103106

107+
impl From<Box<dyn error::Error + Send + Sync>> for DataFusionError {
108+
fn from(err: Box<dyn error::Error + Send + Sync>) -> Self {
109+
DataFusionError::External(err)
110+
}
111+
}
112+
104113
impl Display for DataFusionError {
105114
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
106115
match *self {
@@ -129,6 +138,9 @@ impl Display for DataFusionError {
129138
DataFusionError::Execution(ref desc) => {
130139
write!(f, "Execution error: {}", desc)
131140
}
141+
DataFusionError::External(ref desc) => {
142+
write!(f, "External error: {}", desc)
143+
}
132144
}
133145
}
134146
}

datafusion/src/execution/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,7 @@ impl ExecutionContext {
566566
.unwrap()
567567
.object_store_registry
568568
.get_by_uri(uri)
569+
.map_err(DataFusionError::from)
569570
}
570571

571572
/// Registers a table using a custom `TableProvider` so that

datafusion/src/physical_plan/file_format/file_stream.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use std::{
4141
};
4242

4343
use super::PartitionColumnProjector;
44+
use crate::error::DataFusionError;
4445

4546
pub type FileIter = Box<dyn Iterator<Item = PartitionedFile> + Send + Sync>;
4647
pub type BatchIter = Box<dyn Iterator<Item = ArrowResult<RecordBatch>> + Send + Sync>;
@@ -124,7 +125,9 @@ impl<F: FormatReaderOpener> FileStream<F> {
124125
self.object_store
125126
.file_reader(f.file_meta.sized_file)
126127
.and_then(|r| r.sync_reader())
127-
.map_err(|e| ArrowError::ExternalError(Box::new(e)))
128+
.map_err(|e| {
129+
ArrowError::ExternalError(Box::new(DataFusionError::from(e)))
130+
})
128131
.and_then(|f| {
129132
self.batch_iter = (self.file_reader)(f, &self.remain);
130133
self.next_batch().transpose()

0 commit comments

Comments
 (0)