Skip to content

Commit d55dda7

Browse files
committed
feat(gc): record workspace manifest and target dir in global cache tracker
1 parent bd1cf58 commit d55dda7

File tree

2 files changed

+212
-2
lines changed

2 files changed

+212
-2
lines changed

src/cargo/core/global_cache_tracker.rs

+203-1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ const REGISTRY_CRATE_TABLE: &str = "registry_crate";
138138
const REGISTRY_SRC_TABLE: &str = "registry_src";
139139
const GIT_DB_TABLE: &str = "git_db";
140140
const GIT_CO_TABLE: &str = "git_checkout";
141+
const WORKSPACE_MANIFEST_TABLE: &str = "workspace_manifest_index";
142+
const TARGET_DIR_TABLE: &str = "target_dir_index";
141143

142144
/// How often timestamps will be updated.
143145
///
@@ -209,6 +211,26 @@ pub struct GitCheckout {
209211
pub size: Option<u64>,
210212
}
211213

214+
/// The key for a workspace manifest entry stored in the database.
215+
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
216+
pub struct WorkspaceManifestIndex {
217+
/// A unique name of the workspace manifest.
218+
pub workspace_manifest_name: InternedString,
219+
}
220+
221+
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
222+
pub struct TargetDirIndex {
223+
/// A unique name of the target directory.
224+
pub target_dir_name: InternedString,
225+
}
226+
227+
/// The key for a workspace entry stored in the database.
228+
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
229+
pub struct WorkspaceSrc {
230+
pub workspace_manifest_name: InternedString,
231+
pub target_dir_name: InternedString,
232+
}
233+
212234
/// Filesystem paths in the global cache.
213235
///
214236
/// Accessing these assumes a lock has already been acquired.
@@ -303,6 +325,30 @@ fn migrations() -> Vec<Migration> {
303325
)?;
304326
Ok(())
305327
}),
328+
basic_migration(
329+
"CREATE TABLE workspace_manifest_index (
330+
id INTEGER PRIMARY KEY AUTOINCREMENT,
331+
name TEXT UNIQUE NOT NULL,
332+
timestamp INTEGER NOT NULL
333+
)",
334+
),
335+
basic_migration(
336+
"CREATE TABLE target_dir_index (
337+
id INTEGER PRIMARY KEY AUTOINCREMENT,
338+
name TEXT UNIQUE NOT NULL,
339+
timestamp INTEGER NOT NULL
340+
)",
341+
),
342+
basic_migration(
343+
"CREATE TABLE workspace_src (
344+
workspace_id INTEGER NOT NULL,
345+
target_dir_id INTEGER NOT NULL,
346+
timestamp INTEGER NOT NULL,
347+
PRIMARY KEY (workspace_id, target_dir_id),
348+
FOREIGN KEY (workspace_id) REFERENCES workspace_manifest_index (id) ON DELETE CASCADE,
349+
FOREIGN KEY (target_dir_id) REFERENCES target_dir_index (id) ON DELETE CASCADE
350+
)",
351+
)
306352
]
307353
}
308354

