From f6297dbee0ee340e404c6d4067e986a870625347 Mon Sep 17 00:00:00 2001 From: Luke Sandberg Date: Fri, 3 Apr 2026 17:03:51 -0700 Subject: [PATCH] tiny debugging hacks tracing improvements --- .../crates/turbo-persistence/benches/mod.rs | 3 + .../turbo-persistence/src/bin/sst_inspect.rs | 76 +++++++++---- turbopack/crates/turbo-persistence/src/db.rs | 11 +- turbopack/crates/turbo-persistence/src/lib.rs | 4 +- .../turbo-persistence/src/sst_filter.rs | 6 + .../crates/turbo-persistence/src/tests.rs | 2 + .../turbo-persistence/src/write_batch.rs | 6 +- .../turbo-tasks-backend/src/backend/mod.rs | 35 +++--- .../backend/operation/aggregation_update.rs | 105 ++++++++++-------- .../src/backend/operation/mod.rs | 64 ++++++++--- .../src/backend/operation/update_cell.rs | 1 + .../src/database/key_value_database.rs | 11 ++ 12 files changed, 219 insertions(+), 105 deletions(-) diff --git a/turbopack/crates/turbo-persistence/benches/mod.rs b/turbopack/crates/turbo-persistence/benches/mod.rs index d207fa5dbb4f39..760c088d97314c 100644 --- a/turbopack/crates/turbo-persistence/benches/mod.rs +++ b/turbopack/crates/turbo-persistence/benches/mod.rs @@ -576,6 +576,7 @@ fn prefill_multi_value_database( ) -> Result>> { let db_config = TpDbConfig { family_configs: [FamilyConfig { + name: "test", kind: FamilyKind::MultiValue, }], }; @@ -648,6 +649,7 @@ fn setup_prefilled_multi_value_db( fn open_multi_value_db(path: &Path) -> TurboPersistence { let db_config = TpDbConfig { family_configs: [FamilyConfig { + name: "test", kind: FamilyKind::MultiValue, }], }; @@ -914,6 +916,7 @@ fn bench_write_multi_value(c: &mut Criterion) { |(tempdir, keys, random_data)| { let db_config = TpDbConfig { family_configs: [FamilyConfig { + name: "test", kind: FamilyKind::MultiValue, }], }; diff --git a/turbopack/crates/turbo-persistence/src/bin/sst_inspect.rs b/turbopack/crates/turbo-persistence/src/bin/sst_inspect.rs index dc23188d0109eb..0a2666ba7d51ba 100644 --- a/turbopack/crates/turbo-persistence/src/bin/sst_inspect.rs +++ b/turbopack/crates/turbo-persistence/src/bin/sst_inspect.rs @@ -24,6 +24,7 @@ use turbo_persistence::{ BLOCK_HEADER_SIZE, checksum_block, meta_file::MetaFile, mmap_helper::advise_mmap_for_persistence, + sst_filter::SstFilter, static_sorted_file::{ BLOCK_TYPE_FIXED_KEY_NO_HASH, BLOCK_TYPE_FIXED_KEY_WITH_HASH, BLOCK_TYPE_KEY_NO_HASH, BLOCK_TYPE_KEY_WITH_HASH, KEY_BLOCK_ENTRY_TYPE_BLOB, KEY_BLOCK_ENTRY_TYPE_DELETED, @@ -205,33 +206,68 @@ fn format_bytes(bytes: u64) -> String { } } -/// Collect SST info from all meta files in the database directory +/// Collect SST info from all active meta files in the database directory, +/// mirroring the DB's own open logic: read CURRENT, filter by .del files, +/// and apply SstFilter to skip superseded entries. fn collect_sst_info(db_path: &Path) -> Result>> { - let mut meta_files: Vec = fs::read_dir(db_path)? - .filter_map(|entry| entry.ok()) - .map(|entry| entry.path()) - .filter(|path| path.extension().is_some_and(|ext| ext == "meta")) - .collect(); + // Read the CURRENT sequence number — only files with seq <= current are valid. + let current: u32 = File::open(db_path.join("CURRENT")) + .context("Failed to open CURRENT file")? + .read_u32::() + .context("Failed to read CURRENT file")?; + + // Read .del files to find sequences that were deleted but not yet cleaned up. + let mut deleted_seqs: HashSet = HashSet::new(); + for entry in fs::read_dir(db_path)? { + let path = entry?.path(); + if path.extension().and_then(|s| s.to_str()) == Some("del") { + let content = fs::read(&path)?; + let mut cursor: &[u8] = &content; + while !cursor.is_empty() { + deleted_seqs.insert(cursor.read_u32::()?); + } + } + } - meta_files.sort(); + // Collect valid meta sequence numbers. + let mut meta_seqs: Vec = fs::read_dir(db_path)? + .filter_map(|e| e.ok()) + .filter_map(|e| { + let path = e.path(); + if path.extension().and_then(|s| s.to_str()) != Some("meta") { + return None; + } + let seq: u32 = path.file_stem()?.to_str()?.parse().ok()?; + if seq > current || deleted_seqs.contains(&seq) { + return None; + } + Some(seq) + }) + .collect(); - if meta_files.is_empty() { - bail!("No .meta files found in {}", db_path.display()); + if meta_seqs.is_empty() { + bail!("No active .meta files found in {}", db_path.display()); } - let mut family_sst_info: BTreeMap> = BTreeMap::new(); - - for meta_path in &meta_files { - // Extract sequence number from filename - let filename = meta_path.file_stem().and_then(|s| s.to_str()).unwrap_or(""); - let seq_num: u32 = filename.parse().unwrap_or(0); + meta_seqs.sort_unstable(); - let meta_file = MetaFile::open(db_path, seq_num) - .with_context(|| format!("Failed to open {}", meta_path.display()))?; + let mut meta_files: Vec = meta_seqs + .iter() + .map(|&seq| { + MetaFile::open(db_path, seq).with_context(|| format!("Failed to open {seq:08}.meta")) + }) + .collect::>()?; - let family = meta_file.family(); + // Apply SstFilter (newest first) to drop entries superseded by a newer meta file. + let mut sst_filter = SstFilter::new(); + for meta in meta_files.iter_mut().rev() { + sst_filter.apply_filter(meta); + } - for entry in meta_file.entries() { + let mut family_sst_info: BTreeMap> = BTreeMap::new(); + for meta in &meta_files { + let family = meta.family(); + for entry in meta.entries() { family_sst_info.entry(family).or_default().push(SstInfo { sequence_number: entry.sequence_number(), block_count: entry.block_count(), @@ -317,7 +353,7 @@ fn read_block( /// /// Index block format: `[1B type][2B first_block][N * (8B hash + 2B block_index)]`. fn parse_key_block_indices(index_block: &[u8]) -> HashSet { - assert!(index_block.len() >= 4, "Index block too small"); + assert!(index_block.len() >= 3, "Index block too small"); let mut data = &index_block[1..]; // skip block type byte let first_block = data.read_u16::().unwrap(); let mut indices = HashSet::new(); diff --git a/turbopack/crates/turbo-persistence/src/db.rs b/turbopack/crates/turbo-persistence/src/db.rs index 3ed8c8d9d6a0e4..d340e315dcb92d 100644 --- a/turbopack/crates/turbo-persistence/src/db.rs +++ b/turbopack/crates/turbo-persistence/src/db.rs @@ -1033,7 +1033,10 @@ impl TurboPersistence .collect::>(); // Merge SST files - let span = tracing::trace_span!("merge files"); + let span = tracing::trace_span!( + "merge files", + family = self.config.family_configs[family as usize].name + ); enum PartialMergeResult<'l> { Merged { new_sst_files: Vec<(u32, File, StaticSortedFileBuilderMeta<'static>)>, @@ -1406,7 +1409,7 @@ impl TurboPersistence } let span = tracing::trace_span!( "database read", - name = family, + name = self.config.family_configs[family].name, result_size = tracing::field::Empty ) .entered(); @@ -1436,7 +1439,7 @@ impl TurboPersistence } let span = tracing::trace_span!( "database read multiple", - name = family, + name = self.config.family_configs[family].name, result_count = tracing::field::Empty, result_size = tracing::field::Empty ) @@ -1573,7 +1576,7 @@ impl TurboPersistence } let span = tracing::trace_span!( "database batch read", - name = family, + name = self.config.family_configs[family].name, keys = keys.len(), not_found = tracing::field::Empty, deleted = tracing::field::Empty, diff --git a/turbopack/crates/turbo-persistence/src/lib.rs b/turbopack/crates/turbo-persistence/src/lib.rs index 3a877ae5ee7f9f..9212c573bee65f 100644 --- a/turbopack/crates/turbo-persistence/src/lib.rs +++ b/turbopack/crates/turbo-persistence/src/lib.rs @@ -18,7 +18,7 @@ pub mod mmap_helper; mod parallel_scheduler; mod rc_bytes; mod shared_bytes; -mod sst_filter; +pub mod sst_filter; pub mod static_sorted_file; mod static_sorted_file_builder; mod value_block_count_tracker; @@ -49,6 +49,7 @@ pub enum FamilyKind { /// Configuration for a single family to describe how the data is stored. #[derive(Clone, Copy, Debug)] pub struct FamilyConfig { + pub name: &'static str, pub kind: FamilyKind, } @@ -65,6 +66,7 @@ impl Default for DbConfig { fn default() -> Self { Self { family_configs: [FamilyConfig { + name: "unknown", kind: FamilyKind::SingleValue, }; FAMILIES], } diff --git a/turbopack/crates/turbo-persistence/src/sst_filter.rs b/turbopack/crates/turbo-persistence/src/sst_filter.rs index ca562880666d43..dbba126af7a596 100644 --- a/turbopack/crates/turbo-persistence/src/sst_filter.rs +++ b/turbopack/crates/turbo-persistence/src/sst_filter.rs @@ -67,3 +67,9 @@ impl SstFilter { !used && !meta.has_active_entries() } } + +impl Default for SstFilter { + fn default() -> Self { + Self::new() + } +} diff --git a/turbopack/crates/turbo-persistence/src/tests.rs b/turbopack/crates/turbo-persistence/src/tests.rs index 3ed65ec995204f..a1f63cafcc3c04 100644 --- a/turbopack/crates/turbo-persistence/src/tests.rs +++ b/turbopack/crates/turbo-persistence/src/tests.rs @@ -1521,6 +1521,7 @@ fn compaction_multi_value_preserves_different_values() -> Result<()> { fn multi_value_config() -> DbConfig<1> { let mut config = DbConfig::<1>::default(); config.family_configs[0] = FamilyConfig { + name: "test", kind: FamilyKind::MultiValue, }; config @@ -2097,6 +2098,7 @@ fn compaction_deletes_blob_multi_value_tombstone() -> Result<()> { let config = DbConfig { family_configs: [FamilyConfig { + name: "test", kind: FamilyKind::MultiValue, }], }; diff --git a/turbopack/crates/turbo-persistence/src/write_batch.rs b/turbopack/crates/turbo-persistence/src/write_batch.rs index ce647b349ec767..80265801172488 100644 --- a/turbopack/crates/turbo-persistence/src/write_batch.rs +++ b/turbopack/crates/turbo-persistence/src/write_batch.rs @@ -141,7 +141,7 @@ impl Ok(collector) } - #[tracing::instrument(level = "trace", skip(self, collector))] + #[tracing::instrument(level = "trace", skip(self, collector), fields(family_name = self.family_configs[usize_from_u32(family)].name))] fn flush_thread_local_collector( &self, family: u32, @@ -243,7 +243,7 @@ impl /// /// Caller must ensure that no concurrent put or delete operation is happening on the flushed /// family. - #[tracing::instrument(level = "trace", skip(self))] + #[tracing::instrument(level = "trace", skip(self), fields(family_name = self.family_configs[usize_from_u32(family)].name))] pub unsafe fn flush(&self, family: u32) -> Result<()> { // Flush the thread local collectors to the global collector. let mut collectors = Vec::new(); @@ -452,7 +452,7 @@ impl /// Creates a new SST file with the given collector data. /// Returns a tuple of (sequence number, file). - #[tracing::instrument(level = "trace", skip(self, collector_data))] + #[tracing::instrument(level = "trace", skip(self, collector_data), fields(family_name = self.family_configs[usize_from_u32(family)].name))] fn create_sst_file( &self, family: u32, diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs b/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs index 34a8024821f4c8..37d2df24a0eadc 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs @@ -1912,7 +1912,7 @@ impl TurboTasksBackendInner { let once_task = matches!(task_type, TaskType::Transient(ref tt) if matches!(&**tt, TransientTask::Once(_))); if let Some(tasks) = task.prefetch() { drop(task); - ctx.prepare_tasks(tasks); + ctx.prepare_tasks(tasks, "prefetch"); task = ctx.task(task_id, TaskDataCategory::All); } let in_progress = task.take_in_progress()?; @@ -2399,6 +2399,7 @@ impl TurboTasksBackendInner { output_dependent_tasks .iter() .map(|&id| (id, TaskDataCategory::All)), + "invalidate output dependents", ); } @@ -2491,20 +2492,24 @@ impl TurboTasksBackendInner { debug_assert!(!new_children.is_empty()); let mut queue = AggregationUpdateQueue::new(); - ctx.for_each_task_all(new_children.iter().copied(), |child_task, ctx| { - if !child_task.has_output() { - let child_id = child_task.id(); - make_task_dirty_internal( - child_task, - child_id, - false, - #[cfg(feature = "trace_task_dirty")] - TaskDirtyCause::InitialDirty, - &mut queue, - ctx, - ); - } - }); + ctx.for_each_task_all( + new_children.iter().copied(), + "unfinished children dirty", + |child_task, ctx| { + if !child_task.has_output() { + let child_id = child_task.id(); + make_task_dirty_internal( + child_task, + child_id, + false, + #[cfg(feature = "trace_task_dirty")] + TaskDirtyCause::InitialDirty, + &mut queue, + ctx, + ); + } + }, + ); queue.execute(ctx); } diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/operation/aggregation_update.rs b/turbopack/crates/turbo-tasks-backend/src/backend/operation/aggregation_update.rs index a545a68ac794ee..97ecd1c2d38c67 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/operation/aggregation_update.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/operation/aggregation_update.rs @@ -1256,10 +1256,14 @@ impl AggregationUpdateQueue { self.find_and_schedule_dirty(jobs, ctx); false } else if !self.scheduled_tasks.is_empty() { - ctx.for_each_task_all(self.scheduled_tasks.keys().copied(), |task, ctx| { - let parent_priority = self.scheduled_tasks[&task.id()]; - ctx.schedule_task(task, parent_priority); - }); + ctx.for_each_task_all( + self.scheduled_tasks.keys().copied(), + "schedule tasks", + |task, ctx| { + let parent_priority = self.scheduled_tasks[&task.id()]; + ctx.schedule_task(task, parent_priority); + }, + ); self.scheduled_tasks.clear(); false } else { @@ -1444,18 +1448,22 @@ impl AggregationUpdateQueue { .map(|job| (job.task_id, job.span.clone())) .collect(); // For performance reasons this should stay `Meta` and not `All` - ctx.for_each_task_meta(jobs.into_iter().map(|job| job.task_id), |task, ctx| { - let task_id = task.id(); - // Enter the enqueue-time span and create a per-task child span with the - // task description. Both guards must live until the end of the closure. - #[cfg(feature = "trace_find_and_schedule")] - let _trace = ( - spans.remove(&task_id).flatten().map(|s| s.entered()), - trace_span!("find and schedule", %task_id, name = task.get_task_description()) - .entered(), - ); - self.find_and_schedule_dirty_internal(task_id, task, ctx); - }); + ctx.for_each_task_meta( + jobs.into_iter().map(|job| job.task_id), + "find and schedule dirty", + |task, ctx| { + let task_id = task.id(); + // Enter the enqueue-time span and create a per-task child span with the + // task description. Both guards must live until the end of the closure. + #[cfg(feature = "trace_find_and_schedule")] + let _trace = ( + spans.remove(&task_id).flatten().map(|s| s.entered()), + trace_span!("find and schedule", %task_id, name = task.get_task_description()) + .entered(), + ); + self.find_and_schedule_dirty_internal(task_id, task, ctx); + }, + ); } fn find_and_schedule_dirty_internal( @@ -1507,21 +1515,25 @@ impl AggregationUpdateQueue { update: AggregatedDataUpdate, ) { // For performance reasons this should stay `Meta` and not `All` - ctx.for_each_task_meta(upper_ids.iter().copied(), |mut upper, ctx| { - let diff = update.apply(&mut upper, ctx.should_track_activeness(), self); - if !diff.is_empty() { - let upper_ids = get_uppers(&upper); - if !upper_ids.is_empty() { - self.push( - AggregatedDataUpdateJob { - upper_ids, - update: diff, - } - .into(), - ); + ctx.for_each_task_meta( + upper_ids.iter().copied(), + "aggregated data update", + |mut upper, ctx| { + let diff = update.apply(&mut upper, ctx.should_track_activeness(), self); + if !diff.is_empty() { + let upper_ids = get_uppers(&upper); + if !upper_ids.is_empty() { + self.push( + AggregatedDataUpdateJob { + upper_ids, + update: diff, + } + .into(), + ); + } } - } - }); + }, + ); } fn inner_of_uppers_lost_follower( @@ -1574,20 +1586,24 @@ impl AggregationUpdateQueue { if !data.is_empty() { // remove data from upper // For performance reasons this should stay `Meta` and not `All` - ctx.for_each_task_meta(removed_uppers.iter().copied(), |mut upper, ctx| { - // STEP 6 - let diff = data.apply(&mut upper, ctx.should_track_activeness(), self); - if !diff.is_empty() { - let upper_ids = get_uppers(&upper); - self.push( - AggregatedDataUpdateJob { - upper_ids, - update: diff, - } - .into(), - ) - } - }); + ctx.for_each_task_meta( + removed_uppers.iter().copied(), + "remove data from uppers", + |mut upper, ctx| { + // STEP 6 + let diff = data.apply(&mut upper, ctx.should_track_activeness(), self); + if !diff.is_empty() { + let upper_ids = get_uppers(&upper); + self.push( + AggregatedDataUpdateJob { + upper_ids, + update: diff, + } + .into(), + ) + } + }, + ); } // STEP 7 if !followers.is_empty() { @@ -2061,6 +2077,7 @@ impl AggregationUpdateQueue { upper_ids_with_min_aggregation_number .iter() .map(|(entry, _)| entry.task_id()), + "add data to uppers", |mut upper, ctx| { // STEP 6d if has_data { diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs b/turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs index e06baba14cb68e..88f747d8e15bad 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs @@ -13,6 +13,7 @@ use std::{ }; use bincode::{Decode, Encode}; +use tracing::trace_span; use turbo_tasks::{ CellId, FxIndexMap, TaskExecutionReason, TaskId, TaskPriority, TurboTasksBackendApi, TurboTasksCallApi, TypedSharedReference, backend::CachedTaskType, @@ -44,30 +45,36 @@ pub trait ExecuteContext<'e>: Sized { /// The iterator should not have duplicates, as this would cause over-fetching. fn prepare_tasks( &mut self, - task_ids: impl IntoIterator + Clone, + task_ids: impl IntoIterator, + reason: &'static str, ); fn for_each_task( &mut self, task_ids: impl IntoIterator, + reason: &'static str, func: impl FnMut(Self::TaskGuardImpl, &mut Self), ); fn for_each_task_meta( &mut self, task_ids: impl IntoIterator, + reason: &'static str, func: impl FnMut(Self::TaskGuardImpl, &mut Self), ) { self.for_each_task( task_ids.into_iter().map(|id| (id, TaskDataCategory::Meta)), + reason, func, ) } fn for_each_task_all( &mut self, task_ids: impl IntoIterator, + reason: &'static str, func: impl FnMut(Self::TaskGuardImpl, &mut Self), ) { self.for_each_task( task_ids.into_iter().map(|id| (id, TaskDataCategory::All)), + reason, func, ) } @@ -208,6 +215,7 @@ impl<'e, B: BackingStorage> ExecuteContextImpl<'e, B> { // If we don't need to restore, we return None return None; } + let result = self .backend .backing_storage @@ -230,6 +238,7 @@ impl<'e, B: BackingStorage> ExecuteContextImpl<'e, B> { &mut self, task_ids: impl IntoIterator, call_prepared_task_callback_for_transient_tasks: bool, + reason: &'static str, mut prepared_task_callback: impl FnMut( &mut Self, TaskId, @@ -237,6 +246,13 @@ impl<'e, B: BackingStorage> ExecuteContextImpl<'e, B> { StorageWriteGuard<'e>, ), ) { + let span = trace_span!( + "prepare_tasks_with_callback", + reason, + requested_data = tracing::field::Empty, + requested_meta = tracing::field::Empty, + ); + let _guard = span.enter(); let mut data_count = 0; let mut meta_count = 0; let mut all_count = 0; @@ -267,6 +283,8 @@ impl<'e, B: BackingStorage> ExecuteContextImpl<'e, B> { .collect::>(); data_count += all_count; meta_count += all_count; + span.record("requested_data", data_count); + span.record("requested_meta", meta_count); let mut tasks_to_restore_for_data = Vec::with_capacity(data_count); let mut tasks_to_restore_for_data_indicies = Vec::with_capacity(data_count); @@ -350,7 +368,6 @@ impl<'e, B: BackingStorage> ExecuteContextImpl<'e, B> { } } } - for (task_id, category, storage_for_data, storage_for_meta) in tasks { if storage_for_data.is_none() && storage_for_meta.is_none() { continue; @@ -446,30 +463,41 @@ impl<'e, B: BackingStorage> ExecuteContext<'e> for ExecuteContextImpl<'e, B> { } } - fn prepare_tasks(&mut self, task_ids: impl IntoIterator) { - self.prepare_tasks_with_callback(task_ids, false, |_, _, _, _| {}); + fn prepare_tasks( + &mut self, + task_ids: impl IntoIterator, + reason: &'static str, + ) { + self.prepare_tasks_with_callback(task_ids, false, reason, |_, _, _, _| {}); } fn for_each_task( &mut self, task_ids: impl IntoIterator, + reason: &'static str, mut func: impl FnMut(Self::TaskGuardImpl, &mut Self), ) { let task_lock_counter = self.task_lock_counter.clone(); - self.prepare_tasks_with_callback(task_ids, true, |this, task_id, _category, task| { - // prepare_tasks_with_callback releases the counter before calling this callback, - // so the counter is 0 here. Acquire for the TaskGuardImpl that will release on Drop. - task_lock_counter.acquire(); - - let guard = TaskGuardImpl { - task, - task_id, - #[cfg(debug_assertions)] - category: _category, - task_lock_counter: task_lock_counter.clone(), - }; - func(guard, this); - }); + self.prepare_tasks_with_callback( + task_ids, + true, + reason, + |this, task_id, _category, task| { + // prepare_tasks_with_callback releases the counter before calling this callback, + // so the counter is 0 here. Acquire for the TaskGuardImpl that will release on + // Drop. + task_lock_counter.acquire(); + + let guard = TaskGuardImpl { + task, + task_id, + #[cfg(debug_assertions)] + category: _category, + task_lock_counter: task_lock_counter.clone(), + }; + func(guard, this); + }, + ); } fn task_pair( diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/operation/update_cell.rs b/turbopack/crates/turbo-tasks-backend/src/backend/operation/update_cell.rs index 427820b6e0c7a8..0072f843d5033c 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/operation/update_cell.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/operation/update_cell.rs @@ -153,6 +153,7 @@ impl UpdateCellOperation { dependent_tasks .keys() .map(|&id| (id, TaskDataCategory::All)), + "invalidate cell dependents", ); UpdateCellOperation::InvalidateWhenCellDependency { diff --git a/turbopack/crates/turbo-tasks-backend/src/database/key_value_database.rs b/turbopack/crates/turbo-tasks-backend/src/database/key_value_database.rs index 19ab820051bd94..c5f5da9c35b3b4 100644 --- a/turbopack/crates/turbo-tasks-backend/src/database/key_value_database.rs +++ b/turbopack/crates/turbo-tasks-backend/src/database/key_value_database.rs @@ -27,13 +27,24 @@ impl KeySpace { } } + const fn name(&self) -> &'static str { + match self { + KeySpace::Infra => "Infra", + KeySpace::TaskMeta => "TaskMeta", + KeySpace::TaskData => "TaskData", + KeySpace::TaskCache => "TaskCache", + } + } + /// Returns the persistence configuration for this keyspace. pub const fn family_config(&self) -> FamilyConfig { match self { KeySpace::Infra | KeySpace::TaskMeta | KeySpace::TaskData => FamilyConfig { + name: self.name(), kind: FamilyKind::SingleValue, }, KeySpace::TaskCache => FamilyConfig { + name: self.name(), // TaskCache uses hash-based lookups with potential collisions. kind: FamilyKind::MultiValue, },