1616 *
1717 */
1818
19+ use crate :: catalog:: { self , snapshot:: Snapshot } ;
20+ use crate :: event:: format:: LogSource ;
21+ use crate :: event:: format:: LogSourceEntry ;
22+ use crate :: handlers:: DatasetTag ;
23+ use crate :: handlers:: http:: fetch_schema;
24+ use crate :: handlers:: http:: modal:: ingest_server:: INGESTOR_EXPECT ;
25+ use crate :: handlers:: http:: modal:: ingest_server:: INGESTOR_META ;
26+ use crate :: handlers:: http:: users:: { FILTER_DIR , USERS_ROOT_DIR } ;
27+ use crate :: metrics:: increment_parquets_stored_by_date;
28+ use crate :: metrics:: increment_parquets_stored_size_by_date;
29+ use crate :: metrics:: { EVENTS_STORAGE_SIZE_DATE , LIFETIME_EVENTS_STORAGE_SIZE , STORAGE_SIZE } ;
30+ use crate :: option:: Mode ;
31+ use crate :: parseable:: DEFAULT_TENANT ;
32+ use crate :: parseable:: { LogStream , PARSEABLE , Stream } ;
33+ use crate :: stats:: FullStats ;
34+ use crate :: storage:: SETTINGS_ROOT_DIRECTORY ;
35+ use crate :: storage:: TARGETS_ROOT_DIRECTORY ;
36+ use crate :: storage:: field_stats:: DATASET_STATS_STREAM_NAME ;
37+ use crate :: storage:: field_stats:: calculate_field_stats;
38+ use crate :: storage:: field_stats:: extract_datetime_from_parquet_path_regex;
39+ use crate :: sync:: { ACTIVE_OBJECT_STORE_SYNC_FILES , FLUSH_AND_CONVERT_RUNTIME } ;
1940use arrow_schema:: Schema ;
2041use async_trait:: async_trait;
2142use bytes:: Bytes ;
2243use chrono:: { DateTime , Utc } ;
44+ use dashmap:: mapref:: entry:: Entry ;
2345use datafusion:: { datasource:: listing:: ListingTableUrl , execution:: runtime_env:: RuntimeEnvBuilder } ;
2446use itertools:: Itertools ;
2547use object_store:: ListResult ;
@@ -43,29 +65,6 @@ use tokio::task::JoinSet;
4365use tracing:: { Instrument , error, info, info_span, warn} ;
4466use ulid:: Ulid ;
4567
46- use crate :: catalog:: { self , snapshot:: Snapshot } ;
47- use crate :: event:: format:: LogSource ;
48- use crate :: event:: format:: LogSourceEntry ;
49- use crate :: handlers:: DatasetTag ;
50- use crate :: handlers:: http:: fetch_schema;
51- use crate :: handlers:: http:: modal:: ingest_server:: INGESTOR_EXPECT ;
52- use crate :: handlers:: http:: modal:: ingest_server:: INGESTOR_META ;
53- use crate :: handlers:: http:: users:: { FILTER_DIR , USERS_ROOT_DIR } ;
54- use crate :: metrics:: increment_parquets_stored_by_date;
55- use crate :: metrics:: increment_parquets_stored_size_by_date;
56- use crate :: metrics:: { EVENTS_STORAGE_SIZE_DATE , LIFETIME_EVENTS_STORAGE_SIZE , STORAGE_SIZE } ;
57- use crate :: option:: Mode ;
58- use crate :: parseable:: DEFAULT_TENANT ;
59- use crate :: parseable:: { LogStream , PARSEABLE , Stream } ;
60- use crate :: stats:: FullStats ;
61- use crate :: storage:: SETTINGS_ROOT_DIRECTORY ;
62- use crate :: storage:: TARGETS_ROOT_DIRECTORY ;
63- use crate :: storage:: field_stats:: DATASET_STATS_STREAM_NAME ;
64- use crate :: storage:: field_stats:: calculate_field_stats;
65- use crate :: storage:: field_stats:: extract_datetime_from_parquet_path_regex;
66- use crate :: sync:: ACTIVE_OBJECT_STORE_SYNC_FILES ;
67- use crate :: sync:: FLUSH_AND_CONVERT_RUNTIME ;
68-
6968use super :: {
7069 ALERTS_ROOT_DIRECTORY , MANIFEST_FILE , ObjectStorageError , ObjectStoreFormat ,
7170 PARSEABLE_METADATA_FILE_NAME , PARSEABLE_ROOT_DIRECTORY , SCHEMA_FILE_NAME ,
@@ -1084,22 +1083,20 @@ async fn process_parquet_files(
10841083 let object_store = PARSEABLE . storage ( ) . get_object_store ( ) ;
10851084
10861085 // collect all parquet files to upload
1087- let parquet_paths = {
1088- let mut guard = ACTIVE_OBJECT_STORE_SYNC_FILES . write ( ) . await ;
1089-
1090- let parquet_paths: Vec < PathBuf > = upload_context
1091- . stream
1092- . parquet_files ( )
1093- . into_iter ( )
1094- . filter ( |p| !guard. contains ( p) )
1095- . collect ( ) ;
1096-
1097- let mut ret = Vec :: with_capacity ( parquet_paths. len ( ) ) ;
1098- ret. clone_from ( & parquet_paths) ;
1099- guard. extend ( parquet_paths) ;
1100- tracing:: info!( ACTIVE_OBJECT_STORE_SYNC_FILES =?ACTIVE_OBJECT_STORE_SYNC_FILES ) ;
1101- ret
1102- } ;
1086+ let parquet_paths: Vec < PathBuf > = upload_context
1087+ . stream
1088+ . parquet_files ( )
1089+ . into_par_iter ( )
1090+ . filter_map (
1091+ |path| match ACTIVE_OBJECT_STORE_SYNC_FILES . entry ( path. clone ( ) ) {
1092+ Entry :: Vacant ( entry) => {
1093+ entry. insert ( Instant :: now ( ) ) ;
1094+ Some ( path)
1095+ }
1096+ Entry :: Occupied ( _) => None ,
1097+ } ,
1098+ )
1099+ . collect ( ) ;
11031100
11041101 let mut total_size: u64 = 0 ;
11051102 let mut min_dt: Option < chrono:: DateTime < Utc > > = None ;
@@ -1196,18 +1193,12 @@ async fn collect_upload_results(
11961193 "Parquet file upload size validation failed for {:?}, preserving in staging for retry" ,
11971194 upload_result. file_path
11981195 ) ;
1199- {
1200- let mut guard = ACTIVE_OBJECT_STORE_SYNC_FILES . write ( ) . await ;
1201- guard. remove ( & upload_result. file_path ) ;
1202- }
1196+ ACTIVE_OBJECT_STORE_SYNC_FILES . remove ( & upload_result. file_path ) ;
12031197 }
12041198 }
12051199 Ok ( Err ( ( path, e) ) ) => {
12061200 error ! ( "Error uploading parquet file: {e}" ) ;
1207- {
1208- let mut guard = ACTIVE_OBJECT_STORE_SYNC_FILES . write ( ) . await ;
1209- guard. remove ( & path) ;
1210- }
1201+ ACTIVE_OBJECT_STORE_SYNC_FILES . remove ( & path) ;
12111202 return Err ( e) ;
12121203 }
12131204 Err ( e) => {
@@ -1272,30 +1263,24 @@ async fn calculate_stats_for_uploaded_files(
12721263}
12731264
12741265async fn cleanup_uploaded_staged_files ( uploaded_files : Vec < UploadedParquetFile > ) {
1275- let paths: Vec < _ > = uploaded_files
1276- . into_iter ( )
1277- . map ( |uploaded_file| uploaded_file. file_path )
1278- . collect ( ) ;
1279-
1280- {
1281- let mut guard = ACTIVE_OBJECT_STORE_SYNC_FILES . write ( ) . await ;
1282- for path in paths. iter ( ) {
1283- guard. remove ( path) ;
1284- }
1285-
1286- // check if file has been in hashset for more than 5 minutes
1287- let now = Utc :: now ( ) ;
1288- guard. retain ( |f| {
1289- !extract_datetime_from_parquet_path_regex ( f)
1290- . is_ok_and ( |ts| ( now - ts) . num_minutes ( ) >= 5 )
1291- } ) ;
1266+ // successfully uploaded files, remove from DashMap
1267+ for uploaded_parquet_file in uploaded_files. iter ( ) {
1268+ ACTIVE_OBJECT_STORE_SYNC_FILES . remove ( & uploaded_parquet_file. file_path ) ;
12921269 }
12931270
1294- paths . into_par_iter ( ) . for_each ( |path| {
1295- if let Err ( e ) = remove_file ( & path ) {
1296- warn ! ( "Failed to remove staged file: {e}" ) ;
1297- }
1271+ // Use monotonic time to ensure the 5-minute eviction window(cleanup) is immune to system clock adjustments.
1272+ let now = Instant :: now ( ) ;
1273+ ACTIVE_OBJECT_STORE_SYNC_FILES . retain ( |_ , tracked_instant| {
1274+ now . duration_since ( * tracked_instant ) < Duration :: from_secs ( 300 )
12981275 } ) ;
1276+
1277+ uploaded_files
1278+ . into_par_iter ( )
1279+ . for_each ( |uploaded_parquet_file| {
1280+ if let Err ( e) = remove_file ( & uploaded_parquet_file. file_path ) {
1281+ warn ! ( "Failed to remove staged file: {e}" ) ;
1282+ }
1283+ } ) ;
12991284}
13001285
13011286/// Processes schema files
0 commit comments