@@ -138,6 +138,8 @@ const REGISTRY_CRATE_TABLE: &str = "registry_crate";
138138const REGISTRY_SRC_TABLE : & str = "registry_src" ;
139139const GIT_DB_TABLE : & str = "git_db" ;
140140const 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 encoded_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 encoded_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 encoded_workspace_manifest_name : InternedString ,
231+ pub encoded_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 entries to insert.
1483+ workspace_db_timestamps : HashMap < WorkspaceManifestIndex , Timestamp > ,
1484+ /// New target dir entries to insert.
1485+ target_dir_db_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_db_timestamps : HashMap :: new ( ) ,
1509+ workspace_db_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_db_timestamps . is_empty ( )
1523+ && self . workspace_db_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_db_timestamps . clear ( ) ;
1534+ self . workspace_db_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 [`WorkspaceManifest`] 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,25 @@ 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+ encoded_workspace_manifest_name : workspace_src. encoded_workspace_manifest_name ,
1643+ } ;
1644+ let target_dir_db = TargetDirIndex {
1645+ encoded_target_dir_name : workspace_src. encoded_target_dir_name ,
1646+ } ;
1647+ self . target_dir_db_timestamps
1648+ . insert ( target_dir_db, timestamp) ;
1649+ self . workspace_db_timestamps . insert ( workspace_db, timestamp) ;
1650+ self . workspace_src_timestamps
1651+ . insert ( workspace_src, timestamp) ;
1652+ }
1653+
15561654 /// Saves all of the deferred information to the database.
15571655 ///
15581656 /// This will also clear the state of `self`.
@@ -1566,9 +1664,13 @@ impl DeferredGlobalLastUse {
15661664 // These must run before the ones that refer to their IDs.
15671665 self . insert_registry_index_from_cache ( & tx) ?;
15681666 self . insert_git_db_from_cache ( & tx) ?;
1667+ self . insert_target_dir_index_from_cache ( & tx) ?;
1668+ self . insert_workspace_manifest_index_from_cache ( & tx) ?;
1669+
15691670 self . insert_registry_crate_from_cache ( & tx) ?;
15701671 self . insert_registry_src_from_cache ( & tx) ?;
15711672 self . insert_git_checkout_from_cache ( & tx) ?;
1673+ self . insert_workspace_src_from_cache ( & tx) ?;
15721674 tx. commit ( ) ?;
15731675 trace ! ( target: "gc" , "last-use save complete" ) ;
15741676 Ok ( ( ) )
@@ -1632,6 +1734,32 @@ impl DeferredGlobalLastUse {
16321734 ) ;
16331735 }
16341736
1737+ // Flushes all of the `target_dir_db_timestamps` to the database,
1738+ // clearing `target_dir_index_timestamps`.
1739+ fn insert_target_dir_index_from_cache ( & mut self , conn : & Connection ) -> CargoResult < ( ) > {
1740+ insert_or_update_parent ! (
1741+ self ,
1742+ conn,
1743+ "target_dir_index" ,
1744+ target_dir_db_timestamps,
1745+ target_dir_keys,
1746+ encoded_target_dir_name
1747+ ) ;
1748+ }
1749+
1750+ // Flushes all of the `workspace_db_timestamps` to the database,
1751+ // clearing `workspace_manifest_index_timestamps`.
1752+ fn insert_workspace_manifest_index_from_cache ( & mut self , conn : & Connection ) -> CargoResult < ( ) > {
1753+ insert_or_update_parent ! (
1754+ self ,
1755+ conn,
1756+ "workspace_manifest_index" ,
1757+ workspace_db_timestamps,
1758+ workspace_manifest_keys,
1759+ encoded_workspace_manifest_name
1760+ ) ;
1761+ }
1762+
16351763 /// Flushes all of the `registry_crate_timestamps` to the database,
16361764 /// clearing `registry_index_timestamps`.
16371765 fn insert_registry_crate_from_cache ( & mut self , conn : & Connection ) -> CargoResult < ( ) > {
@@ -1707,6 +1835,80 @@ impl DeferredGlobalLastUse {
17071835 Ok ( ( ) )
17081836 }
17091837
1838+ // Flushes all of the `workspace_src_timestamps` to the database,
1839+ // clearing `workspace_src_timestamps`.
1840+ fn insert_workspace_src_from_cache ( & mut self , conn : & Connection ) -> CargoResult < ( ) > {
1841+ let workspace_src_timestamps = std:: mem:: take ( & mut self . workspace_src_timestamps ) ;
1842+ for ( workspace_src, timestamp) in workspace_src_timestamps {
1843+ let workspace_id =
1844+ self . workspace_id ( conn, workspace_src. encoded_workspace_manifest_name ) ?;
1845+ let target_dir_id = self . target_dir_id ( conn, workspace_src. encoded_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 ///
0 commit comments