Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1x8g3a-00000001QIu-2Rl5 for pgsql-hackers@arkaria.postgresql.org; Mon, 21 Sep 2026 15:35:51 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.98.2) (envelope-from ) id 1x8g3Z-0000000AMnt-0fg2 for pgsql-hackers@arkaria.postgresql.org; Mon, 21 Sep 2026 15:35:49 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1x8g3Y-0000000AMnl-1xLB for pgsql-hackers@lists.postgresql.org; Mon, 21 Sep 2026 15:35:48 +0000 Received: from fhigh-a1-smtp.messagingengine.com ([103.168.172.152]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1x8g3V-00000000WBE-2mQG for pgsql-hackers@lists.postgresql.org; Mon, 21 Sep 2026 15:35:47 +0000 Received: from phl-compute-03.internal (phl-compute-03.internal [10.202.2.43]) by mailfhigh.phl.internal (Postfix) with ESMTP id C502214000BD; Mon, 21 Sep 2026 11:35:44 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-03.internal (MEProxy); Mon, 21 Sep 2026 11:35:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kurilemu.de; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :reply-to:subject:subject:to:to; s=fm3; t=1790004944; x= 1790091344; bh=QQ84z8m3M73iLj3pFRt5UDWjm/bAPdyXbt2Ae3+nNjg=; b=s RYjQ/Nnos7p2ldXnC45lYRLlBbsy5AU0kTRBFnvIwBfNbHryy+RqLoYV8u5xiC73 TphZNKyrDKftdW/ZA2ynP8D8eDFGPDBMXS/fx6lE0Ju+It7Hx9Ax3QeAxRPfjksD pipK9CBpVIxWCG8KoJQLRuYrCX7+7EGMUbHoJpqIzNYa+p5dniWyODDAH26fcXkA euodNfAb+dl16JJt9j22iMQAUvwS4c8nrTEG3EOIeBp1wCB1lj6H0vGNJXDgdZqT VsqzU9I2lOa8LJA6E4kmYt8G0ULIdGk27rTpCh2/0c2KldB7KH48Poj3NXsdGMlc Zz7fFtLuaYk/Pb+RbWgDw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1790004944; x=1790091344; bh=Q Q84z8m3M73iLj3pFRt5UDWjm/bAPdyXbt2Ae3+nNjg=; b=r1Axeynss/zMlpkc2 M32fUsjcqri6TyuXWDo9+XXYsmwQg+lPs1uU0f2eB7UuFuiT4RiH1UnNR0NKtOr1 baf5ec/9+9jj7WHWFM9HFRScW/6zvydU+AKQ9kpTBjyEd9MVsJydaXVCgA6OHOEw BjMCtSXGQ1Ovcf5uDtdGmrr3GqPJ4CRSy9xK5Z7PfzdhlCbFbM7xiiT2p3JNtDdA 2J2ofDd/oPwMHo0YPPrYJgBV6UbzpdBOZEM58Gn9/0iEb9WnsvNUmEP4JJ3OtNQe MDCq7G74KemfprvwVgw8LXWgFlt/kQvFR1xPxgYzD+yVGjEuYdKBNfhrEaIdnXTv FvULQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFP6/Y3PvqYzmhatNmeJzCOUv40g4qoTdI+WrN6pjVdr8XD0a31ChvPtXW2HFUbZ1 WOgRzzDkLJA6TH5Vi/29BS3TrlMPUsGkmnA8N+BLDIy8PIwWYrb6vvY7Uo2XEM5tCqqUMs siClnCMtB9hTSr54JPHSjnxnnVUOyRRVhqSZarRK4U2JqkjpOaYXZL8YO/Xh5zrt3U7PTY 9t8+1Bw5A6Cn4ZwDCZNlOasFSqpOZiI8FgV8TRBxBABkRLMzFknkGrnUxZSwaLo47QVA6R rVxRc4ofyoOaaBj2COQ2Pvy6fsuw5vv2P5CZh3YhvNz5ipGkXUmnrShMeyHwKLs5gjJwDI Sa2+BZP+TiIkUIzq1E8C4Nuhu90E4NHhhrP3g4eZqIxS70jTR9JOh08SrElq7cWj+miQyc Cep7ivL0+btnbaDetz6KM0ucqEItIC4QtH0NhkmvlMhcqucQ/1CPAbdJm+qzwR+mndqZhg 0zd6yxQGSHEqte2pLsIS2PgcOKtAO0zz4L9G0QFcieqdENB2YB4SY6ZOsp/wMueeBNaGGJ fCxsrclPJJp6v81maoXFBy7gSoU4mg5TXkd5nrMJtFKY4LITduS8YS5t4kzUq1qMlRabIt QpOQ7zfxuCtWd4i6RzcpIao8SlPFL7nfnhdql4jFZ+3OQsq4D+aOFfXqa3+Q X-ME-Proxy: Feedback-ID: ie3de48e3:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 21 Sep 2026 11:35:43 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kurilemu.de; s=schmee; t=1790004941; bh=9GKwQHYausZ3NqZbd21Ujsxi61Y8hdf6Lz32Riv7Gio=; h=Date:From:To:Cc:Subject:In-Reply-To:From; b=VDD2sUkNyt5EUU++IVGWHG9KF1Sdi0cAgkDRgbZnHZ/3vAJGvrvqZ8mivCm4NNS2Z erhCoJmvCgGrctE0o5fUs+bjspA8H9sFLofAz+N3IQbB9EnsUtlfMMTmoFChmCNlGy 1gJJ66Q+f/A2zEn3MSmUGZ7Vnu3mVtuuXpKWsUEXnrB+N6zTw1csJsOhi/SZlsWiHy 7IfnM0qH+0w+GskOZHJ7dBqELOdYRFxxjni5/htn8wr8N9vzd6hRPmgW5EteEhrxY6 mRHIYfuctbi9fCEUPiIjsjWNjcWvPDRtTUVLZ1e4NacodOy+htnMkqAzFTMx9uVHWt K6j5N6hy0NReQ== Received: by ida.kurilemu.internal (Postfix, from userid 1000) id 5E18DB00096; Mon, 21 Sep 2026 17:35:41 +0200 (CEST) Date: Mon, 21 Sep 2026 17:35:41 +0200 From: Alvaro Herrera To: Rui Zhao Cc: Antonin Houska , Andres Freund , pgsql-hackers@lists.postgresql.org, Mihail Nikalayeu Subject: Re: Race conditions in logical decoding Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 2026-Sep-20, Rui Zhao wrote: > On 2026-Sep-18 at 14:29 UTC, Alvaro Herrera wrote: > > This does pass the two tests that Rui wrote, also attached. > > In v5-0001, newxcnt++ needs to stay in the test == NULL branch. > Otherwise committed XIDs increase the count without filling an entry > in newxip. Eh, yeah. > On 2026-Sep-17 at 08:37 UTC, Antonin Houska wrote: > > I don't understand why you check all transactions in procarray, instead of > > only those in snap->xip. > > I first tried calling XactLockTableWait() for every XID in snap->xip, > the same per-XID waiting approach as v5. Even for an already finished > XID, that goes through the lock manager and calls > TransactionIdIsInProgress(). Unless its RecentXmin or cached-XID > checks suffice, that takes ProcArrayLock and scans procarray. > > In the patch attached to my original mail, I instead read the > running-XID list once and used bsearch to wait only for XIDs also in > snap->xip. That was to avoid repeating this work for transactions > that had already finished. Yeah, maybe this approach isn't great after all. We could turn that around and search for each loop around the snap->xmin..snap->xmax loop that is found in snap->xip in the running->xids array. That reduces the number of times we go through XactLockTableWait() to only running transactions (same as in Rui's original patch [1]). However, the running->xids array is not sorted, so we would have to qsort() it, or do a plain array walk for each element. In the end, I think the code in your (Rui's) first patch is the simplest approach. It's possible that there's a slight performance difference between scanning the running->xids array with bsearch() on snap->xip, versus scanning the snap->xip array with bsearch on running->xids. However, given the amount of code involved in the XactLockTableWait() that we have to do on each item we find still running, I expect the difference to be negligible. And doing it certainly beats ending up with corrupt data anyway. So I'm going to take the code mostly from Rui's original patch[1]. [1] https://postgr.es/m/CAHWVJhHXyLtS-8mdL9WhEWfsERb=FN7JdPD0GYAXgTmCnqbYGw@mail.gmail.com However, the situation with comments is not completely settled for me. I asked: > On 2026-Sep-18 at 12:28 UTC, Alvaro Herrera wrote: > > I don't understand [this comment]: > > > > * A subtransaction is covered by its top-level transaction, which is in > > * snap->xip as well, or was purged from it because it is below xmin and > > * thus finished long ago. and you said: > The first was meant to explain why we don't have to find every > subxid in the running-XID list. If any backend's subxid cache has > overflowed, GetRunningTransactionData() returns top-level XIDs but no > subxids. We still wait for the parent, which covers its children. However, the code scans running->xids with a limit of + nrunning = running->xcnt + running->subxcnt; which means we scan both main Xids as well as subxids, which seems to contradict what you said. I think we should just go up to running->xcnt only; if any subxids are in there, we can ignore that, because we'd still do the XactLockTableWait with the parent xact. (We know, by construction, that the array has the top-level XIDs first, followed by subxids. This doesn't seem documented anywhere though. Perhaps if this is ever broken, SnapBuildWaitSnapshot would be trouble. Maybe worth adding a comment somewhere.) I also asked: > On 2026-Sep-18 at 12:28 UTC, Alvaro Herrera wrote: > > I don't understand [this other comment]: > > > > * Historic snapshots do not need this: between xmin and xmax they rely on > > * xip alone, and transactions below xmin had left the procarray by the > > * time the xl_running_xacts record that set xmin was written. and you replied: > The second was a different question: why wait only in > SnapBuildInitialSnapshot(), rather than in SnapBuildBuildSnapshot(), > which is also used to build historic snapshots? Here "this" meant > waiting for transactions to finish, not handling subtransactions. > > Historic snapshots use xip for committed-XID checks in [xmin, xmax). > They can consult CLOG below xmin, but those transactions had already > finished when the running-xacts record supplying xmin was written. > So they need no extra wait. Ah, I see. It makes sense when explained like that, but I find it difficult to understand in the broader context of the comment being added. I don't disagree that this is worth commenting about, but I'm not sure this is the best place to do it. Rather, maybe we should add something in SnapBuildBuildSnapshot() to explain why we don't do this there. -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/