Skip to content

Commit 3697ea8

Browse files
ygndotggparmesant
authored andcommitted
Use DashMap for concurrent cache access
1 parent 7fcf0b8 commit 3697ea8

2 files changed

Lines changed: 57 additions & 100 deletions

File tree

src/storage/object_storage.rs

Lines changed: 52 additions & 86 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, SyncFileEntry};
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,29 +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_par_iter()
1094-
.filter(|p| !guard.contains_key(p))
1095-
.collect();
1096-
1097-
let mut ret = Vec::with_capacity(parquet_paths.len());
1098-
ret.clone_from(&parquet_paths);
1099-
for path in parquet_paths {
1100-
guard.insert(
1101-
path,
1102-
SyncFileEntry {
1103-
tracked_instant: Instant::now(),
1104-
tracked_utc: Utc::now(),
1105-
},
1106-
);
1107-
}
1108-
ret
1109-
};
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();
11101100

11111101
let mut total_size: u64 = 0;
11121102
let mut min_dt: Option<chrono::DateTime<Utc>> = None;
@@ -1203,18 +1193,12 @@ async fn collect_upload_results(
12031193
"Parquet file upload size validation failed for {:?}, preserving in staging for retry",
12041194
upload_result.file_path
12051195
);
1206-
{
1207-
let mut guard = ACTIVE_OBJECT_STORE_SYNC_FILES.write().await;
1208-
guard.remove(&upload_result.file_path);
1209-
}
1196+
ACTIVE_OBJECT_STORE_SYNC_FILES.remove(&upload_result.file_path);
12101197
}
12111198
}
12121199
Ok(Err((path, e))) => {
12131200
error!("Error uploading parquet file: {e}");
1214-
{
1215-
let mut guard = ACTIVE_OBJECT_STORE_SYNC_FILES.write().await;
1216-
guard.remove(&path);
1217-
}
1201+
ACTIVE_OBJECT_STORE_SYNC_FILES.remove(&path);
12181202
return Err(e);
12191203
}
12201204
Err(e) => {
@@ -1279,42 +1263,24 @@ async fn calculate_stats_for_uploaded_files(
12791263
}
12801264

12811265
async fn cleanup_uploaded_staged_files(uploaded_files: Vec<UploadedParquetFile>) {
1282-
let paths: Vec<_> = uploaded_files
1283-
.into_iter()
1284-
.map(|uploaded_file| uploaded_file.file_path)
1285-
.collect();
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);
1269+
}
12861270

1287-
{
1288-
let mut guard = ACTIVE_OBJECT_STORE_SYNC_FILES.write().await;
1289-
for path in paths.iter() {
1290-
guard.remove(path);
1291-
}
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)
1275+
});
12921276

1293-
// Use monotonic time to ensure the 5-minute eviction window is immune to system clock adjustments.
1294-
let now = Instant::now();
1295-
guard.retain(|path, entry| {
1296-
let elapsed = now.duration_since(entry.tracked_instant);
1297-
// 5 min eviction window
1298-
if elapsed >= Duration::from_secs(300) {
1299-
// Added log for observability and debugging
1300-
warn!(
1301-
"Removing stale sync file: {} (elapsed: {}s, tracked_at: {})",
1302-
path.display(),
1303-
elapsed.as_secs(),
1304-
entry.tracked_utc.to_rfc3339(),
1305-
);
1306-
false
1307-
} else {
1308-
true
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}");
13091282
}
13101283
});
1311-
}
1312-
1313-
paths.into_par_iter().for_each(|path| {
1314-
if let Err(e) = remove_file(&path) {
1315-
warn!("Failed to remove staged file: {e}");
1316-
}
1317-
});
13181284
}
13191285

13201286
/// Processes schema files

src/sync.rs

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

19-
use chrono::{DateTime, TimeDelta, Timelike, Utc};
19+
use chrono::{TimeDelta, Timelike};
20+
use dashmap::DashMap;
2021
use futures::FutureExt;
2122
use once_cell::sync::Lazy;
2223
use std::collections::HashMap;
2324
use std::future::Future;
2425
use std::panic::AssertUnwindSafe;
2526
use std::path::PathBuf;
26-
use std::sync::Arc;
2727
use std::sync::atomic::{AtomicBool, Ordering};
2828
use tokio::runtime::Runtime;
29-
use tokio::sync::{RwLock, mpsc, oneshot};
29+
use tokio::sync::{mpsc, oneshot};
3030
use tokio::task::JoinSet;
3131
use tokio::time::{Duration, Instant, interval_at, sleep};
3232
use tokio::{select, task};
@@ -38,17 +38,8 @@ pub static FLUSH_AND_CONVERT_RUNTIME: Lazy<Runtime> =
3838
static LOCAL_SYNC_RUNNING: AtomicBool = AtomicBool::new(false);
3939
static REMOTE_SYNC_RUNNING: AtomicBool = AtomicBool::new(false);
4040

41-
// tracks metadata for files being synced to object storage
42-
#[derive(Clone, Debug)]
43-
pub struct SyncFileEntry {
44-
// Monotonic instant when file was added to tracking
45-
pub tracked_instant: std::time::Instant,
46-
// Wall-clock UTC timestamp for observability
47-
pub tracked_utc: DateTime<Utc>,
48-
}
49-
50-
pub static ACTIVE_OBJECT_STORE_SYNC_FILES: Lazy<Arc<RwLock<HashMap<PathBuf, SyncFileEntry>>>> =
51-
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
41+
pub static ACTIVE_OBJECT_STORE_SYNC_FILES: Lazy<DashMap<PathBuf, std::time::Instant>> =
42+
Lazy::new(DashMap::new);
5243
/// RAII guard that clears a sync-running flag on drop, so a panic inside the
5344
/// sync body cannot leave the flag stuck at `true` and wedge future ticks.
5445
struct SyncRunningGuard(&'static AtomicBool);

0 commit comments

Comments
 (0)