]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Avoid early reuse of btree pages, causing incorrect query results.
authorSimon Riggs <simon@2ndQuadrant.com>
Fri, 1 Jun 2012 11:59:54 +0000 (12:59 +0100)
committerSimon Riggs <simon@2ndQuadrant.com>
Fri, 1 Jun 2012 11:59:54 +0000 (12:59 +0100)
When we allowed read-only transactions to skip assigning XIDs
we introduced the possibility that a fully deleted btree page
could be reused. This broke the index link sequence which could
then lead to indexscans silently returning fewer rows than would
have been correct. The actual incidence of silent errors from
this is thought to be very low because of the exact workload
required and locking pre-conditions. Fix is to remove pages only
if index page opaque->btpo.xact precedes RecentGlobalXmin.

Noah Misch, reviewed and backpatched by Simon Riggs

src/backend/access/nbtree/README
src/backend/access/nbtree/nbtpage.c

index af19525cdc30fc8d293452cc668143270cbe9279..32cdba1eb6966706d2a00f4e6e1f5ed9cae6d65d 100644 (file)
@@ -258,13 +258,15 @@ we need to be sure we don't miss or re-scan any items.
 
 A deleted page can only be reclaimed once there is no scan or search that
 has a reference to it; until then, it must stay in place with its
-right-link undisturbed.  We implement this by waiting until all
-transactions that were running at the time of deletion are dead; which is
+right-link undisturbed.  We implement this by waiting until all active
+snapshots and registered snapshots as of the deletion are gone; which is
 overly strong, but is simple to implement within Postgres.  When marked
 dead, a deleted page is labeled with the next-transaction counter value.
 VACUUM can reclaim the page for re-use when this transaction number is
-older than the oldest open transaction.  (NOTE: VACUUM FULL can reclaim
-such pages immediately.)
+older than RecentGlobalXmin.  As collateral damage, this implementation
+also waits for running XIDs with no snapshots and for snapshots taken
+until the next transaction to allocate an XID commits.
+(NOTE: VACUUM FULL can reclaim such pages immediately.)
 
 Reclaiming a page doesn't actually change its state on disk --- we simply
 record it in the shared-memory free space map, from which it will be
index a89e3ba84f472cfbf1a155f10733aa6e3e89716b..0e37a8a0af9441d4f15757b12fe3701737ea98c8 100644 (file)
@@ -633,7 +633,7 @@ _bt_page_recyclable(Page page)
         */
        opaque = (BTPageOpaque) PageGetSpecialPointer(page);
        if (P_ISDELETED(opaque) &&
-               TransactionIdPrecedesOrEquals(opaque->btpo.xact, RecentXmin))
+               TransactionIdPrecedes(opaque->btpo.xact, RecentGlobalXmin))
                return true;
        return false;
 }