Skip to content

Commit 0a70070

Browse files
committed
Move more responsibilities into the KeyValueDatabaseBackingStorage constructor
1 parent 6f89e63 commit 0a70070

File tree

5 files changed

+62
-36
lines changed

5 files changed

+62
-36
lines changed

turbopack/crates/turbo-tasks-backend/src/database/db_invalidation.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,21 @@ use std::{
44
path::Path,
55
};
66

7+
use anyhow::Context;
8+
79
const INVALIDATION_MARKER: &str = "__turbo_tasks_invalidated_db";
810

911
/// Atomically write an invalidation marker.
1012
///
1113
/// Because attempting to delete currently open database files could cause issues, actual deletion
12-
/// of files is deferred until the next start-up (in [`check_db_invalidation`]).
14+
/// of files is deferred until the next start-up (in [`check_db_invalidation_and_cleanup`]).
1315
///
1416
/// In the case that no database is currently open (e.g. via a separate CLI subcommand), you should
15-
/// call [`cleanup_db`] after this to eagerly remove the database files.
17+
/// call [`cleanup_db`] *after* this to eagerly remove the database files.
1618
///
1719
/// This should be run with the base (non-versioned) path, as that likely aligns closest with user
1820
/// expectations (e.g. if they're clearing the cache for disk space reasons).
19-
pub fn invalidate_db(base_path: &Path) -> io::Result<()> {
21+
pub fn invalidate_db(base_path: &Path) -> anyhow::Result<()> {
2022
fs::write(base_path.join(INVALIDATION_MARKER), [0u8; 0])?;
2123
Ok(())
2224
}
@@ -25,7 +27,7 @@ pub fn invalidate_db(base_path: &Path) -> io::Result<()> {
2527
/// delete any invalidated database files.
2628
///
2729
/// This should be run with the base (non-versioned) path.
28-
pub fn check_db_invalidation_and_cleanup(base_path: &Path) -> io::Result<()> {
30+
pub fn check_db_invalidation_and_cleanup(base_path: &Path) -> anyhow::Result<()> {
2931
if fs::exists(base_path.join(INVALIDATION_MARKER))? {
3032
// if this cleanup fails, we might try to open an invalid database later, so it's best to
3133
// just propagate the error here.
@@ -34,8 +36,21 @@ pub fn check_db_invalidation_and_cleanup(base_path: &Path) -> io::Result<()> {
3436
Ok(())
3537
}
3638

37-
/// Helper for `invalidate_db` and `check_db_invalidation`.
38-
pub fn cleanup_db(base_path: &Path) -> io::Result<()> {
39+
/// Helper for [`check_db_invalidation_and_cleanup`]. You can call this to explicitly clean up a
40+
/// database after running [`invalidate_db`] when turbo-tasks is not running.
41+
///
42+
/// You should not run this if the database has not yet been invalidated, as this operation is not
43+
/// atomic and could result in a partially-deleted and corrupted database.
44+
pub fn cleanup_db(base_path: &Path) -> anyhow::Result<()> {
45+
cleanup_db_inner(base_path).with_context(|| {
46+
format!(
47+
"Unable to remove invalid database. If this issue persists you can work around by \
48+
deleting {base_path:?}."
49+
)
50+
})
51+
}
52+
53+
fn cleanup_db_inner(base_path: &Path) -> io::Result<()> {
3954
let Ok(contents) = read_dir(base_path) else {
4055
return Ok(());
4156
};
@@ -44,7 +59,7 @@ pub fn cleanup_db(base_path: &Path) -> io::Result<()> {
4459
for entry in contents {
4560
let entry = entry?;
4661
if entry.file_name() != INVALIDATION_MARKER {
47-
let _ = fs::remove_dir_all(entry.path());
62+
fs::remove_dir_all(entry.path())?;
4863
}
4964
}
5065

turbopack/crates/turbo-tasks-backend/src/database/key_value_database.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ pub trait KeyValueDatabase {
6060
/// during [`KeyValueDatabase::shutdown`].
6161
///
6262
/// This is a best-effort optimization hint, and the database may choose to ignore this and
63-
/// continue file writes.
63+
/// continue file writes. This happens after the database is invalidated, so it is valid for
64+
/// this to leave the database in a half-updated and corrupted state.
6465
fn prevent_writes(&self) {
6566
// this is an optional performance hint to the database
6667
}

turbopack/crates/turbo-tasks-backend/src/database/turbo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub struct TurboKeyValueDatabase {
2424

2525
impl TurboKeyValueDatabase {
2626
pub fn new(versioned_path: PathBuf) -> Result<Self> {
27-
let db = Arc::new(TurboPersistence::open(versioned_path.to_path_buf())?);
27+
let db = Arc::new(TurboPersistence::open(versioned_path)?);
2828
let mut this = Self {
2929
db: db.clone(),
3030
compact_join_handle: Mutex::new(None),

turbopack/crates/turbo-tasks-backend/src/kv_backing_storage.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ use tracing::Span;
88
use turbo_tasks::{SessionId, TaskId, backend::CachedTaskType, turbo_tasks_scope};
99

1010
use crate::{
11+
GitVersionInfo,
1112
backend::{AnyOperation, TaskDataCategory},
1213
backing_storage::BackingStorage,
1314
data::CachedDataItem,
1415
database::{
15-
db_invalidation::invalidate_db,
16+
db_invalidation::{check_db_invalidation_and_cleanup, invalidate_db},
17+
db_versioning::handle_db_versioning,
1618
key_value_database::{KeySpace, KeyValueDatabase},
1719
write_batch::{
1820
BaseWriteBatch, ConcurrentWriteBatch, SerialWriteBatch, WriteBatch, WriteBatchRef,
@@ -89,13 +91,26 @@ pub struct KeyValueDatabaseBackingStorage<T: KeyValueDatabase> {
8991
}
9092

9193
impl<T: KeyValueDatabase> KeyValueDatabaseBackingStorage<T> {
92-
pub fn new(database: T, base_path: Option<PathBuf>) -> Self {
94+
pub fn new_in_memory(database: T) -> Self {
9395
Self {
9496
database,
95-
base_path,
97+
base_path: None,
9698
}
9799
}
98100

101+
pub fn open_versioned_on_disk(
102+
base_path: PathBuf,
103+
version_info: &GitVersionInfo,
104+
database: impl FnOnce(PathBuf) -> Result<T>,
105+
) -> Result<Self> {
106+
check_db_invalidation_and_cleanup(&base_path)?;
107+
let versioned_path = handle_db_versioning(&base_path, version_info)?;
108+
Ok(Self {
109+
database: (database)(versioned_path)?,
110+
base_path: Some(base_path),
111+
})
112+
}
113+
99114
fn with_tx<R>(
100115
&self,
101116
tx: Option<&T::ReadTransaction<'_>>,

turbopack/crates/turbo-tasks-backend/src/lib.rs

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,8 @@ mod utils;
1414
use std::path::Path;
1515

1616
use anyhow::Result;
17-
use database::db_invalidation::check_db_invalidation_and_cleanup;
1817

19-
use crate::database::{
20-
db_versioning::handle_db_versioning, noop_kv::NoopKvDb, turbo::TurboKeyValueDatabase,
21-
};
18+
use crate::database::{noop_kv::NoopKvDb, turbo::TurboKeyValueDatabase};
2219
pub use crate::{
2320
backend::{BackendOptions, StorageMode, TurboTasksBackend},
2421
database::db_versioning::GitVersionInfo,
@@ -47,18 +44,18 @@ pub fn lmdb_backing_storage(
4744
startup_cache::StartupCacheLayer,
4845
};
4946

50-
check_db_invalidation_and_cleanup(base_path)?;
51-
let versioned_path = handle_db_versioning(base_path, version_info)?;
52-
let fresh_db = is_fresh(&versioned_path);
53-
let database = crate::database::lmdb::LmbdKeyValueDatabase::new(&versioned_path)?;
54-
let database = FreshDbOptimization::new(database, fresh_db);
55-
let database =
56-
StartupCacheLayer::new(database, versioned_path.join("startup.cache"), fresh_db)?;
57-
let database = ReadTransactionCache::new(database);
58-
Ok(KeyValueDatabaseBackingStorage::new(
59-
database,
60-
Some(base_path.to_owned()),
61-
))
47+
KeyValueDatabaseBackingStorage::open_versioned_on_disk(
48+
base_path.to_owned(),
49+
version_info,
50+
|versioned_path| {
51+
let fresh_db = is_fresh(&versioned_path);
52+
let database = crate::database::lmdb::LmbdKeyValueDatabase::new(&versioned_path)?;
53+
let database = FreshDbOptimization::new(database, fresh_db);
54+
let database =
55+
StartupCacheLayer::new(database, versioned_path.join("startup.cache"), fresh_db)?;
56+
Ok(ReadTransactionCache::new(database))
57+
},
58+
)
6259
}
6360

6461
pub type TurboBackingStorage = KeyValueDatabaseBackingStorage<TurboKeyValueDatabase>;
@@ -67,19 +64,17 @@ pub fn turbo_backing_storage(
6764
base_path: &Path,
6865
version_info: &GitVersionInfo,
6966
) -> Result<TurboBackingStorage> {
70-
check_db_invalidation_and_cleanup(base_path)?;
71-
let versioned_path = handle_db_versioning(base_path, version_info)?;
72-
let database = TurboKeyValueDatabase::new(versioned_path)?;
73-
Ok(KeyValueDatabaseBackingStorage::new(
74-
database,
75-
Some(base_path.to_owned()),
76-
))
67+
KeyValueDatabaseBackingStorage::open_versioned_on_disk(
68+
base_path.to_owned(),
69+
version_info,
70+
TurboKeyValueDatabase::new,
71+
)
7772
}
7873

7974
pub type NoopBackingStorage = KeyValueDatabaseBackingStorage<NoopKvDb>;
8075

8176
pub fn noop_backing_storage() -> NoopBackingStorage {
82-
KeyValueDatabaseBackingStorage::new(NoopKvDb, None)
77+
KeyValueDatabaseBackingStorage::new_in_memory(NoopKvDb)
8378
}
8479

8580
#[cfg(feature = "lmdb")]

0 commit comments

Comments
 (0)