@@ -857,7 +857,16 @@ impl HotTierManager {
857857 ) ;
858858 return Ok ( false ) ;
859859 }
860- sht. available_size -= parquet_file. file_size ;
860+ sht. available_size = if let Some ( val) =
861+ sht. available_size . checked_sub ( parquet_file. file_size )
862+ {
863+ val
864+ } else {
865+ tracing:: error!(
866+ "file_size > sht.available_size, setting used_available_sizesize to 0 and moving on"
867+ ) ;
868+ 0
869+ } ;
861870 self . put_hot_tier ( stream, & mut sht, tenant_id) . await ?;
862871 info ! (
863872 stream = %stream,
@@ -1113,7 +1122,7 @@ impl HotTierManager {
11131122 path. exists ( )
11141123 }
11151124
1116- ///delete the parquet file from the hot tier directory for the stream
1125+ /// delete entire parquet file minute from the hot tier directory for the stream
11171126 /// loop through all manifests in the hot tier directory for the stream
11181127 /// loop through all parquet files in the manifest
11191128 /// check for the oldest entry to delete if the path exists in hot tier
@@ -1155,61 +1164,66 @@ impl HotTierManager {
11551164 let file = fs:: read ( manifest_file. path ( ) ) . await ?;
11561165 let mut manifest: Manifest = serde_json:: from_slice ( & file) ?;
11571166
1158- manifest. files . sort_by_key ( |file| file. file_path . clone ( ) ) ;
1159- manifest. files . reverse ( ) ;
1160-
1161- ' loop_files: while let Some ( file_to_delete) = manifest. files . pop ( ) {
1162- let file_size = file_to_delete. file_size ;
1163- let path_to_delete = self . hot_tier_path . join ( & file_to_delete. file_path ) ;
1164-
1165- if path_to_delete. exists ( ) {
1166- if let ( Some ( download_date_time) , Some ( delete_date_time) ) = (
1167- extract_datetime ( download_file_path. to_str ( ) . unwrap ( ) ) ,
1168- extract_datetime ( path_to_delete. to_str ( ) . unwrap ( ) ) ,
1169- ) && download_date_time <= delete_date_time
1170- {
1171- info ! (
1172- stream = %stream,
1173- tenant = ?tenant_id,
1174- candidate = %file_to_delete. file_path,
1175- target = %download_file_path. display( ) ,
1176- "skip evict: candidate newer than target"
1177- ) ;
1178- delete_successful = false ;
1179- break ' loop_files;
1180- }
1181-
1182- fs:: write ( manifest_file. path ( ) , serde_json:: to_vec ( & manifest) ?) . await ?;
1167+ if manifest. files . is_empty ( ) {
1168+ continue ;
1169+ }
11831170
1184- fs:: remove_dir_all ( path_to_delete. parent ( ) . unwrap ( ) ) . await ?;
1185- delete_empty_directory_hot_tier (
1186- path_to_delete. parent ( ) . unwrap ( ) . to_path_buf ( ) ,
1187- )
1188- . await ?;
1171+ // sort in an ascending manner
1172+ // idx0: minute=00
1173+ // idx59: minute=59
1174+ manifest. files . sort_by_key ( |file| file. file_path . clone ( ) ) ;
11891175
1190- stream_hot_tier. used_size -= file_size;
1191- stream_hot_tier. available_size += file_size;
1192- self . put_hot_tier ( stream, stream_hot_tier, tenant_id)
1193- . await ?;
1194- delete_successful = true ;
1195- freed_total += file_size;
1176+ // get first file's parent (/hottier/stream/date=d/hour=h/minute=m)
1177+ let first_file = manifest. files . first ( ) . unwrap ( ) ;
1178+ let first_file_path = self . hot_tier_path . join ( & first_file. file_path ) ;
1179+ let minute_to_delete = first_file_path. parent ( ) . unwrap ( ) ;
1180+
1181+ if minute_to_delete. exists ( ) {
1182+ if let ( Some ( download_date_time) , Some ( delete_date_time) ) = (
1183+ extract_datetime ( download_file_path. to_str ( ) . unwrap ( ) ) ,
1184+ extract_datetime ( first_file_path. to_str ( ) . unwrap ( ) ) ,
1185+ ) && download_date_time <= delete_date_time
1186+ {
11961187 info ! (
11971188 stream = %stream,
11981189 tenant = ?tenant_id,
1199- evicted_file = %file_to_delete. file_path,
1200- evicted_size = file_size,
1201- freed_total,
1202- new_available = stream_hot_tier. available_size,
1203- "evicted"
1190+ candidate = %minute_to_delete. display( ) ,
1191+ target = %download_file_path. display( ) ,
1192+ "skip evict: candidate newer than target"
12041193 ) ;
1194+ delete_successful = false ;
1195+ continue ;
1196+ }
12051197
1206- if stream_hot_tier. available_size <= parquet_file_size {
1207- continue ' loop_files;
1198+ manifest. files . retain ( |file| {
1199+ let file_path = self . hot_tier_path . join ( & file. file_path ) ;
1200+ let file_minute = file_path. parent ( ) . unwrap ( ) ;
1201+ if file_minute == minute_to_delete {
1202+ // DELETE
1203+ stream_hot_tier. used_size = if let Some ( val) =
1204+ stream_hot_tier. used_size . checked_sub ( file. file_size )
1205+ {
1206+ val
1207+ } else {
1208+ tracing:: error!(
1209+ "file_size > sht.used_size, setting used_size to 0 and moving on"
1210+ ) ;
1211+ 0
1212+ } ;
1213+ stream_hot_tier. available_size += file. file_size ;
1214+ freed_total += file. file_size ;
1215+ false
12081216 } else {
1209- break ' loop_dates ;
1217+ true
12101218 }
1219+ } ) ;
1220+ fs:: write ( manifest_file. path ( ) , serde_json:: to_vec ( & manifest) ?) . await ?;
1221+ fs:: remove_dir_all ( minute_to_delete) . await ?;
1222+ delete_empty_directory_hot_tier ( minute_to_delete. to_path_buf ( ) ) . await ?;
1223+ if stream_hot_tier. available_size <= parquet_file_size {
1224+ continue ;
12111225 } else {
1212- fs :: write ( manifest_file . path ( ) , serde_json :: to_vec ( & manifest ) ? ) . await ? ;
1226+ break ' loop_dates ;
12131227 }
12141228 }
12151229 }
@@ -1448,4 +1462,8 @@ pub enum HotTierError {
14481462 HotTierValidationError ( #[ from] HotTierValidationError ) ,
14491463 #[ error( "{0}" ) ]
14501464 Anyhow ( #[ from] anyhow:: Error ) ,
1465+ #[ error( "{0}" ) ]
1466+ Underflow ( String ) ,
1467+ #[ error( "{0}" ) ]
1468+ Overflow ( String ) ,
14511469}
0 commit comments