Skip to content

Commit 3899a1b

Browse files
authored
track insertion time instead of data time for eviction (#1650)
* track insertion time instead of data time for eviction * Use DashMap for concurrent cache access
1 parent 169c998 commit 3899a1b

2 files changed

Lines changed: 57 additions & 73 deletions

File tree

src/storage/object_storage.rs

Lines changed: 53 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,32 @@
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};
1940
use arrow_schema::Schema;
2041
use async_trait::async_trait;
2142
use bytes::Bytes;
2243
use chrono::{DateTime, Utc};
44+
use dashmap::mapref::entry::Entry;
2345
use datafusion::{datasource::listing::ListingTableUrl, execution::runtime_env::RuntimeEnvBuilder};
2446
use itertools::Itertools;
2547
use object_store::ListResult;
@@ -43,29 +65,6 @@ use tokio::task::JoinSet;
4365
use tracing::{Instrument, error, info, info_span, warn};
4466
use 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-
6968
use 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

12741265
async 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

src/sync.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,16 @@
1717
*/
1818

1919
use chrono::{TimeDelta, Timelike};
20-
use datafusion::common::HashSet;
20+
use dashmap::DashMap;
2121
use futures::FutureExt;
2222
use once_cell::sync::Lazy;
2323
use std::collections::HashMap;
2424
use std::future::Future;
2525
use std::panic::AssertUnwindSafe;
2626
use std::path::PathBuf;
27-
use std::sync::Arc;
2827
use std::sync::atomic::{AtomicBool, Ordering};
2928
use tokio::runtime::Runtime;
30-
use tokio::sync::{RwLock, mpsc, oneshot};
29+
use tokio::sync::{mpsc, oneshot};
3130
use tokio::task::JoinSet;
3231
use tokio::time::{Duration, Instant, interval_at, sleep};
3332
use tokio::{select, task};
@@ -39,8 +38,8 @@ pub static FLUSH_AND_CONVERT_RUNTIME: Lazy<Runtime> =
3938
static LOCAL_SYNC_RUNNING: AtomicBool = AtomicBool::new(false);
4039
static REMOTE_SYNC_RUNNING: AtomicBool = AtomicBool::new(false);
4140

42-
pub static ACTIVE_OBJECT_STORE_SYNC_FILES: Lazy<Arc<RwLock<HashSet<PathBuf>>>> =
43-
Lazy::new(|| Arc::new(RwLock::new(HashSet::new())));
41+
pub static ACTIVE_OBJECT_STORE_SYNC_FILES: Lazy<DashMap<PathBuf, std::time::Instant>> =
42+
Lazy::new(DashMap::new);
4443
/// RAII guard that clears a sync-running flag on drop, so a panic inside the
4544
/// sync body cannot leave the flag stuck at `true` and wedge future ticks.
4645
struct SyncRunningGuard(&'static AtomicBool);

0 commit comments

Comments
 (0)