Update `version_downloads.counted` last to minimize lock contention
If we defer the update to `version_downloads.counted` until immediately
before the commit, it should eliminate the contention between counting
new downloads and propagating previous downloads.
Refs:
See also:
@@ -52,11 +52,6 @@ fn collect(conn: &PgConnection, rows: &[VersionDownload]) -> QueryResult<()> {
let amt = download.downloads - download.counted;
conn.transaction::<_, diesel::result::Error, _>(|| {
- // increment the number of counted downloads
- update(version_downloads::table.find(download.id()))
- .set(version_downloads::counted.eq(version_downloads::counted + amt))
- .execute(conn)?;
-
// Update the total number of version downloads
let crate_id = update(versions::table.find(download.version_id))
.set(versions::downloads.eq(versions::downloads + amt))
@@ -68,12 +63,18 @@ fn collect(conn: &PgConnection, rows: &[VersionDownload]) -> QueryResult<()> {
.set(crates::downloads.eq(crates::downloads + amt))
.execute(conn)?;
- // Now that everything else for this crate is done, update the global counter of total
- // downloads
+ // Update the global counter of total downloads
update(metadata::table)
.set(metadata::total_downloads.eq(metadata::total_downloads + i64::from(amt)))
.execute(conn)?;
+ // Record that these downloads have been propagated to the other tables. This is done
+ // last, immediately before the transaction is committed, to minimize lock contention
+ // with counting new downloads.
+ update(version_downloads::table.find(download.id()))
+ .set(version_downloads::counted.eq(version_downloads::counted + amt))
+ .execute(conn)?;
+
Ok(())
})?;
}
