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 1vVDao-00GNCv-2f for pgsql-hackers@arkaria.postgresql.org; Mon, 15 Dec 2025 18:46:47 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vVDan-001p2S-0O for pgsql-hackers@arkaria.postgresql.org; Mon, 15 Dec 2025 18:46:45 +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.96) (envelope-from ) id 1vVDam-001p2K-1b for pgsql-hackers@lists.postgresql.org; Mon, 15 Dec 2025 18:46:45 +0000 Received: from mail-ed1-x52a.google.com ([2a00:1450:4864:20::52a]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vVDal-000pZo-1e for pgsql-hackers@lists.postgresql.org; Mon, 15 Dec 2025 18:46:44 +0000 Received: by mail-ed1-x52a.google.com with SMTP id 4fb4d7f45d1cf-6496c4ed38aso5376140a12.1 for ; Mon, 15 Dec 2025 10:46:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1765824397; x=1766429197; darn=lists.postgresql.org; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:from:to:cc:subject:date:message-id:reply-to; bh=X3CV596ns+L2Yv1IyN+7/KHMkN5hx16AYmTjsnnFQps=; b=OC1yIw6wtCjkh3GYYZNrYcOdbzk5YyoBfEIpRvt9T5YNB/6ZRYXFu6nrTbnITTUUVx s58lBeYq7lyHhmvcbdahPlOTIGPYMF11E3z7OiLVITVYTDkQYBSri0mX0TwDJVs6obZk I0OY8HGyFrj8incignukJFdpqT8G3EJbFzB9NKoafr9hQ7Jn+1m5sd10aiJO3vy1h9zk b9WBhcW5WzVL9wPN7J4qrhpA+KujBjNH4Ah5ghacL7oSzxkmQjwZAQC4XvYysIN9HMcR bKQF5csADPo+UE3EwIu9wPbQashg9ciYniCeBEJWyigg5ykvGqW60+OWIn81z9fiaAmS tb0w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1765824397; x=1766429197; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=X3CV596ns+L2Yv1IyN+7/KHMkN5hx16AYmTjsnnFQps=; b=TTRhbK2lOW1MasDO7IIytfquMMY+9n9Ym0jWfrjdjaS4RL844Qpr19F5S7V3XDuHuz I5I6bjW/b0nMQN9ImLfDzo66F8Ss8XPIQBwdsky5ayyta9W7Tl75+G+Dvmqio7xcZeOj /HcwQzRAWng0/DlPWgVk9tRRuLwkhNB1wQXaf6GAzWbLtghMkSb5yzHt8xU4BCx71TSL zMEVykriExcHJieNVv2duTfLKmqrWp3xhxbjZU3zrQmRHBg4k1nLFkXjQKIneCffPynL 7yVl8Ei25dJ8e5y1nAuYTy4KR/SxLVvYT25vEkhs8hgXBdo9tgUKksv6zGwilgvwr+jN KquQ== X-Forwarded-Encrypted: i=1; AJvYcCV19180u4xpBY/Gv/D5NZNrbpA6Bxp75sObGNvXJqScKHpJEbiUCJBF7KwVG9o8dYje1Z+mmCe66uA4QXbN@lists.postgresql.org X-Gm-Message-State: AOJu0YxAtBUm/zms5X/jFFLPHLsw2A+uz9UAHDyDk72q+3ijNqT66XWW byJtzVrq7WGlUmOsjqDm2ix5BCcsYHF7PqmsTO2VvVwCYbr1tktHwN69 X-Gm-Gg: AY/fxX6rGdwoTmxyFHXUKjfJgCsZeIBbYCvgqrRIDWE8eQM+1tgxK444ccup2izHLjx YLoJyRWGC4QraipZwKWCtKqwcqsk5/BEe3Sqgj0t9Oa3Ky3YZeLqNs4abniMzuEF/itDt3kkP+t Dxamy6MkDhs0WcA5fO4jspw8oSYNhjU0nwP+XOV60x9rOR5LlvRJjH9OPh/zVUAd6IZn9uzkpGu Bnk75npSiWirkp/AsFqcf4UcMAY8bSK5rFIYW3THT9Lcd8JEHUiqkv9NBOjNMrfY8yH5GkGzjIw sldBKtJZKXqCNDUOGImukBlNsp+LekX9pHWBJQxgYJRQVer2rT8JWFM7kffB6puR1LVDJqZaFbv dRJKauH1nkoDbZ6Ly/6eyzRijkH301cBfHF8tmkBfpx2k8e/NdYblae+Xhc+fxhdYYxnNvf9Mt9 ryhUeLhJCf6YSI5xMfNMQO8nK8XTqU2NURCDsL1mBNbPYZiBtTCIeFNc04 X-Google-Smtp-Source: AGHT+IEKIHwKzf/SmEyYP1NybgYmIxfd0bQvVlBRdiaLEowqwVm/VWjU09ZbIybNkncEtWk3yWHOFw== X-Received: by 2002:a05:6402:4403:b0:649:2d6b:7dc8 with SMTP id 4fb4d7f45d1cf-6499b1be3f3mr12126933a12.19.1765824396355; Mon, 15 Dec 2025 10:46:36 -0800 (PST) Received: from smtpclient.apple ([2a02:a31a:a49d:1500:74a6:76ef:cb0c:3deb]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-649821316e4sm14992879a12.31.2025.12.15.10.46.34 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 15 Dec 2025 10:46:35 -0800 (PST) From: Oleg Tkachenko X-Google-Original-From: Oleg Tkachenko Message-Id: <22474984-C4CD-4300-A84E-C1CA58F61CDA@gmail.com> Content-Type: multipart/alternative; boundary="Apple-Mail=_2DE1DA9E-03B4-4465-9A4F-35CA96FC234D" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.200.81.1.6\)) Subject: Re: [BUG] [PATCH] pg_basebackup produces wrong incremental files after relation truncation in segmented tables Date: Mon, 15 Dec 2025 19:46:23 +0100 In-Reply-To: Cc: Amul Sul , pgsql-hackers@lists.postgresql.org, Stanislav Bashkyrtsev To: Robert Haas References: <00FEFC88-EA1D-4271-B38F-EB741733A84A@gmail.com> X-Mailer: Apple Mail (2.3864.200.81.1.6) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_2DE1DA9E-03B4-4465-9A4F-35CA96FC234D Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 Hello Robert, Thank you for the explanation. At first, I also thought about clamping truncation_block_length to = RELSEG_SIZE. But I hesitated because I thought the reconstructed = relation file couldn=E2=80=99t be larger than relative_limit. After reading the reconstruction code and the comments on top of the = discussed block of code (many times), I finally understood that = truncation_block_length is the minimum length of the reconstructed file, = not just a safety limit. It determines which blocks must be fetched from = older backups. So a simple clamp could change how reconstruction works = if some blocks are included in incremental backups. I=E2=80=99ve tested the version with the limit enforced to RELSEG_SIZE, = and it works correctly. Also, I=E2=80=99ve attached a patch based on your guidance. The changes = are effectively the same as your suggested approach, but I would be = happy to be listed as a contributor. Regards, Oleg Tkachenko =EF=BF=BC > On Dec 15, 2025, at 17:35, Robert Haas wrote: >=20 > [ sorry for not noticing this thread sooner; thanks to Andres for > pointing me to it ] >=20 > On Mon, Dec 15, 2025 at 9:01=E2=80=AFAM Amul Sul = wrote: >> Thanks for the reproducer; I can see the reported issue, but I am not >> quite sure the proposed fix is correct and might break other cases (I >> haven't tried constructed that case yet) but there is a comment >> detailing that case just before the point where you are planning to = do >> the changes: >>=20 >> /* >> * The truncation block length is the minimum length of the = reconstructed >> * file. Any block numbers below this threshold that are not = present in >> * the backup need to be fetched from the prior backup. At or = above this >> * threshold, blocks should only be included in the result if they = are >> * present in the backup. (This may require inserting zero blocks = if the >> * blocks included in the backup are non-consecutive.) >> */ >>=20 >> IIUC, we might need the original assignment logic as it is. But we >> need to ensure that truncation_block_length is not set to a value = that >> exceeds RELSEG_SIZE. >=20 > I think you're right. By way of example, let's say that the current > length of the file is 200 blocks, but the limit block is 100 blocks > into the current segment. That means that the only blocks that we can > get from any previous backup are blocks 0-99. Blocks 100-199 of the > current segment are either mentioned in the WAL summaries we're using > for this backup, or they're all zeroes. We can't set the > truncation_block_length to a value greater than 100, or we'll go > looking for the contents of any zero-filled blocks in previous > backups, will will either fail or produce the wrong answer. But Oleg > is correct that we also shouldn't set it to a value greater than > RELSEG_SIZE. So my guess is that the correct fix might be something > like the attached (untested, for discussion). >=20 > --=20 > Robert Haas > EDB: http://www.enterprisedb.com =EF=BF=BC --Apple-Mail=_2DE1DA9E-03B4-4465-9A4F-35CA96FC234D Content-Type: multipart/mixed; boundary="Apple-Mail=_40CFB0D5-5304-4E38-8DBC-298E9786F080" --Apple-Mail=_40CFB0D5-5304-4E38-8DBC-298E9786F080 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8
Hello = Robert,

Thank you for the = explanation.

At first, I also thought about = clamping truncation_block_length to RELSEG_SIZE. But I hesitated because = I thought the reconstructed relation file couldn=E2=80=99t be larger = than relative_limit.

After reading the = reconstruction code and the comments on top of the discussed block of = code (many times), I finally understood that truncation_block_length is = the minimum length of the reconstructed file, not = just a safety limit. It determines which blocks must be fetched = from older backups. So a simple clamp could change how reconstruction = works if some blocks are included in incremental = backups.

I=E2=80=99ve tested the version with = the limit enforced to RELSEG_SIZE, and it works = correctly.

Also, I=E2=80=99ve attached a patch = based on your guidance. The changes are effectively the same as your = suggested approach, but I would be happy to be listed as a = contributor.

Regards,
Oleg = Tkachenko

= --Apple-Mail=_40CFB0D5-5304-4E38-8DBC-298E9786F080 Content-Disposition: attachment; filename=0001-Clamp-truncation_block_length-to-RELSEG_SIZE.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="0001-Clamp-truncation_block_length-to-RELSEG_SIZE.patch" Content-Transfer-Encoding: quoted-printable =46rom=20f8ab0228c1125e07e81b7f1aeaee6e5af2370b21=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Oleg=20Tkachenko=20=0ADate:=20= Mon,=2015=20Dec=202025=2019:29:50=20+0100=0ASubject:=20[PATCH]=20Clamp=20= truncation_block_length=20to=20RELSEG_SIZE=0A=0AFix=20an=20issue=20where=20= truncation_block_length=20could=20exceed=20RELSEG_SIZE,=0Acausing=20= restore=20failures=20when=20reconstructing=20incremental=20backups.=0A= ---=0A=20src/backend/backup/basebackup_incremental.c=20|=2014=20= ++++++++++++++=0A=201=20file=20changed,=2014=20insertions(+)=0A=0Adiff=20= --git=20a/src/backend/backup/basebackup_incremental.c=20= b/src/backend/backup/basebackup_incremental.c=0Aindex=20= 7678e4f6ec3..f4ef33f6672=20100644=0A---=20= a/src/backend/backup/basebackup_incremental.c=0A+++=20= b/src/backend/backup/basebackup_incremental.c=0A@@=20-850,8=20+850,22=20= @@=20GetFileBackupMethod(IncrementalBackupInfo=20*ib,=20const=20char=20= *path,=0A=20=09{=0A=20=09=09unsigned=09relative_limit=20=3D=20= limit_block=20-=20segno=20*=20RELSEG_SIZE;=0A=20=0A+=09=09/*=0A+=09=09=20= *=20We=20can't=20set=20a=20truncation_block_length=20in=20excess=20of=20= the=20limit=20block=0A+=09=09=20*=20number=20(relativized=20to=20the=20= current=20segment).=20To=20do=20so=20would=20be=20to=0A+=09=09=20*=20= treat=20blocks=20from=20older=20backups=20as=20valid=20current=20= contents=20even=20if=0A+=09=09=20*=20they=20were=20subsequently=20= truncated=20away.=0A+=09=09=20*/=0A=20=09=09if=20= (*truncation_block_length=20<=20relative_limit)=0A=20=09=09=09= *truncation_block_length=20=3D=20relative_limit;=0A+=0A+=09=09/*=0A+=09=09= =20*=20We=20also=20can't=20set=20a=20truncation_block_length=20in=20= excess=20of=20the=0A+=09=09=20*=20segment=20size,=20since=20the=20= reconstructed=20file=20can't=20be=20larger=20than=0A+=09=09=20*=20that.=0A= +=09=09=20*/=0A+=09=09if=20(*truncation_block_length=20>=20RELSEG_SIZE)=0A= +=09=09=09*truncation_block_length=20=3D=20RELSEG_SIZE;=0A=20=09}=0A=20=0A= =20=09/*=20Send=20it=20incrementally.=20*/=0A--=20=0A2.52.0=0A=0A= --Apple-Mail=_40CFB0D5-5304-4E38-8DBC-298E9786F080 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8

On = Dec 15, 2025, at 17:35, Robert Haas <robertmhaas@gmail.com> = wrote:

[ sorry = for not noticing this thread sooner; thanks to Andres for
pointing me = to it ]

On Mon, Dec 15, 2025 at 9:01=E2=80=AFAM Amul Sul = <sulamul@gmail.com> wrote:
Thanks for = the reproducer; I can see the reported issue, but I am not
quite sure = the proposed fix is correct and might break other cases (I
haven't = tried constructed that case yet) but there is a comment
detailing = that case just before the point where you are planning to do
the = changes:

   /*
    * The = truncation block length is the minimum length of the reconstructed
=     * file. Any block numbers below this threshold = that are not present in
    * the backup need to = be fetched from the prior backup. At or above this
=     * threshold, blocks should only be included in = the result if they are
    * present in the = backup. (This may require inserting zero blocks if the
=     * blocks included in the backup are = non-consecutive.)
    */

IIUC, we might = need the original assignment logic as it is. But we
need to ensure = that truncation_block_length is not set to a value that
exceeds = RELSEG_SIZE.

I think you're right. By way of = example, let's say that the current
length of the file is 200 blocks, = but the limit block is 100 blocks
into the current segment. That = means that the only blocks that we can
get from any previous backup = are blocks 0-99. Blocks 100-199 of the
current segment are either = mentioned in the WAL summaries we're using
for this backup, or = they're all zeroes. We can't set the
truncation_block_length to a = value greater than 100, or we'll go
looking for the contents of any = zero-filled blocks in previous
backups, will will either fail or = produce the wrong answer. But Oleg
is correct that we also shouldn't = set it to a value greater than
RELSEG_SIZE. So my guess is that the = correct fix might be something
like the attached (untested, for = discussion).

--
Robert Haas
EDB: = http://www.enterprisedb.com
= --Apple-Mail=_40CFB0D5-5304-4E38-8DBC-298E9786F080 Content-Disposition: attachment; filename=v1-0001-Don-t-set-the-truncation_block_length-rather-than.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v1-0001-Don-t-set-the-truncation_block_length-rather-than.patch" Content-Transfer-Encoding: quoted-printable =46rom=20bac3a98cd4e4b3007e140d9db334b040cf6772c5=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Robert=20Haas=20=0ADate:=20= Mon,=2015=20Dec=202025=2011:34:34=20-0500=0ASubject:=20[PATCH=20v1]=20= Don't=20set=20the=20truncation_block_length=20rather=20than=0A=20= RELSEG_SIZE.=0A=0AAlso,=20add=20some=20comments=20to=20explain=20the=20= logic.=0A---=0A=20src/backend/backup/basebackup_incremental.c=20|=2014=20= ++++++++++++++=0A=201=20file=20changed,=2014=20insertions(+)=0A=0Adiff=20= --git=20a/src/backend/backup/basebackup_incremental.c=20= b/src/backend/backup/basebackup_incremental.c=0Aindex=20= 7678e4f6ec3..f4ef33f6672=20100644=0A---=20= a/src/backend/backup/basebackup_incremental.c=0A+++=20= b/src/backend/backup/basebackup_incremental.c=0A@@=20-850,8=20+850,22=20= @@=20GetFileBackupMethod(IncrementalBackupInfo=20*ib,=20const=20char=20= *path,=0A=20=09{=0A=20=09=09unsigned=09relative_limit=20=3D=20= limit_block=20-=20segno=20*=20RELSEG_SIZE;=0A=20=0A+=09=09/*=0A+=09=09=20= *=20We=20can't=20set=20a=20truncation_block_length=20in=20excess=20of=20= the=20limit=20block=0A+=09=09=20*=20number=20(relativized=20to=20the=20= current=20segment).=20To=20do=20so=20would=20be=20to=0A+=09=09=20*=20= treat=20blocks=20from=20older=20backups=20as=20valid=20current=20= contents=20even=20if=0A+=09=09=20*=20they=20were=20subsequently=20= truncated=20away.=0A+=09=09=20*/=0A=20=09=09if=20= (*truncation_block_length=20<=20relative_limit)=0A=20=09=09=09= *truncation_block_length=20=3D=20relative_limit;=0A+=0A+=09=09/*=0A+=09=09= =20*=20We=20also=20can't=20set=20a=20truncation_block_length=20in=20= excess=20of=20the=0A+=09=09=20*=20segment=20size,=20since=20the=20= reconstructed=20file=20can't=20be=20larger=20than=0A+=09=09=20*=20that.=0A= +=09=09=20*/=0A+=09=09if=20(*truncation_block_length=20>=20RELSEG_SIZE)=0A= +=09=09=09*truncation_block_length=20=3D=20RELSEG_SIZE;=0A=20=09}=0A=20=0A= =20=09/*=20Send=20it=20incrementally.=20*/=0A--=20=0A2.51.0=0A=0A= --Apple-Mail=_40CFB0D5-5304-4E38-8DBC-298E9786F080 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii

--Apple-Mail=_40CFB0D5-5304-4E38-8DBC-298E9786F080-- --Apple-Mail=_2DE1DA9E-03B4-4465-9A4F-35CA96FC234D--