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