aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2016-05-24 15:47:51 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2016-05-24 15:47:51 -0400
commit5551dac59c0601b49d57a3f897fb0a6d581e58ac (patch)
tree16114f6cba862c73b2e77ad7efa0f948b84a8178 /src
parentfe1731fca27008836f2208f4be8c22acf8ec1f67 (diff)
downloadpostgresql-5551dac59c0601b49d57a3f897fb0a6d581e58ac.tar.gz
postgresql-5551dac59c0601b49d57a3f897fb0a6d581e58ac.zip
Fetch XIDs atomically during vac_truncate_clog().
Because vac_update_datfrozenxid() updates datfrozenxid and datminmxid in-place, it's unsafe to assume that successive reads of those values will give consistent results. Fetch each one just once to ensure sane behavior in the minimum calculation. Noted while reviewing Alexander Korotkov's patch in the same area. Discussion: <8564.1464116473@sss.pgh.pa.us>
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/vacuum.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 15c36eca94f..6820b70229f 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -797,6 +797,12 @@ vac_truncate_clog(TransactionId frozenXID)
/*
* Scan pg_database to compute the minimum datfrozenxid
*
+ * Since vac_update_datfrozenxid updates datfrozenxid in-place,
+ * the values could change while we look at them. Fetch each one just
+ * once to ensure sane behavior of the comparison logic. (Here, as in
+ * many other places, we assume that fetching or updating an XID in shared
+ * storage is atomic.)
+ *
* Note: we need not worry about a race condition with new entries being
* inserted by CREATE DATABASE. Any such entry will have a copy of some
* existing DB's datfrozenxid, and that source DB cannot be ours because
@@ -812,15 +818,16 @@ vac_truncate_clog(TransactionId frozenXID)
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
- Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
+ volatile FormData_pg_database *dbform = (Form_pg_database) GETSTRUCT(tuple);
+ TransactionId datfrozenxid = dbform->datfrozenxid;
- Assert(TransactionIdIsNormal(dbform->datfrozenxid));
+ Assert(TransactionIdIsNormal(datfrozenxid));
- if (TransactionIdPrecedes(nextXID, dbform->datfrozenxid))
+ if (TransactionIdPrecedes(nextXID, datfrozenxid))
frozenAlreadyWrapped = true;
- else if (TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
+ else if (TransactionIdPrecedes(datfrozenxid, frozenXID))
{
- frozenXID = dbform->datfrozenxid;
+ frozenXID = datfrozenxid;
oldest_datoid = HeapTupleGetOid(tuple);
}
}