@@ -34,15 +34,15 @@ use datafusion::{
34
34
execution:: runtime_env:: { RuntimeConfig , RuntimeEnv } ,
35
35
} ;
36
36
use fs_extra:: file:: { move_file, CopyOptions } ;
37
- use futures:: StreamExt ;
37
+ use futures:: { stream :: FuturesUnordered , TryStreamExt } ;
38
38
use relative_path:: RelativePath ;
39
- use tokio:: fs;
39
+ use tokio:: fs:: { self , DirEntry } ;
40
40
use tokio_stream:: wrappers:: ReadDirStream ;
41
41
42
42
use crate :: metrics:: storage:: { localfs:: REQUEST_RESPONSE_TIME , StorageMetrics } ;
43
43
use crate :: { option:: validation, utils:: validate_path_is_writeable} ;
44
44
45
- use super :: { LogStream , ObjectStorage , ObjectStorageError , ObjectStorageProvider } ;
45
+ use super :: { object_storage , LogStream , ObjectStorage , ObjectStorageError , ObjectStorageProvider } ;
46
46
47
47
#[ derive( Debug , Clone , clap:: Args ) ]
48
48
#[ command(
@@ -152,29 +152,25 @@ impl ObjectStorage for LocalFS {
152
152
let path = self . root . join ( stream_name) ;
153
153
Ok ( fs:: remove_dir_all ( path) . await ?)
154
154
}
155
+
155
156
async fn list_streams ( & self ) -> Result < Vec < LogStream > , ObjectStorageError > {
157
+ let ignore_dir = & [ "lost+found" ] ;
156
158
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 ( ) ;
176
172
177
- Ok ( directories )
173
+ Ok ( logstreams )
178
174
}
179
175
180
176
async fn upload_file ( & self , key : & str , path : & Path ) -> Result < ( ) , ObjectStorageError > {
@@ -228,6 +224,37 @@ impl ObjectStorage for LocalFS {
228
224
}
229
225
}
230
226
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
+
231
258
impl From < fs_extra:: error:: Error > for ObjectStorageError {
232
259
fn from ( e : fs_extra:: error:: Error ) -> Self {
233
260
ObjectStorageError :: UnhandledError ( Box :: new ( e) )
0 commit comments