Skip to content

Commit 309473f

Browse files
committed
Auto merge of #12958 - ehuss:fix-last-use-now-race, r=epage
Fix non-deterministic behavior in last-use repopulation This fixes an issue where some last-use tests would fail sporadically because the code that populates missing database entries was using the current time as it was iterating over the files. If the clock happened to roll over while it was iterating, then different files would get different timestamps non-deterministically. The fix is to snapshot the current time when it starts, and reuse that time while repopulating. I didn't do this originally just because I was reluctant to pass yet another argument around. However, it seems like this is necessary. In #12634, we discussed other options such as having some kind of process-global "now" snapshot (like in `Config`), but I'm reluctant to do that because I am uneasy dealing with long-lived programs, or handling before/after relationships (like different parts of the code not considering that all timestamps might be equal). It might be something that we could consider in the future, but I'm not sure I want to try right now.
2 parents 9a1b092 + 7637016 commit 309473f

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

src/cargo/core/global_cache_tracker.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ impl GlobalCacheTracker {
567567
// TODO: Investigate how slow this might be.
568568
Self::sync_db_with_files(
569569
&tx,
570+
now,
570571
config,
571572
&base,
572573
gc_opts.is_download_cache_size_set(),
@@ -695,6 +696,7 @@ impl GlobalCacheTracker {
695696
/// caller can delete them.
696697
fn sync_db_with_files(
697698
conn: &Connection,
699+
now: Timestamp,
698700
config: &Config,
699701
base: &BasePaths,
700702
sync_size: bool,
@@ -703,8 +705,8 @@ impl GlobalCacheTracker {
703705
let _p = crate::util::profile::start("global cache db sync");
704706
debug!(target: "gc", "starting db sync");
705707
// For registry_index and git_db, add anything that is missing in the db.
706-
Self::update_parent_for_missing_from_db(conn, REGISTRY_INDEX_TABLE, &base.index)?;
707-
Self::update_parent_for_missing_from_db(conn, GIT_DB_TABLE, &base.git_db)?;
708+
Self::update_parent_for_missing_from_db(conn, now, REGISTRY_INDEX_TABLE, &base.index)?;
709+
Self::update_parent_for_missing_from_db(conn, now, GIT_DB_TABLE, &base.git_db)?;
708710

709711
// For registry_crate, registry_src, and git_checkout, remove anything
710712
// from the db that isn't on disk.
@@ -746,9 +748,10 @@ impl GlobalCacheTracker {
746748

747749
// For registry_crate, registry_src, and git_checkout, add anything
748750
// that is missing in the db.
749-
Self::populate_untracked_crate(conn, &base.crate_dir)?;
751+
Self::populate_untracked_crate(conn, now, &base.crate_dir)?;
750752
Self::populate_untracked(
751753
conn,
754+
now,
752755
config,
753756
REGISTRY_INDEX_TABLE,
754757
"registry_id",
@@ -758,6 +761,7 @@ impl GlobalCacheTracker {
758761
)?;
759762
Self::populate_untracked(
760763
conn,
764+
now,
761765
config,
762766
GIT_DB_TABLE,
763767
"git_id",
@@ -791,6 +795,7 @@ impl GlobalCacheTracker {
791795
/// For parent tables, add any entries that are on disk but aren't tracked in the db.
792796
fn update_parent_for_missing_from_db(
793797
conn: &Connection,
798+
now: Timestamp,
794799
parent_table_name: &str,
795800
base_path: &Path,
796801
) -> CargoResult<()> {
@@ -805,7 +810,6 @@ impl GlobalCacheTracker {
805810
VALUES (?1, ?2)
806811
ON CONFLICT DO NOTHING",
807812
))?;
808-
let now = now();
809813
for name in names {
810814
stmt.execute(params![name, now])?;
811815
}
@@ -882,15 +886,18 @@ impl GlobalCacheTracker {
882886
/// Updates the database to add any `.crate` files that are currently
883887
/// not tracked (such as when they are downloaded by an older version of
884888
/// cargo).
885-
fn populate_untracked_crate(conn: &Connection, base_path: &Path) -> CargoResult<()> {
889+
fn populate_untracked_crate(
890+
conn: &Connection,
891+
now: Timestamp,
892+
base_path: &Path,
893+
) -> CargoResult<()> {
886894
let _p = crate::util::profile::start("populate untracked crate");
887895
trace!(target: "gc", "populating untracked crate files");
888896
let mut insert_stmt = conn.prepare_cached(
889897
"INSERT INTO registry_crate (registry_id, name, size, timestamp)
890898
VALUES (?1, ?2, ?3, ?4)
891899
ON CONFLICT DO NOTHING",
892900
)?;
893-
let now = now();
894901
let index_names = Self::names_from(&base_path)?;
895902
for index_name in index_names {
896903
let Some(id) = Self::id_from_name(conn, REGISTRY_INDEX_TABLE, &index_name)? else {
@@ -915,6 +922,7 @@ impl GlobalCacheTracker {
915922
/// (such as when they are downloaded by an older version of cargo).
916923
fn populate_untracked(
917924
conn: &Connection,
925+
now: Timestamp,
918926
config: &Config,
919927
id_table_name: &str,
920928
id_column_name: &str,
@@ -940,7 +948,6 @@ impl GlobalCacheTracker {
940948
ON CONFLICT DO NOTHING",
941949
))?;
942950
let mut progress = Progress::with_style("Scanning", ProgressStyle::Ratio, config);
943-
let now = now();
944951
// Compute the size of any directory not in the database.
945952
for id_name in id_names {
946953
let Some(id) = Self::id_from_name(conn, id_table_name, &id_name)? else {

0 commit comments

Comments
 (0)