@@ -1413,7 +1459,16 @@ pub struct DeferredGlobalLastUse {
14131459
/// The key is the git db name (which is its directory name) and the value
14141460
/// is the `id` in the `git_db` table.
14151461
git_keys: HashMap<InternedString, ParentId>,
1416-
1462+
/// Cache of workspace manifest keys, used for faster fetching.
1463+
///
1464+
/// The key is the workspace manifest path and the value
1465+
/// is the `id` in the `workspace_manifest` table.
1466+
workspace_manifest_keys: HashMap<InternedString, ParentId>,
1467+
/// Cache of target dir keys, used for faster fetching.
1468+
///
1469+
/// The key is the target dir path and the value
1470+
/// is the `id` in the `target_dir` table.
1471+
target_dir_keys: HashMap<InternedString, ParentId>,
14171472
/// New registry index entries to insert.
14181473
registry_index_timestamps: HashMap<RegistryIndex, Timestamp>,
14191474
/// New registry `.crate` entries to insert.
@@ -1424,6 +1479,12 @@ pub struct DeferredGlobalLastUse {
14241479
git_db_timestamps: HashMap<GitDb, Timestamp>,
14251480
/// New git checkout entries to insert.
14261481
git_checkout_timestamps: HashMap<GitCheckout, Timestamp>,
1482+
/// New workspace manifest index entries to insert.
1483+
workspace_manifest_index_timestamps: HashMap<WorkspaceManifestIndex, Timestamp>,
1484+
/// New target dir index entries to insert.
1485+
target_dir_index_timestamps: HashMap<TargetDirIndex, Timestamp>,
1486+
/// New workspace src entries to insert.
1487+
workspace_src_timestamps: HashMap<WorkspaceSrc, Timestamp>,
14271488
/// This is used so that a warning about failing to update the database is
14281489
/// only displayed once.
14291490
save_err_has_warned: bool,
@@ -1437,11 +1498,16 @@ impl DeferredGlobalLastUse {
14371498
DeferredGlobalLastUse {
14381499
registry_keys: HashMap::new(),
14391500
git_keys: HashMap::new(),
1501+
workspace_manifest_keys: HashMap::new(),
1502+
target_dir_keys: HashMap::new(),
14401503
registry_index_timestamps: HashMap::new(),
14411504
registry_crate_timestamps: HashMap::new(),
14421505
registry_src_timestamps: HashMap::new(),
14431506
git_db_timestamps: HashMap::new(),
14441507
git_checkout_timestamps: HashMap::new(),
1508+
target_dir_index_timestamps: HashMap::new(),
1509+
workspace_manifest_index_timestamps: HashMap::new(),
1510+
workspace_src_timestamps: HashMap::new(),
14451511
save_err_has_warned: false,
14461512
now: now(),
14471513
}
@@ -1453,6 +1519,9 @@ impl DeferredGlobalLastUse {
14531519
&& self.registry_src_timestamps.is_empty()
14541520
&& self.git_db_timestamps.is_empty()
14551521
&& self.git_checkout_timestamps.is_empty()
1522+
&& self.target_dir_index_timestamps.is_empty()
1523+
&& self.workspace_manifest_index_timestamps.is_empty()
1524+
&& self.workspace_src_timestamps.is_empty()
14561525
}
14571526

14581527
fn clear(&mut self) {
@@ -1461,6 +1530,9 @@ impl DeferredGlobalLastUse {
14611530
self.registry_src_timestamps.clear();
14621531
self.git_db_timestamps.clear();
14631532
self.git_checkout_timestamps.clear();
1533+
self.target_dir_index_timestamps.clear();
1534+
self.workspace_manifest_index_timestamps.clear();
1535+
self.workspace_src_timestamps.clear();
14641536
}
14651537

14661538
/// Indicates the given [`RegistryIndex`] has been used right now.
@@ -1489,6 +1561,13 @@ impl DeferredGlobalLastUse {
14891561
self.mark_git_checkout_used_stamp(git_checkout, None);
14901562
}
14911563

1564+
/// Indicates the given [`WorkspaceSrc`] has been used right now.
1565+
///
1566+
/// Also implicitly marks the workspace manifest used, too.
1567+
pub fn mark_workspace_src_used(&mut self, workspace_src: WorkspaceSrc) {
1568+
self.mark_workspace_src_used_stamp(workspace_src, None);
1569+
}
1570+
14921571
/// Indicates the given [`RegistryIndex`] has been used with the given
14931572
/// time (or "now" if `None`).
14941573
pub fn mark_registry_index_used_stamp(
@@ -1553,6 +1632,26 @@ impl DeferredGlobalLastUse {
15531632
self.git_checkout_timestamps.insert(git_checkout, timestamp);
15541633
}
15551634

1635+
pub fn mark_workspace_src_used_stamp(
1636+
&mut self,
1637+
workspace_src: WorkspaceSrc,
1638+
timestamp: Option<&SystemTime>,
1639+
) {
1640+
let timestamp = timestamp.map_or(self.now, to_timestamp);
1641+
let workspace_db = WorkspaceManifestIndex {
1642+
workspace_manifest_name: workspace_src.workspace_manifest_name,
1643+
};
1644+
let target_dir_db = TargetDirIndex {
1645+
target_dir_name: workspace_src.target_dir_name,
1646+
};
1647+
self.target_dir_index_timestamps
1648+
.insert(target_dir_db, timestamp);
1649+
self.workspace_manifest_index_timestamps
1650+
.insert(workspace_db, timestamp);
1651+
self.workspace_src_timestamps
1652+
.insert(workspace_src, timestamp);
1653+
}
1654+
15561655
/// Saves all of the deferred information to the database.
15571656
///
15581657
/// This will also clear the state of `self`.
@@ -1566,9 +1665,13 @@ impl DeferredGlobalLastUse {
15661665
// These must run before the ones that refer to their IDs.
15671666
self.insert_registry_index_from_cache(&tx)?;
15681667
self.insert_git_db_from_cache(&tx)?;
1668+
self.insert_target_dir_index_from_cache(&tx)?;
1669+
self.insert_workspace_manifest_index_from_cache(&tx)?;
1670+
15691671
self.insert_registry_crate_from_cache(&tx)?;
15701672
self.insert_registry_src_from_cache(&tx)?;
15711673
self.insert_git_checkout_from_cache(&tx)?;
1674+
self.insert_workspace_src_from_cache(&tx)?;
15721675
tx.commit()?;
15731676
trace!(target: "gc", "last-use save complete");
15741677
Ok(())
@@ -1632,6 +1735,32 @@ impl DeferredGlobalLastUse {
16321735
);
16331736
}
16341737

1738+
// Flushes all of the `target_dir_db_timestamps` to the database,
1739+
// clearing `target_dir_index_timestamps`.
1740+
fn insert_target_dir_index_from_cache(&mut self, conn: &Connection) -> CargoResult<()> {
1741+
insert_or_update_parent!(
1742+
self,
1743+
conn,
1744+
"target_dir_index",
1745+
target_dir_index_timestamps,
1746+
target_dir_keys,
1747+
target_dir_name
1748+
);
1749+
}
1750+
1751+
// Flushes all of the `workspace_db_timestamps` to the database,
1752+
// clearing `workspace_manifest_index_timestamps`.
1753+
fn insert_workspace_manifest_index_from_cache(&mut self, conn: &Connection) -> CargoResult<()> {
1754+
insert_or_update_parent!(
1755+
self,
1756+
conn,
1757+
"workspace_manifest_index",
1758+
workspace_manifest_index_timestamps,
1759+
workspace_manifest_keys,
1760+
workspace_manifest_name
1761+
);
1762+
}
1763+
16351764
/// Flushes all of the `registry_crate_timestamps` to the database,
16361765
/// clearing `registry_index_timestamps`.
16371766
fn insert_registry_crate_from_cache(&mut self, conn: &Connection) -> CargoResult<()> {
@@ -1707,6 +1836,79 @@ impl DeferredGlobalLastUse {
17071836
Ok(())
17081837
}
17091838

1839+
// Flushes all of the `workspace_src_timestamps` to the database,
1840+
// clearing `workspace_src_timestamps`.
1841+
fn insert_workspace_src_from_cache(&mut self, conn: &Connection) -> CargoResult<()> {
1842+
let workspace_src_timestamps = std::mem::take(&mut self.workspace_src_timestamps);
1843+
for (workspace_src, timestamp) in workspace_src_timestamps {
1844+
let workspace_id = self.workspace_id(conn, workspace_src.workspace_manifest_name)?;
1845+
let target_dir_id = self.target_dir_id(conn, workspace_src.target_dir_name)?;
1846+
let mut stmt = conn.prepare_cached(
1847+
"INSERT INTO workspace_src (workspace_id, target_dir_id, timestamp)
1848+
VALUES (?1, ?2, ?3)
1849+
ON CONFLICT DO UPDATE SET timestamp=excluded.timestamp
1850+
WHERE timestamp < ?4",
1851+
)?;
1852+
stmt.execute(params![
1853+
workspace_id,
1854+
target_dir_id,
1855+
timestamp,
1856+
timestamp - UPDATE_RESOLUTION
1857+
])?;
1858+
}
1859+
Ok(())
1860+
}
1861+
1862+
fn workspace_id(
1863+
&mut self,
1864+
conn: &Connection,
1865+
encoded_workspace_manifest_name: InternedString,
1866+
) -> CargoResult<ParentId> {
1867+
match self
1868+
.workspace_manifest_keys
1869+
.get(&encoded_workspace_manifest_name)
1870+
{
1871+
Some(i) => Ok(*i),
1872+
None => {
1873+
let Some(id) = GlobalCacheTracker::id_from_name(
1874+
conn,
1875+
WORKSPACE_MANIFEST_TABLE,
1876+
&encoded_workspace_manifest_name,
1877+
)?
1878+
else {
1879+
bail!("expected workspace_manifest {encoded_workspace_manifest_name} to exist, but wasn't found");
1880+
};
1881+
self.workspace_manifest_keys
1882+
.insert(encoded_workspace_manifest_name, id);
1883+
Ok(id)
1884+
}
1885+
}
1886+
}
1887+
1888+
fn target_dir_id(
1889+
&mut self,
1890+
conn: &Connection,
1891+
encoded_target_dir_name: InternedString,
1892+
) -> CargoResult<ParentId> {
1893+
match self.target_dir_keys.get(&encoded_target_dir_name) {
1894+
Some(i) => Ok(*i),
1895+
None => {
1896+
let Some(id) = GlobalCacheTracker::id_from_name(
1897+
conn,
1898+
TARGET_DIR_TABLE,
1899+
&encoded_target_dir_name,
1900+
)?
1901+
else {
1902+
bail!(
1903+
"expected target_dir {encoded_target_dir_name} to exist, but wasn't found"
1904+
);
1905+
};
1906+
self.target_dir_keys.insert(encoded_target_dir_name, id);
1907+
Ok(id)
1908+
}
1909+
}
1910+
}
1911+
17101912
/// Returns the numeric ID of the registry, either fetching from the local
17111913
/// cache, or getting it from the database.
17121914
///

src/cargo/ops/cargo_compile/mod.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner};
4949
use crate::core::profiles::Profiles;
5050
use crate::core::resolver::features::{self, CliFeatures, FeaturesFor};
5151
use crate::core::resolver::{HasDevUnits, Resolve};
52-
use crate::core::{PackageId, PackageSet, SourceId, TargetKind, Workspace};
52+
use crate::core::{global_cache_tracker, PackageId, PackageSet, SourceId, TargetKind, Workspace};
5353
use crate::drop_println;
5454
use crate::ops;
5555
use crate::ops::resolve::WorkspaceResolve;
@@ -264,6 +264,14 @@ pub fn create_bcx<'a, 'gctx>(
264264
HasDevUnits::No
265265
}
266266
};
267+
let _ = &gctx.deferred_global_last_use()?.mark_workspace_src_used(
268+
global_cache_tracker::WorkspaceSrc {
269+
workspace_manifest_name: InternedString::new(ws.root_manifest().to_str().unwrap()),
270+
target_dir_name: InternedString::new(
271+
ws.target_dir().as_path_unlocked().to_str().unwrap(),
272+
),
273+
},
274+
);
267275
let resolve = ops::resolve_ws_with_opts(
268276
ws,
269277
&mut target_data,

0 commit comments

Comments
 (0)