Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hCdTl-0001Yy-EO for pgsql-hackers@arkaria.postgresql.org; Sat, 06 Apr 2019 05:02:58 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1hCdTk-0004oG-40 for pgsql-hackers@arkaria.postgresql.org; Sat, 06 Apr 2019 05:02:56 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hCdTj-0004o8-0N for pgsql-hackers@lists.postgresql.org; Sat, 06 Apr 2019 05:02:55 +0000 Received: from out2-smtp.messagingengine.com ([66.111.4.26]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hCdTc-0000Hk-MN for pgsql-hackers@postgresql.org; Sat, 06 Apr 2019 05:02:52 +0000 Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id 5146021EAB; Sat, 6 Apr 2019 01:02:46 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Sat, 06 Apr 2019 01:02:46 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=anarazel.de; h= date:from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm1; bh=dLE1fki+9SRgSuM5sdlWx/KlOyw PxV5yxA7NtCLy184=; b=5nDkyAq6PoTxq9kv969OzDU290tAKCKYeYPtGp/yPcL PxKciM0N4tn6qiE8aooT9tVokut9UKxwRU5S0JmJ2Zk06uNQvdA3YEX7yUd3stKa dMaAbGFO0cj83vtITpMlt16rcjkmo/sskTEjKYsL8l/IyR408NFVlUnVMW/IPj4i bxad5n0x19Rhob7GTinGYVPc/ljH7Qc4HIonuLKiRZvoIcyQ2a1umqhhBlUKPKhC 5Hi7WmA/a4K9L0atXbIONtCp/J6iCRTVy6PwP2CGO8ZJSVoODIRUq6vtw+3TQJiI GDHFLwmqwZ9QwUNR77Z8sYMCz/vuYnNU3LxaVw5dH4w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=dLE1fk i+9SRgSuM5sdlWx/KlOywPxV5yxA7NtCLy184=; b=XBUqNzppF0DY8VO7bk7JJX qKoHyYDadfrnSeDkzn5q0uxIMRsgojUQMFB4h29g6/ccyPdX+wpLvAk26spM4yQ0 7+QAFh+04gDNb+gyJmWMgmhG/+n0CdFxU2ycY6JFqhuwz7INXEzMRhTPaY2n/B1M YqAMk1JDkz2u5cKxz+hjrqY7AWU4gDs7UmF4PID5AtUhDQVz1PDYCoDTjM6FwX34 94sNGEncfaReqP48h3YD9zniB1l3zb6nqgKHmgA1adxBDlepAl0HrOIby57iCafj uoIuRP/k3kCnXBvKCZxTUhRVyP5y7TsoGoHwIJBjChbAJ7rlmcHZqTW63cYUFnzA == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduuddrtdekgdelkeculddtuddrgedutddrtddtmd cutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivg hnthhsucdlqddutddtmdenucfjughrpeffhffvuffkfhggtggujgesmhdtreertddtvden ucfhrhhomheptehnughrvghsucfhrhgvuhhnugcuoegrnhgurhgvshesrghnrghrrgiivg hlrdguvgeqnecukfhppeelkedrvddutddrudegtddrudejudenucfrrghrrghmpehmrghi lhhfrhhomheprghnughrvghssegrnhgrrhgriigvlhdruggvnecuvehluhhsthgvrhfuih iivgeptd X-ME-Proxy: Received: from intern.anarazel.de (c-98-210-140-171.hsd1.ca.comcast.net [98.210.140.171]) by mail.messagingengine.com (Postfix) with ESMTPA id 1D02DE40E3; Sat, 6 Apr 2019 01:02:45 -0400 (EDT) Date: Fri, 5 Apr 2019 22:02:43 -0700 From: Andres Freund To: Alexander Korotkov Cc: pgsql-hackers , Teodor Sigaev , Anastasia Lubennikova Subject: Re: gist microvacuum doesn't appear to care about hot standby? Message-ID: <20190406050243.bszosdg4buvabfrt@alap3.anarazel.de> References: <20181212224524.scafnlyjindmrbe6@alap3.anarazel.de> <20181216222501.mevn443eap57trfh@alap3.anarazel.de> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="yldqtt4fnfhymb2r" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --yldqtt4fnfhymb2r Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, On 2018-12-21 02:40:18 +0300, Alexander Korotkov wrote: > On Thu, Dec 20, 2018 at 1:41 AM Alexander Korotkov > wrote: > > Please, find attached two patches I'm going to commit: for master and > > for backpatching. > > So, pushed. I noticed that I didn't adapt this in commit 558a9165e081d1936573e5a7d576f5febd7fb55a Author: Andres Freund Date: 2019-03-26 14:41:46 -0700 Compute XID horizon for page level index vacuum on primary. Attached you thus can find the conversion of gist to the new logic for computing the horizon. Any comments? Greetings, Andres Freund --yldqtt4fnfhymb2r Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0001-Convert-gist-to-compute-page-level-xid-horizon-on-pr.patch" From f12b1105e4a0c356083a8dbae81e6a2c11da7bbe Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Fri, 5 Apr 2019 22:01:51 -0700 Subject: [PATCH] Convert gist to compute page level xid horizon on primary. Author: Reviewed-By: Discussion: https://postgr.es/m/ Backpatch: --- src/backend/access/gist/gist.c | 8 +- src/backend/access/gist/gistxlog.c | 153 +------------------------ src/backend/access/rmgrdesc/gistdesc.c | 7 +- src/include/access/gist_private.h | 2 +- src/include/access/gistxlog.h | 3 +- src/include/access/xlog_internal.h | 2 +- 6 files changed, 18 insertions(+), 157 deletions(-) diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 2db790c840c..769aca42e3b 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -1616,6 +1616,7 @@ gistprunepage(Relation rel, Page page, Buffer buffer, Relation heapRel) int ndeletable = 0; OffsetNumber offnum, maxoff; + TransactionId latestRemovedXid = InvalidTransactionId; Assert(GistPageIsLeaf(page)); @@ -1634,6 +1635,11 @@ gistprunepage(Relation rel, Page page, Buffer buffer, Relation heapRel) deletable[ndeletable++] = offnum; } + if (XLogStandbyInfoActive() && RelationNeedsWAL(rel)) + latestRemovedXid = + index_compute_xid_horizon_for_tuples(rel, heapRel, buffer, + deletable, ndeletable); + if (ndeletable > 0) { START_CRIT_SECTION(); @@ -1658,7 +1664,7 @@ gistprunepage(Relation rel, Page page, Buffer buffer, Relation heapRel) recptr = gistXLogDelete(buffer, deletable, ndeletable, - heapRel->rd_node); + latestRemovedXid); PageSetLSN(page, recptr); } diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c index 4fb1855e890..503db34d863 100644 --- a/src/backend/access/gist/gistxlog.c +++ b/src/backend/access/gist/gistxlog.c @@ -165,152 +165,6 @@ gistRedoPageUpdateRecord(XLogReaderState *record) UnlockReleaseBuffer(buffer); } -/* - * Get the latestRemovedXid from the heap pages pointed at by the index - * tuples being deleted. See also btree_xlog_delete_get_latestRemovedXid, - * on which this function is based. - */ -static TransactionId -gistRedoDeleteRecordGetLatestRemovedXid(XLogReaderState *record) -{ - gistxlogDelete *xlrec = (gistxlogDelete *) XLogRecGetData(record); - OffsetNumber *todelete; - Buffer ibuffer, - hbuffer; - Page ipage, - hpage; - RelFileNode rnode; - BlockNumber blkno; - ItemId iitemid, - hitemid; - IndexTuple itup; - HeapTupleHeader htuphdr; - BlockNumber hblkno; - OffsetNumber hoffnum; - TransactionId latestRemovedXid = InvalidTransactionId; - int i; - - /* - * If there's nothing running on the standby we don't need to derive a - * full latestRemovedXid value, so use a fast path out of here. This - * returns InvalidTransactionId, and so will conflict with all HS - * transactions; but since we just worked out that that's zero people, - * it's OK. - * - * XXX There is a race condition here, which is that a new backend might - * start just after we look. If so, it cannot need to conflict, but this - * coding will result in throwing a conflict anyway. - */ - if (CountDBBackends(InvalidOid) == 0) - return latestRemovedXid; - - /* - * In what follows, we have to examine the previous state of the index - * page, as well as the heap page(s) it points to. This is only valid if - * WAL replay has reached a consistent database state; which means that - * the preceding check is not just an optimization, but is *necessary*. We - * won't have let in any user sessions before we reach consistency. - */ - if (!reachedConsistency) - elog(PANIC, "gistRedoDeleteRecordGetLatestRemovedXid: cannot operate with inconsistent data"); - - /* - * Get index page. If the DB is consistent, this should not fail, nor - * should any of the heap page fetches below. If one does, we return - * InvalidTransactionId to cancel all HS transactions. That's probably - * overkill, but it's safe, and certainly better than panicking here. - */ - XLogRecGetBlockTag(record, 0, &rnode, NULL, &blkno); - ibuffer = XLogReadBufferExtended(rnode, MAIN_FORKNUM, blkno, RBM_NORMAL); - if (!BufferIsValid(ibuffer)) - return InvalidTransactionId; - LockBuffer(ibuffer, BUFFER_LOCK_EXCLUSIVE); - ipage = (Page) BufferGetPage(ibuffer); - - /* - * Loop through the deleted index items to obtain the TransactionId from - * the heap items they point to. - */ - todelete = (OffsetNumber *) ((char *) xlrec + SizeOfGistxlogDelete); - - for (i = 0; i < xlrec->ntodelete; i++) - { - /* - * Identify the index tuple about to be deleted - */ - iitemid = PageGetItemId(ipage, todelete[i]); - itup = (IndexTuple) PageGetItem(ipage, iitemid); - - /* - * Locate the heap page that the index tuple points at - */ - hblkno = ItemPointerGetBlockNumber(&(itup->t_tid)); - hbuffer = XLogReadBufferExtended(xlrec->hnode, MAIN_FORKNUM, hblkno, RBM_NORMAL); - if (!BufferIsValid(hbuffer)) - { - UnlockReleaseBuffer(ibuffer); - return InvalidTransactionId; - } - LockBuffer(hbuffer, BUFFER_LOCK_SHARE); - hpage = (Page) BufferGetPage(hbuffer); - - /* - * Look up the heap tuple header that the index tuple points at by - * using the heap node supplied with the xlrec. We can't use - * heap_fetch, since it uses ReadBuffer rather than XLogReadBuffer. - * Note that we are not looking at tuple data here, just headers. - */ - hoffnum = ItemPointerGetOffsetNumber(&(itup->t_tid)); - hitemid = PageGetItemId(hpage, hoffnum); - - /* - * Follow any redirections until we find something useful. - */ - while (ItemIdIsRedirected(hitemid)) - { - hoffnum = ItemIdGetRedirect(hitemid); - hitemid = PageGetItemId(hpage, hoffnum); - CHECK_FOR_INTERRUPTS(); - } - - /* - * If the heap item has storage, then read the header and use that to - * set latestRemovedXid. - * - * Some LP_DEAD items may not be accessible, so we ignore them. - */ - if (ItemIdHasStorage(hitemid)) - { - htuphdr = (HeapTupleHeader) PageGetItem(hpage, hitemid); - - HeapTupleHeaderAdvanceLatestRemovedXid(htuphdr, &latestRemovedXid); - } - else if (ItemIdIsDead(hitemid)) - { - /* - * Conjecture: if hitemid is dead then it had xids before the xids - * marked on LP_NORMAL items. So we just ignore this item and move - * onto the next, for the purposes of calculating - * latestRemovedxids. - */ - } - else - Assert(!ItemIdIsUsed(hitemid)); - - UnlockReleaseBuffer(hbuffer); - } - - UnlockReleaseBuffer(ibuffer); - - /* - * If all heap tuples were LP_DEAD then we will be returning - * InvalidTransactionId here, which avoids conflicts. This matches - * existing logic which assumes that LP_DEAD tuples must already be older - * than the latestRemovedXid on the cleanup record that set them as - * LP_DEAD, hence must already have generated a conflict. - */ - return latestRemovedXid; -} /* * redo delete on gist index page to remove tuples marked as DEAD during index @@ -337,12 +191,11 @@ gistRedoDeleteRecord(XLogReaderState *record) */ if (InHotStandby) { - TransactionId latestRemovedXid = gistRedoDeleteRecordGetLatestRemovedXid(record); RelFileNode rnode; XLogRecGetBlockTag(record, 0, &rnode, NULL, NULL); - ResolveRecoveryConflictWithSnapshot(latestRemovedXid, rnode); + ResolveRecoveryConflictWithSnapshot(xldata->latestRemovedXid, rnode); } if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO) @@ -800,12 +653,12 @@ gistXLogUpdate(Buffer buffer, */ XLogRecPtr gistXLogDelete(Buffer buffer, OffsetNumber *todelete, int ntodelete, - RelFileNode hnode) + TransactionId latestRemovedXid) { gistxlogDelete xlrec; XLogRecPtr recptr; - xlrec.hnode = hnode; + xlrec.latestRemovedXid = latestRemovedXid; xlrec.ntodelete = ntodelete; XLogBeginInsert(); diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c index eb308c72d6b..767864b58e6 100644 --- a/src/backend/access/rmgrdesc/gistdesc.c +++ b/src/backend/access/rmgrdesc/gistdesc.c @@ -33,8 +33,11 @@ out_gistxlogPageReuse(StringInfo buf, gistxlogPageReuse *xlrec) } static void -out_gistxlogDelete(StringInfo buf, gistxlogPageUpdate *xlrec) +out_gistxlogDelete(StringInfo buf, gistxlogDelete *xlrec) { + appendStringInfo(buf, "delete: latestRemovedXid %u, nitems: %u", + xlrec->latestRemovedXid, xlrec->ntodelete); + } static void @@ -66,7 +69,7 @@ gist_desc(StringInfo buf, XLogReaderState *record) out_gistxlogPageReuse(buf, (gistxlogPageReuse *) rec); break; case XLOG_GIST_DELETE: - out_gistxlogDelete(buf, (gistxlogPageUpdate *) rec); + out_gistxlogDelete(buf, (gistxlogDelete *) rec); break; case XLOG_GIST_PAGE_SPLIT: out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec); diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 78e2e3fb312..ccf050cd62d 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -431,7 +431,7 @@ extern XLogRecPtr gistXLogUpdate(Buffer buffer, Buffer leftchild); extern XLogRecPtr gistXLogDelete(Buffer buffer, OffsetNumber *todelete, - int ntodelete, RelFileNode hnode); + int ntodelete, TransactionId latestRemovedXid); extern XLogRecPtr gistXLogSplit(bool page_is_leaf, SplitedPageLayout *dist, diff --git a/src/include/access/gistxlog.h b/src/include/access/gistxlog.h index 9990d97cbd3..e66b034d7b8 100644 --- a/src/include/access/gistxlog.h +++ b/src/include/access/gistxlog.h @@ -47,8 +47,7 @@ typedef struct gistxlogPageUpdate */ typedef struct gistxlogDelete { - RelFileNode hnode; /* RelFileNode of the heap the index currently - * points at */ + TransactionId latestRemovedXid; uint16 ntodelete; /* number of deleted offsets */ /* diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 8b1348c36db..39a474c4996 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -31,7 +31,7 @@ /* * Each page of XLOG file has a header like this: */ -#define XLOG_PAGE_MAGIC 0xD100 /* can be used as WAL version indicator */ +#define XLOG_PAGE_MAGIC 0xD101 /* can be used as WAL version indicator */ typedef struct XLogPageHeaderData { -- 2.21.0.dirty --yldqtt4fnfhymb2r--