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.96) (envelope-from ) id 1wgjWi-006MYd-2o for pgsql-bugs@arkaria.postgresql.org; Mon, 06 Jul 2026 13:38:25 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wgjWh-000tBG-2Z for pgsql-bugs@arkaria.postgresql.org; Mon, 06 Jul 2026 13:38:23 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wgjWh-000tB7-19 for pgsql-bugs@lists.postgresql.org; Mon, 06 Jul 2026 13:38:23 +0000 Received: from mail-ed1-x536.google.com ([2a00:1450:4864:20::536]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wgjWd-0000000243t-1rai for pgsql-bugs@lists.postgresql.org; Mon, 06 Jul 2026 13:38:23 +0000 Received: by mail-ed1-x536.google.com with SMTP id 4fb4d7f45d1cf-698c0ff45b5so5383047a12.1 for ; Mon, 06 Jul 2026 06:38:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=garret-ru.20251104.gappssmtp.com; s=20251104; t=1783345097; x=1783949897; darn=lists.postgresql.org; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=5pHwwqhl39UpG04FV7qopShkkDAW0HBgC4EcVatEC48=; b=lBcMtR/vup8ZBYaZecikUn81aaAljGp43mAdWd0fFsHIxC7IuUqNcOgTIecD5Gyb5x bW6PwZi6tA/ITwTD8mpOZQ0EP0fh2Gssd1MD6Dh+iEoRV+1KdCBrgJxZzBWVozOvSSXR DLdJ+drxdvhrr7s8k/dtjy++bQgwIxVX0niHmdGc0hOy4ePYNtdE+ZchMzv0HA8Uukpe xB9slz5BeKamDyhea9XB8cQSWYWlhxnTbJcTHDLUx7lZmyiecsQE1EA7xLro9cfXv0Dt Dm4tmsupacnLq3fsjtpMnNHjVTkvs7paEksXHj7GREbNWaPuq4hx+OKPR9HFkaYVRuE5 /Xtw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783345097; x=1783949897; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=5pHwwqhl39UpG04FV7qopShkkDAW0HBgC4EcVatEC48=; b=gaVvqGeM27vkeUEo1ZM7E+3Rwf2hdhg7KuASEbd4RchImD3UKFfxSKS+iaVzsx8Rig DRnXWR/00DYTULCrI4Ey+BKKkO+Ml69P6bYCcst/Cmh5z4kR32qn7OkhqVQYB5U5q/mx YMy6rO9TOd5bfmvfg8o6sml9j1jy+X/Gy+VRyLQgPkwxnPpe74k9iUmhJ2xDi5/Ag9wa RIifAdaTUxUkwEOU0NAiZKWaBFKInTKoRcQXuEGHBigj2vZd9qagn6UjpI5YXXGJuoEm imbwTia8BZYEMnSJYhs/Y8AvyJZmzxhTNIkmLQKdjOd02dp6ptwl4xGikHQ5+vph5HdB BZjA== X-Forwarded-Encrypted: i=1; AHgh+RrOl+cnVo95DkuRUHPTngHDelKAUCC9MKs2Z+L36Tvu47FHk/BpdYx1Fw6IhMNlZr8JIORuEp+PcRBg@lists.postgresql.org X-Gm-Message-State: AOJu0Yz9PWT2ohLAfttW4R4v1JqWsfynBpIwEjoqr37K6FC21JIRYUSP mDqYqC3JJgIX7dqW2HR2epa8GHzjM2Fh9yYqxb1YltO8IHnseBGwR1/glfIMeskfNg== X-Gm-Gg: AfdE7cneZkWSjc/zbGsZH8Q8NieHjuHT7HgDoRw1FssZmIqMIyuZKlAINeZX3FPxIjq nKEWoqO2uz7dr5ge6CtrHxarbS1Ht3Kbk89CrNT7f/fPzBSZ3/O7xrj9gagDyZakhQJA/ex2Dbx ZVT32lVg3iRsTZTBLZIZzB3n8NmDu6Jj6sw6tBjiow6EgNV7oQZ1mVMt3OIi4PSXcw+DQMVnymS 07n/baFnBGrKlw5gBoLxaEZJqligltpfWYebPQ/26rxODAjJ5Gi6Mw74ItgRbw2otUv/8uw4LeE ltmLMIXm/tvQmZyN4XFGBd+UCXzKjBFAM26V8Xi9ZsWf1p2DOOMmHoZ0Vbd5qkex7jsoDje88Zt +KQHXXmMMCdmC4AeEhKxRTzRm6gMRHFXeWcpUcf7bjR6UYYM6P8I4WQMSRnVsFZHrVY0mT0mfwK CdkR8+rBD5KjNZ/SwNYW2Kz4dhRg== X-Received: by 2002:a17:906:99ce:b0:c12:7f28:bfd9 with SMTP id a640c23a62f3a-c12c9ec690dmr704249166b.25.1783345097332; Mon, 06 Jul 2026 06:38:17 -0700 (PDT) Received: from [10.248.56.12] ([130.41.208.1]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c12b628d65dsm764489266b.35.2026.07.06.06.38.15 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 06 Jul 2026 06:38:16 -0700 (PDT) Message-ID: <0610480a-70e3-4a77-8bdf-94143fc3a4d7@garret.ru> Date: Mon, 6 Jul 2026 16:38:14 +0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: BUG #19519: REPACK can fail due to missing chunk for toast value To: Michael Paquier , Imran Zaheer Cc: Srinath Reddy Sadipiralla , exclusion@gmail.com, pgsql-bugs@lists.postgresql.org References: <19519-fe02d8ff679d834d@postgresql.org> Content-Language: en-US From: Konstantin Knizhnik In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 06/07/2026 9:36 AM, Michael Paquier wrote: > On Fri, Jul 03, 2026 at 11:45:42AM +0500, Imran Zaheer wrote: >> Can we safely use the same fix in the index build path too? Can we use >> GetOldestNonRemovableTransactionIdforRewrite or something similar >> here? Normal serial index builds use SnapShotAny and concurrent index >> builds use MVCC, but the bug only exists in the serial index build >> path. > Yeah, I think that we should be able to safely reuse your ForRewrite() > API for the index build case (SnapshotAny part) as well to make the > horizon computations more conservative, exclusing one own XID as we > do in the lazy VACUUM case. > >> Other than that, after applying your patch, the bug was not >> reproducible with either this repro or the other report's repro [1] in >> the rewrite path. However, the create index bug is still there. You >> can use the following repro as mentioned in the thread [1]. > The assymetry between the global xmin computation and the per-database > horizon is what's killing us here. All these patterns are complicated > enough that they warrant some tests, even if it is necessary to have > multiple databases to trigger the buggy horizon computations. TAP > tests would be an obvious choice for that. Now I have a set of tricks > in my sleeves to make an isolation test fully deterministic: > - dblink() that opens a transaction to a different database than the > one of the isolation regression database. > - Rename of a TOAST table using allow_system_table_mods, for a VACUUM. > > The second one is one of the dirtiest tricks I've done in the past for > a REINDEX CONCURRENTLY test with TOAST. Quite useful. If the backend > side change is reverted, the tests fail. > > The attached includes both test suites for all four cases reported > (REPACK, VACUUM, CLUSTER, non-MVCC index builds). We'll need to > remove one of them, just keeping both posted as I am not sure if the > isolation tests would be entirely stable in the buildfarm.. > > I still need to dive more into the code, but for now this bit stands > out: > vacuum_get_cutoffs(OldHeap, ¶ms, &cutoffs); > > + /* > + * vacuum_get_cutoffs() folds our own backend's xmin into OldestXmin. For > + * a rewrite that is too conservative: the snapshot we hold exists only to > + * evaluate index expressions against other relations, not to read > + * OldHeap's historical rows. If our xmin is held back by a transaction > + * that cannot even see OldHeap (e.g. one in another database), we would > + * preserve a recently-dead tuple whose TOAST chunks a concurrent or prior > + * lazy vacuum was free to remove, and then fail with "missing chunk" while > + * copying it. Recompute OldestXmin ignoring our own backend so it matches > + * the horizon lazy vacuum uses. This can only move OldestXmin forward, so > + * the freeze cutoffs derived above remain valid. > + */ > + cutoffs.OldestXmin = GetOldestNonRemovableTransactionIdForRewrite(OldHeap); > > In copy_table_data() (for the data copy with repack, cluster, vacuum > full), I think that this is incorrect. For one, this breaks the > FreezeLimit which should always be older than OldestXmin, and this > patch enforces a new recomputation of OldestXmin ignoring most of the > internals of vacuum_get_cutoffs(). That's brittle, to say the least > if we change the way the vacuum cutoffs are calculated in the future. > > Thoughts and comments from others are welcome for now. My day is > almost out, at least I got all these scenarios working some tests. > -- > Michael I wonder if we also need to replace GetOldestNonRemovableTransactionId with GetOldestNonRemovableTransactionIdForRewrite in  vacuum.c: diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index be863db81cb..aaa7e6eeeaa 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -1149,7 +1149,7 @@ vacuum_get_cutoffs(Relation rel, const VacuumParams *params,          * that only one vacuum process can be working on a particular table at          * any time, and that each vacuum is always an independent transaction.          */ -       cutoffs->OldestXmin = GetOldestNonRemovableTransactionId(rel); +       cutoffs->OldestXmin = GetOldestNonRemovableTransactionIdForRewrite(rel);         Assert(TransactionIdIsNormal(cutoffs->OldestXmin)); For some reasons the problem is not reproduced with current master, but when I applied your patch to PG18 and run repro script with REPACK replaced with VACUUM FULL, then I still get missing chunk error.