16
16
*
17
17
*/
18
18
19
- use crate :: catalog:: manifest:: File ;
20
- use crate :: hottier:: HotTierManager ;
21
- use crate :: option:: Mode ;
22
- use crate :: parseable:: STREAM_EXISTS ;
23
- use crate :: {
24
- catalog:: snapshot:: { self , Snapshot } ,
25
- storage:: { ObjectStoreFormat , STREAM_ROOT_DIRECTORY } ,
26
- } ;
19
+ use std:: any:: Any ;
20
+ use std:: collections:: HashMap ;
21
+ use std:: ops:: Bound ;
22
+ use std:: os:: unix:: fs:: MetadataExt ;
23
+ use std:: sync:: Arc ;
24
+
27
25
use arrow_array:: RecordBatch ;
28
26
use arrow_schema:: { Schema , SchemaRef , SortOptions } ;
29
27
use bytes:: Bytes ;
30
28
use chrono:: { DateTime , NaiveDateTime , TimeDelta , Timelike , Utc } ;
31
- use datafusion:: catalog:: Session ;
32
- use datafusion:: common:: stats:: Precision ;
33
- use datafusion:: logical_expr:: utils:: conjunction;
34
- use datafusion:: physical_expr:: LexOrdering ;
35
29
use datafusion:: {
36
- catalog:: SchemaProvider ,
30
+ catalog:: { SchemaProvider , Session } ,
37
31
common:: {
32
+ stats:: Precision ,
38
33
tree_node:: { TreeNode , TreeNodeRecursion } ,
39
34
ToDFSchema ,
40
35
} ,
@@ -46,28 +41,32 @@ use datafusion::{
46
41
} ,
47
42
error:: { DataFusionError , Result as DataFusionResult } ,
48
43
execution:: { context:: SessionState , object_store:: ObjectStoreUrl } ,
49
- logical_expr:: { BinaryExpr , Operator , TableProviderFilterPushDown , TableType } ,
50
- physical_expr:: { create_physical_expr, PhysicalSortExpr } ,
44
+ logical_expr:: {
45
+ utils:: conjunction, BinaryExpr , Operator , TableProviderFilterPushDown , TableType ,
46
+ } ,
47
+ physical_expr:: { create_physical_expr, LexOrdering , PhysicalSortExpr } ,
51
48
physical_plan:: { self , empty:: EmptyExec , union:: UnionExec , ExecutionPlan , Statistics } ,
52
49
prelude:: Expr ,
53
50
scalar:: ScalarValue ,
54
51
} ;
55
-
56
52
use futures_util:: { stream:: FuturesOrdered , StreamExt , TryFutureExt , TryStreamExt } ;
57
53
use itertools:: Itertools ;
58
54
use object_store:: { path:: Path , ObjectStore } ;
59
55
use relative_path:: RelativePathBuf ;
60
- use std:: { any:: Any , collections:: HashMap , ops:: Bound , sync:: Arc } ;
61
56
use url:: Url ;
62
57
63
58
use crate :: {
64
59
catalog:: {
65
- self , column:: TypedStatistics , manifest:: Manifest , snapshot:: ManifestItem , ManifestFile ,
60
+ self , column:: TypedStatistics , manifest:: File , manifest:: Manifest , snapshot:: ManifestItem ,
61
+ snapshot:: Snapshot , ManifestFile ,
66
62
} ,
67
63
event:: DEFAULT_TIMESTAMP_KEY ,
64
+ hottier:: HotTierManager ,
68
65
metrics:: QUERY_CACHE_HIT ,
66
+ option:: Mode ,
69
67
parseable:: PARSEABLE ,
70
- storage:: ObjectStorage ,
68
+ parseable:: STREAM_EXISTS ,
69
+ storage:: { ObjectStorage , ObjectStoreFormat , STREAM_ROOT_DIRECTORY } ,
71
70
} ;
72
71
73
72
use super :: listing_table_builder:: ListingTableBuilder ;
@@ -223,6 +222,50 @@ impl StandardTableProvider {
223
222
Ok ( ( ) )
224
223
}
225
224
225
+ async fn get_staging_execution_plan (
226
+ & self ,
227
+ execution_plans : & mut Vec < Arc < dyn ExecutionPlan > > ,
228
+ projection : Option < & Vec < usize > > ,
229
+ filters : & [ Expr ] ,
230
+ limit : Option < usize > ,
231
+ state : & dyn Session ,
232
+ time_partition : Option < & String > ,
233
+ ) -> Result < ( ) , DataFusionError > {
234
+ let Ok ( staging) = PARSEABLE . get_stream ( & self . stream ) else {
235
+ return Ok ( ( ) ) ;
236
+ } ;
237
+ let records = staging. recordbatches_cloned ( & self . schema ) ;
238
+ let reversed_mem_table = reversed_mem_table ( records, self . schema . clone ( ) ) ?;
239
+
240
+ let memory_exec = reversed_mem_table
241
+ . scan ( state, projection, filters, limit)
242
+ . await ?;
243
+ execution_plans. push ( memory_exec) ;
244
+
245
+ let target_partition = num_cpus:: get ( ) ;
246
+ let mut partitioned_files = Vec :: from_iter ( ( 0 ..target_partition) . map ( |_| Vec :: new ( ) ) ) ;
247
+ for ( index, file_path) in staging. parquet_files ( ) . into_iter ( ) . enumerate ( ) {
248
+ let Ok ( file_meta) = file_path. metadata ( ) else {
249
+ continue ;
250
+ } ;
251
+ let file = PartitionedFile :: new ( file_path. display ( ) . to_string ( ) , file_meta. size ( ) ) ;
252
+ partitioned_files[ index % target_partition] . push ( file)
253
+ }
254
+
255
+ self . create_parquet_physical_plan (
256
+ execution_plans,
257
+ ObjectStoreUrl :: parse ( "file:///" ) . unwrap ( ) ,
258
+ partitioned_files,
259
+ Statistics :: new_unknown ( & self . schema ) ,
260
+ projection,
261
+ filters,
262
+ limit,
263
+ state,
264
+ time_partition. cloned ( ) ,
265
+ )
266
+ . await
267
+ }
268
+
226
269
#[ allow( clippy:: too_many_arguments) ]
227
270
async fn legacy_listing_table (
228
271
& self ,
@@ -443,17 +486,17 @@ impl TableProvider for StandardTableProvider {
443
486
}
444
487
445
488
if is_within_staging_window ( & time_filters) {
446
- if let Ok ( staging ) = PARSEABLE . get_stream ( & self . stream ) {
447
- let records = staging . recordbatches_cloned ( & self . schema ) ;
448
- let reversed_mem_table = reversed_mem_table ( records , self . schema . clone ( ) ) ? ;
449
-
450
- let memory_exec = reversed_mem_table
451
- . scan ( state, projection , filters , limit )
452
- . await ? ;
453
- execution_plans . push ( memory_exec ) ;
454
- }
489
+ self . get_staging_execution_plan (
490
+ & mut execution_plans ,
491
+ projection ,
492
+ filters ,
493
+ limit ,
494
+ state,
495
+ time_partition . as_ref ( ) ,
496
+ )
497
+ . await ? ;
455
498
} ;
456
- let mut merged_snapshot: snapshot :: Snapshot = Snapshot :: default ( ) ;
499
+ let mut merged_snapshot = Snapshot :: default ( ) ;
457
500
if PARSEABLE . options . mode == Mode :: Query {
458
501
let path = RelativePathBuf :: from_iter ( [ & self . stream , STREAM_ROOT_DIRECTORY ] ) ;
459
502
let obs = glob_storage
0 commit comments