Skip to main content

turbo_tasks_backend/
lib.rs

1#![feature(anonymous_lifetime_in_impl_trait)]
2#![feature(box_patterns)]
3
4mod backend;
5mod backing_storage;
6mod data;
7mod database;
8mod error;
9mod kv_backing_storage;
10mod utils;
11
12use std::path::Path;
13
14use anyhow::Result;
15use turbo_persistence::{CompactConfig, TurboPersistence};
16
17use crate::database::{
18    noop_kv::NoopKvDb,
19    turbo::{self, TurboKeyValueDatabase},
20};
21pub use crate::{
22    backend::{BackendOptions, StorageMode, TurboTasksBackend},
23    backing_storage::BackingStorage,
24    database::{
25        db_invalidation,
26        db_invalidation::StartupCacheState,
27        db_versioning::{GitVersionInfo, handle_db_versioning},
28    },
29    kv_backing_storage::KeyValueDatabaseBackingStorage,
30};
31
32pub type TurboBackingStorage = KeyValueDatabaseBackingStorage<TurboKeyValueDatabase>;
33
34/// Creates a `BackingStorage` to be passed to [`TurboTasksBackend::new`].
35///
36/// Information about the state of the on-disk cache is returned using [`StartupCacheState`].
37pub fn turbo_backing_storage(
38    base_path: &Path,
39    version_info: &GitVersionInfo,
40    is_ci: bool,
41    is_short_session: bool,
42    skip_compaction: bool,
43) -> Result<(TurboBackingStorage, StartupCacheState)> {
44    KeyValueDatabaseBackingStorage::open_versioned_on_disk(
45        base_path.to_owned(),
46        version_info,
47        is_ci,
48        |path| TurboKeyValueDatabase::new(path, is_ci, is_short_session, skip_compaction),
49    )
50}
51
52pub type NoopBackingStorage = KeyValueDatabaseBackingStorage<NoopKvDb>;
53
54/// Creates an no-op in-memory `BackingStorage` to be passed to [`TurboTasksBackend::new`].
55pub fn noop_backing_storage() -> NoopBackingStorage {
56    KeyValueDatabaseBackingStorage::new_in_memory(NoopKvDb)
57}
58
59/// Opens a Turbopack persistent cache database at the given base path and performs a full
60/// compaction. This is intended for use by the `next internal post-build` CLI command to optimize
61/// the database after a build, without requiring the full turbo-tasks runtime.
62///
63/// The parallel scheduler requires a Tokio runtime. If one is already active (e.g. when called
64/// from a NAPI async function), it is reused. Otherwise a new multi-threaded runtime is created.
65pub fn compact_database(
66    base_path: &Path,
67    version_info: &GitVersionInfo,
68    is_ci: bool,
69) -> Result<()> {
70    let versioned_path = handle_db_versioning(base_path, version_info, is_ci)?;
71    // The parallel scheduler uses `tokio::task::block_in_place` internally, which
72    // requires a multi-threaded Tokio runtime. Create one only if there is no
73    // active runtime (e.g. when called from a standalone CLI context).
74    let _owned_runtime = if tokio::runtime::Handle::try_current().is_ok() {
75        None
76    } else {
77        Some(
78            tokio::runtime::Builder::new_multi_thread()
79                .enable_all()
80                .build()?,
81        )
82    };
83    // If we created a runtime, enter it so the scheduler can find it.
84    let _guard = _owned_runtime.as_ref().map(|rt| rt.enter());
85    let db =
86        TurboPersistence::<turbo::TurboTasksParallelScheduler, { turbo::FAMILIES }>::open_with_config(
87            versioned_path,
88            turbo::db_config(),
89        )?;
90    // Fully compact with no segment count limit (unlike the runtime shutdown path
91    // which caps segments based on available parallelism).
92    db.compact(&CompactConfig {
93        max_merge_segment_count: usize::MAX,
94        ..turbo::COMPACT_CONFIG
95    })?;
96    db.shutdown()
97}