Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d53a566

Browse files
committed
Initialize the minimum frozen Xid in vac_update_datfrozenxid using
GetOldestXmin() instead of RecentGlobalXmin; this is safer because we do not depend on the latter being correctly set elsewhere, and while it is more expensive, this code path is not performance-critical. This is a real risk for autovacuum, because it can execute whole cycles without doing a single vacuum, which would mean that RecentGlobalXmin would stay at its initialization value, FirstNormalTransactionId, causing a bogus value to be inserted in pg_database. This bug could explain some recent reports of failure to truncate pg_clog. At the same time, change the initialization of RecentGlobalXmin to InvalidTransactionId, and ensure that it's set to something else whenever it's going to be used. Using it as FirstNormalTransactionId in HOT page pruning could incur in data loss. InitPostgres takes care of setting it to a valid value, but the extra checks are there to prevent "special" backends from behaving in unusual ways. Per Tom Lane's detailed problem dissection in 29544.1221061979@sss.pgh.pa.us
1 parent b864601 commit d53a566

File tree

6 files changed

+43
-35
lines changed

6 files changed

+43
-35
lines changed

src/backend/access/heap/heapam.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.262 2008/08/11 11:05:10 heikki Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.263 2008/09/11 14:01:09 alvherre Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
@@ -219,6 +219,7 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
219219
/*
220220
* Prune and repair fragmentation for the whole page, if possible.
221221
*/
222+
Assert(TransactionIdIsValid(RecentGlobalXmin));
222223
heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);
223224

224225
/*
@@ -1469,6 +1470,8 @@ heap_hot_search_buffer(ItemPointer tid, Buffer buffer, Snapshot snapshot,
14691470
if (all_dead)
14701471
*all_dead = true;
14711472

1473+
Assert(TransactionIdIsValid(RecentGlobalXmin));
1474+
14721475
Assert(ItemPointerGetBlockNumber(tid) == BufferGetBlockNumber(buffer));
14731476
offnum = ItemPointerGetOffsetNumber(tid);
14741477
at_chain_start = true;

src/backend/access/index/indexam.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.109 2008/06/19 00:46:03 alvherre Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.110 2008/09/11 14:01:09 alvherre Exp $
1212
*
1313
* INTERFACE ROUTINES
1414
* index_open - open an index relation by relation OID
@@ -419,6 +419,8 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
419419
SCAN_CHECKS;
420420
GET_SCAN_PROCEDURE(amgettuple);
421421

422+
Assert(TransactionIdIsValid(RecentGlobalXmin));
423+
422424
/*
423425
* We always reset xs_hot_dead; if we are here then either we are just
424426
* starting the scan, or we previously returned a visible tuple, and in

src/backend/commands/vacuum.c

+19-28
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.376 2008/08/13 00:07:50 alvherre Exp $
16+
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.377 2008/09/11 14:01:09 alvherre Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -790,14 +790,12 @@ vac_update_datfrozenxid(void)
790790
bool dirty = false;
791791

792792
/*
793-
* Initialize the "min" calculation with RecentGlobalXmin. Any
794-
* not-yet-committed pg_class entries for new tables must have
795-
* relfrozenxid at least this high, because any other open xact must have
796-
* RecentXmin >= its PGPROC.xmin >= our RecentGlobalXmin; see
797-
* AddNewRelationTuple(). So we cannot produce a wrong minimum by
798-
* starting with this.
793+
* Initialize the "min" calculation with GetOldestXmin, which is a
794+
* reasonable approximation to the minimum relfrozenxid for not-yet-
795+
* committed pg_class entries for new tables; see AddNewRelationTuple().
796+
* Se we cannot produce a wrong minimum by starting with this.
799797
*/
800-
newFrozenXid = RecentGlobalXmin;
798+
newFrozenXid = GetOldestXmin(true, true);
801799

802800
/*
803801
* We must seqscan pg_class to find the minimum Xid, because there is no
@@ -990,18 +988,16 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
990988
/* Begin a transaction for vacuuming this relation */
991989
StartTransactionCommand();
992990

