@@ -34,15 +34,15 @@ use datafusion::{
3434 execution:: runtime_env:: { RuntimeConfig , RuntimeEnv } ,
3535} ;
3636use fs_extra:: file:: { move_file, CopyOptions } ;
37- use futures:: StreamExt ;
37+ use futures:: { stream :: FuturesUnordered , TryStreamExt } ;
3838use relative_path:: RelativePath ;
39- use tokio:: fs;
39+ use tokio:: fs:: { self , DirEntry } ;
4040use tokio_stream:: wrappers:: ReadDirStream ;
4141
4242use crate :: metrics:: storage:: { localfs:: REQUEST_RESPONSE_TIME , StorageMetrics } ;
4343use crate :: { option:: validation, utils:: validate_path_is_writeable} ;
4444
45- use super :: { LogStream , ObjectStorage , ObjectStorageError , ObjectStorageProvider } ;
45+ use super :: { object_storage , LogStream , ObjectStorage , ObjectStorageError , ObjectStorageProvider } ;
4646
4747#[ derive( Debug , Clone , clap:: Args ) ]
4848#[ command(
@@ -152,29 +152,25 @@ impl ObjectStorage for LocalFS {
152152 let path = self . root . join ( stream_name) ;
153153 Ok ( fs:: remove_dir_all ( path) . await ?)
154154 }
155+
155156 async fn list_streams ( & self ) -> Result < Vec < LogStream > , ObjectStorageError > {
157+ let ignore_dir = & [ "lost+found" ] ;
156158 let directories = ReadDirStream :: new ( fs:: read_dir ( & self . root ) . await ?) ;
157- let directories = directories
158- . filter_map ( |res| async {
159- let entry = res. ok ( ) ?;
160- if entry. file_type ( ) . await . ok ( ) ?. is_dir ( ) {
161- Some ( LogStream {
162- name : entry
163- . path ( )
164- . file_name ( )
165- . expect ( "valid path" )
166- . to_str ( )
167- . expect ( "valid unicode" )
168- . to_string ( ) ,
169- } )
170- } else {
171- None
172- }
173- } )
174- . collect :: < Vec < LogStream > > ( )
175- . await ;
159+ let entries: Vec < DirEntry > = directories. try_collect ( ) . await ?;
160+ let entries = entries
161+ . into_iter ( )
162+ . map ( |entry| dir_with_stream ( entry, ignore_dir) ) ;
163+
164+ let logstream_dirs: Vec < Option < String > > =
165+ FuturesUnordered :: from_iter ( entries) . try_collect ( ) . await ?;
166+
167+ let logstreams = logstream_dirs
168+ . into_iter ( )
169+ . flatten ( )
170+ . map ( |name| LogStream { name } )
171+ . collect ( ) ;
176172
177- Ok ( directories )
173+ Ok ( logstreams )
178174 }
179175
180176 async fn upload_file ( & self , key : & str , path : & Path ) -> Result < ( ) , ObjectStorageError > {
@@ -228,6 +224,37 @@ impl ObjectStorage for LocalFS {
228224 }
229225}
230226
227+ async fn dir_with_stream (
228+ entry : DirEntry ,
229+ ignore_dirs : & [ & str ] ,
230+ ) -> Result < Option < String > , ObjectStorageError > {
231+ let dir_name = entry
232+ . path ( )
233+ . file_name ( )
234+ . expect ( "valid path" )
235+ . to_str ( )
236+ . expect ( "valid unicode" )
237+ . to_owned ( ) ;
238+
239+ if ignore_dirs. contains ( & dir_name. as_str ( ) ) {
240+ return Ok ( None ) ;
241+ }
242+
243+ if entry. file_type ( ) . await ?. is_dir ( ) {
244+ let path = entry. path ( ) ;
245+ let stream_json_path = path. join ( object_storage:: STREAM_METADATA_FILE_NAME ) ;
246+ if stream_json_path. exists ( ) {
247+ Ok ( Some ( dir_name) )
248+ } else {
249+ let err: Box < dyn std:: error:: Error + Send + Sync + ' static > =
250+ format ! ( "found {}" , entry. path( ) . display( ) ) . into ( ) ;
251+ Err ( ObjectStorageError :: UnhandledError ( err) )
252+ }
253+ } else {
254+ Ok ( None )
255+ }
256+ }
257+
231258impl From < fs_extra:: error:: Error > for ObjectStorageError {
232259 fn from ( e : fs_extra:: error:: Error ) -> Self {
233260 ObjectStorageError :: UnhandledError ( Box :: new ( e) )
0 commit comments