@@ -138,6 +138,8 @@ const REGISTRY_CRATE_TABLE: &str = "registry_crate";
138
138
const REGISTRY_SRC_TABLE : & str = "registry_src" ;
139
139
const GIT_DB_TABLE : & str = "git_db" ;
140
140
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" ;
141
143
142
144
/// How often timestamps will be updated.
143
145
///
@@ -209,6 +211,26 @@ pub struct GitCheckout {
209
211
pub size : Option < u64 > ,
210
212
}
211
213
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
+
212
234
/// Filesystem paths in the global cache.
213
235
///
214
236
/// Accessing these assumes a lock has already been acquired.
@@ -303,6 +325,30 @@ fn migrations() -> Vec<Migration> {
303
325
) ?;
304
326
Ok ( ( ) )
305
327
} ) ,
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
+ )
306
352
]
307
353
}
308
354
@@ -1413,7 +1459,16 @@ pub struct DeferredGlobalLastUse {
1413
1459
/// The key is the git db name (which is its directory name) and the value
1414
1460
/// is the `id` in the `git_db` table.
1415
1461
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 > ,
1417
1472
/// New registry index entries to insert.
1418
1473
registry_index_timestamps : HashMap < RegistryIndex , Timestamp > ,
1419
1474
/// New registry `.crate` entries to insert.
@@ -1424,6 +1479,12 @@ pub struct DeferredGlobalLastUse {
1424
1479
git_db_timestamps : HashMap < GitDb , Timestamp > ,
1425
1480
/// New git checkout entries to insert.
1426
1481
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 > ,
1427
1488
/// This is used so that a warning about failing to update the database is
1428
1489
/// only displayed once.
1429
1490
save_err_has_warned : bool ,
@@ -1437,11 +1498,16 @@ impl DeferredGlobalLastUse {
1437
1498
DeferredGlobalLastUse {
1438
1499
registry_keys : HashMap :: new ( ) ,
1439
1500
git_keys : HashMap :: new ( ) ,
1501
+ workspace_manifest_keys : HashMap :: new ( ) ,
1502
+ target_dir_keys : HashMap :: new ( ) ,
1440
1503
registry_index_timestamps : HashMap :: new ( ) ,
1441
1504
registry_crate_timestamps : HashMap :: new ( ) ,
1442
1505
registry_src_timestamps : HashMap :: new ( ) ,
1443
1506
git_db_timestamps : HashMap :: new ( ) ,
1444
1507
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 ( ) ,
1445
1511
save_err_has_warned : false ,
1446
1512
now : now ( ) ,
1447
1513
}
@@ -1453,6 +1519,9 @@ impl DeferredGlobalLastUse {
1453
1519
&& self . registry_src_timestamps . is_empty ( )
1454
1520
&& self . git_db_timestamps . is_empty ( )
1455
1521
&& 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 ( )
1456
1525
}
1457
1526
1458
1527
fn clear ( & mut self ) {
@@ -1461,6 +1530,9 @@ impl DeferredGlobalLastUse {
1461
1530
self . registry_src_timestamps . clear ( ) ;
1462
1531
self . git_db_timestamps . clear ( ) ;
1463
1532
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 ( ) ;
1464
1536
}
1465
1537
1466
1538
/// Indicates the given [`RegistryIndex`] has been used right now.
@@ -1489,6 +1561,13 @@ impl DeferredGlobalLastUse {
1489
1561
self . mark_git_checkout_used_stamp ( git_checkout, None ) ;
1490
1562
}
1491
1563
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
+
1492
1571
/// Indicates the given [`RegistryIndex`] has been used with the given
1493
1572
/// time (or "now" if `None`).
1494
1573
pub fn mark_registry_index_used_stamp (
@@ -1553,6 +1632,26 @@ impl DeferredGlobalLastUse {
1553
1632
self . git_checkout_timestamps . insert ( git_checkout, timestamp) ;
1554
1633
}
1555
1634
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
+
1556
1655
/// Saves all of the deferred information to the database.
1557
1656
///
1558
1657
/// This will also clear the state of `self`.
@@ -1566,9 +1665,13 @@ impl DeferredGlobalLastUse {
1566
1665
// These must run before the ones that refer to their IDs.
1567
1666
self . insert_registry_index_from_cache ( & tx) ?;
1568
1667
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
+
1569
1671
self . insert_registry_crate_from_cache ( & tx) ?;
1570
1672
self . insert_registry_src_from_cache ( & tx) ?;
1571
1673
self . insert_git_checkout_from_cache ( & tx) ?;
1674
+ self . insert_workspace_src_from_cache ( & tx) ?;
1572
1675
tx. commit ( ) ?;
1573
1676
trace ! ( target: "gc" , "last-use save complete" ) ;
1574
1677
Ok ( ( ) )
@@ -1632,6 +1735,32 @@ impl DeferredGlobalLastUse {
1632
1735
) ;
1633
1736
}
1634
1737
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
+
1635
1764
/// Flushes all of the `registry_crate_timestamps` to the database,
1636
1765
/// clearing `registry_index_timestamps`.
1637
1766
fn insert_registry_crate_from_cache ( & mut self , conn : & Connection ) -> CargoResult < ( ) > {
@@ -1707,6 +1836,79 @@ impl DeferredGlobalLastUse {
1707
1836
Ok ( ( ) )
1708
1837
}
1709
1838
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
+
1710
1912
/// Returns the numeric ID of the registry, either fetching from the local
1711
1913
/// cache, or getting it from the database.
1712
1914
///
0 commit comments