diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-10-20 19:43:31 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-10-20 19:43:45 -0400 |
commit | d1d094e4cf7d80cb2b4f68b5e8ce11aa9ebcbf3c (patch) | |
tree | 4bfc68c15afd421339f218e72a60308ccf405523 /src/backend/storage/ipc | |
parent | 790fa1fdd8bb32e2e9055dd47d76c2382c51c84a (diff) | |
download | postgresql-d1d094e4cf7d80cb2b4f68b5e8ce11aa9ebcbf3c.tar.gz postgresql-d1d094e4cf7d80cb2b4f68b5e8ce11aa9ebcbf3c.zip |
Simplify and improve ProcessStandbyHSFeedbackMessage logic.
There's no need to clamp the standby's xmin to be greater than
GetOldestXmin's result; if there were any such need this logic would be
hopelessly inadequate anyway, because it fails to account for
within-database versus cluster-wide values of GetOldestXmin. So get rid of
that, and just rely on sanity-checking that the xmin is not wrapped around
relative to the nextXid counter. Also, don't reset the walsender's xmin if
the current feedback xmin is indeed out of range; that just creates more
problems than we already had. Lastly, don't bother to take the
ProcArrayLock; there's no need to do that to set xmin.
Also improve the comments about this in GetOldestXmin itself.
Diffstat (limited to 'src/backend/storage/ipc')
-rw-r--r-- | src/backend/storage/ipc/procarray.c | 50 |
1 files changed, 31 insertions, 19 deletions
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index e7593fa2ebe..a0e36bfeb8c 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -998,22 +998,32 @@ TransactionIdIsActive(TransactionId xid) * This is also used to determine where to truncate pg_subtrans. allDbs * must be TRUE for that case, and ignoreVacuum FALSE. * - * Note: it's possible for the calculated value to move backwards on repeated - * calls. The calculated value is conservative, so that anything older is - * definitely not considered as running by anyone anymore, but the exact - * value calculated depends on a number of things. For example, if allDbs is - * TRUE and there are no transactions running in the current database, - * GetOldestXmin() returns latestCompletedXid. If a transaction begins after - * that, its xmin will include in-progress transactions in other databases - * that started earlier, so another call will return an lower value. The - * return value is also adjusted with vacuum_defer_cleanup_age, so increasing - * that setting on the fly is an easy way to have GetOldestXmin() move - * backwards. - * * Note: we include all currently running xids in the set of considered xids. * This ensures that if a just-started xact has not yet set its snapshot, * when it does set the snapshot it cannot set xmin less than what we compute. * See notes in src/backend/access/transam/README. + * + * Note: despite the above, it's possible for the calculated value to move + * backwards on repeated calls. The calculated value is conservative, so that + * anything older is definitely not considered as running by anyone anymore, + * but the exact value calculated depends on a number of things. For example, + * if allDbs is FALSE and there are no transactions running in the current + * database, GetOldestXmin() returns latestCompletedXid. If a transaction + * begins after that, its xmin will include in-progress transactions in other + * databases that started earlier, so another call will return a lower value. + * Nonetheless it is safe to vacuum a table in the current database with the + * first result. There are also replication-related effects: a walsender + * process can set its xmin based on transactions that are no longer running + * in the master but are still being replayed on the standby, thus possibly + * making the GetOldestXmin reading go backwards. In this case there is a + * possibility that we lose data that the standby would like to have, but + * there is little we can do about that --- data is only protected if the + * walsender runs continuously while queries are executed on the standby. + * (The Hot Standby code deals with such cases by failing standby queries + * that needed to access already-removed data, so there's no integrity bug.) + * The return value is also adjusted with vacuum_defer_cleanup_age, so + * increasing that setting on the fly is another easy way to make + * GetOldestXmin() move backwards, with no consequences for data integrity. */ TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum) @@ -1046,7 +1056,7 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum) if (allDbs || proc->databaseId == MyDatabaseId || - proc->databaseId == 0) /* include WalSender */ + proc->databaseId == 0) /* always include WalSender */ { /* Fetch xid just once - see GetNewTransactionId */ TransactionId xid = proc->xid; @@ -1092,16 +1102,18 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum) LWLockRelease(ProcArrayLock); /* - * Compute the cutoff XID, being careful not to generate a "permanent" - * XID. We need do this only on the primary, never on standby. + * Compute the cutoff XID by subtracting vacuum_defer_cleanup_age, + * being careful not to generate a "permanent" XID. * * vacuum_defer_cleanup_age provides some additional "slop" for the * benefit of hot standby queries on slave servers. This is quick and * dirty, and perhaps not all that useful unless the master has a - * predictable transaction rate, but it's what we've got. Note that - * we are assuming vacuum_defer_cleanup_age isn't large enough to - * cause wraparound --- so guc.c should limit it to no more than the - * xidStopLimit threshold in varsup.c. + * predictable transaction rate, but it offers some protection when + * there's no walsender connection. Note that we are assuming + * vacuum_defer_cleanup_age isn't large enough to cause wraparound --- + * so guc.c should limit it to no more than the xidStopLimit threshold + * in varsup.c. Also note that we intentionally don't apply + * vacuum_defer_cleanup_age on standby servers. */ result -= vacuum_defer_cleanup_age; if (!TransactionIdIsNormal(result)) |