993-
if (vacstmt->full)
994-
{
995-
/* functions in indexes may want a snapshot set */
996-
PushActiveSnapshot(GetTransactionSnapshot());
997-
}
998-
else
991+
/*
992+
* Functions in indexes may want a snapshot set. Also, setting
993+
* a snapshot ensures that RecentGlobalXmin is kept truly recent.
994+
*/
995+
PushActiveSnapshot(GetTransactionSnapshot());
996+
997+
if (!vacstmt->full)
999998
{
1000999
/*
1001-
* During a lazy VACUUM we do not run any user-supplied functions, and
1002-
* so it should be safe to not create a transaction snapshot.
1003-
*
1004-
* We can furthermore set the PROC_IN_VACUUM flag, which lets other
1000+
* In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets other
10051001
* concurrent VACUUMs know that they can ignore this one while
10061002
* determining their OldestXmin. (The reason we don't set it during a
10071003
* full VACUUM is exactly that we may have to run user- defined
@@ -1050,8 +1046,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
10501046

10511047
if (!onerel)
10521048
{
1053-
if (vacstmt->full)
1054-
PopActiveSnapshot();
1049+
PopActiveSnapshot();
10551050
CommitTransactionCommand();
10561051
return;
10571052
}
@@ -1082,8 +1077,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
10821077
(errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
10831078
RelationGetRelationName(onerel))));
10841079
relation_close(onerel, lmode);
1085-
if (vacstmt->full)
1086-
PopActiveSnapshot();
1080+
PopActiveSnapshot();
10871081
CommitTransactionCommand();
10881082
return;
10891083
}
@@ -1099,8 +1093,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
10991093
(errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables",
11001094
RelationGetRelationName(onerel))));
11011095
relation_close(onerel, lmode);
1102-
if (vacstmt->full)
1103-
PopActiveSnapshot();
1096+
PopActiveSnapshot();
11041097
CommitTransactionCommand();
11051098
return;
11061099
}
@@ -1115,8 +1108,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
11151108
if (isOtherTempNamespace(RelationGetNamespace(onerel)))
11161109
{
11171110
relation_close(onerel, lmode);
1118-
if (vacstmt->full)
1119-
PopActiveSnapshot();
1111+
PopActiveSnapshot();
11201112
CommitTransactionCommand();
11211113
return;
11221114
}
@@ -1168,8 +1160,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
11681160
/*
11691161
* Complete the transaction and free all temporary memory used.
11701162
*/
1171-
if (vacstmt->full)
1172-
PopActiveSnapshot();
1163+
PopActiveSnapshot();
11731164
CommitTransactionCommand();
11741165

11751166
/*

src/backend/executor/nodeBitmapHeapscan.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
*
2222
*
2323
* IDENTIFICATION
24-
* $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.29 2008/06/19 00:46:04 alvherre Exp $
24+
* $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.30 2008/09/11 14:01:09 alvherre Exp $
2525
*
2626
*-------------------------------------------------------------------------
2727
*/
@@ -37,6 +37,7 @@
3737

3838
#include "access/heapam.h"
3939
#include "access/relscan.h"
40+
#include "access/transam.h"
4041
#include "executor/execdebug.h"
4142
#include "executor/nodeBitmapHeapscan.h"
4243
#include "pgstat.h"
@@ -262,6 +263,7 @@ bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
262263
/*
263264
* Prune and repair fragmentation for the whole page, if possible.
264265
*/
266+
Assert(TransactionIdIsValid(RecentGlobalXmin));
265267
heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);
266268

267269
/*

src/backend/utils/init/postinit.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.184 2008/05/12 00:00:52 alvherre Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.185 2008/09/11 14:01:09 alvherre Exp $
1212
*
1313
*
1414
*-------------------------------------------------------------------------
@@ -47,6 +47,7 @@
4747
#include "utils/plancache.h"
4848
#include "utils/portal.h"
4949
#include "utils/relcache.h"
50+
#include "utils/snapmgr.h"
5051
#include "utils/syscache.h"
5152
#include "utils/tqual.h"
5253

@@ -461,10 +462,15 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
461462
on_shmem_exit(ShutdownPostgres, 0);
462463

463464
/*
464-
* Start a new transaction here before first access to db
465+
* Start a new transaction here before first access to db, and get a
466+
* snapshot. We don't have a use for the snapshot itself, but we're
467+
* interested in the secondary effect that it sets RecentGlobalXmin.
465468
*/
466469
if (!bootstrap)
470+
{
467471
StartTransactionCommand();
472+
(void) GetTransactionSnapshot();
473+
}
468474

469475
/*
470476
* Now that we have a transaction, we can take locks. Take a writer's

src/backend/utils/time/snapmgr.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* Portions Copyright (c) 1994, Regents of the University of California
2323
*
2424
* IDENTIFICATION
25-
* $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.4 2008/07/11 02:10:14 alvherre Exp $
25+
* $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.5 2008/09/11 14:01:10 alvherre Exp $
2626
*
2727
*-------------------------------------------------------------------------
2828
*/
@@ -59,10 +59,14 @@ static Snapshot SecondarySnapshot = NULL;
5959
* These are updated by GetSnapshotData. We initialize them this way
6060
* for the convenience of TransactionIdIsInProgress: even in bootstrap
6161
* mode, we don't want it to say that BootstrapTransactionId is in progress.
62+
*
63+
* RecentGlobalXmin is initialized to InvalidTransactionId, to ensure that no
64+
* one tries to use a stale value. Readers should ensure that it has been set
65+
* to something else before using it.
6266
*/
6367
TransactionId TransactionXmin = FirstNormalTransactionId;
6468
TransactionId RecentXmin = FirstNormalTransactionId;
65-
TransactionId RecentGlobalXmin = FirstNormalTransactionId;
69+
TransactionId RecentGlobalXmin = InvalidTransactionId;
6670

6771
/*
6872
* Elements of the list of registered snapshots.

0 commit comments

Comments
 (0)