mirror of
https://github.com/postgres/postgres.git
synced 2025-08-21 10:42:50 +03:00
Prevent GIN deleted pages from being reclaimed too early
When GIN vacuum deletes a posting tree page, it assumes that no concurrent searchers can access it, thanks to ginStepRight() locking two pages at once. However, since 9.4 searches can skip parts of posting trees descending from the root. That leads to the risk that page is deleted and reclaimed before concurrent search can access it. This commit prevents the risk of above by waiting for every transaction, which might wait to reference this page, to finish. Due to binary compatibility we can't change GinPageOpaqueData to store corresponding transaction id. Instead we reuse page header pd_prune_xid field, which is unused in index pages. Discussion: https://postgr.es/m/31a702a.14dd.166c1366ac1.Coremail.chjischj%40163.com Author: Andrey Borodin, Alexander Korotkov Reviewed-by: Alexander Korotkov Backpatch-through: 9.4
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#ifndef GINBLOCK_H
|
||||
#define GINBLOCK_H
|
||||
|
||||
#include "access/transam.h"
|
||||
#include "storage/block.h"
|
||||
#include "storage/itemptr.h"
|
||||
#include "storage/off.h"
|
||||
@@ -127,6 +128,15 @@ typedef struct GinMetaPageData
|
||||
|
||||
#define GinPageRightMost(page) ( GinPageGetOpaque(page)->rightlink == InvalidBlockNumber)
|
||||
|
||||
/*
|
||||
* We should reclaim deleted page only once every transaction started before
|
||||
* its deletion is over.
|
||||
*/
|
||||
#define GinPageGetDeleteXid(page) ( ((PageHeader) (page))->pd_prune_xid )
|
||||
#define GinPageSetDeleteXid(page, xid) ( ((PageHeader) (page))->pd_prune_xid = xid)
|
||||
#define GinPageIsRecyclable(page) ( PageIsNew(page) || (GinPageIsDeleted(page) \
|
||||
&& TransactionIdPrecedes(GinPageGetDeleteXid(page), RecentGlobalXmin)))
|
||||
|
||||
/*
|
||||
* We use our own ItemPointerGet(BlockNumber|OffsetNumber)
|
||||
* to avoid Asserts, since sometimes the ip_posid isn't "valid"
|
||||
|
@@ -158,6 +158,7 @@ typedef struct ginxlogDeletePage
|
||||
{
|
||||
OffsetNumber parentOffset;
|
||||
BlockNumber rightLink;
|
||||
TransactionId deleteXid; /* last Xid which could see this page in scan */
|
||||
} ginxlogDeletePage;
|
||||
|
||||
#define XLOG_GIN_UPDATE_META_PAGE 0x60
|
||||
|
Reference in New Issue
Block a user