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.94.2) (envelope-from ) id 1u3ceF-000pFH-VB for pgsql-hackers@arkaria.postgresql.org; Sat, 12 Apr 2025 15:20:01 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1u3cdE-0066Sn-Qq for pgsql-hackers@arkaria.postgresql.org; Sat, 12 Apr 2025 15:18:57 +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.94.2) (envelope-from ) id 1u3cdD-0066PF-5n for pgsql-hackers@lists.postgresql.org; Sat, 12 Apr 2025 15:18:56 +0000 Received: from m16.mail.163.com ([117.135.210.3]) by makus.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1u3cd2-004ULD-0j for pgsql-hackers@postgresql.org; Sat, 12 Apr 2025 15:18:51 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Message-Id:Content-Type:Mime-Version:Subject: Date; bh=J30248zTvLXVKwI+QZ38Mih0Qv40EsEedfxsmTzQJGk=; b=Qfdslwx BKvEa6p66VwyN/NZ6QRq1OD9hjIIs+MA40/yb8o8FZOWhbhYRp47HCOxXSYPZzVu HthAIpdkh1ugJSoK8XsK0fJwqv6EYZmiYp6YnKyu8pocqmfztCel97dlD5bogZDL bj6glGfkBD8vHEbTb/LEXc853yuIHwZGHKIU= Received: from smtpclient.apple (unknown []) by gzsmtp5 (Coremail) with SMTP id QCgvCgAnl9I4hPpnYLazAA--.19672S2; Sat, 12 Apr 2025 23:18:17 +0800 (CST) From: =?utf-8?B?6LS+5piO5Lyf?= Message-Id: <355C0849-820C-4373-9CC9-9A257C661C3A@163.com> Content-Type: multipart/alternative; boundary="Apple-Mail=_ED800A29-636A-4AE7-B7C0-FC8948D9BD53" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3818.100.11.1.3\)) Subject: Re: CSN snapshots in hot standby Date: Sat, 12 Apr 2025 23:18:06 +0800 In-Reply-To: <80f254d3-8ee9-4cde-a7e3-ee99998154da@iki.fi> Cc: John Naylor , pgsql-hackers , Andres Freund , "Andrey M. Borodin" , Kirill Reshke To: Heikki Linnakangas References: <08da26cc-95ef-4c0e-9573-8b930f80ce27@iki.fi> <53C9CD5A-4403-4FF0-9F00-8B8A00F922A7@yandex-team.ru> <7cd97248-fd04-4fb2-9f7f-096c1d7660e8@iki.fi> <718d1788-b058-40e6-bc37-8f15612b5646@iki.fi> <80f254d3-8ee9-4cde-a7e3-ee99998154da@iki.fi> X-Mailer: Apple Mail (2.3818.100.11.1.3) X-CM-TRANSID:QCgvCgAnl9I4hPpnYLazAA--.19672S2 X-Coremail-Antispam: 1Uf129KBjvdXoWrtF1rury3AFW7CF4kZrW3Awb_yoW3urb_Cr W3ur92grnrGa1q9r45KFn8trZ29rW7Gr15Xw1v9r13Zr93ZF47uF4v9ryrZw1fGayfKr9x urWftw4akw129jkaLaAFLSUrUUUUjb8apTn2vfkv8UJUUUU8Yxn0WfASr-VFAUDa7-sFnT 9fnUUvcSsGvfC2KfnxnUUI43ZEXa7IUbrgA3UUUUU== X-Originating-IP: [60.25.59.51] X-CM-SenderInfo: 5zhlimiywqmjqs6rljoofrz/1tbiOhQtGWf6gt8qawAAsb List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_ED800A29-636A-4AE7-B7C0-FC8948D9BD53 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 Hi, Thanks for the proposal, it's an interesting approach. I have a question regarding the xid visibility during standby startup.=20= If the checkpoint=E2=80=99s `oldestActiveXid` is smaller than `nextXid`, = then there may be already-committed transactions=20 in that range which will not be replayed on standby. In that case, I = believe clog needs to be used for visibility=20 checks within that xid range =E2=80=94 is that correct? On top of your previous discussion, I wrote a test case and attempted to = fix the issue. Patches 0001=E2=80=930012 are your original commits, unchanged. Patch = 0013 contains my own ideas. Since this is my first time replying to the mailing list, I was worried = about breaking the thread, so I=E2=80=99ve included everything as = attachments instead. Looking forward to your thoughts. Best regards, =20 Mingwei Jia =EF=BF=BC=EF=BF=BC=EF=BF=BC=EF=BF=BC=EF=BF=BC=EF=BF=BC=EF=BF=BC=EF=BF=BC=EF= =BF=BC=EF=BF=BC=EF=BF=BC=EF=BF=BC=EF=BF=BC > 2025=E5=B9=B44=E6=9C=881=E6=97=A5 05:31=EF=BC=8CHeikki Linnakangas = =E5=86=99=E9=81=93=EF=BC=9A >=20 > Here's a new patchset version. Not much has changed in the actual CSN = patches. But I spent a lot of time refactoring the snapshot management = code, so that there is a simple place to add the "inprogress XID cache" = for the CSN snapshots, in a way that avoids duplicating the cache if a = snapshot is copied around. >=20 > Patches 0001-0002 are the patches I posted on a separate thread = earlier. See = https://www.postgresql.org/message-id/ec10d398-c9b3-4542-8095-5fc6408b17d1= %40iki.fi. >=20 > Patches 0003-0006 contain more snapshot manager changes. The end state = is that an MVCC snapshot consists of two structs: a shared "inner" = struct that contains xmin, xmax and the XID lists, and an "outer" struct = that contains a pointer to the shared struct and the current command ID. = As a snapshot is copied around, all the copies share the same shared, = reference-counted struct. >=20 > The rest of the patches are the same CSN patches I posted before, = rebased over the snapshot manager changes. >=20 >=20 > There's one thing that hasn't been discussed yet: The = ProcArrayRecoveryEndTransaction() function, which replaces = ExpireTreeKnownAssignedTransactionIds() and is called on replay of every = commit/abort record, does this: >=20 >> /* >> * If this was the oldest XID that was still running, advance = it. This is >> * important for advancing the global xmin, which avoids = unnecessary >> * recovery conflicts >> * >> * No locking required because this runs in the startup process. >> * >> * XXX: the caller actually has a list of XIDs that just = committed. We >> * could save some clog lookups by taking advantage of that = list. >> */ >> oldest_running_primary_xid =3D = procArray->oldest_running_primary_xid; >> while (oldest_running_primary_xid < max_xid) >> { >> if (!TransactionIdDidCommit(oldest_running_primary_xid) = && >> = !TransactionIdDidAbort(oldest_running_primary_xid)) >> { >> break; >> } >> TransactionIdAdvance(oldest_running_primary_xid); >> } >> if (max_xid =3D=3D oldest_running_primary_xid) >> TransactionIdAdvance(oldest_running_primary_xid); >=20 > The point is to maintain an "oldest xmin" value based on the WAL = records that are being replayed. Whenever the currently oldest running = XID finishes, we scan the CLOG to find the next oldest XID that hasn't = completed yet. >=20 > That adds approximately one or two CLOG lookup to every commit record = replay on average. I haven't tried measuring that, but it seems like it = could slow down recovery. There are ways that could be improved. For = example, do it in larger batches. >=20 >=20 > A bunch of other small XXX comments remain, but they're just markers = for comments that need to be adjusted, or for further cleanups that are = now possible. >=20 >=20 > There are also several ways the inprogress cache could be made more = efficient, which I haven't explored: >=20 > - For each XID in the cache radix tree, we store one bit to indicate = whether the lookup has been performed, i.e. if the cache is valid for = the XID, and another bit to indicate if the XID is visible or not. With = 64-bit cache words stored in the radix tree, each cache word can store = the status of 32 transactions. It would probably be better to work in = bigger chunks. For example, when doing a lookup in the cache, check the = status of 64 transactions at once. Assuming they're all stored on the = same CSN page, it would not be much more expensive than a single XID = lookup. That would make the cache 2x more compact, and save on future = lookups of XIDS falling on the same cache word. >=20 > - Initializing the radix tree cache is fairly expensive, with several = memory allocations. Many of those allocations could be done lazily with = some effort in radixtree.h. >=20 > - Or start the cache as a small array of XIDs, and switch to the radix = tree only after it fills up. >=20 > --=20 > Heikki Linnakangas > Neon (https://neon.tech) > = --Apple-Mail=_ED800A29-636A-4AE7-B7C0-FC8948D9BD53 Content-Type: multipart/mixed; boundary="Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794" --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8
Hi,

Thanks for the = proposal, it's an interesting approach.

I have = a question regarding the xid visibility during standby = startup. 
If the checkpoint=E2=80=99s `oldestActiveXid` = is smaller than `nextXid`, then there may be already-committed = transactions 
in that range which will not be replayed on = standby. In that case, I believe clog needs to be used for = visibility 
checks within that xid range =E2=80=94 is = that correct?

On top of = your previous discussion, I wrote a test case and attempted to fix the = issue.
Patches 0001=E2=80=930012 = are your original commits, unchanged. Patch 0013 contains my own = ideas.

Since this is my first = time replying to the mailing list, I was worried about breaking the = thread, so I=E2=80=99ve included everything as attachments = instead.

Looking forward to your = thoughts.
Best regards,  
Mingwei = Jia
= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0001-Split-SnapshotData-into-separate-structs-for-each.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0001-Split-SnapshotData-into-separate-structs-for-each.patch" Content-Transfer-Encoding: quoted-printable =46rom=20c2b5bc5f1f2cd959c695a91bd2eec047440426fc=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Fri,=2020=20Dec=202024=2000:36:33=20= +0200=0ASubject:=20[PATCH=20v6=2001/12]=20Split=20SnapshotData=20into=20= separate=20structs=20for=20each=0A=20kind=20of=20snapshot=0A=0AThe=20= SnapshotData=20fields=20were=20repurposed=20for=20different=20uses=20= depending=0Athe=20kind=20of=20snapshot.=20Split=20it=20into=20separate=20= structs=20for=20different=0Akinds=20of=20snapshots,=20so=20that=20it=20= is=20more=20clear=20which=20fields=20are=20used=0Awith=20which=20= snapshot=20kind,=20and=20the=20fields=20can=20have=20more=20descriptive=0A= names.=0A---=0A=20contrib/amcheck/verify_heapam.c=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20|=20=20=202=20+-=0A=20= contrib/amcheck/verify_nbtree.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=20=202=20+-=0A=20src/backend/access/heap/heapam.c=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20=20=203=20+-=0A=20= src/backend/access/heap/heapam_handler.c=20=20=20=20=20=20|=20=20=206=20= +-=0A=20src/backend/access/heap/heapam_visibility.c=20=20=20|=20=2024=20= +--=0A=20src/backend/access/index/indexam.c=20=20=20=20=20=20=20=20=20=20= =20=20|=20=2011=20+-=0A=20src/backend/access/nbtree/nbtinsert.c=20=20=20=20= =20=20=20=20=20|=20=20=204=20+-=0A=20= src/backend/access/spgist/spgvacuum.c=20=20=20=20=20=20=20=20=20|=20=20=20= 2=20+-=0A=20src/backend/access/table/tableam.c=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=208=20+-=0A=20src/backend/access/transam/parallel.c=20=20= =20=20=20=20=20=20=20|=20=2014=20+-=0A=20= src/backend/catalog/pg_inherits.c=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=202=20+-=0A=20src/backend/commands/async.c=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20|=20=20=204=20+-=0A=20= src/backend/commands/indexcmds.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=204=20+-=0A=20src/backend/commands/tablecmds.c=20=20=20=20=20=20=20= =20=20=20=20=20=20=20|=20=20=202=20+-=0A=20= src/backend/executor/execIndexing.c=20=20=20=20=20=20=20=20=20=20=20|=20=20= =204=20+-=0A=20src/backend/executor/execReplication.c=20=20=20=20=20=20=20= =20|=20=20=208=20+-=0A=20src/backend/partitioning/partdesc.c=20=20=20=20=20= =20=20=20=20=20=20|=20=20=202=20+-=0A=20= src/backend/replication/logical/decode.c=20=20=20=20=20=20|=20=20=202=20= +-=0A=20src/backend/replication/logical/origin.c=20=20=20=20=20=20|=20=20= =204=20+-=0A=20.../replication/logical/reorderbuffer.c=20=20=20=20=20=20=20= |=20114=20+++++-----=0A=20src/backend/replication/logical/snapbuild.c=20=20= =20|=20114=20+++++-----=0A=20src/backend/replication/walsender.c=20=20=20= =20=20=20=20=20=20=20=20|=20=20=202=20+-=0A=20= src/backend/storage/ipc/procarray.c=20=20=20=20=20=20=20=20=20=20=20|=20=20= =206=20+-=0A=20src/backend/storage/lmgr/predicate.c=20=20=20=20=20=20=20=20= =20=20|=20=2032=20+--=0A=20src/backend/utils/adt/xid8funcs.c=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20=20=204=20+-=0A=20= src/backend/utils/time/snapmgr.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20198=20+++++++++++-------=0A=20src/include/access/heapam.h=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=202=20+-=0A=20= src/include/access/relscan.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=206=20+-=0A=20src/include/replication/reorderbuffer.h=20= =20=20=20=20=20=20|=20=2012=20+-=0A=20= src/include/replication/snapbuild.h=20=20=20=20=20=20=20=20=20=20=20|=20=20= =206=20+-=0A=20src/include/replication/snapbuild_internal.h=20=20|=20=20=20= 2=20+-=0A=20src/include/storage/predicate.h=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20|=20=20=204=20+-=0A=20src/include/storage/procarray.h=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=202=20+-=0A=20= src/include/utils/snapmgr.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=2016=20+-=0A=20src/include/utils/snapshot.h=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20155=20+++++++++-----=0A=20= src/tools/pgindent/typedefs.list=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=204=20+=0A=2036=20files=20changed,=20451=20insertions(+),=20336=20= deletions(-)=0A=0Adiff=20--git=20a/contrib/amcheck/verify_heapam.c=20= b/contrib/amcheck/verify_heapam.c=0Aindex=201970fc8620a..6665cafc179=20= 100644=0A---=20a/contrib/amcheck/verify_heapam.c=0A+++=20= b/contrib/amcheck/verify_heapam.c=0A@@=20-310,7=20+310,7=20@@=20= verify_heapam(PG_FUNCTION_ARGS)=0A=20=09=20*=20Any=20xmin=20newer=20than=20= the=20xmin=20of=20our=20snapshot=20can't=20become=20all-visible=0A=20=09=20= *=20while=20we're=20running.=0A=20=09=20*/=0A-=09ctx.safe_xmin=20=3D=20= GetTransactionSnapshot()->xmin;=0A+=09ctx.safe_xmin=20=3D=20= GetTransactionSnapshot()->mvcc.xmin;=0A=20=0A=20=09/*=0A=20=09=20*=20If=20= we=20report=20corruption=20when=20not=20examining=20some=20individual=20= attribute,=0Adiff=20--git=20a/contrib/amcheck/verify_nbtree.c=20= b/contrib/amcheck/verify_nbtree.c=0Aindex=20f11c43a0ed7..e90b4a2ad5a=20= 100644=0A---=20a/contrib/amcheck/verify_nbtree.c=0A+++=20= b/contrib/amcheck/verify_nbtree.c=0A@@=20-458,7=20+458,7=20@@=20= bt_check_every_level(Relation=20rel,=20Relation=20heaprel,=20bool=20= heapkeyspace,=0A=20=09=09=09=20*/=0A=20=09=09=09if=20= (IsolationUsesXactSnapshot()=20&&=20rel->rd_index->indcheckxmin=20&&=0A=20= =09=09=09=09= !TransactionIdPrecedes(HeapTupleHeaderGetXmin(rel->rd_indextuple->t_data),= =0A-=09=09=09=09=09=09=09=09=09=20=20=20snapshot->xmin))=0A+=09=09=09=09=09= =09=09=09=09=20=20=20snapshot->mvcc.xmin))=0A=20=09=09=09=09= ereport(ERROR,=0A=20=09=09=09=09=09=09= (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),=0A=20=09=09=09=09=09=09=20= errmsg("index=20\"%s\"=20cannot=20be=20verified=20using=20transaction=20= snapshot",=0Adiff=20--git=20a/src/backend/access/heap/heapam.c=20= b/src/backend/access/heap/heapam.c=0Aindex=206e433db039e..0cfa100cbd1=20= 100644=0A---=20a/src/backend/access/heap/heapam.c=0A+++=20= b/src/backend/access/heap/heapam.c=0A@@=20-605,7=20+605,8=20@@=20= heap_prepare_pagescan(TableScanDesc=20sscan)=0A=20=09=20*=20full=20page=20= write.=20Until=20we=20can=20prove=20that=20beyond=20doubt,=20let's=20= check=20each=0A=20=09=20*=20tuple=20for=20visibility=20the=20hard=20way.=0A= =20=09=20*/=0A-=09all_visible=20=3D=20PageIsAllVisible(page)=20&&=20= !snapshot->takenDuringRecovery;=0A+=09all_visible=20=3D=20= PageIsAllVisible(page)=20&&=0A+=09=09(snapshot->snapshot_type=20!=3D=20= SNAPSHOT_MVCC=20||=20!snapshot->mvcc.takenDuringRecovery);=0A=20=09= check_serializable=20=3D=0A=20=09=09= CheckForSerializableConflictOutNeeded(scan->rs_base.rs_rd,=20snapshot);=0A= =20=0Adiff=20--git=20a/src/backend/access/heap/heapam_handler.c=20= b/src/backend/access/heap/heapam_handler.c=0Aindex=20= 24d3765aa20..fce657f00f6=20100644=0A---=20= a/src/backend/access/heap/heapam_handler.c=0A+++=20= b/src/backend/access/heap/heapam_handler.c=0A@@=20-390,7=20+390,7=20@@=20= tuple_lock_retry:=0A=20=0A=20=09=09if=20(!ItemPointerEquals(&tmfd->ctid,=20= &tuple->t_self))=0A=20=09=09{=0A-=09=09=09SnapshotData=20SnapshotDirty;=0A= +=09=09=09DirtySnapshotData=20SnapshotDirty;=0A=20=09=09=09TransactionId=20= priorXmax;=0A=20=0A=20=09=09=09/*=20it=20was=20updated,=20so=20look=20at=20= the=20updated=20version=20*/=0A@@=20-415,7=20+415,7=20@@=20= tuple_lock_retry:=0A=20=09=09=09=09=09=09=09=20errmsg("tuple=20to=20be=20= locked=20was=20already=20moved=20to=20another=20partition=20due=20to=20= concurrent=20update")));=0A=20=0A=20=09=09=09=09tuple->t_self=20=3D=20= *tid;=0A-=09=09=09=09if=20(heap_fetch(relation,=20&SnapshotDirty,=20= tuple,=20&buffer,=20true))=0A+=09=09=09=09if=20(heap_fetch(relation,=20= (Snapshot)=20&SnapshotDirty,=20tuple,=20&buffer,=20true))=0A=20=09=09=09=09= {=0A=20=09=09=09=09=09/*=0A=20=09=09=09=09=09=20*=20If=20xmin=20isn't=20= what=20we're=20expecting,=20the=20slot=20must=20have=0A@@=20-2308,7=20= +2308,7=20@@=20heapam_scan_sample_next_tuple(TableScanDesc=20scan,=20= SampleScanState=20*scanstate,=0A=20=0A=20=09page=20=3D=20(Page)=20= BufferGetPage(hscan->rs_cbuf);=0A=20=09all_visible=20=3D=20= PageIsAllVisible(page)=20&&=0A-=09=09= !scan->rs_snapshot->takenDuringRecovery;=0A+=09=09= (scan->rs_snapshot->snapshot_type=20!=3D=20SNAPSHOT_MVCC=20||=20= !scan->rs_snapshot->mvcc.takenDuringRecovery);=0A=20=09maxoffset=20=3D=20= PageGetMaxOffsetNumber(page);=0A=20=0A=20=09for=20(;;)=0Adiff=20--git=20= a/src/backend/access/heap/heapam_visibility.c=20= b/src/backend/access/heap/heapam_visibility.c=0Aindex=20= 05f6946fe60..f5d69b558f1=20100644=0A---=20= a/src/backend/access/heap/heapam_visibility.c=0A+++=20= b/src/backend/access/heap/heapam_visibility.c=0A@@=20-740,7=20+740,7=20= @@=20HeapTupleSatisfiesUpdate(HeapTuple=20htup,=20CommandId=20curcid,=0A=20= =20*=20token=20is=20also=20returned=20in=20snapshot->speculativeToken.=0A= =20=20*/=0A=20static=20bool=0A-HeapTupleSatisfiesDirty(HeapTuple=20htup,=20= Snapshot=20snapshot,=0A+HeapTupleSatisfiesDirty(HeapTuple=20htup,=20= DirtySnapshotData=20*snapshot,=0A=20=09=09=09=09=09=09Buffer=20buffer)=0A= =20{=0A=20=09HeapTupleHeader=20tuple=20=3D=20htup->t_data;=0A@@=20-957,7=20= +957,7=20@@=20HeapTupleSatisfiesDirty(HeapTuple=20htup,=20Snapshot=20= snapshot,=0A=20=20*=20and=20more=20contention=20on=20ProcArrayLock.=0A=20= =20*/=0A=20static=20bool=0A-HeapTupleSatisfiesMVCC(HeapTuple=20htup,=20= Snapshot=20snapshot,=0A+HeapTupleSatisfiesMVCC(HeapTuple=20htup,=20= MVCCSnapshot=20snapshot,=0A=20=09=09=09=09=09=20=20=20Buffer=20buffer)=0A= =20{=0A=20=09HeapTupleHeader=20tuple=20=3D=20htup->t_data;=0A@@=20= -1435,7=20+1435,7=20@@=20HeapTupleSatisfiesVacuumHorizon(HeapTuple=20= htup,=20Buffer=20buffer,=20TransactionId=20*de=0A=20=20*=09= snapshot->vistest=20must=20have=20been=20set=20up=20with=20the=20horizon=20= to=20use.=0A=20=20*/=0A=20static=20bool=0A= -HeapTupleSatisfiesNonVacuumable(HeapTuple=20htup,=20Snapshot=20= snapshot,=0A+HeapTupleSatisfiesNonVacuumable(HeapTuple=20htup,=20= NonVacuumableSnapshotData=20*snapshot,=0A=20=09=09=09=09=09=09=09=09= Buffer=20buffer)=0A=20{=0A=20=09TransactionId=20dead_after=20=3D=20= InvalidTransactionId;=0A@@=20-1593,7=20+1593,7=20@@=20= TransactionIdInArray(TransactionId=20xid,=20TransactionId=20*xip,=20Size=20= num)=0A=20=20*=20complicated=20than=20when=20dealing=20"only"=20with=20= the=20present.=0A=20=20*/=0A=20static=20bool=0A= -HeapTupleSatisfiesHistoricMVCC(HeapTuple=20htup,=20Snapshot=20snapshot,=0A= +HeapTupleSatisfiesHistoricMVCC(HeapTuple=20htup,=20HistoricMVCCSnapshot=20= snapshot,=0A=20=09=09=09=09=09=09=09=20=20=20Buffer=20buffer)=0A=20{=0A=20= =09HeapTupleHeader=20tuple=20=3D=20htup->t_data;=0A@@=20-1610,7=20= +1610,7=20@@=20HeapTupleSatisfiesHistoricMVCC(HeapTuple=20htup,=20= Snapshot=20snapshot,=0A=20=09=09return=20false;=0A=20=09}=0A=20=09/*=20= check=20if=20it's=20one=20of=20our=20txids,=20toplevel=20is=20also=20in=20= there=20*/=0A-=09else=20if=20(TransactionIdInArray(xmin,=20= snapshot->subxip,=20snapshot->subxcnt))=0A+=09else=20if=20= (TransactionIdInArray(xmin,=20snapshot->curxip,=20snapshot->curxcnt))=0A=20= =09{=0A=20=09=09bool=09=09resolved;=0A=20=09=09CommandId=09cmin=20=3D=20= HeapTupleHeaderGetRawCommandId(tuple);=0A@@=20-1669,7=20+1669,7=20@@=20= HeapTupleSatisfiesHistoricMVCC(HeapTuple=20htup,=20Snapshot=20snapshot,=0A= =20=09=09return=20false;=0A=20=09}=0A=20=09/*=20check=20if=20it's=20a=20= committed=20transaction=20in=20[xmin,=20xmax)=20*/=0A-=09else=20if=20= (TransactionIdInArray(xmin,=20snapshot->xip,=20snapshot->xcnt))=0A+=09= else=20if=20(TransactionIdInArray(xmin,=20snapshot->committed_xids,=20= snapshot->xcnt))=0A=20=09{=0A=20=09=09/*=20fall=20through=20*/=0A=20=09}=0A= @@=20-1702,7=20+1702,7=20@@=20HeapTupleSatisfiesHistoricMVCC(HeapTuple=20= htup,=20Snapshot=20snapshot,=0A=20=09}=0A=20=0A=20=09/*=20check=20if=20= it's=20one=20of=20our=20txids,=20toplevel=20is=20also=20in=20there=20*/=0A= -=09if=20(TransactionIdInArray(xmax,=20snapshot->subxip,=20= snapshot->subxcnt))=0A+=09if=20(TransactionIdInArray(xmax,=20= snapshot->curxip,=20snapshot->curxcnt))=0A=20=09{=0A=20=09=09bool=09=09= resolved;=0A=20=09=09CommandId=09cmin;=0A@@=20-1755,7=20+1755,7=20@@=20= HeapTupleSatisfiesHistoricMVCC(HeapTuple=20htup,=20Snapshot=20snapshot,=0A= =20=09else=20if=20(TransactionIdFollowsOrEquals(xmax,=20snapshot->xmax))=0A= =20=09=09return=20true;=0A=20=09/*=20xmax=20is=20between=20[xmin,=20= xmax),=20check=20known=20committed=20array=20*/=0A-=09else=20if=20= (TransactionIdInArray(xmax,=20snapshot->xip,=20snapshot->xcnt))=0A+=09= else=20if=20(TransactionIdInArray(xmax,=20snapshot->committed_xids,=20= snapshot->xcnt))=0A=20=09=09return=20false;=0A=20=09/*=20xmax=20is=20= between=20[xmin,=20xmax),=20but=20known=20not=20to=20have=20committed=20= yet=20*/=0A=20=09else=0A@@=20-1778,7=20+1778,7=20@@=20= HeapTupleSatisfiesVisibility(HeapTuple=20htup,=20Snapshot=20snapshot,=20= Buffer=20buffer)=0A=20=09switch=20(snapshot->snapshot_type)=0A=20=09{=0A=20= =09=09case=20SNAPSHOT_MVCC:=0A-=09=09=09return=20= HeapTupleSatisfiesMVCC(htup,=20snapshot,=20buffer);=0A+=09=09=09return=20= HeapTupleSatisfiesMVCC(htup,=20&snapshot->mvcc,=20buffer);=0A=20=09=09= case=20SNAPSHOT_SELF:=0A=20=09=09=09return=20= HeapTupleSatisfiesSelf(htup,=20snapshot,=20buffer);=0A=20=09=09case=20= SNAPSHOT_ANY:=0A@@=20-1786,11=20+1786,11=20@@=20= HeapTupleSatisfiesVisibility(HeapTuple=20htup,=20Snapshot=20snapshot,=20= Buffer=20buffer)=0A=20=09=09case=20SNAPSHOT_TOAST:=0A=20=09=09=09return=20= HeapTupleSatisfiesToast(htup,=20snapshot,=20buffer);=0A=20=09=09case=20= SNAPSHOT_DIRTY:=0A-=09=09=09return=20HeapTupleSatisfiesDirty(htup,=20= snapshot,=20buffer);=0A+=09=09=09return=20HeapTupleSatisfiesDirty(htup,=20= &snapshot->dirty,=20buffer);=0A=20=09=09case=20SNAPSHOT_HISTORIC_MVCC:=0A= -=09=09=09return=20HeapTupleSatisfiesHistoricMVCC(htup,=20snapshot,=20= buffer);=0A+=09=09=09return=20HeapTupleSatisfiesHistoricMVCC(htup,=20= &snapshot->historic_mvcc,=20buffer);=0A=20=09=09case=20= SNAPSHOT_NON_VACUUMABLE:=0A-=09=09=09return=20= HeapTupleSatisfiesNonVacuumable(htup,=20snapshot,=20buffer);=0A+=09=09=09= return=20HeapTupleSatisfiesNonVacuumable(htup,=20= &snapshot->nonvacuumable,=20buffer);=0A=20=09}=0A=20=0A=20=09return=20= false;=09=09=09=09/*=20keep=20compiler=20quiet=20*/=0Adiff=20--git=20= a/src/backend/access/index/indexam.c=20= b/src/backend/access/index/indexam.c=0Aindex=2055ec4c10352..769170a37d5=20= 100644=0A---=20a/src/backend/access/index/indexam.c=0A+++=20= b/src/backend/access/index/indexam.c=0A@@=20-469,7=20+469,7=20@@=20= index_parallelscan_estimate(Relation=20indexRelation,=20int=20nkeys,=20= int=20norderbys,=0A=20=09RELATION_CHECKS;=0A=20=0A=20=09nbytes=20=3D=20= offsetof(ParallelIndexScanDescData,=20ps_snapshot_data);=0A-=09nbytes=20= =3D=20add_size(nbytes,=20EstimateSnapshotSpace(snapshot));=0A+=09nbytes=20= =3D=20add_size(nbytes,=20EstimateSnapshotSpace(&snapshot->mvcc));=0A=20=09= nbytes=20=3D=20MAXALIGN(nbytes);=0A=20=0A=20=09if=20(instrument)=0A@@=20= -517,16=20+517,17=20@@=20index_parallelscan_initialize(Relation=20= heapRelation,=20Relation=20indexRelation,=0A=20=09Assert(instrument=20||=20= parallel_aware);=0A=20=0A=20=09RELATION_CHECKS;=0A+=09= Assert(snapshot->snapshot_type=20=3D=3D=20SNAPSHOT_MVCC);=0A=20=0A=20=09= offset=20=3D=20add_size(offsetof(ParallelIndexScanDescData,=20= ps_snapshot_data),=0A-=09=09=09=09=09=20=20= EstimateSnapshotSpace(snapshot));=0A+=09=09=09=09=09=20=20= EstimateSnapshotSpace((MVCCSnapshot)=20snapshot));=0A=20=09offset=20=3D=20= MAXALIGN(offset);=0A=20=0A=20=09target->ps_locator=20=3D=20= heapRelation->rd_locator;=0A=20=09target->ps_indexlocator=20=3D=20= indexRelation->rd_locator;=0A=20=09target->ps_offset_ins=20=3D=200;=0A=20= =09target->ps_offset_am=20=3D=200;=0A-=09SerializeSnapshot(snapshot,=20= target->ps_snapshot_data);=0A+=09SerializeSnapshot((MVCCSnapshot)=20= snapshot,=20target->ps_snapshot_data);=0A=20=0A=20=09if=20(instrument)=0A= =20=09{=0A@@=20-590,8=20+591,8=20@@=20index_beginscan_parallel(Relation=20= heaprel,=20Relation=20indexrel,=0A=20=09= Assert(RelFileLocatorEquals(heaprel->rd_locator,=20pscan->ps_locator));=0A= =20=09Assert(RelFileLocatorEquals(indexrel->rd_locator,=20= pscan->ps_indexlocator));=0A=20=0A-=09snapshot=20=3D=20= RestoreSnapshot(pscan->ps_snapshot_data);=0A-=09= RegisterSnapshot(snapshot);=0A+=09snapshot=20=3D=20(Snapshot)=20= RestoreSnapshot(pscan->ps_snapshot_data);=0A+=09snapshot=20=3D=20= RegisterSnapshot(snapshot);=0A=20=09scan=20=3D=20= index_beginscan_internal(indexrel,=20nkeys,=20norderbys,=20snapshot,=0A=20= =09=09=09=09=09=09=09=09=09pscan,=20true);=0A=20=0Adiff=20--git=20= a/src/backend/access/nbtree/nbtinsert.c=20= b/src/backend/access/nbtree/nbtinsert.c=0Aindex=20= aa82cede30a..714e4ee3f0b=20100644=0A---=20= a/src/backend/access/nbtree/nbtinsert.c=0A+++=20= b/src/backend/access/nbtree/nbtinsert.c=0A@@=20-413,7=20+413,7=20@@=20= _bt_check_unique(Relation=20rel,=20BTInsertState=20insertstate,=20= Relation=20heapRel,=0A=20=09IndexTuple=09curitup=20=3D=20NULL;=0A=20=09= ItemId=09=09curitemid=20=3D=20NULL;=0A=20=09BTScanInsert=20itup_key=20=3D=20= insertstate->itup_key;=0A-=09SnapshotData=20SnapshotDirty;=0A+=09= DirtySnapshotData=20SnapshotDirty;=0A=20=09OffsetNumber=20offset;=0A=20=09= OffsetNumber=20maxoff;=0A=20=09Page=09=09page;=0A@@=20-558,7=20+558,7=20= @@=20_bt_check_unique(Relation=20rel,=20BTInsertState=20insertstate,=20= Relation=20heapRel,=0A=20=09=09=09=09=20*=20index=20entry=20for=20the=20= entire=20chain.=0A=20=09=09=09=09=20*/=0A=20=09=09=09=09else=20if=20= (table_index_fetch_tuple_check(heapRel,=20&htid,=0A-=09=09=09=09=09=09=09= =09=09=09=09=09=09=20=20=20&SnapshotDirty,=0A+=09=09=09=09=09=09=09=09=09= =09=09=09=09=20=20=20(Snapshot)=20&SnapshotDirty,=0A=20=09=09=09=09=09=09= =09=09=09=09=09=09=09=20=20=20&all_dead))=0A=20=09=09=09=09{=0A=20=09=09=09= =09=09TransactionId=20xwait;=0Adiff=20--git=20= a/src/backend/access/spgist/spgvacuum.c=20= b/src/backend/access/spgist/spgvacuum.c=0Aindex=20= b3df2d89074..850ad36cd0a=20100644=0A---=20= a/src/backend/access/spgist/spgvacuum.c=0A+++=20= b/src/backend/access/spgist/spgvacuum.c=0A@@=20-808,7=20+808,7=20@@=20= spgvacuumscan(spgBulkDeleteState=20*bds)=0A=20=09/*=20Finish=20setting=20= up=20spgBulkDeleteState=20*/=0A=20=09initSpGistState(&bds->spgstate,=20= index);=0A=20=09bds->pendingList=20=3D=20NULL;=0A-=09bds->myXmin=20=3D=20= GetActiveSnapshot()->xmin;=0A+=09bds->myXmin=20=3D=20= GetActiveSnapshot()->mvcc.xmin;=0A=20=09bds->lastFilledBlock=20=3D=20= SPGIST_LAST_FIXED_BLKNO;=0A=20=0A=20=09/*=0Adiff=20--git=20= a/src/backend/access/table/tableam.c=20= b/src/backend/access/table/tableam.c=0Aindex=20a56c5eceb14..4eb81e40d99=20= 100644=0A---=20a/src/backend/access/table/tableam.c=0A+++=20= b/src/backend/access/table/tableam.c=0A@@=20-133,7=20+133,7=20@@=20= table_parallelscan_estimate(Relation=20rel,=20Snapshot=20snapshot)=0A=20=09= Size=09=09sz=20=3D=200;=0A=20=0A=20=09if=20(IsMVCCSnapshot(snapshot))=0A= -=09=09sz=20=3D=20add_size(sz,=20EstimateSnapshotSpace(snapshot));=0A+=09= =09sz=20=3D=20add_size(sz,=20EstimateSnapshotSpace((MVCCSnapshot)=20= snapshot));=0A=20=09else=0A=20=09=09Assert(snapshot=20=3D=3D=20= SnapshotAny);=0A=20=0A@@=20-152,7=20+152,7=20@@=20= table_parallelscan_initialize(Relation=20rel,=20ParallelTableScanDesc=20= pscan,=0A=20=0A=20=09if=20(IsMVCCSnapshot(snapshot))=0A=20=09{=0A-=09=09= SerializeSnapshot(snapshot,=20(char=20*)=20pscan=20+=20= pscan->phs_snapshot_off);=0A+=09=09SerializeSnapshot((MVCCSnapshot)=20= snapshot,=20(char=20*)=20pscan=20+=20pscan->phs_snapshot_off);=0A=20=09=09= pscan->phs_snapshot_any=20=3D=20false;=0A=20=09}=0A=20=09else=0A@@=20= -174,8=20+174,8=20@@=20table_beginscan_parallel(Relation=20relation,=20= ParallelTableScanDesc=20pscan)=0A=20=09if=20(!pscan->phs_snapshot_any)=0A= =20=09{=0A=20=09=09/*=20Snapshot=20was=20serialized=20--=20restore=20it=20= */=0A-=09=09snapshot=20=3D=20RestoreSnapshot((char=20*)=20pscan=20+=20= pscan->phs_snapshot_off);=0A-=09=09RegisterSnapshot(snapshot);=0A+=09=09= snapshot=20=3D=20(Snapshot)=20RestoreSnapshot((char=20*)=20pscan=20+=20= pscan->phs_snapshot_off);=0A+=09=09snapshot=20=3D=20= RegisterSnapshot(snapshot);=0A=20=09=09flags=20|=3D=20SO_TEMP_SNAPSHOT;=0A= =20=09}=0A=20=09else=0Adiff=20--git=20= a/src/backend/access/transam/parallel.c=20= b/src/backend/access/transam/parallel.c=0Aindex=20= 94db1ec3012..8046e14abf7=20100644=0A---=20= a/src/backend/access/transam/parallel.c=0A+++=20= b/src/backend/access/transam/parallel.c=0A@@=20-275,10=20+275,10=20@@=20= InitializeParallelDSM(ParallelContext=20*pcxt)=0A=20=09=09= shm_toc_estimate_chunk(&pcxt->estimator,=20combocidlen);=0A=20=09=09if=20= (IsolationUsesXactSnapshot())=0A=20=09=09{=0A-=09=09=09tsnaplen=20=3D=20= EstimateSnapshotSpace(transaction_snapshot);=0A+=09=09=09tsnaplen=20=3D=20= EstimateSnapshotSpace((MVCCSnapshot)=20transaction_snapshot);=0A=20=09=09= =09shm_toc_estimate_chunk(&pcxt->estimator,=20tsnaplen);=0A=20=09=09}=0A= -=09=09asnaplen=20=3D=20EstimateSnapshotSpace(active_snapshot);=0A+=09=09= asnaplen=20=3D=20EstimateSnapshotSpace((MVCCSnapshot)=20= active_snapshot);=0A=20=09=09shm_toc_estimate_chunk(&pcxt->estimator,=20= asnaplen);=0A=20=09=09tstatelen=20=3D=20EstimateTransactionStateSpace();=0A= =20=09=09shm_toc_estimate_chunk(&pcxt->estimator,=20tstatelen);=0A@@=20= -400,14=20+400,14=20@@=20InitializeParallelDSM(ParallelContext=20*pcxt)=0A= =20=09=09if=20(IsolationUsesXactSnapshot())=0A=20=09=09{=0A=20=09=09=09= tsnapspace=20=3D=20shm_toc_allocate(pcxt->toc,=20tsnaplen);=0A-=09=09=09= SerializeSnapshot(transaction_snapshot,=20tsnapspace);=0A+=09=09=09= SerializeSnapshot((MVCCSnapshot)=20transaction_snapshot,=20tsnapspace);=0A= =20=09=09=09shm_toc_insert(pcxt->toc,=20= PARALLEL_KEY_TRANSACTION_SNAPSHOT,=0A=20=09=09=09=09=09=09=20=20=20= tsnapspace);=0A=20=09=09}=0A=20=0A=20=09=09/*=20Serialize=20the=20active=20= snapshot.=20*/=0A=20=09=09asnapspace=20=3D=20shm_toc_allocate(pcxt->toc,=20= asnaplen);=0A-=09=09SerializeSnapshot(active_snapshot,=20asnapspace);=0A= +=09=09SerializeSnapshot((MVCCSnapshot)=20active_snapshot,=20= asnapspace);=0A=20=09=09shm_toc_insert(pcxt->toc,=20= PARALLEL_KEY_ACTIVE_SNAPSHOT,=20asnapspace);=0A=20=0A=20=09=09/*=20= Provide=20the=20handle=20for=20per-session=20segment.=20*/=0A@@=20= -1493,9=20+1493,9=20@@=20ParallelWorkerMain(Datum=20main_arg)=0A=20=09=20= */=0A=20=09asnapspace=20=3D=20shm_toc_lookup(toc,=20= PARALLEL_KEY_ACTIVE_SNAPSHOT,=20false);=0A=20=09tsnapspace=20=3D=20= shm_toc_lookup(toc,=20PARALLEL_KEY_TRANSACTION_SNAPSHOT,=20true);=0A-=09= asnapshot=20=3D=20RestoreSnapshot(asnapspace);=0A-=09tsnapshot=20=3D=20= tsnapspace=20?=20RestoreSnapshot(tsnapspace)=20:=20asnapshot;=0A-=09= RestoreTransactionSnapshot(tsnapshot,=0A+=09asnapshot=20=3D=20(Snapshot)=20= RestoreSnapshot(asnapspace);=0A+=09tsnapshot=20=3D=20tsnapspace=20?=20= (Snapshot)=20RestoreSnapshot(tsnapspace)=20:=20asnapshot;=0A+=09= RestoreTransactionSnapshot((MVCCSnapshot)=20tsnapshot,=0A=20=09=09=09=09=09= =09=09=20=20=20fps->parallel_leader_pgproc);=0A=20=09= PushActiveSnapshot(asnapshot);=0A=20=0Adiff=20--git=20= a/src/backend/catalog/pg_inherits.c=20= b/src/backend/catalog/pg_inherits.c=0Aindex=20929bb53b620..b658601bf77=20= 100644=0A---=20a/src/backend/catalog/pg_inherits.c=0A+++=20= b/src/backend/catalog/pg_inherits.c=0A@@=20-148,7=20+148,7=20@@=20= find_inheritance_children_extended(Oid=20parentrelId,=20bool=20= omit_detached,=0A=20=09=09=09=09xmin=20=3D=20= HeapTupleHeaderGetXmin(inheritsTuple->t_data);=0A=20=09=09=09=09snap=20=3D= =20GetActiveSnapshot();=0A=20=0A-=09=09=09=09if=20= (!XidInMVCCSnapshot(xmin,=20snap))=0A+=09=09=09=09if=20= (!XidInMVCCSnapshot(xmin,=20(MVCCSnapshot)=20snap))=0A=20=09=09=09=09{=0A= =20=09=09=09=09=09if=20(detached_xmin)=0A=20=09=09=09=09=09{=0Adiff=20= --git=20a/src/backend/commands/async.c=20b/src/backend/commands/async.c=0A= index=204bd37d5beb5..1ffb6f5fa70=20100644=0A---=20= a/src/backend/commands/async.c=0A+++=20b/src/backend/commands/async.c=0A= @@=20-2022,6=20+2022,8=20@@=20asyncQueueProcessPageEntries(volatile=20= QueuePosition=20*current,=0A=20=09bool=09=09reachedEndOfPage;=0A=20=09= AsyncQueueEntry=20*qe;=0A=20=0A+=09Assert(snapshot->snapshot_type=20=3D=3D= =20SNAPSHOT_MVCC);=0A+=0A=20=09do=0A=20=09{=0A=20=09=09QueuePosition=20= thisentry=20=3D=20*current;=0A@@=20-2041,7=20+2043,7=20@@=20= asyncQueueProcessPageEntries(volatile=20QueuePosition=20*current,=0A=20=09= =09/*=20Ignore=20messages=20destined=20for=20other=20databases=20*/=0A=20= =09=09if=20(qe->dboid=20=3D=3D=20MyDatabaseId)=0A=20=09=09{=0A-=09=09=09= if=20(XidInMVCCSnapshot(qe->xid,=20snapshot))=0A+=09=09=09if=20= (XidInMVCCSnapshot(qe->xid,=20(MVCCSnapshot)=20snapshot))=0A=20=09=09=09= {=0A=20=09=09=09=09/*=0A=20=09=09=09=09=20*=20The=20source=20transaction=20= is=20still=20in=20progress,=20so=20we=20can't=0Adiff=20--git=20= a/src/backend/commands/indexcmds.c=20b/src/backend/commands/indexcmds.c=0A= index=2033c2106c17c..da3e02398bb=20100644=0A---=20= a/src/backend/commands/indexcmds.c=0A+++=20= b/src/backend/commands/indexcmds.c=0A@@=20-1761,7=20+1761,7=20@@=20= DefineIndex(Oid=20tableId,=0A=20=09=20*=20they=20must=20wait=20for.=20=20= But=20first,=20save=20the=20snapshot's=20xmin=20to=20use=20as=0A=20=09=20= *=20limitXmin=20for=20GetCurrentVirtualXIDs().=0A=20=09=20*/=0A-=09= limitXmin=20=3D=20snapshot->xmin;=0A+=09limitXmin=20=3D=20= snapshot->mvcc.xmin;=0A=20=0A=20=09PopActiveSnapshot();=0A=20=09= UnregisterSnapshot(snapshot);=0A@@=20-4156,7=20+4156,7=20@@=20= ReindexRelationConcurrently(const=20ReindexStmt=20*stmt,=20Oid=20= relationOid,=20const=20Rein=0A=20=09=09=20*=20We=20can=20now=20do=20away=20= with=20our=20active=20snapshot,=20we=20still=20need=20to=20save=0A=20=09=09= =20*=20the=20xmin=20limit=20to=20wait=20for=20older=20snapshots.=0A=20=09= =09=20*/=0A-=09=09limitXmin=20=3D=20snapshot->xmin;=0A+=09=09limitXmin=20= =3D=20snapshot->mvcc.xmin;=0A=20=0A=20=09=09PopActiveSnapshot();=0A=20=09= =09UnregisterSnapshot(snapshot);=0Adiff=20--git=20= a/src/backend/commands/tablecmds.c=20b/src/backend/commands/tablecmds.c=0A= index=2010624353b0a..c55b5a7a014=20100644=0A---=20= a/src/backend/commands/tablecmds.c=0A+++=20= b/src/backend/commands/tablecmds.c=0A@@=20-20797,7=20+20797,7=20@@=20= ATExecDetachPartitionFinalize(Relation=20rel,=20RangeVar=20*name)=0A=20=09= =20*=20all=20such=20queries=20are=20complete=20(otherwise=20we=20would=20= present=20them=20with=20an=0A=20=09=20*=20inconsistent=20view=20of=20= catalogs).=0A=20=09=20*/=0A-=09WaitForOlderSnapshots(snap->xmin,=20= false);=0A+=09WaitForOlderSnapshots(snap->mvcc.xmin,=20false);=0A=20=0A=20= =09DetachPartitionFinalize(rel,=20partRel,=20true,=20InvalidOid);=0A=20=0A= diff=20--git=20a/src/backend/executor/execIndexing.c=20= b/src/backend/executor/execIndexing.c=0Aindex=20e3fe9b78bb5..a3955792729=20= 100644=0A---=20a/src/backend/executor/execIndexing.c=0A+++=20= b/src/backend/executor/execIndexing.c=0A@@=20-717,7=20+717,7=20@@=20= check_exclusion_or_unique_constraint(Relation=20heap,=20Relation=20= index,=0A=20=09int=09=09=09indnkeyatts=20=3D=20= IndexRelationGetNumberOfKeyAttributes(index);=0A=20=09IndexScanDesc=20= index_scan;=0A=20=09ScanKeyData=20scankeys[INDEX_MAX_KEYS];=0A-=09= SnapshotData=20DirtySnapshot;=0A+=09DirtySnapshotData=20DirtySnapshot;=0A= =20=09int=09=09=09i;=0A=20=09bool=09=09conflict;=0A=20=09bool=09=09= found_self;=0A@@=20-816,7=20+816,7=20@@=20= check_exclusion_or_unique_constraint(Relation=20heap,=20Relation=20= index,=0A=20retry:=0A=20=09conflict=20=3D=20false;=0A=20=09found_self=20= =3D=20false;=0A-=09index_scan=20=3D=20index_beginscan(heap,=20index,=20= &DirtySnapshot,=20NULL,=20indnkeyatts,=200);=0A+=09index_scan=20=3D=20= index_beginscan(heap,=20index,=20(Snapshot)=20&DirtySnapshot,=20NULL,=20= indnkeyatts,=200);=0A=20=09index_rescan(index_scan,=20scankeys,=20= indnkeyatts,=20NULL,=200);=0A=20=0A=20=09while=20= (index_getnext_slot(index_scan,=20ForwardScanDirection,=20= existing_slot))=0Adiff=20--git=20= a/src/backend/executor/execReplication.c=20= b/src/backend/executor/execReplication.c=0Aindex=20= ede89ea3cf9..84aa7c3268c=20100644=0A---=20= a/src/backend/executor/execReplication.c=0A+++=20= b/src/backend/executor/execReplication.c=0A@@=20-184,7=20+184,7=20@@=20= RelationFindReplTupleByIndex(Relation=20rel,=20Oid=20idxoid,=0A=20=09= ScanKeyData=20skey[INDEX_MAX_KEYS];=0A=20=09int=09=09=09skey_attoff;=0A=20= =09IndexScanDesc=20scan;=0A-=09SnapshotData=20snap;=0A+=09= DirtySnapshotData=20snap;=0A=20=09TransactionId=20xwait;=0A=20=09= Relation=09idxrel;=0A=20=09bool=09=09found;=0A@@=20-202,7=20+202,7=20@@=20= RelationFindReplTupleByIndex(Relation=20rel,=20Oid=20idxoid,=0A=20=09= skey_attoff=20=3D=20build_replindex_scan_key(skey,=20rel,=20idxrel,=20= searchslot);=0A=20=0A=20=09/*=20Start=20an=20index=20scan.=20*/=0A-=09= scan=20=3D=20index_beginscan(rel,=20idxrel,=20&snap,=20NULL,=20= skey_attoff,=200);=0A+=09scan=20=3D=20index_beginscan(rel,=20idxrel,=20= (Snapshot)=20&snap,=20NULL,=20skey_attoff,=200);=0A=20=0A=20retry:=0A=20=09= found=20=3D=20false;=0A@@=20-357,7=20+357,7=20@@=20= RelationFindReplTupleSeq(Relation=20rel,=20LockTupleMode=20lockmode,=0A=20= {=0A=20=09TupleTableSlot=20*scanslot;=0A=20=09TableScanDesc=20scan;=0A-=09= SnapshotData=20snap;=0A+=09DirtySnapshotData=20snap;=0A=20=09= TypeCacheEntry=20**eq;=0A=20=09TransactionId=20xwait;=0A=20=09bool=09=09= found;=0A@@=20-369,7=20+369,7=20@@=20RelationFindReplTupleSeq(Relation=20= rel,=20LockTupleMode=20lockmode,=0A=20=0A=20=09/*=20Start=20a=20heap=20= scan.=20*/=0A=20=09InitDirtySnapshot(snap);=0A-=09scan=20=3D=20= table_beginscan(rel,=20&snap,=200,=20NULL);=0A+=09scan=20=3D=20= table_beginscan(rel,=20(Snapshot)=20&snap,=200,=20NULL);=0A=20=09= scanslot=20=3D=20table_slot_create(rel,=20NULL);=0A=20=0A=20retry:=0A= diff=20--git=20a/src/backend/partitioning/partdesc.c=20= b/src/backend/partitioning/partdesc.c=0Aindex=20328b4d450e4..7c15c634181=20= 100644=0A---=20a/src/backend/partitioning/partdesc.c=0A+++=20= b/src/backend/partitioning/partdesc.c=0A@@=20-102,7=20+102,7=20@@=20= RelationGetPartitionDesc(Relation=20rel,=20bool=20omit_detached)=0A=20=09= =09Assert(TransactionIdIsValid(rel->rd_partdesc_nodetached_xmin));=0A=20=09= =09activesnap=20=3D=20GetActiveSnapshot();=0A=20=0A-=09=09if=20= (!XidInMVCCSnapshot(rel->rd_partdesc_nodetached_xmin,=20activesnap))=0A+=09= =09if=20(!XidInMVCCSnapshot(rel->rd_partdesc_nodetached_xmin,=20= &activesnap->mvcc))=0A=20=09=09=09return=20rel->rd_partdesc_nodetached;=0A= =20=09}=0A=20=0Adiff=20--git=20= a/src/backend/replication/logical/decode.c=20= b/src/backend/replication/logical/decode.c=0Aindex=20= 78f9a0a11c4..6a428e9720e=20100644=0A---=20= a/src/backend/replication/logical/decode.c=0A+++=20= b/src/backend/replication/logical/decode.c=0A@@=20-586,7=20+586,7=20@@=20= logicalmsg_decode(LogicalDecodingContext=20*ctx,=20XLogRecordBuffer=20= *buf)=0A=20=09TransactionId=20xid=20=3D=20XLogRecGetXid(r);=0A=20=09= uint8=09=09info=20=3D=20XLogRecGetInfo(r)=20&=20~XLR_INFO_MASK;=0A=20=09= RepOriginId=20origin_id=20=3D=20XLogRecGetOrigin(r);=0A-=09Snapshot=09= snapshot=20=3D=20NULL;=0A+=09HistoricMVCCSnapshot=20snapshot=20=3D=20= NULL;=0A=20=09xl_logical_message=20*message;=0A=20=0A=20=09if=20(info=20= !=3D=20XLOG_LOGICAL_MESSAGE)=0Adiff=20--git=20= a/src/backend/replication/logical/origin.c=20= b/src/backend/replication/logical/origin.c=0Aindex=20= 6583dd497da..51fc6460251=20100644=0A---=20= a/src/backend/replication/logical/origin.c=0A+++=20= b/src/backend/replication/logical/origin.c=0A@@=20-260,7=20+260,7=20@@=20= replorigin_create(const=20char=20*roname)=0A=20=09HeapTuple=09tuple=20=3D=20= NULL;=0A=20=09Relation=09rel;=0A=20=09Datum=09=09roname_d;=0A-=09= SnapshotData=20SnapshotDirty;=0A+=09DirtySnapshotData=20SnapshotDirty;=0A= =20=09SysScanDesc=20scan;=0A=20=09ScanKeyData=20key;=0A=20=0A@@=20-302,7=20= +302,7=20@@=20replorigin_create(const=20char=20*roname)=0A=20=0A=20=09=09= scan=20=3D=20systable_beginscan(rel,=20ReplicationOriginIdentIndex,=0A=20= =09=09=09=09=09=09=09=09=20=20true=20/*=20indexOK=20*/=20,=0A-=09=09=09=09= =09=09=09=09=20=20&SnapshotDirty,=0A+=09=09=09=09=09=09=09=09=20=20= (Snapshot)=20&SnapshotDirty,=0A=20=09=09=09=09=09=09=09=09=20=201,=20= &key);=0A=20=0A=20=09=09collides=20=3D=20= HeapTupleIsValid(systable_getnext(scan));=0Adiff=20--git=20= a/src/backend/replication/logical/reorderbuffer.c=20= b/src/backend/replication/logical/reorderbuffer.c=0Aindex=20= 977fbcd2474..e8196a8d5d5=20100644=0A---=20= a/src/backend/replication/logical/reorderbuffer.c=0A+++=20= b/src/backend/replication/logical/reorderbuffer.c=0A@@=20-268,9=20+268,9=20= @@=20static=20void=20ReorderBufferSerializedPath(char=20*path,=20= ReplicationSlot=20*slot,=0A=20=09=09=09=09=09=09=09=09=09=09= TransactionId=20xid,=20XLogSegNo=20segno);=0A=20static=20int=09= ReorderBufferTXNSizeCompare(const=20pairingheap_node=20*a,=20const=20= pairingheap_node=20*b,=20void=20*arg);=0A=20=0A-static=20void=20= ReorderBufferFreeSnap(ReorderBuffer=20*rb,=20Snapshot=20snap);=0A-static=20= Snapshot=20ReorderBufferCopySnap(ReorderBuffer=20*rb,=20Snapshot=20= orig_snap,=0A-=09=09=09=09=09=09=09=09=09=20=20ReorderBufferTXN=20*txn,=20= CommandId=20cid);=0A+static=20void=20ReorderBufferFreeSnap(ReorderBuffer=20= *rb,=20HistoricMVCCSnapshot=20snap);=0A+static=20HistoricMVCCSnapshot=20= ReorderBufferCopySnap(ReorderBuffer=20*rb,=20HistoricMVCCSnapshot=20= orig_snap,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=20=20ReorderBufferTXN=20= *txn,=20CommandId=20cid);=0A=20=0A=20/*=0A=20=20*=20= ---------------------------------------=0A@@=20-852,7=20+852,7=20@@=20= ReorderBufferQueueChange(ReorderBuffer=20*rb,=20TransactionId=20xid,=20= XLogRecPtr=20lsn,=0A=20=20*/=0A=20void=0A=20= ReorderBufferQueueMessage(ReorderBuffer=20*rb,=20TransactionId=20xid,=0A= -=09=09=09=09=09=09=20=20Snapshot=20snap,=20XLogRecPtr=20lsn,=0A+=09=09=09= =09=09=09=20=20HistoricMVCCSnapshot=20snap,=20XLogRecPtr=20lsn,=0A=20=09=09= =09=09=09=09=20=20bool=20transactional,=20const=20char=20*prefix,=0A=20=09= =09=09=09=09=09=20=20Size=20message_size,=20const=20char=20*message)=0A=20= {=0A@@=20-886,7=20+886,7=20@@=20ReorderBufferQueueMessage(ReorderBuffer=20= *rb,=20TransactionId=20xid,=0A=20=09else=0A=20=09{=0A=20=09=09= ReorderBufferTXN=20*txn=20=3D=20NULL;=0A-=09=09volatile=20Snapshot=20= snapshot_now=20=3D=20snap;=0A+=09=09volatile=09HistoricMVCCSnapshot=20= snapshot_now=20=3D=20snap;=0A=20=0A=20=09=09/*=20Non-transactional=20= changes=20require=20a=20valid=20snapshot.=20*/=0A=20=09=09= Assert(snapshot_now);=0A@@=20-1886,55=20+1886,55=20@@=20= ReorderBufferBuildTupleCidHash(ReorderBuffer=20*rb,=20ReorderBufferTXN=20= *txn)=0A=20=20*=20that=20catalog=20modifying=20transactions=20can=20look=20= into=20intermediate=20catalog=0A=20=20*=20states.=0A=20=20*/=0A-static=20= Snapshot=0A-ReorderBufferCopySnap(ReorderBuffer=20*rb,=20Snapshot=20= orig_snap,=0A+static=20HistoricMVCCSnapshot=0A= +ReorderBufferCopySnap(ReorderBuffer=20*rb,=20HistoricMVCCSnapshot=20= orig_snap,=0A=20=09=09=09=09=09=20=20ReorderBufferTXN=20*txn,=20= CommandId=20cid)=0A=20{=0A-=09Snapshot=09snap;=0A+=09= HistoricMVCCSnapshot=20snap;=0A=20=09dlist_iter=09iter;=0A=20=09int=09=09= =09i=20=3D=200;=0A=20=09Size=09=09size;=0A=20=0A-=09size=20=3D=20= sizeof(SnapshotData)=20+=0A+=09size=20=3D=20= sizeof(HistoricMVCCSnapshotData)=20+=0A=20=09=09sizeof(TransactionId)=20= *=20orig_snap->xcnt=20+=0A=20=09=09sizeof(TransactionId)=20*=20= (txn->nsubtxns=20+=201);=0A=20=0A=20=09snap=20=3D=20= MemoryContextAllocZero(rb->context,=20size);=0A-=09memcpy(snap,=20= orig_snap,=20sizeof(SnapshotData));=0A+=09memcpy(snap,=20orig_snap,=20= sizeof(HistoricMVCCSnapshotData));=0A=20=0A=20=09snap->copied=20=3D=20= true;=0A-=09snap->active_count=20=3D=201;=09=09/*=20mark=20as=20active=20= so=20nobody=20frees=20it=20*/=0A+=09snap->refcount=20=3D=201;=09=09=09/*=20= mark=20as=20active=20so=20nobody=20frees=20it=20*/=0A=20=09= snap->regd_count=20=3D=200;=0A-=09snap->xip=20=3D=20(TransactionId=20*)=20= (snap=20+=201);=0A+=09snap->committed_xids=20=3D=20(TransactionId=20*)=20= (snap=20+=201);=0A=20=0A-=09memcpy(snap->xip,=20orig_snap->xip,=20= sizeof(TransactionId)=20*=20snap->xcnt);=0A+=09= memcpy(snap->committed_xids,=20orig_snap->committed_xids,=20= sizeof(TransactionId)=20*=20snap->xcnt);=0A=20=0A=20=09/*=0A-=09=20*=20= snap->subxip=20contains=20all=20txids=20that=20belong=20to=20our=20= transaction=20which=20we=0A+=09=20*=20snap->curxip=20contains=20all=20= txids=20that=20belong=20to=20our=20transaction=20which=20we=0A=20=09=20*=20= need=20to=20check=20via=20cmin/cmax.=20That's=20why=20we=20store=20the=20= toplevel=0A=20=09=20*=20transaction=20in=20there=20as=20well.=0A=20=09=20= */=0A-=09snap->subxip=20=3D=20snap->xip=20+=20snap->xcnt;=0A-=09= snap->subxip[i++]=20=3D=20txn->xid;=0A+=09snap->curxip=20=3D=20= snap->committed_xids=20+=20snap->xcnt;=0A+=09snap->curxip[i++]=20=3D=20= txn->xid;=0A=20=0A=20=09/*=0A=20=09=20*=20txn->nsubtxns=20isn't=20= decreased=20when=20subtransactions=20abort,=20so=20count=0A=20=09=20*=20= manually.=20Since=20it's=20an=20upper=20boundary=20it=20is=20safe=20to=20= use=20it=20for=20the=0A=20=09=20*=20allocation=20above.=0A=20=09=20*/=0A= -=09snap->subxcnt=20=3D=201;=0A+=09snap->curxcnt=20=3D=201;=0A=20=0A=20=09= dlist_foreach(iter,=20&txn->subtxns)=0A=20=09{=0A=20=09=09= ReorderBufferTXN=20*sub_txn;=0A=20=0A=20=09=09sub_txn=20=3D=20= dlist_container(ReorderBufferTXN,=20node,=20iter.cur);=0A-=09=09= snap->subxip[i++]=20=3D=20sub_txn->xid;=0A-=09=09snap->subxcnt++;=0A+=09=09= snap->curxip[i++]=20=3D=20sub_txn->xid;=0A+=09=09snap->curxcnt++;=0A=20=09= }=0A=20=0A=20=09/*=20sort=20so=20we=20can=20bsearch()=20later=20*/=0A-=09= qsort(snap->subxip,=20snap->subxcnt,=20sizeof(TransactionId),=20= xidComparator);=0A+=09qsort(snap->curxip,=20snap->curxcnt,=20= sizeof(TransactionId),=20xidComparator);=0A=20=0A=20=09/*=20store=20the=20= specified=20current=20CommandId=20*/=0A=20=09snap->curcid=20=3D=20cid;=0A= @@=20-1946,7=20+1946,7=20@@=20ReorderBufferCopySnap(ReorderBuffer=20*rb,=20= Snapshot=20orig_snap,=0A=20=20*=20Free=20a=20previously=20= ReorderBufferCopySnap'ed=20snapshot=0A=20=20*/=0A=20static=20void=0A= -ReorderBufferFreeSnap(ReorderBuffer=20*rb,=20Snapshot=20snap)=0A= +ReorderBufferFreeSnap(ReorderBuffer=20*rb,=20HistoricMVCCSnapshot=20= snap)=0A=20{=0A=20=09if=20(snap->copied)=0A=20=09=09pfree(snap);=0A@@=20= -2099,7=20+2099,7=20@@=20ReorderBufferApplyMessage(ReorderBuffer=20*rb,=20= ReorderBufferTXN=20*txn,=0A=20=20*/=0A=20static=20inline=20void=0A=20= ReorderBufferSaveTXNSnapshot(ReorderBuffer=20*rb,=20ReorderBufferTXN=20= *txn,=0A-=09=09=09=09=09=09=09=20Snapshot=20snapshot_now,=20CommandId=20= command_id)=0A+=09=09=09=09=09=09=09=20HistoricMVCCSnapshot=20= snapshot_now,=20CommandId=20command_id)=0A=20{=0A=20=09txn->command_id=20= =3D=20command_id;=0A=20=0A@@=20-2144,7=20+2144,7=20@@=20= ReorderBufferMaybeMarkTXNStreamed(ReorderBuffer=20*rb,=20= ReorderBufferTXN=20*txn)=0A=20=20*/=0A=20static=20void=0A=20= ReorderBufferResetTXN(ReorderBuffer=20*rb,=20ReorderBufferTXN=20*txn,=0A= -=09=09=09=09=09=20=20Snapshot=20snapshot_now,=0A+=09=09=09=09=09=20=20= HistoricMVCCSnapshot=20snapshot_now,=0A=20=09=09=09=09=09=20=20CommandId=20= command_id,=0A=20=09=09=09=09=09=20=20XLogRecPtr=20last_lsn,=0A=20=09=09=09= =09=09=20=20ReorderBufferChange=20*specinsert)=0A@@=20-2191,7=20+2191,7=20= @@=20ReorderBufferResetTXN(ReorderBuffer=20*rb,=20ReorderBufferTXN=20= *txn,=0A=20static=20void=0A=20ReorderBufferProcessTXN(ReorderBuffer=20= *rb,=20ReorderBufferTXN=20*txn,=0A=20=09=09=09=09=09=09XLogRecPtr=20= commit_lsn,=0A-=09=09=09=09=09=09volatile=20Snapshot=20snapshot_now,=0A+=09= =09=09=09=09=09volatile=20HistoricMVCCSnapshot=20snapshot_now,=0A=20=09=09= =09=09=09=09volatile=20CommandId=20command_id,=0A=20=09=09=09=09=09=09= bool=20streaming)=0A=20{=0A@@=20-2779,7=20+2779,7=20@@=20= ReorderBufferReplay(ReorderBufferTXN=20*txn,=0A=20=09=09=09=09=09= TimestampTz=20commit_time,=0A=20=09=09=09=09=09RepOriginId=20origin_id,=20= XLogRecPtr=20origin_lsn)=0A=20{=0A-=09Snapshot=09snapshot_now;=0A+=09= HistoricMVCCSnapshot=20snapshot_now;=0A=20=09CommandId=09command_id=20=3D=20= FirstCommandId;=0A=20=0A=20=09txn->final_lsn=20=3D=20commit_lsn;=0A@@=20= -3251,7=20+3251,7=20@@=20ReorderBufferProcessXid(ReorderBuffer=20*rb,=20= TransactionId=20xid,=20XLogRecPtr=20lsn)=0A=20=20*/=0A=20void=0A=20= ReorderBufferAddSnapshot(ReorderBuffer=20*rb,=20TransactionId=20xid,=0A-=09= =09=09=09=09=09=20XLogRecPtr=20lsn,=20Snapshot=20snap)=0A+=09=09=09=09=09= =09=20XLogRecPtr=20lsn,=20HistoricMVCCSnapshot=20snap)=0A=20{=0A=20=09= ReorderBufferChange=20*change=20=3D=20ReorderBufferAllocChange(rb);=0A=20= =0A@@=20-3269,7=20+3269,7=20@@=20ReorderBufferAddSnapshot(ReorderBuffer=20= *rb,=20TransactionId=20xid,=0A=20=20*/=0A=20void=0A=20= ReorderBufferSetBaseSnapshot(ReorderBuffer=20*rb,=20TransactionId=20xid,=0A= -=09=09=09=09=09=09=09=20XLogRecPtr=20lsn,=20Snapshot=20snap)=0A+=09=09=09= =09=09=09=09=20XLogRecPtr=20lsn,=20HistoricMVCCSnapshot=20snap)=0A=20{=0A= =20=09ReorderBufferTXN=20*txn;=0A=20=09bool=09=09is_new;=0A@@=20-4043,14=20= +4043,14=20@@=20ReorderBufferSerializeChange(ReorderBuffer=20*rb,=20= ReorderBufferTXN=20*txn,=0A=20=09=09=09}=0A=20=09=09case=20= REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:=0A=20=09=09=09{=0A-=09=09=09=09= Snapshot=09snap;=0A+=09=09=09=09HistoricMVCCSnapshot=20snap;=0A=20=09=09=09= =09char=09=20=20=20*data;=0A=20=0A=20=09=09=09=09snap=20=3D=20= change->data.snapshot;=0A=20=0A-=09=09=09=09sz=20+=3D=20= sizeof(SnapshotData)=20+=0A+=09=09=09=09sz=20+=3D=20= sizeof(HistoricMVCCSnapshotData)=20+=0A=20=09=09=09=09=09= sizeof(TransactionId)=20*=20snap->xcnt=20+=0A-=09=09=09=09=09= sizeof(TransactionId)=20*=20snap->subxcnt;=0A+=09=09=09=09=09= sizeof(TransactionId)=20*=20snap->curxcnt;=0A=20=0A=20=09=09=09=09/*=20= make=20sure=20we=20have=20enough=20space=20*/=0A=20=09=09=09=09= ReorderBufferSerializeReserve(rb,=20sz);=0A@@=20-4058,21=20+4058,21=20@@=20= ReorderBufferSerializeChange(ReorderBuffer=20*rb,=20ReorderBufferTXN=20= *txn,=0A=20=09=09=09=09/*=20might=20have=20been=20reallocated=20above=20= */=0A=20=09=09=09=09ondisk=20=3D=20(ReorderBufferDiskChange=20*)=20= rb->outbuf;=0A=20=0A-=09=09=09=09memcpy(data,=20snap,=20= sizeof(SnapshotData));=0A-=09=09=09=09data=20+=3D=20= sizeof(SnapshotData);=0A+=09=09=09=09memcpy(data,=20snap,=20= sizeof(HistoricMVCCSnapshotData));=0A+=09=09=09=09data=20+=3D=20= sizeof(HistoricMVCCSnapshotData);=0A=20=0A=20=09=09=09=09if=20= (snap->xcnt)=0A=20=09=09=09=09{=0A-=09=09=09=09=09memcpy(data,=20= snap->xip,=0A+=09=09=09=09=09memcpy(data,=20snap->committed_xids,=0A=20=09= =09=09=09=09=09=20=20=20sizeof(TransactionId)=20*=20snap->xcnt);=0A=20=09= =09=09=09=09data=20+=3D=20sizeof(TransactionId)=20*=20snap->xcnt;=0A=20=09= =09=09=09}=0A=20=0A-=09=09=09=09if=20(snap->subxcnt)=0A+=09=09=09=09if=20= (snap->curxcnt)=0A=20=09=09=09=09{=0A-=09=09=09=09=09memcpy(data,=20= snap->subxip,=0A-=09=09=09=09=09=09=20=20=20sizeof(TransactionId)=20*=20= snap->subxcnt);=0A-=09=09=09=09=09data=20+=3D=20sizeof(TransactionId)=20= *=20snap->subxcnt;=0A+=09=09=09=09=09memcpy(data,=20snap->curxip,=0A+=09=09= =09=09=09=09=20=20=20sizeof(TransactionId)=20*=20snap->curxcnt);=0A+=09=09= =09=09=09data=20+=3D=20sizeof(TransactionId)=20*=20snap->curxcnt;=0A=20=09= =09=09=09}=0A=20=09=09=09=09break;=0A=20=09=09=09}=0A@@=20-4177,7=20= +4177,7=20@@=20ReorderBufferCanStartStreaming(ReorderBuffer=20*rb)=0A=20= static=20void=0A=20ReorderBufferStreamTXN(ReorderBuffer=20*rb,=20= ReorderBufferTXN=20*txn)=0A=20{=0A-=09Snapshot=09snapshot_now;=0A+=09= HistoricMVCCSnapshot=20snapshot_now;=0A=20=09CommandId=09command_id;=0A=20= =09Size=09=09stream_bytes;=0A=20=09bool=09=09txn_is_streamed;=0A@@=20= -4196,10=20+4196,10=20@@=20ReorderBufferStreamTXN(ReorderBuffer=20*rb,=20= ReorderBufferTXN=20*txn)=0A=20=09=20*=20After=20that=20we=20need=20to=20= reuse=20the=20snapshot=20from=20the=20previous=20run.=0A=20=09=20*=0A=20=09= =20*=20Unlike=20DecodeCommit=20which=20adds=20xids=20of=20all=20the=20= subtransactions=20in=0A-=09=20*=20snapshot's=20xip=20array=20via=20= SnapBuildCommitTxn,=20we=20can't=20do=20that=20here=20but=0A-=09=20*=20= we=20do=20add=20them=20to=20subxip=20array=20instead=20via=20= ReorderBufferCopySnap.=20This=0A-=09=20*=20allows=20the=20catalog=20= changes=20made=20in=20subtransactions=20decoded=20till=20now=20to=0A-=09=20= *=20be=20visible.=0A+=09=20*=20snapshot's=20committed_xids=20array=20via=20= SnapBuildCommitTxn,=20we=20can't=20do=0A+=09=20*=20that=20here=20but=20= we=20do=20add=20them=20to=20curxip=20array=20instead=20via=0A+=09=20*=20= ReorderBufferCopySnap.=20This=20allows=20the=20catalog=20changes=20made=20= in=0A+=09=20*=20subtransactions=20decoded=20till=20now=20to=20be=20= visible.=0A=20=09=20*/=0A=20=09if=20(txn->snapshot_now=20=3D=3D=20NULL)=0A= =20=09{=0A@@=20-4345,13=20+4345,13=20@@=20= ReorderBufferChangeSize(ReorderBufferChange=20*change)=0A=20=09=09=09}=0A= =20=09=09case=20REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:=0A=20=09=09=09{=0A= -=09=09=09=09Snapshot=09snap;=0A+=09=09=09=09HistoricMVCCSnapshot=20= snap;=0A=20=0A=20=09=09=09=09snap=20=3D=20change->data.snapshot;=0A=20=0A= -=09=09=09=09sz=20+=3D=20sizeof(SnapshotData)=20+=0A+=09=09=09=09sz=20+=3D= =20sizeof(HistoricMVCCSnapshotData)=20+=0A=20=09=09=09=09=09= sizeof(TransactionId)=20*=20snap->xcnt=20+=0A-=09=09=09=09=09= sizeof(TransactionId)=20*=20snap->subxcnt;=0A+=09=09=09=09=09= sizeof(TransactionId)=20*=20snap->curxcnt;=0A=20=0A=20=09=09=09=09break;=0A= =20=09=09=09}=0A@@=20-4629,24=20+4629,24=20@@=20= ReorderBufferRestoreChange(ReorderBuffer=20*rb,=20ReorderBufferTXN=20= *txn,=0A=20=09=09=09}=0A=20=09=09case=20= REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:=0A=20=09=09=09{=0A-=09=09=09=09= Snapshot=09oldsnap;=0A-=09=09=09=09Snapshot=09newsnap;=0A+=09=09=09=09= HistoricMVCCSnapshot=20oldsnap;=0A+=09=09=09=09HistoricMVCCSnapshot=20= newsnap;=0A=20=09=09=09=09Size=09=09size;=0A=20=0A-=09=09=09=09oldsnap=20= =3D=20(Snapshot)=20data;=0A+=09=09=09=09oldsnap=20=3D=20= (HistoricMVCCSnapshot)=20data;=0A=20=0A-=09=09=09=09size=20=3D=20= sizeof(SnapshotData)=20+=0A+=09=09=09=09size=20=3D=20= sizeof(HistoricMVCCSnapshotData)=20+=0A=20=09=09=09=09=09= sizeof(TransactionId)=20*=20oldsnap->xcnt=20+=0A-=09=09=09=09=09= sizeof(TransactionId)=20*=20(oldsnap->subxcnt=20+=200);=0A+=09=09=09=09=09= sizeof(TransactionId)=20*=20(oldsnap->curxcnt=20+=200);=0A=20=0A=20=09=09= =09=09change->data.snapshot=20=3D=20MemoryContextAllocZero(rb->context,=20= size);=0A=20=0A=20=09=09=09=09newsnap=20=3D=20change->data.snapshot;=0A=20= =0A=20=09=09=09=09memcpy(newsnap,=20data,=20size);=0A-=09=09=09=09= newsnap->xip=20=3D=20(TransactionId=20*)=0A-=09=09=09=09=09(((char=20*)=20= newsnap)=20+=20sizeof(SnapshotData));=0A-=09=09=09=09newsnap->subxip=20=3D= =20newsnap->xip=20+=20newsnap->xcnt;=0A+=09=09=09=09= newsnap->committed_xids=20=3D=20(TransactionId=20*)=0A+=09=09=09=09=09= (((char=20*)=20newsnap)=20+=20sizeof(HistoricMVCCSnapshotData));=0A+=09=09= =09=09newsnap->curxip=20=3D=20newsnap->committed_xids=20+=20= newsnap->xcnt;=0A=20=09=09=09=09newsnap->copied=20=3D=20true;=0A=20=09=09= =09=09break;=0A=20=09=09=09}=0A@@=20-5316,7=20+5316,7=20@@=20= file_sort_by_lsn(const=20ListCell=20*a_p,=20const=20ListCell=20*b_p)=0A=20= =20*=20transaction=20for=20relid.=0A=20=20*/=0A=20static=20void=0A= -UpdateLogicalMappings(HTAB=20*tuplecid_data,=20Oid=20relid,=20Snapshot=20= snapshot)=0A+UpdateLogicalMappings(HTAB=20*tuplecid_data,=20Oid=20relid,=20= HistoricMVCCSnapshot=20snapshot)=0A=20{=0A=20=09DIR=09=09=20=20=20= *mapping_dir;=0A=20=09struct=20dirent=20*mapping_de;=0A@@=20-5364,7=20= +5364,7=20@@=20UpdateLogicalMappings(HTAB=20*tuplecid_data,=20Oid=20= relid,=20Snapshot=20snapshot)=0A=20=09=09=09continue;=0A=20=0A=20=09=09= /*=20not=20for=20our=20transaction=20*/=0A-=09=09if=20= (!TransactionIdInArray(f_mapped_xid,=20snapshot->subxip,=20= snapshot->subxcnt))=0A+=09=09if=20(!TransactionIdInArray(f_mapped_xid,=20= snapshot->curxip,=20snapshot->curxcnt))=0A=20=09=09=09continue;=0A=20=0A=20= =09=09/*=20ok,=20relevant,=20queue=20for=20apply=20*/=0A@@=20-5383,7=20= +5383,7=20@@=20UpdateLogicalMappings(HTAB=20*tuplecid_data,=20Oid=20= relid,=20Snapshot=20snapshot)=0A=20=09=09RewriteMappingFile=20*f=20=3D=20= (RewriteMappingFile=20*)=20lfirst(file);=0A=20=0A=20=09=09elog(DEBUG1,=20= "applying=20mapping:=20\"%s\"=20in=20%u",=20f->fname,=0A-=09=09=09=20= snapshot->subxip[0]);=0A+=09=09=09=20snapshot->curxip[0]);=0A=20=09=09= ApplyLogicalMappingFile(tuplecid_data,=20relid,=20f->fname);=0A=20=09=09= pfree(f);=0A=20=09}=0A@@=20-5395,7=20+5395,7=20@@=20= UpdateLogicalMappings(HTAB=20*tuplecid_data,=20Oid=20relid,=20Snapshot=20= snapshot)=0A=20=20*/=0A=20bool=0A=20ResolveCminCmaxDuringDecoding(HTAB=20= *tuplecid_data,=0A-=09=09=09=09=09=09=09=20=20Snapshot=20snapshot,=0A+=09= =09=09=09=09=09=09=20=20HistoricMVCCSnapshot=20snapshot,=0A=20=09=09=09=09= =09=09=09=20=20HeapTuple=20htup,=20Buffer=20buffer,=0A=20=09=09=09=09=09=09= =09=20=20CommandId=20*cmin,=20CommandId=20*cmax)=0A=20{=0Adiff=20--git=20= a/src/backend/replication/logical/snapbuild.c=20= b/src/backend/replication/logical/snapbuild.c=0Aindex=20= b64e53de017..7a341418a74=20100644=0A---=20= a/src/backend/replication/logical/snapbuild.c=0A+++=20= b/src/backend/replication/logical/snapbuild.c=0A@@=20-155,11=20+155,11=20= @@=20static=20bool=20ExportInProgress=20=3D=20false;=0A=20static=20void=20= SnapBuildPurgeOlderTxn(SnapBuild=20*builder);=0A=20=0A=20/*=20snapshot=20= building/manipulation/distribution=20functions=20*/=0A-static=20Snapshot=20= SnapBuildBuildSnapshot(SnapBuild=20*builder);=0A+static=20= HistoricMVCCSnapshot=20SnapBuildBuildSnapshot(SnapBuild=20*builder);=0A=20= =0A-static=20void=20SnapBuildFreeSnapshot(Snapshot=20snap);=0A+static=20= void=20SnapBuildFreeSnapshot(HistoricMVCCSnapshot=20snap);=0A=20=0A= -static=20void=20SnapBuildSnapIncRefcount(Snapshot=20snap);=0A+static=20= void=20SnapBuildSnapIncRefcount(HistoricMVCCSnapshot=20snap);=0A=20=0A=20= static=20void=20SnapBuildDistributeNewCatalogSnapshot(SnapBuild=20= *builder,=20XLogRecPtr=20lsn);=0A=20=0A@@=20-249,23=20+249,21=20@@=20= FreeSnapshotBuilder(SnapBuild=20*builder)=0A=20=20*=20Free=20an=20= unreferenced=20snapshot=20that=20has=20previously=20been=20built=20by=20= us.=0A=20=20*/=0A=20static=20void=0A-SnapBuildFreeSnapshot(Snapshot=20= snap)=0A+SnapBuildFreeSnapshot(HistoricMVCCSnapshot=20snap)=0A=20{=0A=20=09= /*=20make=20sure=20we=20don't=20get=20passed=20an=20external=20snapshot=20= */=0A=20=09Assert(snap->snapshot_type=20=3D=3D=20= SNAPSHOT_HISTORIC_MVCC);=0A=20=0A=20=09/*=20make=20sure=20nobody=20= modified=20our=20snapshot=20*/=0A=20=09Assert(snap->curcid=20=3D=3D=20= FirstCommandId);=0A-=09Assert(!snap->suboverflowed);=0A-=09= Assert(!snap->takenDuringRecovery);=0A=20=09Assert(snap->regd_count=20=3D=3D= =200);=0A=20=0A=20=09/*=20slightly=20more=20likely,=20so=20it's=20= checked=20even=20without=20c-asserts=20*/=0A=20=09if=20(snap->copied)=0A=20= =09=09elog(ERROR,=20"cannot=20free=20a=20copied=20snapshot");=0A=20=0A-=09= if=20(snap->active_count)=0A-=09=09elog(ERROR,=20"cannot=20free=20an=20= active=20snapshot");=0A+=09if=20(snap->refcount)=0A+=09=09elog(ERROR,=20= "cannot=20free=20a=20snapshot=20that's=20in=20use");=0A=20=0A=20=09= pfree(snap);=0A=20}=0A@@=20-313,9=20+311,9=20@@=20= SnapBuildXactNeedsSkip(SnapBuild=20*builder,=20XLogRecPtr=20ptr)=0A=20=20= *=20adding=20a=20Snapshot=20as=20builder->snapshot.=0A=20=20*/=0A=20= static=20void=0A-SnapBuildSnapIncRefcount(Snapshot=20snap)=0A= +SnapBuildSnapIncRefcount(HistoricMVCCSnapshot=20snap)=0A=20{=0A-=09= snap->active_count++;=0A+=09snap->refcount++;=0A=20}=0A=20=0A=20/*=0A@@=20= -325,26=20+323,23=20@@=20SnapBuildSnapIncRefcount(Snapshot=20snap)=0A=20=20= *=20IncRef'ed=20Snapshot=20can=20adjust=20its=20refcount=20easily.=0A=20=20= */=0A=20void=0A-SnapBuildSnapDecRefcount(Snapshot=20snap)=0A= +SnapBuildSnapDecRefcount(HistoricMVCCSnapshot=20snap)=0A=20{=0A=20=09/*=20= make=20sure=20we=20don't=20get=20passed=20an=20external=20snapshot=20*/=0A= =20=09Assert(snap->snapshot_type=20=3D=3D=20SNAPSHOT_HISTORIC_MVCC);=0A=20= =0A=20=09/*=20make=20sure=20nobody=20modified=20our=20snapshot=20*/=0A=20= =09Assert(snap->curcid=20=3D=3D=20FirstCommandId);=0A-=09= Assert(!snap->suboverflowed);=0A-=09Assert(!snap->takenDuringRecovery);=0A= =20=0A+=09Assert(snap->refcount=20>=200);=0A=20=09= Assert(snap->regd_count=20=3D=3D=200);=0A=20=0A-=09= Assert(snap->active_count=20>=200);=0A-=0A=20=09/*=20slightly=20more=20= likely,=20so=20it's=20checked=20even=20without=20casserts=20*/=0A=20=09= if=20(snap->copied)=0A=20=09=09elog(ERROR,=20"cannot=20free=20a=20copied=20= snapshot");=0A=20=0A-=09snap->active_count--;=0A-=09if=20= (snap->active_count=20=3D=3D=200)=0A+=09snap->refcount--;=0A+=09if=20= (snap->refcount=20=3D=3D=200)=0A=20=09=09SnapBuildFreeSnapshot(snap);=0A=20= }=0A=20=0A@@=20-356,15=20+351,15=20@@=20= SnapBuildSnapDecRefcount(Snapshot=20snap)=0A=20=20*=20these=20snapshots;=20= they=20have=20to=20copy=20them=20and=20fill=20in=20appropriate=20= ->curcid=0A=20=20*=20and=20->subxip/subxcnt=20values.=0A=20=20*/=0A= -static=20Snapshot=0A+static=20HistoricMVCCSnapshot=0A=20= SnapBuildBuildSnapshot(SnapBuild=20*builder)=0A=20{=0A-=09Snapshot=09= snapshot;=0A+=09HistoricMVCCSnapshot=20snapshot;=0A=20=09Size=09=09= ssize;=0A=20=0A=20=09Assert(builder->state=20>=3D=20= SNAPBUILD_FULL_SNAPSHOT);=0A=20=0A-=09ssize=20=3D=20sizeof(SnapshotData)=0A= +=09ssize=20=3D=20sizeof(HistoricMVCCSnapshotData)=0A=20=09=09+=20= sizeof(TransactionId)=20*=20builder->committed.xcnt=0A=20=09=09+=20= sizeof(TransactionId)=20*=201=20/*=20toplevel=20xid=20*/=20;=0A=20=0A@@=20= -400,31=20+395,28=20@@=20SnapBuildBuildSnapshot(SnapBuild=20*builder)=0A=20= =09snapshot->xmax=20=3D=20builder->xmax;=0A=20=0A=20=09/*=20store=20all=20= transactions=20to=20be=20treated=20as=20committed=20by=20this=20snapshot=20= */=0A-=09snapshot->xip=20=3D=0A-=09=09(TransactionId=20*)=20((char=20*)=20= snapshot=20+=20sizeof(SnapshotData));=0A+=09snapshot->committed_xids=20=3D= =0A+=09=09(TransactionId=20*)=20((char=20*)=20snapshot=20+=20= sizeof(HistoricMVCCSnapshotData));=0A=20=09snapshot->xcnt=20=3D=20= builder->committed.xcnt;=0A-=09memcpy(snapshot->xip,=0A+=09= memcpy(snapshot->committed_xids,=0A=20=09=09=20=20=20= builder->committed.xip,=0A=20=09=09=20=20=20builder->committed.xcnt=20*=20= sizeof(TransactionId));=0A=20=0A=20=09/*=20sort=20so=20we=20can=20= bsearch()=20*/=0A-=09qsort(snapshot->xip,=20snapshot->xcnt,=20= sizeof(TransactionId),=20xidComparator);=0A+=09= qsort(snapshot->committed_xids,=20snapshot->xcnt,=20= sizeof(TransactionId),=20xidComparator);=0A=20=0A=20=09/*=0A-=09=20*=20= Initially,=20subxip=20is=20empty,=20i.e.=20it's=20a=20snapshot=20to=20be=20= used=20by=0A+=09=20*=20Initially,=20curxip=20is=20empty,=20i.e.=20it's=20= a=20snapshot=20to=20be=20used=20by=0A=20=09=20*=20transactions=20that=20= don't=20modify=20the=20catalog.=20Will=20be=20filled=20by=0A=20=09=20*=20= ReorderBufferCopySnap()=20if=20necessary.=0A=20=09=20*/=0A-=09= snapshot->subxcnt=20=3D=200;=0A-=09snapshot->subxip=20=3D=20NULL;=0A+=09= snapshot->curxcnt=20=3D=200;=0A+=09snapshot->curxip=20=3D=20NULL;=0A=20=0A= -=09snapshot->suboverflowed=20=3D=20false;=0A-=09= snapshot->takenDuringRecovery=20=3D=20false;=0A=20=09snapshot->copied=20= =3D=20false;=0A=20=09snapshot->curcid=20=3D=20FirstCommandId;=0A-=09= snapshot->active_count=20=3D=200;=0A+=09snapshot->refcount=20=3D=200;=0A=20= =09snapshot->regd_count=20=3D=200;=0A-=09= snapshot->snapXactCompletionCount=20=3D=200;=0A=20=0A=20=09return=20= snapshot;=0A=20}=0A@@=20-436,13=20+428,13=20@@=20= SnapBuildBuildSnapshot(SnapBuild=20*builder)=0A=20=20*=20The=20snapshot=20= will=20be=20usable=20directly=20in=20current=20transaction=20or=20= exported=0A=20=20*=20for=20loading=20in=20different=20transaction.=0A=20=20= */=0A-Snapshot=0A+MVCCSnapshot=0A=20SnapBuildInitialSnapshot(SnapBuild=20= *builder)=0A=20{=0A-=09Snapshot=09snap;=0A+=09HistoricMVCCSnapshot=20= historicsnap;=0A+=09MVCCSnapshot=20mvccsnap;=0A=20=09TransactionId=20= xid;=0A=20=09TransactionId=20safeXid;=0A-=09TransactionId=20*newxip;=0A=20= =09int=09=09=09newxcnt=20=3D=200;=0A=20=0A=20=09Assert(XactIsoLevel=20=3D=3D= =20XACT_REPEATABLE_READ);=0A@@=20-464,10=20+456,10=20@@=20= SnapBuildInitialSnapshot(SnapBuild=20*builder)=0A=20=09if=20= (TransactionIdIsValid(MyProc->xmin))=0A=20=09=09elog(ERROR,=20"cannot=20= build=20an=20initial=20slot=20snapshot=20when=20MyProc->xmin=20already=20= is=20valid");=0A=20=0A-=09snap=20=3D=20SnapBuildBuildSnapshot(builder);=0A= +=09historicsnap=20=3D=20SnapBuildBuildSnapshot(builder);=0A=20=0A=20=09= /*=0A-=09=20*=20We=20know=20that=20snap->xmin=20is=20alive,=20enforced=20= by=20the=20logical=20xmin=0A+=09=20*=20We=20know=20that=20= historicsnap->xmin=20is=20alive,=20enforced=20by=20the=20logical=20xmin=0A= =20=09=20*=20mechanism.=20Due=20to=20that=20we=20can=20do=20this=20= without=20locks,=20we're=20only=0A=20=09=20*=20changing=20our=20own=20= value.=0A=20=09=20*=0A@@=20-479,15=20+471,18=20@@=20= SnapBuildInitialSnapshot(SnapBuild=20*builder)=0A=20=09safeXid=20=3D=20= GetOldestSafeDecodingTransactionId(false);=0A=20=09= LWLockRelease(ProcArrayLock);=0A=20=0A-=09if=20= (TransactionIdFollows(safeXid,=20snap->xmin))=0A+=09if=20= (TransactionIdFollows(safeXid,=20historicsnap->xmin))=0A=20=09=09= elog(ERROR,=20"cannot=20build=20an=20initial=20slot=20snapshot=20as=20= oldest=20safe=20xid=20%u=20follows=20snapshot's=20xmin=20%u",=0A-=09=09=09= =20safeXid,=20snap->xmin);=0A+=09=09=09=20safeXid,=20= historicsnap->xmin);=0A=20=0A-=09MyProc->xmin=20=3D=20snap->xmin;=0A+=09= MyProc->xmin=20=3D=20historicsnap->xmin;=0A=20=0A=20=09/*=20allocate=20= in=20transaction=20context=20*/=0A-=09newxip=20=3D=20(TransactionId=20*)=0A= -=09=09palloc(sizeof(TransactionId)=20*=20GetMaxSnapshotXidCount());=0A+=09= mvccsnap=20=3D=20palloc(sizeof(MVCCSnapshotData)=20+=20= sizeof(TransactionId)=20*=20GetMaxSnapshotXidCount());=0A+=09= mvccsnap->snapshot_type=20=3D=20SNAPSHOT_MVCC;=0A+=09mvccsnap->xmin=20=3D=20= historicsnap->xmin;=0A+=09mvccsnap->xmax=20=3D=20historicsnap->xmax;=0A+=09= mvccsnap->xip=20=3D=20(TransactionId=20*)=20((char=20*)=20mvccsnap=20+=20= sizeof(MVCCSnapshotData));=0A=20=0A=20=09/*=0A=20=09=20*=20snapbuild.c=20= builds=20transactions=20in=20an=20"inverted"=20manner,=20which=20means=20= it=0A@@=20-495,15=20+490,15=20@@=20SnapBuildInitialSnapshot(SnapBuild=20= *builder)=0A=20=09=20*=20classical=20snapshot=20by=20marking=20all=20= non-committed=20transactions=20as=0A=20=09=20*=20in-progress.=20This=20= can=20be=20expensive.=0A=20=09=20*/=0A-=09for=20(xid=20=3D=20snap->xmin;=20= NormalTransactionIdPrecedes(xid,=20snap->xmax);)=0A+=09for=20(xid=20=3D=20= historicsnap->xmin;=20NormalTransactionIdPrecedes(xid,=20= historicsnap->xmax);)=0A=20=09{=0A=20=09=09void=09=20=20=20*test;=0A=20=0A= =20=09=09/*=0A-=09=09=20*=20Check=20whether=20transaction=20committed=20= using=20the=20decoding=20snapshot=0A-=09=09=20*=20meaning=20of=20->xip.=0A= +=09=09=20*=20Check=20whether=20transaction=20committed=20using=20the=20= decoding=20snapshot's=0A+=09=09=20*=20committed_xids=20array.=0A=20=09=09= =20*/=0A-=09=09test=20=3D=20bsearch(&xid,=20snap->xip,=20snap->xcnt,=0A+=09= =09test=20=3D=20bsearch(&xid,=20historicsnap->committed_xids,=20= historicsnap->xcnt,=0A=20=09=09=09=09=09=20=20=20sizeof(TransactionId),=20= xidComparator);=0A=20=0A=20=09=09if=20(test=20=3D=3D=20NULL)=0A@@=20= -513,18=20+508,27=20@@=20SnapBuildInitialSnapshot(SnapBuild=20*builder)=0A= =20=09=09=09=09=09=09(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),=0A=20=09= =09=09=09=09=09=20errmsg("initial=20slot=20snapshot=20too=20large")));=0A= =20=0A-=09=09=09newxip[newxcnt++]=20=3D=20xid;=0A+=09=09=09= mvccsnap->xip[newxcnt++]=20=3D=20xid;=0A=20=09=09}=0A=20=0A=20=09=09= TransactionIdAdvance(xid);=0A=20=09}=0A-=0A-=09/*=20adjust=20remaining=20= snapshot=20fields=20as=20needed=20*/=0A-=09snap->snapshot_type=20=3D=20= SNAPSHOT_MVCC;=0A-=09snap->xcnt=20=3D=20newxcnt;=0A-=09snap->xip=20=3D=20= newxip;=0A-=0A-=09return=20snap;=0A+=09mvccsnap->xcnt=20=3D=20newxcnt;=0A= +=0A+=09/*=20Initialize=20remaining=20MVCCSnapshot=20fields=20*/=0A+=09= mvccsnap->subxip=20=3D=20NULL;=0A+=09mvccsnap->subxcnt=20=3D=200;=0A+=09= mvccsnap->suboverflowed=20=3D=20false;=0A+=09= mvccsnap->takenDuringRecovery=20=3D=20false;=0A+=09mvccsnap->copied=20=3D=20= true;=0A+=09mvccsnap->curcid=20=3D=20FirstCommandId;=0A+=09= mvccsnap->active_count=20=3D=200;=0A+=09mvccsnap->regd_count=20=3D=200;=0A= +=09mvccsnap->snapXactCompletionCount=20=3D=200;=0A+=0A+=09= pfree(historicsnap);=0A+=0A+=09return=20mvccsnap;=0A=20}=0A=20=0A=20/*=0A= @@=20-538,7=20+542,7=20@@=20SnapBuildInitialSnapshot(SnapBuild=20= *builder)=0A=20const=20char=20*=0A=20SnapBuildExportSnapshot(SnapBuild=20= *builder)=0A=20{=0A-=09Snapshot=09snap;=0A+=09MVCCSnapshot=20snap;=0A=20=09= char=09=20=20=20*snapname;=0A=20=0A=20=09if=20= (IsTransactionOrTransactionBlock())=0A@@=20-575,7=20+579,7=20@@=20= SnapBuildExportSnapshot(SnapBuild=20*builder)=0A=20/*=0A=20=20*=20Ensure=20= there=20is=20a=20snapshot=20and=20if=20not=20build=20one=20for=20current=20= transaction.=0A=20=20*/=0A-Snapshot=0A+HistoricMVCCSnapshot=0A=20= SnapBuildGetOrBuildSnapshot(SnapBuild=20*builder)=0A=20{=0A=20=09= Assert(builder->state=20=3D=3D=20SNAPBUILD_CONSISTENT);=0Adiff=20--git=20= a/src/backend/replication/walsender.c=20= b/src/backend/replication/walsender.c=0Aindex=201028919aecb..1a7a35e25eb=20= 100644=0A---=20a/src/backend/replication/walsender.c=0A+++=20= b/src/backend/replication/walsender.c=0A@@=20-1307,7=20+1307,7=20@@=20= CreateReplicationSlot(CreateReplicationSlotCmd=20*cmd)=0A=20=09=09}=0A=20= =09=09else=20if=20(snapshot_action=20=3D=3D=20CRS_USE_SNAPSHOT)=0A=20=09=09= {=0A-=09=09=09Snapshot=09snap;=0A+=09=09=09MVCCSnapshot=20snap;=0A=20=0A=20= =09=09=09snap=20=3D=20SnapBuildInitialSnapshot(ctx->snapshot_builder);=0A= =20=09=09=09RestoreTransactionSnapshot(snap,=20MyProc);=0Adiff=20--git=20= a/src/backend/storage/ipc/procarray.c=20= b/src/backend/storage/ipc/procarray.c=0Aindex=20e5b945a9ee3..535755614a9=20= 100644=0A---=20a/src/backend/storage/ipc/procarray.c=0A+++=20= b/src/backend/storage/ipc/procarray.c=0A@@=20-2092,7=20+2092,7=20@@=20= GetMaxSnapshotSubxidCount(void)=0A=20=20*=20least=20in=20the=20case=20we=20= already=20hold=20a=20snapshot),=20but=20that's=20for=20another=20day.=0A=20= =20*/=0A=20static=20bool=0A-GetSnapshotDataReuse(Snapshot=20snapshot)=0A= +GetSnapshotDataReuse(MVCCSnapshot=20snapshot)=0A=20{=0A=20=09uint64=09=09= curXactCompletionCount;=0A=20=0A@@=20-2171,8=20+2171,8=20@@=20= GetSnapshotDataReuse(Snapshot=20snapshot)=0A=20=20*=20Note:=20this=20= function=20should=20probably=20not=20be=20called=20with=20an=20argument=20= that's=0A=20=20*=20not=20statically=20allocated=20(see=20xip=20= allocation=20below).=0A=20=20*/=0A-Snapshot=0A-GetSnapshotData(Snapshot=20= snapshot)=0A+MVCCSnapshot=0A+GetSnapshotData(MVCCSnapshot=20snapshot)=0A=20= {=0A=20=09ProcArrayStruct=20*arrayP=20=3D=20procArray;=0A=20=09= TransactionId=20*other_xids=20=3D=20ProcGlobal->xids;=0Adiff=20--git=20= a/src/backend/storage/lmgr/predicate.c=20= b/src/backend/storage/lmgr/predicate.c=0Aindex=20= 5b21a053981..dd52782ff22=20100644=0A---=20= a/src/backend/storage/lmgr/predicate.c=0A+++=20= b/src/backend/storage/lmgr/predicate.c=0A@@=20-449,10=20+449,10=20@@=20= static=20void=20SerialSetActiveSerXmin(TransactionId=20xid);=0A=20=0A=20= static=20uint32=20predicatelock_hash(const=20void=20*key,=20Size=20= keysize);=0A=20static=20void=20SummarizeOldestCommittedSxact(void);=0A= -static=20Snapshot=20GetSafeSnapshot(Snapshot=20origSnapshot);=0A-static=20= Snapshot=20GetSerializableTransactionSnapshotInt(Snapshot=20snapshot,=0A= -=09=09=09=09=09=09=09=09=09=09=09=09=09=20=20VirtualTransactionId=20= *sourcevxid,=0A-=09=09=09=09=09=09=09=09=09=09=09=09=09=20=20int=20= sourcepid);=0A+static=20MVCCSnapshot=20GetSafeSnapshot(MVCCSnapshot=20= origSnapshot);=0A+static=20MVCCSnapshot=20= GetSerializableTransactionSnapshotInt(MVCCSnapshot=20snapshot,=0A+=09=09=09= =09=09=09=09=09=09=09=09=09=09=09=20=20VirtualTransactionId=20= *sourcevxid,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09=09=20=20int=20= sourcepid);=0A=20static=20bool=20PredicateLockExists(const=20= PREDICATELOCKTARGETTAG=20*targettag);=0A=20static=20bool=20= GetParentPredicateLockTag(const=20PREDICATELOCKTARGETTAG=20*tag,=0A=20=09= =09=09=09=09=09=09=09=09=20=20PREDICATELOCKTARGETTAG=20*parent);=0A@@=20= -1544,10=20+1544,10=20@@=20SummarizeOldestCommittedSxact(void)=0A=20=20*=09= =09for),=20the=20passed-in=20Snapshot=20pointer=20should=20reference=20a=20= static=20data=0A=20=20*=09=09area=20that=20can=20safely=20be=20passed=20= to=20GetSnapshotData.=0A=20=20*/=0A-static=20Snapshot=0A= -GetSafeSnapshot(Snapshot=20origSnapshot)=0A+static=20MVCCSnapshot=0A= +GetSafeSnapshot(MVCCSnapshot=20origSnapshot)=0A=20{=0A-=09Snapshot=09= snapshot;=0A+=09MVCCSnapshot=20snapshot;=0A=20=0A=20=09= Assert(XactReadOnly=20&&=20XactDeferrable);=0A=20=0A@@=20-1668,8=20= +1668,8=20@@=20GetSafeSnapshotBlockingPids(int=20blocked_pid,=20int=20= *output,=20int=20output_size)=0A=20=20*=20always=20this=20same=20= pointer;=20no=20new=20snapshot=20data=20structure=20is=20allocated=0A=20=20= *=20within=20this=20function.=0A=20=20*/=0A-Snapshot=0A= -GetSerializableTransactionSnapshot(Snapshot=20snapshot)=0A+MVCCSnapshot=0A= +GetSerializableTransactionSnapshot(MVCCSnapshot=20snapshot)=0A=20{=0A=20= =09Assert(IsolationIsSerializable());=0A=20=0A@@=20-1709,7=20+1709,7=20= @@=20GetSerializableTransactionSnapshot(Snapshot=20snapshot)=0A=20=20*=20= read-only.=0A=20=20*/=0A=20void=0A= -SetSerializableTransactionSnapshot(Snapshot=20snapshot,=0A= +SetSerializableTransactionSnapshot(MVCCSnapshot=20snapshot,=0A=20=09=09=09= =09=09=09=09=09=20=20=20VirtualTransactionId=20*sourcevxid,=0A=20=09=09=09= =09=09=09=09=09=20=20=20int=20sourcepid)=0A=20{=0A@@=20-1750,8=20+1750,8=20= @@=20SetSerializableTransactionSnapshot(Snapshot=20snapshot,=0A=20=20*=20= source=20xact=20is=20still=20running=20after=20we=20acquire=20= SerializableXactHashLock.=0A=20=20*=20We=20do=20that=20by=20calling=20= ProcArrayInstallImportedXmin.=0A=20=20*/=0A-static=20Snapshot=0A= -GetSerializableTransactionSnapshotInt(Snapshot=20snapshot,=0A+static=20= MVCCSnapshot=0A+GetSerializableTransactionSnapshotInt(MVCCSnapshot=20= snapshot,=0A=20=09=09=09=09=09=09=09=09=09=20=20VirtualTransactionId=20= *sourcevxid,=0A=20=09=09=09=09=09=09=09=09=09=20=20int=20sourcepid)=0A=20= {=0A@@=20-3961,12=20+3961,12=20@@=20= ReleaseOneSerializableXact(SERIALIZABLEXACT=20*sxact,=20bool=20partial,=0A= =20static=20bool=0A=20XidIsConcurrent(TransactionId=20xid)=0A=20{=0A-=09= Snapshot=09snap;=0A+=09MVCCSnapshot=20snap;=0A=20=0A=20=09= Assert(TransactionIdIsValid(xid));=0A=20=09= Assert(!TransactionIdEquals(xid,=20GetTopTransactionIdIfAny()));=0A=20=0A= -=09snap=20=3D=20GetTransactionSnapshot();=0A+=09snap=20=3D=20= (MVCCSnapshot)=20GetTransactionSnapshot();=0A=20=0A=20=09if=20= (TransactionIdPrecedes(xid,=20snap->xmin))=0A=20=09=09return=20false;=0A= @@=20-4214,7=20+4214,7=20@@=20= CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG=20*targettag)=0A=20=09=09= }=0A=20=09=09else=20if=20(!SxactIsDoomed(sxact)=0A=20=09=09=09=09=20&&=20= (!SxactIsCommitted(sxact)=0A-=09=09=09=09=09=20||=20= TransactionIdPrecedes(GetTransactionSnapshot()->xmin,=0A+=09=09=09=09=09=20= ||=20TransactionIdPrecedes(TransactionXmin,=0A=20=09=09=09=09=09=09=09=09= =09=09=09=20=20sxact->finishedBefore))=0A=20=09=09=09=09=20&&=20= !RWConflictExists(sxact,=20MySerializableXact))=0A=20=09=09{=0A@@=20= -4227,7=20+4227,7=20@@=20= CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG=20*targettag)=0A=20=09=09= =09=20*/=0A=20=09=09=09if=20(!SxactIsDoomed(sxact)=0A=20=09=09=09=09&&=20= (!SxactIsCommitted(sxact)=0A-=09=09=09=09=09||=20= TransactionIdPrecedes(GetTransactionSnapshot()->xmin,=0A+=09=09=09=09=09= ||=20TransactionIdPrecedes(TransactionXmin,=0A=20=09=09=09=09=09=09=09=09= =09=09=09=20sxact->finishedBefore))=0A=20=09=09=09=09&&=20= !RWConflictExists(sxact,=20MySerializableXact))=0A=20=09=09=09{=0Adiff=20= --git=20a/src/backend/utils/adt/xid8funcs.c=20= b/src/backend/utils/adt/xid8funcs.c=0Aindex=201da3964ca6f..d4aa8ef9e4e=20= 100644=0A---=20a/src/backend/utils/adt/xid8funcs.c=0A+++=20= b/src/backend/utils/adt/xid8funcs.c=0A@@=20-372,10=20+372,10=20@@=20= pg_current_snapshot(PG_FUNCTION_ARGS)=0A=20=09pg_snapshot=20*snap;=0A=20=09= uint32=09=09nxip,=0A=20=09=09=09=09i;=0A-=09Snapshot=09cur;=0A+=09= MVCCSnapshot=20cur;=0A=20=09FullTransactionId=20next_fxid=20=3D=20= ReadNextFullTransactionId();=0A=20=0A-=09cur=20=3D=20= GetActiveSnapshot();=0A+=09cur=20=3D=20(MVCCSnapshot)=20= GetActiveSnapshot();=0A=20=09if=20(cur=20=3D=3D=20NULL)=0A=20=09=09= elog(ERROR,=20"no=20active=20snapshot=20set");=0A=20=0Adiff=20--git=20= a/src/backend/utils/time/snapmgr.c=20b/src/backend/utils/time/snapmgr.c=0A= index=20ea35f30f494..78adb6d575a=20100644=0A---=20= a/src/backend/utils/time/snapmgr.c=0A+++=20= b/src/backend/utils/time/snapmgr.c=0A@@=20-137,18=20+137,18=20@@=0A=20=20= *=20These=20SnapshotData=20structs=20are=20static=20to=20simplify=20= memory=20allocation=0A=20=20*=20(see=20the=20hack=20in=20GetSnapshotData=20= to=20avoid=20repeated=20malloc/free).=0A=20=20*/=0A-static=20= SnapshotData=20CurrentSnapshotData=20=3D=20{SNAPSHOT_MVCC};=0A-static=20= SnapshotData=20SecondarySnapshotData=20=3D=20{SNAPSHOT_MVCC};=0A-static=20= SnapshotData=20CatalogSnapshotData=20=3D=20{SNAPSHOT_MVCC};=0A+static=20= MVCCSnapshotData=20CurrentSnapshotData=20=3D=20{SNAPSHOT_MVCC};=0A= +static=20MVCCSnapshotData=20SecondarySnapshotData=20=3D=20= {SNAPSHOT_MVCC};=0A+static=20MVCCSnapshotData=20CatalogSnapshotData=20=3D=20= {SNAPSHOT_MVCC};=0A=20SnapshotData=20SnapshotSelfData=20=3D=20= {SNAPSHOT_SELF};=0A=20SnapshotData=20SnapshotAnyData=20=3D=20= {SNAPSHOT_ANY};=0A=20SnapshotData=20SnapshotToastData=20=3D=20= {SNAPSHOT_TOAST};=0A=20=0A=20/*=20Pointers=20to=20valid=20snapshots=20*/=0A= -static=20Snapshot=20CurrentSnapshot=20=3D=20NULL;=0A-static=20Snapshot=20= SecondarySnapshot=20=3D=20NULL;=0A-static=20Snapshot=20CatalogSnapshot=20= =3D=20NULL;=0A-static=20Snapshot=20HistoricSnapshot=20=3D=20NULL;=0A= +static=20MVCCSnapshot=20CurrentSnapshot=20=3D=20NULL;=0A+static=20= MVCCSnapshot=20SecondarySnapshot=20=3D=20NULL;=0A+static=20MVCCSnapshot=20= CatalogSnapshot=20=3D=20NULL;=0A+static=20HistoricMVCCSnapshot=20= HistoricSnapshot=20=3D=20NULL;=0A=20=0A=20/*=0A=20=20*=20These=20are=20= updated=20by=20GetSnapshotData.=20=20We=20initialize=20them=20this=20way=0A= @@=20-171,7=20+171,7=20@@=20static=20HTAB=20*tuplecid_data=20=3D=20NULL;=0A= =20=20*/=0A=20typedef=20struct=20ActiveSnapshotElt=0A=20{=0A-=09Snapshot=09= as_snap;=0A+=09MVCCSnapshot=20as_snap;=0A=20=09int=09=09=09as_level;=0A=20= =09struct=20ActiveSnapshotElt=20*as_next;=0A=20}=20ActiveSnapshotElt;=0A= @@=20-196,7=20+196,7=20@@=20bool=09=09FirstSnapshotSet=20=3D=20false;=0A=20= =20*=20FirstSnapshotSet=20in=20combination=20with=20= IsolationUsesXactSnapshot(),=20because=0A=20=20*=20GUC=20may=20be=20= reset=20before=20us,=20changing=20the=20value=20of=20= IsolationUsesXactSnapshot.=0A=20=20*/=0A-static=20Snapshot=20= FirstXactSnapshot=20=3D=20NULL;=0A+static=20MVCCSnapshot=20= FirstXactSnapshot=20=3D=20NULL;=0A=20=0A=20/*=20Define=20pathname=20of=20= exported-snapshot=20files=20*/=0A=20#define=20SNAPSHOT_EXPORT_DIR=20= "pg_snapshots"=0A@@=20-205,16=20+205,16=20@@=20static=20Snapshot=20= FirstXactSnapshot=20=3D=20NULL;=0A=20typedef=20struct=20ExportedSnapshot=0A= =20{=0A=20=09char=09=20=20=20*snapfile;=0A-=09Snapshot=09snapshot;=0A+=09= MVCCSnapshot=20snapshot;=0A=20}=20ExportedSnapshot;=0A=20=0A=20/*=20= Current=20xact's=20exported=20snapshots=20(a=20list=20of=20= ExportedSnapshot=20structs)=20*/=0A=20static=20List=20*exportedSnapshots=20= =3D=20NIL;=0A=20=0A=20/*=20Prototypes=20for=20local=20functions=20*/=0A= -static=20Snapshot=20CopySnapshot(Snapshot=20snapshot);=0A+static=20= MVCCSnapshot=20CopyMVCCSnapshot(MVCCSnapshot=20snapshot);=0A=20static=20= void=20UnregisterSnapshotNoOwner(Snapshot=20snapshot);=0A-static=20void=20= FreeSnapshot(Snapshot=20snapshot);=0A+static=20void=20= FreeMVCCSnapshot(MVCCSnapshot=20snapshot);=0A=20static=20void=20= SnapshotResetXmin(void);=0A=20=0A=20/*=20ResourceOwner=20callbacks=20to=20= track=20snapshot=20references=20*/=0A@@=20-308,8=20+308,9=20@@=20= GetTransactionSnapshot(void)=0A=20=09=09=09=09CurrentSnapshot=20=3D=20= GetSerializableTransactionSnapshot(&CurrentSnapshotData);=0A=20=09=09=09= else=0A=20=09=09=09=09CurrentSnapshot=20=3D=20= GetSnapshotData(&CurrentSnapshotData);=0A+=0A=20=09=09=09/*=20Make=20a=20= saved=20copy=20*/=0A-=09=09=09CurrentSnapshot=20=3D=20= CopySnapshot(CurrentSnapshot);=0A+=09=09=09CurrentSnapshot=20=3D=20= CopyMVCCSnapshot(CurrentSnapshot);=0A=20=09=09=09FirstXactSnapshot=20=3D=20= CurrentSnapshot;=0A=20=09=09=09/*=20Mark=20it=20as=20"registered"=20in=20= FirstXactSnapshot=20*/=0A=20=09=09=09FirstXactSnapshot->regd_count++;=0A= @@=20-319,18=20+320,18=20@@=20GetTransactionSnapshot(void)=0A=20=09=09=09= CurrentSnapshot=20=3D=20GetSnapshotData(&CurrentSnapshotData);=0A=20=0A=20= =09=09FirstSnapshotSet=20=3D=20true;=0A-=09=09return=20CurrentSnapshot;=0A= +=09=09return=20(Snapshot)=20CurrentSnapshot;=0A=20=09}=0A=20=0A=20=09if=20= (IsolationUsesXactSnapshot())=0A-=09=09return=20CurrentSnapshot;=0A+=09=09= return=20(Snapshot)=20CurrentSnapshot;=0A=20=0A=20=09/*=20Don't=20allow=20= catalog=20snapshot=20to=20be=20older=20than=20xact=20snapshot.=20*/=0A=20= =09InvalidateCatalogSnapshot();=0A=20=0A=20=09CurrentSnapshot=20=3D=20= GetSnapshotData(&CurrentSnapshotData);=0A=20=0A-=09return=20= CurrentSnapshot;=0A+=09return=20(Snapshot)=20CurrentSnapshot;=0A=20}=0A=20= =0A=20/*=0A@@=20-361,7=20+362,7=20@@=20GetLatestSnapshot(void)=0A=20=0A=20= =09SecondarySnapshot=20=3D=20GetSnapshotData(&SecondarySnapshotData);=0A=20= =0A-=09return=20SecondarySnapshot;=0A+=09return=20(Snapshot)=20= SecondarySnapshot;=0A=20}=0A=20=0A=20/*=0A@@=20-380,7=20+381,7=20@@=20= GetCatalogSnapshot(Oid=20relid)=0A=20=09=20*=20finishing=20decoding.=0A=20= =09=20*/=0A=20=09if=20(HistoricSnapshotActive())=0A-=09=09return=20= HistoricSnapshot;=0A+=09=09return=20(Snapshot)=20HistoricSnapshot;=0A=20=0A= =20=09return=20GetNonHistoricCatalogSnapshot(relid);=0A=20}=0A@@=20= -426,7=20+427,7=20@@=20GetNonHistoricCatalogSnapshot(Oid=20relid)=0A=20=09= =09pairingheap_add(&RegisteredSnapshots,=20&CatalogSnapshot->ph_node);=0A= =20=09}=0A=20=0A-=09return=20CatalogSnapshot;=0A+=09return=20(Snapshot)=20= CatalogSnapshot;=0A=20}=0A=20=0A=20/*=0A@@=20-495,7=20+496,7=20@@=20= SnapshotSetCommandId(CommandId=20curcid)=0A=20=20*=20in=20= GetTransactionSnapshot.=0A=20=20*/=0A=20static=20void=0A= -SetTransactionSnapshot(Snapshot=20sourcesnap,=20VirtualTransactionId=20= *sourcevxid,=0A+SetTransactionSnapshot(MVCCSnapshot=20sourcesnap,=20= VirtualTransactionId=20*sourcevxid,=0A=20=09=09=09=09=09=20=20=20int=20= sourcepid,=20PGPROC=20*sourceproc)=0A=20{=0A=20=09/*=20Caller=20should=20= have=20checked=20this=20already=20*/=0A@@=20-574,7=20+575,7=20@@=20= SetTransactionSnapshot(Snapshot=20sourcesnap,=20VirtualTransactionId=20= *sourcevxid,=0A=20=09=09=09= SetSerializableTransactionSnapshot(CurrentSnapshot,=20sourcevxid,=0A=20=09= =09=09=09=09=09=09=09=09=09=09=20=20=20sourcepid);=0A=20=09=09/*=20Make=20= a=20saved=20copy=20*/=0A-=09=09CurrentSnapshot=20=3D=20= CopySnapshot(CurrentSnapshot);=0A+=09=09CurrentSnapshot=20=3D=20= CopyMVCCSnapshot(CurrentSnapshot);=0A=20=09=09FirstXactSnapshot=20=3D=20= CurrentSnapshot;=0A=20=09=09/*=20Mark=20it=20as=20"registered"=20in=20= FirstXactSnapshot=20*/=0A=20=09=09FirstXactSnapshot->regd_count++;=0A@@=20= -585,29=20+586,27=20@@=20SetTransactionSnapshot(Snapshot=20sourcesnap,=20= VirtualTransactionId=20*sourcevxid,=0A=20}=0A=20=0A=20/*=0A-=20*=20= CopySnapshot=0A+=20*=20CopyMVCCSnapshot=0A=20=20*=09=09Copy=20the=20= given=20snapshot.=0A=20=20*=0A=20=20*=20The=20copy=20is=20palloc'd=20in=20= TopTransactionContext=20and=20has=20initial=20refcounts=20set=0A=20=20*=20= to=200.=20=20The=20returned=20snapshot=20has=20the=20copied=20flag=20= set.=0A=20=20*/=0A-static=20Snapshot=0A-CopySnapshot(Snapshot=20= snapshot)=0A+static=20MVCCSnapshot=0A+CopyMVCCSnapshot(MVCCSnapshot=20= snapshot)=0A=20{=0A-=09Snapshot=09newsnap;=0A+=09MVCCSnapshot=20newsnap;=0A= =20=09Size=09=09subxipoff;=0A=20=09Size=09=09size;=0A=20=0A-=09= Assert(snapshot=20!=3D=20InvalidSnapshot);=0A-=0A=20=09/*=20We=20= allocate=20any=20XID=20arrays=20needed=20in=20the=20same=20palloc=20= block.=20*/=0A-=09size=20=3D=20subxipoff=20=3D=20sizeof(SnapshotData)=20= +=0A+=09size=20=3D=20subxipoff=20=3D=20sizeof(MVCCSnapshotData)=20+=0A=20= =09=09snapshot->xcnt=20*=20sizeof(TransactionId);=0A=20=09if=20= (snapshot->subxcnt=20>=200)=0A=20=09=09size=20+=3D=20snapshot->subxcnt=20= *=20sizeof(TransactionId);=0A=20=0A-=09newsnap=20=3D=20(Snapshot)=20= MemoryContextAlloc(TopTransactionContext,=20size);=0A-=09memcpy(newsnap,=20= snapshot,=20sizeof(SnapshotData));=0A+=09newsnap=20=3D=20(MVCCSnapshot)=20= MemoryContextAlloc(TopTransactionContext,=20size);=0A+=09memcpy(newsnap,=20= snapshot,=20sizeof(MVCCSnapshotData));=0A=20=0A=20=09newsnap->regd_count=20= =3D=200;=0A=20=09newsnap->active_count=20=3D=200;=0A@@=20-644,11=20= +643,11=20@@=20CopySnapshot(Snapshot=20snapshot)=0A=20}=0A=20=0A=20/*=0A= -=20*=20FreeSnapshot=0A+=20*=20FreeMVCCSnapshot=0A=20=20*=09=09Free=20= the=20memory=20associated=20with=20a=20snapshot.=0A=20=20*/=0A=20static=20= void=0A-FreeSnapshot(Snapshot=20snapshot)=0A= +FreeMVCCSnapshot(MVCCSnapshot=20snapshot)=0A=20{=0A=20=09= Assert(snapshot->regd_count=20=3D=3D=200);=0A=20=09= Assert(snapshot->active_count=20=3D=3D=200);=0A@@=20-664,6=20+663,8=20@@=20= FreeSnapshot(Snapshot=20snapshot)=0A=20=20*=20If=20the=20passed=20= snapshot=20is=20a=20statically-allocated=20one,=20or=20it=20is=20= possibly=0A=20=20*=20subject=20to=20a=20future=20command=20counter=20= update,=20create=20a=20new=20long-lived=20copy=0A=20=20*=20with=20active=20= refcount=3D1.=20=20Otherwise,=20only=20increment=20the=20refcount.=0A+=20= *=0A+=20*=20Only=20regular=20MVCC=20snaphots=20can=20be=20used=20as=20= the=20active=20snapshot.=0A=20=20*/=0A=20void=0A=20= PushActiveSnapshot(Snapshot=20snapshot)=0A@@=20-682,9=20+683,12=20@@=20= PushActiveSnapshot(Snapshot=20snapshot)=0A=20void=0A=20= PushActiveSnapshotWithLevel(Snapshot=20snapshot,=20int=20snap_level)=0A=20= {=0A+=09MVCCSnapshot=20origsnap;=0A=20=09ActiveSnapshotElt=20*newactive;=0A= =20=0A-=09Assert(snapshot=20!=3D=20InvalidSnapshot);=0A+=09= Assert(snapshot->snapshot_type=20=3D=3D=20SNAPSHOT_MVCC);=0A+=09origsnap=20= =3D=20&snapshot->mvcc;=0A+=0A=20=09Assert(ActiveSnapshot=20=3D=3D=20NULL=20= ||=20snap_level=20>=3D=20ActiveSnapshot->as_level);=0A=20=0A=20=09= newactive=20=3D=20MemoryContextAlloc(TopTransactionContext,=20= sizeof(ActiveSnapshotElt));=0A@@=20-693,11=20+697,11=20@@=20= PushActiveSnapshotWithLevel(Snapshot=20snapshot,=20int=20snap_level)=0A=20= =09=20*=20Checking=20SecondarySnapshot=20is=20probably=20useless=20here,=20= but=20it=20seems=0A=20=09=20*=20better=20to=20be=20sure.=0A=20=09=20*/=0A= -=09if=20(snapshot=20=3D=3D=20CurrentSnapshot=20||=20snapshot=20=3D=3D=20= SecondarySnapshot=20||=0A-=09=09!snapshot->copied)=0A-=09=09= newactive->as_snap=20=3D=20CopySnapshot(snapshot);=0A+=09if=20(origsnap=20= =3D=3D=20CurrentSnapshot=20||=20origsnap=20=3D=3D=20SecondarySnapshot=20= ||=0A+=09=09!origsnap->copied)=0A+=09=09newactive->as_snap=20=3D=20= CopyMVCCSnapshot(origsnap);=0A=20=09else=0A-=09=09newactive->as_snap=20=3D= =20snapshot;=0A+=09=09newactive->as_snap=20=3D=20origsnap;=0A=20=0A=20=09= newactive->as_next=20=3D=20ActiveSnapshot;=0A=20=09newactive->as_level=20= =3D=20snap_level;=0A@@=20-718,7=20+722,8=20@@=20= PushActiveSnapshotWithLevel(Snapshot=20snapshot,=20int=20snap_level)=0A=20= void=0A=20PushCopiedSnapshot(Snapshot=20snapshot)=0A=20{=0A-=09= PushActiveSnapshot(CopySnapshot(snapshot));=0A+=09= Assert(snapshot->snapshot_type=20=3D=3D=20SNAPSHOT_MVCC);=0A+=09= PushActiveSnapshot((Snapshot)=20CopyMVCCSnapshot(&snapshot->mvcc));=0A=20= }=0A=20=0A=20/*=0A@@=20-771,7=20+776,7=20@@=20PopActiveSnapshot(void)=0A=20= =0A=20=09if=20(ActiveSnapshot->as_snap->active_count=20=3D=3D=200=20&&=0A= =20=09=09ActiveSnapshot->as_snap->regd_count=20=3D=3D=200)=0A-=09=09= FreeSnapshot(ActiveSnapshot->as_snap);=0A+=09=09= FreeMVCCSnapshot(ActiveSnapshot->as_snap);=0A=20=0A=20=09= pfree(ActiveSnapshot);=0A=20=09ActiveSnapshot=20=3D=20newstack;=0A@@=20= -788,7=20+793,7=20@@=20GetActiveSnapshot(void)=0A=20{=0A=20=09= Assert(ActiveSnapshot=20!=3D=20NULL);=0A=20=0A-=09return=20= ActiveSnapshot->as_snap;=0A+=09return=20(Snapshot)=20= ActiveSnapshot->as_snap;=0A=20}=0A=20=0A=20/*=0A@@=20-805,7=20+810,8=20= @@=20ActiveSnapshotSet(void)=0A=20=20*=20RegisterSnapshot=0A=20=20*=09=09= Register=20a=20snapshot=20as=20being=20in=20use=20by=20the=20current=20= resource=20owner=0A=20=20*=0A-=20*=20If=20InvalidSnapshot=20is=20passed,=20= it=20is=20not=20registered.=0A+=20*=20Only=20regular=20MVCC=20snaphots=20= and=20"historic"=20MVCC=20snapshots=20can=20be=20registered.=0A+=20*=20= InvalidSnapshot=20is=20also=20accepted,=20as=20a=20no-op.=0A=20=20*/=0A=20= Snapshot=0A=20RegisterSnapshot(Snapshot=20snapshot)=0A@@=20-821,25=20= +827,39=20@@=20RegisterSnapshot(Snapshot=20snapshot)=0A=20=20*=09=09As=20= above,=20but=20use=20the=20specified=20resource=20owner=0A=20=20*/=0A=20= Snapshot=0A-RegisterSnapshotOnOwner(Snapshot=20snapshot,=20ResourceOwner=20= owner)=0A+RegisterSnapshotOnOwner(Snapshot=20orig_snapshot,=20= ResourceOwner=20owner)=0A=20{=0A-=09Snapshot=09snap;=0A+=09MVCCSnapshot=20= snapshot;=0A=20=0A-=09if=20(snapshot=20=3D=3D=20InvalidSnapshot)=0A+=09= if=20(orig_snapshot=20=3D=3D=20InvalidSnapshot)=0A=20=09=09return=20= InvalidSnapshot;=0A=20=0A+=09if=20(orig_snapshot->snapshot_type=20=3D=3D=20= SNAPSHOT_HISTORIC_MVCC)=0A+=09{=0A+=09=09HistoricMVCCSnapshot=20= historicsnap=20=3D=20&orig_snapshot->historic_mvcc;=0A+=0A+=09=09= ResourceOwnerEnlarge(owner);=0A+=09=09historicsnap->regd_count++;=0A+=09=09= ResourceOwnerRememberSnapshot(owner,=20(Snapshot)=20historicsnap);=0A+=0A= +=09=09return=20(Snapshot)=20historicsnap;=0A+=09}=0A+=0A+=09= Assert(orig_snapshot->snapshot_type=20=3D=3D=20SNAPSHOT_MVCC);=0A+=09= snapshot=20=3D=20&orig_snapshot->mvcc;=0A+=0A=20=09/*=20Static=20= snapshot?=20=20Create=20a=20persistent=20copy=20*/=0A-=09snap=20=3D=20= snapshot->copied=20?=20snapshot=20:=20CopySnapshot(snapshot);=0A+=09= snapshot=20=3D=20snapshot->copied=20?=20snapshot=20:=20= CopyMVCCSnapshot(snapshot);=0A=20=0A=20=09/*=20and=20tell=20resowner.c=20= about=20it=20*/=0A=20=09ResourceOwnerEnlarge(owner);=0A-=09= snap->regd_count++;=0A-=09ResourceOwnerRememberSnapshot(owner,=20snap);=0A= +=09snapshot->regd_count++;=0A+=09ResourceOwnerRememberSnapshot(owner,=20= (Snapshot)=20snapshot);=0A=20=0A-=09if=20(snap->regd_count=20=3D=3D=201)=0A= -=09=09pairingheap_add(&RegisteredSnapshots,=20&snap->ph_node);=0A+=09if=20= (snapshot->regd_count=20=3D=3D=201)=0A+=09=09= pairingheap_add(&RegisteredSnapshots,=20&snapshot->ph_node);=0A=20=0A-=09= return=20snap;=0A+=09return=20(Snapshot)=20snapshot;=0A=20}=0A=20=0A=20= /*=0A@@=20-875,18=20+895,41=20@@=20UnregisterSnapshotFromOwner(Snapshot=20= snapshot,=20ResourceOwner=20owner)=0A=20static=20void=0A=20= UnregisterSnapshotNoOwner(Snapshot=20snapshot)=0A=20{=0A-=09= Assert(snapshot->regd_count=20>=200);=0A-=09= Assert(!pairingheap_is_empty(&RegisteredSnapshots));=0A+=09if=20= (snapshot->snapshot_type=20=3D=3D=20SNAPSHOT_MVCC)=0A+=09{=0A+=09=09= MVCCSnapshot=20mvccsnap=20=3D=20&snapshot->mvcc;=0A+=0A+=09=09= Assert(mvccsnap->regd_count=20>=200);=0A+=09=09= Assert(!pairingheap_is_empty(&RegisteredSnapshots));=0A=20=0A-=09= snapshot->regd_count--;=0A-=09if=20(snapshot->regd_count=20=3D=3D=200)=0A= -=09=09pairingheap_remove(&RegisteredSnapshots,=20&snapshot->ph_node);=0A= +=09=09mvccsnap->regd_count--;=0A+=09=09if=20(mvccsnap->regd_count=20=3D=3D= =200)=0A+=09=09=09pairingheap_remove(&RegisteredSnapshots,=20= &mvccsnap->ph_node);=0A=20=0A-=09if=20(snapshot->regd_count=20=3D=3D=200=20= &&=20snapshot->active_count=20=3D=3D=200)=0A+=09=09if=20= (mvccsnap->regd_count=20=3D=3D=200=20&&=20mvccsnap->active_count=20=3D=3D=20= 0)=0A+=09=09{=0A+=09=09=09FreeMVCCSnapshot(mvccsnap);=0A+=09=09=09= SnapshotResetXmin();=0A+=09=09}=0A+=09}=0A+=09else=20if=20= (snapshot->snapshot_type=20=3D=3D=20SNAPSHOT_HISTORIC_MVCC)=0A=20=09{=0A= -=09=09FreeSnapshot(snapshot);=0A-=09=09SnapshotResetXmin();=0A+=09=09= HistoricMVCCSnapshot=20historicsnap=20=3D=20&snapshot->historic_mvcc;=0A= +=0A+=09=09/*=0A+=09=09=20*=20Historic=20snapshots=20don't=20rely=20on=20= the=20resource=20owner=20machinery=20for=0A+=09=09=20*=20cleanup,=20the=20= snapbuild.c=20machinery=20ensures=20that=20whenever=20a=20historic=0A+=09= =09=20*=20snapshot=20is=20in=20use,=20it=20has=20a=20non-zero=20= refcount.=20=20Registration=20is=0A+=09=09=20*=20only=20supported=20so=20= that=20the=20callers=20don't=20need=20to=20treat=20regular=20MVCC=0A+=09=09= =20*=20catalog=20snapshots=20and=20historic=20snapshots=20differently.=0A= +=09=09=20*/=0A+=09=09Assert(historicsnap->refcount=20>=200);=0A+=0A+=09=09= Assert(historicsnap->regd_count=20>=200);=0A+=09=09= historicsnap->regd_count--;=0A=20=09}=0A+=09else=0A+=09=09elog(ERROR,=20= "registered=20snapshot=20has=20unexpected=20type");=0A=20}=0A=20=0A=20/*=0A= @@=20-896,8=20+939,8=20@@=20UnregisterSnapshotNoOwner(Snapshot=20= snapshot)=0A=20static=20int=0A=20xmin_cmp(const=20pairingheap_node=20*a,=20= const=20pairingheap_node=20*b,=20void=20*arg)=0A=20{=0A-=09const=20= SnapshotData=20*asnap=20=3D=20pairingheap_const_container(SnapshotData,=20= ph_node,=20a);=0A-=09const=20SnapshotData=20*bsnap=20=3D=20= pairingheap_const_container(SnapshotData,=20ph_node,=20b);=0A+=09const=20= MVCCSnapshotData=20*asnap=20=3D=20= pairingheap_const_container(MVCCSnapshotData,=20ph_node,=20a);=0A+=09= const=20MVCCSnapshotData=20*bsnap=20=3D=20= pairingheap_const_container(MVCCSnapshotData,=20ph_node,=20b);=0A=20=0A=20= =09if=20(TransactionIdPrecedes(asnap->xmin,=20bsnap->xmin))=0A=20=09=09= return=201;=0A@@=20-923,7=20+966,7=20@@=20xmin_cmp(const=20= pairingheap_node=20*a,=20const=20pairingheap_node=20*b,=20void=20*arg)=0A= =20static=20void=0A=20SnapshotResetXmin(void)=0A=20{=0A-=09Snapshot=09= minSnapshot;=0A+=09MVCCSnapshot=20minSnapshot;=0A=20=0A=20=09if=20= (ActiveSnapshot=20!=3D=20NULL)=0A=20=09=09return;=0A@@=20-934,7=20+977,7=20= @@=20SnapshotResetXmin(void)=0A=20=09=09return;=0A=20=09}=0A=20=0A-=09= minSnapshot=20=3D=20pairingheap_container(SnapshotData,=20ph_node,=0A+=09= minSnapshot=20=3D=20pairingheap_container(MVCCSnapshotData,=20ph_node,=0A= =20=09=09=09=09=09=09=09=09=09=09= pairingheap_first(&RegisteredSnapshots));=0A=20=0A=20=09if=20= (TransactionIdPrecedes(MyProc->xmin,=20minSnapshot->xmin))=0A@@=20-984,7=20= +1027,7=20@@=20AtSubAbort_Snapshot(int=20level)=0A=20=0A=20=09=09if=20= (ActiveSnapshot->as_snap->active_count=20=3D=3D=200=20&&=0A=20=09=09=09= ActiveSnapshot->as_snap->regd_count=20=3D=3D=200)=0A-=09=09=09= FreeSnapshot(ActiveSnapshot->as_snap);=0A+=09=09=09= FreeMVCCSnapshot(ActiveSnapshot->as_snap);=0A=20=0A=20=09=09/*=20and=20= free=20the=20stack=20element=20*/=0A=20=09=09pfree(ActiveSnapshot);=0A@@=20= -1006,7=20+1049,7=20@@=20AtEOXact_Snapshot(bool=20isCommit,=20bool=20= resetXmin)=0A=20=09=20*=20In=20transaction-snapshot=20mode=20we=20must=20= release=20our=20privately-managed=0A=20=09=20*=20reference=20to=20the=20= transaction=20snapshot.=20=20We=20must=20remove=20it=20from=0A=20=09=20*=20= RegisteredSnapshots=20to=20keep=20the=20check=20below=20happy.=20=20But=20= we=20don't=20bother=0A-=09=20*=20to=20do=20FreeSnapshot,=20for=20two=20= reasons:=20the=20memory=20will=20go=20away=20with=0A+=09=20*=20to=20do=20= FreeMVCCSnapshot,=20for=20two=20reasons:=20the=20memory=20will=20go=20= away=20with=0A=20=09=20*=20TopTransactionContext=20anyway,=20and=20if=20= someone=20has=20left=20the=20snapshot=0A=20=09=20*=20stacked=20as=20= active,=20we=20don't=20want=20the=20code=20below=20to=20be=20chasing=20= through=20a=0A=20=09=20*=20dangling=20pointer.=0A@@=20-1099,7=20+1142,7=20= @@=20AtEOXact_Snapshot(bool=20isCommit,=20bool=20resetXmin)=0A=20=20*=09=09= snapshot.=0A=20=20*/=0A=20char=20*=0A-ExportSnapshot(Snapshot=20= snapshot)=0A+ExportSnapshot(MVCCSnapshot=20snapshot)=0A=20{=0A=20=09= TransactionId=20topXid;=0A=20=09TransactionId=20*children;=0A@@=20= -1163,7=20+1206,7=20@@=20ExportSnapshot(Snapshot=20snapshot)=0A=20=09=20= *=20ensure=20that=20the=20snapshot's=20xmin=20is=20honored=20for=20the=20= rest=20of=20the=0A=20=09=20*=20transaction.=0A=20=09=20*/=0A-=09snapshot=20= =3D=20CopySnapshot(snapshot);=0A+=09snapshot=20=3D=20= CopyMVCCSnapshot(snapshot);=0A=20=0A=20=09oldcxt=20=3D=20= MemoryContextSwitchTo(TopTransactionContext);=0A=20=09esnap=20=3D=20= (ExportedSnapshot=20*)=20palloc(sizeof(ExportedSnapshot));=0A@@=20= -1280,7=20+1323,7=20@@=20pg_export_snapshot(PG_FUNCTION_ARGS)=0A=20{=0A=20= =09char=09=20=20=20*snapshotName;=0A=20=0A-=09snapshotName=20=3D=20= ExportSnapshot(GetActiveSnapshot());=0A+=09snapshotName=20=3D=20= ExportSnapshot((MVCCSnapshot)=20GetActiveSnapshot());=0A=20=09= PG_RETURN_TEXT_P(cstring_to_text(snapshotName));=0A=20}=0A=20=0A@@=20= -1384,7=20+1427,7=20@@=20ImportSnapshot(const=20char=20*idstr)=0A=20=09= Oid=09=09=09src_dbid;=0A=20=09int=09=09=09src_isolevel;=0A=20=09bool=09=09= src_readonly;=0A-=09SnapshotData=20snapshot;=0A+=09MVCCSnapshotData=20= snapshot;=0A=20=0A=20=09/*=0A=20=09=20*=20Must=20be=20at=20top=20level=20= of=20a=20fresh=20transaction.=20=20Note=20in=20particular=20that=0A@@=20= -1653,7=20+1696,7=20@@=20HaveRegisteredOrActiveSnapshot(void)=0A=20=20*=20= Needed=20for=20logical=20decoding.=0A=20=20*/=0A=20void=0A= -SetupHistoricSnapshot(Snapshot=20historic_snapshot,=20HTAB=20= *tuplecids)=0A+SetupHistoricSnapshot(HistoricMVCCSnapshot=20= historic_snapshot,=20HTAB=20*tuplecids)=0A=20{=0A=20=09= Assert(historic_snapshot=20!=3D=20NULL);=0A=20=0A@@=20-1696,11=20= +1739,10=20@@=20HistoricSnapshotGetTupleCids(void)=0A=20=20*=20= SerializedSnapshotData.=0A=20=20*/=0A=20Size=0A= -EstimateSnapshotSpace(Snapshot=20snapshot)=0A= +EstimateSnapshotSpace(MVCCSnapshot=20snapshot)=0A=20{=0A=20=09Size=09=09= size;=0A=20=0A-=09Assert(snapshot=20!=3D=20InvalidSnapshot);=0A=20=09= Assert(snapshot->snapshot_type=20=3D=3D=20SNAPSHOT_MVCC);=0A=20=0A=20=09= /*=20We=20allocate=20any=20XID=20arrays=20needed=20in=20the=20same=20= palloc=20block.=20*/=0A@@=20-1720,7=20+1762,7=20@@=20= EstimateSnapshotSpace(Snapshot=20snapshot)=0A=20=20*=09=09memory=20= location=20at=20start_address.=0A=20=20*/=0A=20void=0A= -SerializeSnapshot(Snapshot=20snapshot,=20char=20*start_address)=0A= +SerializeSnapshot(MVCCSnapshot=20snapshot,=20char=20*start_address)=0A=20= {=0A=20=09SerializedSnapshotData=20serialized_snapshot;=0A=20=0A@@=20= -1776,12=20+1818,12=20@@=20SerializeSnapshot(Snapshot=20snapshot,=20char=20= *start_address)=0A=20=20*=20The=20copy=20is=20palloc'd=20in=20= TopTransactionContext=20and=20has=20initial=20refcounts=20set=0A=20=20*=20= to=200.=20=20The=20returned=20snapshot=20has=20the=20copied=20flag=20= set.=0A=20=20*/=0A-Snapshot=0A+MVCCSnapshot=0A=20RestoreSnapshot(char=20= *start_address)=0A=20{=0A=20=09SerializedSnapshotData=20= serialized_snapshot;=0A=20=09Size=09=09size;=0A-=09Snapshot=09snapshot;=0A= +=09MVCCSnapshot=20snapshot;=0A=20=09TransactionId=20*serialized_xids;=0A= =20=0A=20=09memcpy(&serialized_snapshot,=20start_address,=0A@@=20= -1790,12=20+1832,12=20@@=20RestoreSnapshot(char=20*start_address)=0A=20=09= =09(start_address=20+=20sizeof(SerializedSnapshotData));=0A=20=0A=20=09= /*=20We=20allocate=20any=20XID=20arrays=20needed=20in=20the=20same=20= palloc=20block.=20*/=0A-=09size=20=3D=20sizeof(SnapshotData)=0A+=09size=20= =3D=20sizeof(MVCCSnapshotData)=0A=20=09=09+=20serialized_snapshot.xcnt=20= *=20sizeof(TransactionId)=0A=20=09=09+=20serialized_snapshot.subxcnt=20*=20= sizeof(TransactionId);=0A=20=0A=20=09/*=20Copy=20all=20required=20fields=20= */=0A-=09snapshot=20=3D=20(Snapshot)=20= MemoryContextAlloc(TopTransactionContext,=20size);=0A+=09snapshot=20=3D=20= (MVCCSnapshot)=20MemoryContextAlloc(TopTransactionContext,=20size);=0A=20= =09snapshot->snapshot_type=20=3D=20SNAPSHOT_MVCC;=0A=20=09snapshot->xmin=20= =3D=20serialized_snapshot.xmin;=0A=20=09snapshot->xmax=20=3D=20= serialized_snapshot.xmax;=0A@@=20-1840,7=20+1882,7=20@@=20= RestoreSnapshot(char=20*start_address)=0A=20=20*=20the=20declaration=20= for=20PGPROC.=0A=20=20*/=0A=20void=0A= -RestoreTransactionSnapshot(Snapshot=20snapshot,=20void=20= *source_pgproc)=0A+RestoreTransactionSnapshot(MVCCSnapshot=20snapshot,=20= void=20*source_pgproc)=0A=20{=0A=20=09SetTransactionSnapshot(snapshot,=20= NULL,=20InvalidPid,=20source_pgproc);=0A=20}=0A@@=20-1856,7=20+1898,7=20= @@=20RestoreTransactionSnapshot(Snapshot=20snapshot,=20void=20= *source_pgproc)=0A=20=20*=20XID=20could=20not=20be=20ours=20anyway.=0A=20= =20*/=0A=20bool=0A-XidInMVCCSnapshot(TransactionId=20xid,=20Snapshot=20= snapshot)=0A+XidInMVCCSnapshot(TransactionId=20xid,=20MVCCSnapshot=20= snapshot)=0A=20{=0A=20=09/*=0A=20=09=20*=20Make=20a=20quick=20range=20= check=20to=20eliminate=20most=20XIDs=20without=20looking=20at=20the=0A= diff=20--git=20a/src/include/access/heapam.h=20= b/src/include/access/heapam.h=0Aindex=201640d9c32f7..3d3ea109a4c=20= 100644=0A---=20a/src/include/access/heapam.h=0A+++=20= b/src/include/access/heapam.h=0A@@=20-431,7=20+431,7=20@@=20extern=20= bool=20HeapTupleIsSurelyDead(HeapTuple=20htup,=0A=20=20*/=0A=20struct=20= HTAB;=0A=20extern=20bool=20ResolveCminCmaxDuringDecoding(struct=20HTAB=20= *tuplecid_data,=0A-=09=09=09=09=09=09=09=09=09=09=20=20Snapshot=20= snapshot,=0A+=09=09=09=09=09=09=09=09=09=09=20=20HistoricMVCCSnapshot=20= snapshot,=0A=20=09=09=09=09=09=09=09=09=09=09=20=20HeapTuple=20htup,=0A=20= =09=09=09=09=09=09=09=09=09=09=20=20Buffer=20buffer,=0A=20=09=09=09=09=09= =09=09=09=09=09=20=20CommandId=20*cmin,=20CommandId=20*cmax);=0Adiff=20= --git=20a/src/include/access/relscan.h=20b/src/include/access/relscan.h=0A= index=20b5e0fb386c0..2626f2996d8=20100644=0A---=20= a/src/include/access/relscan.h=0A+++=20b/src/include/access/relscan.h=0A= @@=20-34,7=20+34,7=20@@=20typedef=20struct=20TableScanDescData=0A=20{=0A=20= =09/*=20scan=20parameters=20*/=0A=20=09Relation=09rs_rd;=09=09=09/*=20= heap=20relation=20descriptor=20*/=0A-=09struct=20SnapshotData=20= *rs_snapshot;=09/*=20snapshot=20to=20see=20*/=0A+=09union=20SnapshotData=20= *rs_snapshot;=09/*=20snapshot=20to=20see=20*/=0A=20=09int=09=09=09= rs_nkeys;=09=09/*=20number=20of=20scan=20keys=20*/=0A=20=09struct=20= ScanKeyData=20*rs_key;=20/*=20array=20of=20scan=20key=20descriptors=20*/=0A= =20=0A@@=20-135,7=20+135,7=20@@=20typedef=20struct=20IndexScanDescData=0A= =20=09/*=20scan=20parameters=20*/=0A=20=09Relation=09heapRelation;=09/*=20= heap=20relation=20descriptor,=20or=20NULL=20*/=0A=20=09Relation=09= indexRelation;=09/*=20index=20relation=20descriptor=20*/=0A-=09struct=20= SnapshotData=20*xs_snapshot;=09/*=20snapshot=20to=20see=20*/=0A+=09union=20= SnapshotData=20*xs_snapshot;=09/*=20snapshot=20to=20see=20*/=0A=20=09int=09= =09=09numberOfKeys;=09/*=20number=20of=20index=20qualifier=20conditions=20= */=0A=20=09int=09=09=09numberOfOrderBys;=09/*=20number=20of=20ordering=20= operators=20*/=0A=20=09struct=20ScanKeyData=20*keyData;=09/*=20array=20= of=20index=20qualifier=20descriptors=20*/=0A@@=20-210,7=20+210,7=20@@=20= typedef=20struct=20SysScanDescData=0A=20=09Relation=09irel;=09=09=09/*=20= NULL=20if=20doing=20heap=20scan=20*/=0A=20=09struct=20TableScanDescData=20= *scan;=20/*=20only=20valid=20in=20storage-scan=20case=20*/=0A=20=09= struct=20IndexScanDescData=20*iscan;=09/*=20only=20valid=20in=20= index-scan=20case=20*/=0A-=09struct=20SnapshotData=20*snapshot;=09/*=20= snapshot=20to=20unregister=20at=20end=20of=20scan=20*/=0A+=09union=20= SnapshotData=20*snapshot;=09/*=20snapshot=20to=20unregister=20at=20end=20= of=20scan=20*/=0A=20=09struct=20TupleTableSlot=20*slot;=0A=20}=09=09=09= SysScanDescData;=0A=20=0Adiff=20--git=20= a/src/include/replication/reorderbuffer.h=20= b/src/include/replication/reorderbuffer.h=0Aindex=20= 3be0cbd7ebe..8bf72c64c94=20100644=0A---=20= a/src/include/replication/reorderbuffer.h=0A+++=20= b/src/include/replication/reorderbuffer.h=0A@@=20-127,7=20+127,7=20@@=20= typedef=20struct=20ReorderBufferChange=0A=20=09=09}=09=09=09msg;=0A=20=0A= =20=09=09/*=20New=20snapshot,=20set=20when=20action=20=3D=3D=20= *_INTERNAL_SNAPSHOT=20*/=0A-=09=09Snapshot=09snapshot;=0A+=09=09= HistoricMVCCSnapshot=20snapshot;=0A=20=0A=20=09=09/*=0A=20=09=09=20*=20= New=20command=20id=20for=20existing=20snapshot=20in=20a=20catalog=20= changing=20tx.=20Set=0A@@=20-359,7=20+359,7=20@@=20typedef=20struct=20= ReorderBufferTXN=0A=20=09=20*=20transaction=20modifies=20the=20catalog,=20= or=20another=20catalog-modifying=0A=20=09=20*=20transaction=20commits.=0A= =20=09=20*/=0A-=09Snapshot=09base_snapshot;=0A+=09HistoricMVCCSnapshot=20= base_snapshot;=0A=20=09XLogRecPtr=09base_snapshot_lsn;=0A=20=09= dlist_node=09base_snapshot_node;=20/*=20link=20in=20= txns_by_base_snapshot_lsn=20*/=0A=20=0A@@=20-367,7=20+367,7=20@@=20= typedef=20struct=20ReorderBufferTXN=0A=20=09=20*=20Snapshot/CID=20from=20= the=20previous=20streaming=20run.=20Only=20valid=20for=20already=0A=20=09= =20*=20streamed=20transactions=20(NULL/InvalidCommandId=20otherwise).=0A=20= =09=20*/=0A-=09Snapshot=09snapshot_now;=0A+=09HistoricMVCCSnapshot=20= snapshot_now;=0A=20=09CommandId=09command_id;=0A=20=0A=20=09/*=0A@@=20= -703,7=20+703,7=20@@=20extern=20void=20= ReorderBufferQueueChange(ReorderBuffer=20*rb,=20TransactionId=20xid,=0A=20= =09=09=09=09=09=09=09=09=09=20XLogRecPtr=20lsn,=20ReorderBufferChange=20= *change,=0A=20=09=09=09=09=09=09=09=09=09=20bool=20toast_insert);=0A=20= extern=20void=20ReorderBufferQueueMessage(ReorderBuffer=20*rb,=20= TransactionId=20xid,=0A-=09=09=09=09=09=09=09=09=09=20=20Snapshot=20= snap,=20XLogRecPtr=20lsn,=0A+=09=09=09=09=09=09=09=09=09=20=20= HistoricMVCCSnapshot=20snap,=20XLogRecPtr=20lsn,=0A=20=09=09=09=09=09=09=09= =09=09=20=20bool=20transactional,=20const=20char=20*prefix,=0A=20=09=09=09= =09=09=09=09=09=09=20=20Size=20message_size,=20const=20char=20*message);=0A= =20extern=20void=20ReorderBufferCommit(ReorderBuffer=20*rb,=20= TransactionId=20xid,=0A@@=20-727,9=20+727,9=20@@=20extern=20void=20= ReorderBufferForget(ReorderBuffer=20*rb,=20TransactionId=20xid,=20= XLogRecPtr=0A=20extern=20void=20ReorderBufferInvalidate(ReorderBuffer=20= *rb,=20TransactionId=20xid,=20XLogRecPtr=20lsn);=0A=20=0A=20extern=20= void=20ReorderBufferSetBaseSnapshot(ReorderBuffer=20*rb,=20TransactionId=20= xid,=0A-=09=09=09=09=09=09=09=09=09=09=20XLogRecPtr=20lsn,=20Snapshot=20= snap);=0A+=09=09=09=09=09=09=09=09=09=09=20XLogRecPtr=20lsn,=20= HistoricMVCCSnapshot=20snap);=0A=20extern=20void=20= ReorderBufferAddSnapshot(ReorderBuffer=20*rb,=20TransactionId=20xid,=0A-=09= =09=09=09=09=09=09=09=09=20XLogRecPtr=20lsn,=20Snapshot=20snap);=0A+=09=09= =09=09=09=09=09=09=09=20XLogRecPtr=20lsn,=20HistoricMVCCSnapshot=20= snap);=0A=20extern=20void=20ReorderBufferAddNewCommandId(ReorderBuffer=20= *rb,=20TransactionId=20xid,=0A=20=09=09=09=09=09=09=09=09=09=09=20= XLogRecPtr=20lsn,=20CommandId=20cid);=0A=20extern=20void=20= ReorderBufferAddNewTupleCids(ReorderBuffer=20*rb,=20TransactionId=20xid,=0A= diff=20--git=20a/src/include/replication/snapbuild.h=20= b/src/include/replication/snapbuild.h=0Aindex=2044031dcf6e3..5930ffb55a8=20= 100644=0A---=20a/src/include/replication/snapbuild.h=0A+++=20= b/src/include/replication/snapbuild.h=0A@@=20-70,15=20+70,15=20@@=20= extern=20SnapBuild=20*AllocateSnapshotBuilder(struct=20ReorderBuffer=20= *reorder,=0A=20=09=09=09=09=09=09=09=09=09=09=20=20XLogRecPtr=20= two_phase_at);=0A=20extern=20void=20FreeSnapshotBuilder(SnapBuild=20= *builder);=0A=20=0A-extern=20void=20SnapBuildSnapDecRefcount(Snapshot=20= snap);=0A+extern=20void=20SnapBuildSnapDecRefcount(HistoricMVCCSnapshot=20= snap);=0A=20=0A-extern=20Snapshot=20SnapBuildInitialSnapshot(SnapBuild=20= *builder);=0A+extern=20MVCCSnapshot=20SnapBuildInitialSnapshot(SnapBuild=20= *builder);=0A=20extern=20const=20char=20= *SnapBuildExportSnapshot(SnapBuild=20*builder);=0A=20extern=20void=20= SnapBuildClearExportedSnapshot(void);=0A=20extern=20void=20= SnapBuildResetExportedSnapshotState(void);=0A=20=0A=20extern=20= SnapBuildState=20SnapBuildCurrentState(SnapBuild=20*builder);=0A-extern=20= Snapshot=20SnapBuildGetOrBuildSnapshot(SnapBuild=20*builder);=0A+extern=20= HistoricMVCCSnapshot=20SnapBuildGetOrBuildSnapshot(SnapBuild=20= *builder);=0A=20=0A=20extern=20bool=20SnapBuildXactNeedsSkip(SnapBuild=20= *builder,=20XLogRecPtr=20ptr);=0A=20extern=20XLogRecPtr=20= SnapBuildGetTwoPhaseAt(SnapBuild=20*builder);=0Adiff=20--git=20= a/src/include/replication/snapbuild_internal.h=20= b/src/include/replication/snapbuild_internal.h=0Aindex=20= 3b915dc8793..9bed20efa31=20100644=0A---=20= a/src/include/replication/snapbuild_internal.h=0A+++=20= b/src/include/replication/snapbuild_internal.h=0A@@=20-74,7=20+74,7=20@@=20= struct=20SnapBuild=0A=20=09/*=0A=20=09=20*=20Snapshot=20that's=20valid=20= to=20see=20the=20catalog=20state=20seen=20at=20this=20moment.=0A=20=09=20= */=0A-=09Snapshot=09snapshot;=0A+=09HistoricMVCCSnapshot=20snapshot;=0A=20= =0A=20=09/*=0A=20=09=20*=20LSN=20of=20the=20last=20location=20we=20are=20= sure=20a=20snapshot=20has=20been=20serialized=20to.=0Adiff=20--git=20= a/src/include/storage/predicate.h=20b/src/include/storage/predicate.h=0A= index=20267d5d90e94..6a78dfeac96=20100644=0A---=20= a/src/include/storage/predicate.h=0A+++=20= b/src/include/storage/predicate.h=0A@@=20-47,8=20+47,8=20@@=20extern=20= void=20CheckPointPredicate(void);=0A=20extern=20bool=20= PageIsPredicateLocked(Relation=20relation,=20BlockNumber=20blkno);=0A=20=0A= =20/*=20predicate=20lock=20maintenance=20*/=0A-extern=20Snapshot=20= GetSerializableTransactionSnapshot(Snapshot=20snapshot);=0A-extern=20= void=20SetSerializableTransactionSnapshot(Snapshot=20snapshot,=0A+extern=20= MVCCSnapshot=20GetSerializableTransactionSnapshot(MVCCSnapshot=20= snapshot);=0A+extern=20void=20= SetSerializableTransactionSnapshot(MVCCSnapshot=20snapshot,=0A=20=09=09=09= =09=09=09=09=09=09=09=09=20=20=20VirtualTransactionId=20*sourcevxid,=0A=20= =09=09=09=09=09=09=09=09=09=09=09=20=20=20int=20sourcepid);=0A=20extern=20= void=20RegisterPredicateLockingXid(TransactionId=20xid);=0Adiff=20--git=20= a/src/include/storage/procarray.h=20b/src/include/storage/procarray.h=0A= index=20ef0b733ebe8..7f5727c2586=20100644=0A---=20= a/src/include/storage/procarray.h=0A+++=20= b/src/include/storage/procarray.h=0A@@=20-44,7=20+44,7=20@@=20extern=20= void=20KnownAssignedTransactionIdsIdleMaintenance(void);=0A=20extern=20= int=09GetMaxSnapshotXidCount(void);=0A=20extern=20int=09= GetMaxSnapshotSubxidCount(void);=0A=20=0A-extern=20Snapshot=20= GetSnapshotData(Snapshot=20snapshot);=0A+extern=20MVCCSnapshot=20= GetSnapshotData(MVCCSnapshot=20snapshot);=0A=20=0A=20extern=20bool=20= ProcArrayInstallImportedXmin(TransactionId=20xmin,=0A=20=09=09=09=09=09=09= =09=09=09=09=20VirtualTransactionId=20*sourcevxid);=0Adiff=20--git=20= a/src/include/utils/snapmgr.h=20b/src/include/utils/snapmgr.h=0Aindex=20= d346be71642..1f627ff966d=20100644=0A---=20a/src/include/utils/snapmgr.h=0A= +++=20b/src/include/utils/snapmgr.h=0A@@=20-49,7=20+49,7=20@@=20extern=20= PGDLLIMPORT=20SnapshotData=20SnapshotToastData;=0A=20=20*/=0A=20#define=20= InitNonVacuumableSnapshot(snapshotdata,=20vistestp)=20=20\=0A=20=09= ((snapshotdata).snapshot_type=20=3D=20SNAPSHOT_NON_VACUUMABLE,=20\=0A-=09= =20(snapshotdata).vistest=20=3D=20(vistestp))=0A+=09=20= (snapshotdata).nonvacuumable.vistest=20=3D=20(vistestp))=0A=20=0A=20/*=20= This=20macro=20encodes=20the=20knowledge=20of=20which=20snapshots=20are=20= MVCC-safe=20*/=0A=20#define=20IsMVCCSnapshot(snapshot)=20=20\=0A@@=20= -89,7=20+89,7=20@@=20extern=20void=20WaitForOlderSnapshots(TransactionId=20= limitXmin,=20bool=20progress);=0A=20extern=20bool=20= ThereAreNoPriorRegisteredSnapshots(void);=0A=20extern=20bool=20= HaveRegisteredOrActiveSnapshot(void);=0A=20=0A-extern=20char=20= *ExportSnapshot(Snapshot=20snapshot);=0A+extern=20char=20= *ExportSnapshot(MVCCSnapshot=20snapshot);=0A=20=0A=20/*=0A=20=20*=20= These=20live=20in=20procarray.c=20because=20they're=20intimately=20= linked=20to=20the=0A@@=20-105,18=20+105,18=20@@=20extern=20bool=20= GlobalVisCheckRemovableFullXid(Relation=20rel,=20FullTransactionId=20= fxid)=0A=20/*=0A=20=20*=20Utility=20functions=20for=20implementing=20= visibility=20routines=20in=20table=20AMs.=0A=20=20*/=0A-extern=20bool=20= XidInMVCCSnapshot(TransactionId=20xid,=20Snapshot=20snapshot);=0A+extern=20= bool=20XidInMVCCSnapshot(TransactionId=20xid,=20MVCCSnapshot=20= snapshot);=0A=20=0A=20/*=20Support=20for=20catalog=20timetravel=20for=20= logical=20decoding=20*/=0A=20struct=20HTAB;=0A=20extern=20struct=20HTAB=20= *HistoricSnapshotGetTupleCids(void);=0A-extern=20void=20= SetupHistoricSnapshot(Snapshot=20historic_snapshot,=20struct=20HTAB=20= *tuplecids);=0A+extern=20void=20= SetupHistoricSnapshot(HistoricMVCCSnapshot=20historic_snapshot,=20struct=20= HTAB=20*tuplecids);=0A=20extern=20void=20TeardownHistoricSnapshot(bool=20= is_error);=0A=20extern=20bool=20HistoricSnapshotActive(void);=0A=20=0A= -extern=20Size=20EstimateSnapshotSpace(Snapshot=20snapshot);=0A-extern=20= void=20SerializeSnapshot(Snapshot=20snapshot,=20char=20*start_address);=0A= -extern=20Snapshot=20RestoreSnapshot(char=20*start_address);=0A-extern=20= void=20RestoreTransactionSnapshot(Snapshot=20snapshot,=20void=20= *source_pgproc);=0A+extern=20Size=20EstimateSnapshotSpace(MVCCSnapshot=20= snapshot);=0A+extern=20void=20SerializeSnapshot(MVCCSnapshot=20snapshot,=20= char=20*start_address);=0A+extern=20MVCCSnapshot=20RestoreSnapshot(char=20= *start_address);=0A+extern=20void=20= RestoreTransactionSnapshot(MVCCSnapshot=20snapshot,=20void=20= *source_pgproc);=0A=20=0A=20#endif=09=09=09=09=09=09=09/*=20SNAPMGR_H=20= */=0Adiff=20--git=20a/src/include/utils/snapshot.h=20= b/src/include/utils/snapshot.h=0Aindex=200e546ec1497..93c1f51784f=20= 100644=0A---=20a/src/include/utils/snapshot.h=0A+++=20= b/src/include/utils/snapshot.h=0A@@=20-17,7=20+17,7=20@@=0A=20=0A=20=0A=20= /*=0A-=20*=20The=20different=20snapshot=20types.=20=20We=20use=20= SnapshotData=20structures=20to=20represent=0A+=20*=20The=20different=20= snapshot=20types.=20=20We=20use=20the=20SnapshotData=20union=20to=20= represent=0A=20=20*=20both=20"regular"=20(MVCC)=20snapshots=20and=20= "special"=20snapshots=20that=20have=20non-MVCC=0A=20=20*=20semantics.=20=20= The=20specific=20semantics=20of=20a=20snapshot=20are=20encoded=20by=20= its=20type.=0A=20=20*=0A@@=20-27,6=20+27,9=20@@=0A=20=20*=20The=20reason=20= the=20snapshot=20type=20rather=20than=20a=20callback=20as=20it=20used=20= to=20be=20is=0A=20=20*=20that=20that=20allows=20to=20use=20the=20same=20= snapshot=20for=20different=20table=20AMs=20without=0A=20=20*=20having=20= one=20callback=20per=20AM.=0A+=20*=0A+=20*=20The=20executor=20deals=20= with=20MVCC=20snapshots,=20but=20the=20table=20AM=20and=20some=20other=0A= +=20*=20parts=20of=20the=20system=20also=20support=20the=20special=20= snapshots.=0A=20=20*/=0A=20typedef=20enum=20SnapshotType=0A=20{=0A@@=20= -100,7=20+103,9=20@@=20typedef=20enum=20SnapshotType=0A=20=09/*=0A=20=09=20= *=20A=20tuple=20is=20visible=20iff=20it=20follows=20the=20rules=20of=20= SNAPSHOT_MVCC,=20but=0A=20=09=20*=20supports=20being=20called=20in=20= timetravel=20context=20(for=20decoding=20catalog=0A-=09=20*=20contents=20= in=20the=20context=20of=20logical=20decoding).=0A+=09=20*=20contents=20= in=20the=20context=20of=20logical=20decoding).=20=20A=20historic=20MVCC=20= snapshot=0A+=09=20*=20should=20only=20be=20used=20on=20catalog=20tables,=20= as=20we=20only=20track=20XIDs=20that=0A+=09=20*=20modify=20catalogs=20= during=20logical=20decoding.=0A=20=09=20*/=0A=20=09= SNAPSHOT_HISTORIC_MVCC,=0A=20=0A@@=20-114,37=20+119,18=20@@=20typedef=20= enum=20SnapshotType=0A=20=09SNAPSHOT_NON_VACUUMABLE,=0A=20}=20= SnapshotType;=0A=20=0A-typedef=20struct=20SnapshotData=20*Snapshot;=0A-=0A= -#define=20InvalidSnapshot=09=09((Snapshot)=20NULL)=0A-=0A=20/*=0A-=20*=20= Struct=20representing=20all=20kind=20of=20possible=20snapshots.=0A+=20*=20= Struct=20representing=20a=20normal=20MVCC=20snapshot.=0A=20=20*=0A-=20*=20= There=20are=20several=20different=20kinds=20of=20snapshots:=0A-=20*=20*=20= Normal=20MVCC=20snapshots=0A-=20*=20*=20MVCC=20snapshots=20taken=20= during=20recovery=20(in=20Hot-Standby=20mode)=0A-=20*=20*=20Historic=20= MVCC=20snapshots=20used=20during=20logical=20decoding=0A-=20*=20*=20= snapshots=20passed=20to=20HeapTupleSatisfiesDirty()=0A-=20*=20*=20= snapshots=20passed=20to=20HeapTupleSatisfiesNonVacuumable()=0A-=20*=20*=20= snapshots=20used=20for=20SatisfiesAny,=20Toast,=20Self=20where=20no=20= members=20are=0A-=20*=09=20accessed.=0A-=20*=0A-=20*=20TODO:=20It's=20= probably=20a=20good=20idea=20to=20split=20this=20struct=20using=20a=20= NodeTag=0A-=20*=20similar=20to=20how=20parser=20and=20executor=20nodes=20= are=20handled,=20with=20one=20type=20for=0A-=20*=20each=20different=20= kind=20of=20snapshot=20to=20avoid=20overloading=20the=20meaning=20of=0A-=20= *=20individual=20fields.=0A+=20*=20MVCC=20snapshots=20come=20in=20two=20= variants:=20those=20taken=20during=20recovery=20in=20hot=0A+=20*=20= standby=20mode,=20and=20"normal"=20MVCC=20snapshots.=20=20They=20are=20= distinguished=20by=0A+=20*=20takenDuringRecovery.=0A=20=20*/=0A-typedef=20= struct=20SnapshotData=0A+typedef=20struct=20MVCCSnapshotData=0A=20{=0A-=09= SnapshotType=20snapshot_type;=20/*=20type=20of=20snapshot=20*/=0A+=09= SnapshotType=20snapshot_type;=20/*=20type=20of=20snapshot,=20must=20be=20= first=20*/=0A=20=0A=20=09/*=0A-=09=20*=20The=20remaining=20fields=20are=20= used=20only=20for=20MVCC=20snapshots,=20and=20are=20normally=0A-=09=20*=20= just=20zeroes=20in=20special=20snapshots.=20=20(But=20xmin=20and=20xmax=20= are=20used=0A-=09=20*=20specially=20by=20HeapTupleSatisfiesDirty,=20and=20= xmin=20is=20used=20specially=20by=0A-=09=20*=20= HeapTupleSatisfiesNonVacuumable.)=0A-=09=20*=0A=20=09=20*=20An=20MVCC=20= snapshot=20can=20never=20see=20the=20effects=20of=20XIDs=20>=3D=20xmax.=20= It=20can=20see=0A=20=09=20*=20the=20effects=20of=20all=20older=20XIDs=20= except=20those=20listed=20in=20the=20snapshot.=20xmin=0A=20=09=20*=20is=20= stored=20as=20an=20optimization=20to=20avoid=20needing=20to=20search=20= the=20XID=20arrays=0A@@=20-154,10=20+140,8=20@@=20typedef=20struct=20= SnapshotData=0A=20=09TransactionId=20xmax;=09=09=09/*=20all=20XID=20>=3D=20= xmax=20are=20invisible=20to=20me=20*/=0A=20=0A=20=09/*=0A-=09=20*=20For=20= normal=20MVCC=20snapshot=20this=20contains=20the=20all=20xact=20IDs=20= that=20are=20in=0A-=09=20*=20progress,=20unless=20the=20snapshot=20was=20= taken=20during=20recovery=20in=20which=20case=0A-=09=20*=20it's=20empty.=20= For=20historic=20MVCC=20snapshots,=20the=20meaning=20is=20inverted,=20= i.e.=0A-=09=20*=20it=20contains=20*committed*=20transactions=20between=20= xmin=20and=20xmax.=0A+=09=20*=20xip=20contains=20the=20all=20xact=20IDs=20= that=20are=20in=20progress,=20unless=20the=20snapshot=0A+=09=20*=20was=20= taken=20during=20recovery=20in=20which=20case=20it's=20empty.=0A=20=09=20= *=0A=20=09=20*=20note:=20all=20ids=20in=20xip[]=20satisfy=20xmin=20<=3D=20= xip[i]=20<=20xmax=0A=20=09=20*/=0A@@=20-165,10=20+149,8=20@@=20typedef=20= struct=20SnapshotData=0A=20=09uint32=09=09xcnt;=09=09=09/*=20#=20of=20= xact=20ids=20in=20xip[]=20*/=0A=20=0A=20=09/*=0A-=09=20*=20For=20= non-historic=20MVCC=20snapshots,=20this=20contains=20subxact=20IDs=20= that=20are=20in=0A-=09=20*=20progress=20(and=20other=20transactions=20= that=20are=20in=20progress=20if=20taken=20during=0A-=09=20*=20recovery).=20= For=20historic=20snapshot=20it=20contains=20*all*=20xids=20assigned=20to=20= the=0A-=09=20*=20replayed=20transaction,=20including=20the=20toplevel=20= xid.=0A+=09=20*=20subxip=20contains=20subxact=20IDs=20that=20are=20in=20= progress=20(and=20other=0A+=09=20*=20transactions=20that=20are=20in=20= progress=20if=20taken=20during=20recovery).=0A=20=09=20*=0A=20=09=20*=20= note:=20all=20ids=20in=20subxip[]=20are=20>=3D=20xmin,=20but=20we=20= don't=20bother=20filtering=0A=20=09=20*=20out=20any=20that=20are=20>=3D=20= xmax=0A@@=20-182,18=20+164,6=20@@=20typedef=20struct=20SnapshotData=0A=20= =0A=20=09CommandId=09curcid;=09=09=09/*=20in=20my=20xact,=20CID=20<=20= curcid=20are=20visible=20*/=0A=20=0A-=09/*=0A-=09=20*=20An=20extra=20= return=20value=20for=20HeapTupleSatisfiesDirty,=20not=20used=20in=20MVCC=0A= -=09=20*=20snapshots.=0A-=09=20*/=0A-=09uint32=09=09speculativeToken;=0A= -=0A-=09/*=0A-=09=20*=20For=20SNAPSHOT_NON_VACUUMABLE=20(and=20hopefully=20= more=20in=20the=20future)=20this=20is=0A-=09=20*=20used=20to=20determine=20= whether=20row=20could=20be=20vacuumed.=0A-=09=20*/=0A-=09struct=20= GlobalVisState=20*vistest;=0A-=0A=20=09/*=0A=20=09=20*=20Book-keeping=20= information,=20used=20by=20the=20snapshot=20manager=0A=20=09=20*/=0A@@=20= -207,6=20+177,97=20@@=20typedef=20struct=20SnapshotData=0A=20=09=20*=20= transactions=20completed=20since=20the=20last=20GetSnapshotData().=0A=20=09= =20*/=0A=20=09uint64=09=09snapXactCompletionCount;=0A+}=20= MVCCSnapshotData;=0A+=0A+typedef=20struct=20MVCCSnapshotData=20= *MVCCSnapshot;=0A+=0A+#define=20InvalidMVCCSnapshot=20((MVCCSnapshot)=20= NULL)=0A+=0A+/*=0A+=20*=20Struct=20representing=20a=20"historic"=20MVCC=20= snapshot=20during=20logical=20decoding.=0A+=20*=20These=20are=20= constructed=20by=20src/replication/logical/snapbuild.c.=0A+=20*/=0A= +typedef=20struct=20HistoricMVCCSnapshotData=0A+{=0A+=09SnapshotType=20= snapshot_type;=20/*=20type=20of=20snapshot,=20must=20be=20first=20*/=0A+=0A= +=09/*=0A+=09=20*=20xmin=20and=20xmax=20like=20in=20a=20normal=20MVCC=20= snapshot.=0A+=09=20*/=0A+=09TransactionId=20xmin;=09=09=09/*=20all=20XID=20= <=20xmin=20are=20visible=20to=20me=20*/=0A+=09TransactionId=20xmax;=09=09= =09/*=20all=20XID=20>=3D=20xmax=20are=20invisible=20to=20me=20*/=0A+=0A+=09= /*=0A+=09=20*=20committed_xids=20contains=20*committed*=20transactions=20= between=20xmin=20and=20xmax.=0A+=09=20*=20(This=20is=20the=20inverse=20= of=20'xip'=20in=20normal=20MVCC=20snapshots,=20which=20contains=0A+=09=20= *=20all=20non-committed=20transactions.)=20=20The=20array=20is=20sorted=20= by=20XID=20to=20allow=0A+=09=20*=20binary=20search.=0A+=09=20*=0A+=09=20= *=20note:=20all=20ids=20in=20committed_xids[]=20satisfy=20xmin=20<=3D=20= committed_xids[i]=20<=0A+=09=20*=20xmax=0A+=09=20*/=0A+=09TransactionId=20= *committed_xids;=0A+=09uint32=09=09xcnt;=09=09=09/*=20#=20of=20xact=20= ids=20in=20committed_xids[]=20*/=0A+=0A+=09/*=0A+=09=20*=20curxip=20= contains=20*all*=20xids=20assigned=20to=20the=20replayed=20transaction,=0A= +=09=20*=20including=20the=20toplevel=20xid.=0A+=09=20*/=0A+=09= TransactionId=20*curxip;=0A+=09int32=09=09curxcnt;=09=09/*=20#=20of=20= xact=20ids=20in=20curxip[]=20*/=0A+=0A+=09CommandId=09curcid;=09=09=09/*=20= in=20my=20xact,=20CID=20<=20curcid=20are=20visible=20*/=0A+=0A+=09bool=09= =09copied;=09=09=09/*=20false=20if=20it's=20a=20"base"=20snapshot=20*/=0A= +=0A+=09uint32=09=09refcount;=09=09/*=20refcount=20managed=20by=20= snapbuild.c=20=20*/=0A+=09uint32=09=09regd_count;=09=09/*=20refcount=20= registered=20with=20resource=20owners=20*/=0A+=0A+}=20= HistoricMVCCSnapshotData;=0A+=0A+typedef=20struct=20= HistoricMVCCSnapshotData=20*HistoricMVCCSnapshot;=0A+=0A+/*=0A+=20*=20= Struct=20representing=20a=20special=20"snapshot"=20which=20sees=20all=20= tuples=20as=20visible=0A+=20*=20if=20they=20are=20visible=20to=20anyone,=20= i.e.=20if=20they=20are=20not=20vacuumable.=0A+=20*=20i.e.=20= SNAPSHOT_NON_VACUUMABLE.=0A+=20*/=0A+typedef=20struct=20= NonVacuumableSnapshotData=0A+{=0A+=09SnapshotType=20snapshot_type;=20/*=20= type=20of=20snapshot,=20must=20be=20first=20*/=0A+=0A+=09/*=20This=20is=20= used=20to=20determine=20whether=20row=20could=20be=20vacuumed.=20*/=0A+=09= struct=20GlobalVisState=20*vistest;=0A+}=20NonVacuumableSnapshotData;=0A= +=0A+/*=0A+=20*=20Return=20values=20to=20the=20caller=20of=20= HeapTupleSatisfyDirty.=0A+=20*/=0A+typedef=20struct=20DirtySnapshotData=0A= +{=0A+=09SnapshotType=20snapshot_type;=20/*=20type=20of=20snapshot,=20= must=20be=20first=20*/=0A+=0A+=09TransactionId=20xmin;=0A+=09= TransactionId=20xmax;=0A+=09uint32=09=09speculativeToken;=0A+}=20= DirtySnapshotData;=0A+=0A+/*=0A+=20*=20Generic=20union=20representing=20= all=20kind=20of=20possible=20snapshots.=20=20Some=20have=0A+=20*=20= type-specific=20structs.=0A+=20*/=0A+typedef=20union=20SnapshotData=0A+{=0A= +=09SnapshotType=20snapshot_type;=20/*=20type=20of=20snapshot=20*/=0A+=0A= +=09MVCCSnapshotData=20mvcc;=0A+=09DirtySnapshotData=20dirty;=0A+=09= HistoricMVCCSnapshotData=20historic_mvcc;=0A+=09= NonVacuumableSnapshotData=20nonvacuumable;=0A=20}=20SnapshotData;=0A=20=0A= +typedef=20union=20SnapshotData=20*Snapshot;=0A+=0A+#define=20= InvalidSnapshot=09=09((Snapshot)=20NULL)=0A+=0A=20#endif=09=09=09=09=09=09= =09/*=20SNAPSHOT_H=20*/=0Adiff=20--git=20= a/src/tools/pgindent/typedefs.list=20b/src/tools/pgindent/typedefs.list=0A= index=20b66cecd8799..c8ed18cf580=20100644=0A---=20= a/src/tools/pgindent/typedefs.list=0A+++=20= b/src/tools/pgindent/typedefs.list=0A@@=20-633,6=20+633,7=20@@=20= DictThesaurus=0A=20DimensionInfo=0A=20DirectoryMethodData=0A=20= DirectoryMethodFile=0A+DirtySnapshotData=0A=20DisableTimeoutParams=0A=20= DiscardMode=0A=20DiscardStmt=0A@@=20-1183,6=20+1184,7=20@@=20= HeapTupleFreeze=0A=20HeapTupleHeader=0A=20HeapTupleHeaderData=0A=20= HeapTupleTableSlot=0A+HistoricMVCCSnapshotData=0A=20HistControl=0A=20= HotStandbyState=0A=20I32=0A@@=20-1633,6=20+1635,7=20@@=20= MINIDUMPWRITEDUMP=0A=20MINIDUMP_TYPE=0A=20MJEvalResult=0A=20= MTTargetRelLookup=0A+MVCCSnapshotData=0A=20MVDependencies=0A=20= MVDependency=0A=20MVNDistinct=0A@@=20-1732,6=20+1735,7=20@@=20= NextValueExpr=0A=20Node=0A=20NodeTag=0A=20NonEmptyRange=0A= +NonVacuumableSnapshotData=0A=20Notification=0A=20NotificationList=0A=20= NotifyStmt=0A--=20=0A2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0002-Simplify-historic-snapshot-refcounting.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0002-Simplify-historic-snapshot-refcounting.patch" Content-Transfer-Encoding: quoted-printable =46rom=203228848876610c7b13216ffca6b42a9f5465e300=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Thu,=2013=20Mar=202025=2016:45:12=20= +0200=0ASubject:=20[PATCH=20v6=2002/12]=20Simplify=20historic=20snapshot=20= refcounting=0A=0AReorderBufferProcessTXN()=20handled=20"copied"=20= snapshots=20created=20with=0AReorderBufferCopySnap()=20differently=20= from=20"base"=20historic=20snapshots=0Acreated=20by=20snapbuild.c.=20The=20= base=20snapshots=20used=20a=20reference=20count,=0Awhile=20copied=20= snapshots=20did=20not.=20Simplify=20by=20using=20the=20reference=20count=0A= for=20both.=0A---=0A=20.../replication/logical/reorderbuffer.c=20=20=20=20= =20=20=20|=2097=20++++++++-----------=0A=20= src/backend/replication/logical/snapbuild.c=20=20=20|=2048=20+--------=0A= =20src/include/replication/snapbuild.h=20=20=20=20=20=20=20=20=20=20=20|=20= =201=20+=0A=20src/include/utils/snapshot.h=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20|=20=202=20-=0A=204=20files=20changed,=2046=20= insertions(+),=20102=20deletions(-)=0A=0Adiff=20--git=20= a/src/backend/replication/logical/reorderbuffer.c=20= b/src/backend/replication/logical/reorderbuffer.c=0Aindex=20= e8196a8d5d5..e47970f1c82=20100644=0A---=20= a/src/backend/replication/logical/reorderbuffer.c=0A+++=20= b/src/backend/replication/logical/reorderbuffer.c=0A@@=20-103,7=20+103,7=20= @@=0A=20#include=20"replication/logical.h"=0A=20#include=20= "replication/reorderbuffer.h"=0A=20#include=20"replication/slot.h"=0A= -#include=20"replication/snapbuild.h"=09/*=20just=20for=20= SnapBuildSnapDecRefcount=20*/=0A+#include=20"replication/snapbuild.h"=0A=20= #include=20"storage/bufmgr.h"=0A=20#include=20"storage/fd.h"=0A=20= #include=20"storage/procarray.h"=0A@@=20-268,7=20+268,6=20@@=20static=20= void=20ReorderBufferSerializedPath(char=20*path,=20ReplicationSlot=20= *slot,=0A=20=09=09=09=09=09=09=09=09=09=09TransactionId=20xid,=20= XLogSegNo=20segno);=0A=20static=20int=09= ReorderBufferTXNSizeCompare(const=20pairingheap_node=20*a,=20const=20= pairingheap_node=20*b,=20void=20*arg);=0A=20=0A-static=20void=20= ReorderBufferFreeSnap(ReorderBuffer=20*rb,=20HistoricMVCCSnapshot=20= snap);=0A=20static=20HistoricMVCCSnapshot=20= ReorderBufferCopySnap(ReorderBuffer=20*rb,=20HistoricMVCCSnapshot=20= orig_snap,=0A=20=09=09=09=09=09=09=09=09=09=09=09=09=20=20= ReorderBufferTXN=20*txn,=20CommandId=20cid);=0A=20=0A@@=20-543,7=20= +542,7=20@@=20ReorderBufferFreeChange(ReorderBuffer=20*rb,=20= ReorderBufferChange=20*change,=0A=20=09=09case=20= REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:=0A=20=09=09=09if=20= (change->data.snapshot)=0A=20=09=09=09{=0A-=09=09=09=09= ReorderBufferFreeSnap(rb,=20change->data.snapshot);=0A+=09=09=09=09= SnapBuildSnapDecRefcount(change->data.snapshot);=0A=20=09=09=09=09= change->data.snapshot=20=3D=20NULL;=0A=20=09=09=09}=0A=20=09=09=09break;=0A= @@=20-1593,7=20+1592,8=20@@=20ReorderBufferCleanupTXN(ReorderBuffer=20= *rb,=20ReorderBufferTXN=20*txn)=0A=20=09if=20(txn->snapshot_now=20!=3D=20= NULL)=0A=20=09{=0A=20=09=09Assert(rbtxn_is_streamed(txn));=0A-=09=09= ReorderBufferFreeSnap(rb,=20txn->snapshot_now);=0A+=09=09= SnapBuildSnapDecRefcount(txn->snapshot_now);=0A+=09=09txn->snapshot_now=20= =3D=20NULL;=0A=20=09}=0A=20=0A=20=09/*=0A@@=20-1902,7=20+1902,6=20@@=20= ReorderBufferCopySnap(ReorderBuffer=20*rb,=20HistoricMVCCSnapshot=20= orig_snap,=0A=20=09snap=20=3D=20MemoryContextAllocZero(rb->context,=20= size);=0A=20=09memcpy(snap,=20orig_snap,=20= sizeof(HistoricMVCCSnapshotData));=0A=20=0A-=09snap->copied=20=3D=20= true;=0A=20=09snap->refcount=20=3D=201;=09=09=09/*=20mark=20as=20active=20= so=20nobody=20frees=20it=20*/=0A=20=09snap->regd_count=20=3D=200;=0A=20=09= snap->committed_xids=20=3D=20(TransactionId=20*)=20(snap=20+=201);=0A@@=20= -1942,18=20+1941,6=20@@=20ReorderBufferCopySnap(ReorderBuffer=20*rb,=20= HistoricMVCCSnapshot=20orig_snap,=0A=20=09return=20snap;=0A=20}=0A=20=0A= -/*=0A-=20*=20Free=20a=20previously=20ReorderBufferCopySnap'ed=20= snapshot=0A-=20*/=0A-static=20void=0A= -ReorderBufferFreeSnap(ReorderBuffer=20*rb,=20HistoricMVCCSnapshot=20= snap)=0A-{=0A-=09if=20(snap->copied)=0A-=09=09pfree(snap);=0A-=09else=0A= -=09=09SnapBuildSnapDecRefcount(snap);=0A-}=0A-=0A=20/*=0A=20=20*=20If=20= the=20transaction=20was=20(partially)=20streamed,=20we=20need=20to=20= prepare=20or=20commit=0A=20=20*=20it=20in=20a=20'streamed'=20way.=20=20= That=20is,=20we=20first=20stream=20the=20remaining=20part=20of=20the=0A= @@=20-2104,11=20+2091,8=20@@=20= ReorderBufferSaveTXNSnapshot(ReorderBuffer=20*rb,=20ReorderBufferTXN=20= *txn,=0A=20=09txn->command_id=20=3D=20command_id;=0A=20=0A=20=09/*=20= Avoid=20copying=20if=20it's=20already=20copied.=20*/=0A-=09if=20= (snapshot_now->copied)=0A-=09=09txn->snapshot_now=20=3D=20snapshot_now;=0A= -=09else=0A-=09=09txn->snapshot_now=20=3D=20ReorderBufferCopySnap(rb,=20= snapshot_now,=0A-=09=09=09=09=09=09=09=09=09=09=09=09=20=20txn,=20= command_id);=0A+=09txn->snapshot_now=20=3D=20snapshot_now;=0A+=09= SnapBuildSnapIncRefcount(txn->snapshot_now);=0A=20}=0A=20=0A=20/*=0A@@=20= -2208,6=20+2192,8=20@@=20ReorderBufferProcessTXN(ReorderBuffer=20*rb,=20= ReorderBufferTXN=20*txn,=0A=20=0A=20=09/*=20setup=20the=20initial=20= snapshot=20*/=0A=20=09SetupHistoricSnapshot(snapshot_now,=20= txn->tuplecid_hash);=0A+=09/*=20increase=20refcount=20for=20the=20= installed=20historic=20snapshot=20*/=0A+=09= SnapBuildSnapIncRefcount(snapshot_now);=0A=20=0A=20=09/*=0A=20=09=20*=20= Decoding=20needs=20access=20to=20syscaches=20et=20al.,=20which=20in=20= turn=20use=0A@@=20-2511,33=20+2497,12=20@@=20= ReorderBufferProcessTXN(ReorderBuffer=20*rb,=20ReorderBufferTXN=20*txn,=0A= =20=09=09=09=09case=20REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:=0A=20=09=09= =09=09=09/*=20get=20rid=20of=20the=20old=20*/=0A=20=09=09=09=09=09= TeardownHistoricSnapshot(false);=0A-=0A-=09=09=09=09=09if=20= (snapshot_now->copied)=0A-=09=09=09=09=09{=0A-=09=09=09=09=09=09= ReorderBufferFreeSnap(rb,=20snapshot_now);=0A-=09=09=09=09=09=09= snapshot_now=20=3D=0A-=09=09=09=09=09=09=09ReorderBufferCopySnap(rb,=20= change->data.snapshot,=0A-=09=09=09=09=09=09=09=09=09=09=09=09=20=20txn,=20= command_id);=0A-=09=09=09=09=09}=0A-=0A-=09=09=09=09=09/*=0A-=09=09=09=09= =09=20*=20Restored=20from=20disk,=20need=20to=20be=20careful=20not=20to=20= double=0A-=09=09=09=09=09=20*=20free.=20We=20could=20introduce=20= refcounting=20for=20that,=20but=20for=0A-=09=09=09=09=09=20*=20now=20= this=20seems=20infrequent=20enough=20not=20to=20care.=0A-=09=09=09=09=09=20= */=0A-=09=09=09=09=09else=20if=20(change->data.snapshot->copied)=0A-=09=09= =09=09=09{=0A-=09=09=09=09=09=09snapshot_now=20=3D=0A-=09=09=09=09=09=09=09= ReorderBufferCopySnap(rb,=20change->data.snapshot,=0A-=09=09=09=09=09=09=09= =09=09=09=09=09=20=20txn,=20command_id);=0A-=09=09=09=09=09}=0A-=09=09=09= =09=09else=0A-=09=09=09=09=09{=0A-=09=09=09=09=09=09snapshot_now=20=3D=20= change->data.snapshot;=0A-=09=09=09=09=09}=0A+=09=09=09=09=09= SnapBuildSnapDecRefcount(snapshot_now);=0A=20=0A=20=09=09=09=09=09/*=20= and=20continue=20with=20the=20new=20one=20*/=0A+=09=09=09=09=09= snapshot_now=20=3D=20change->data.snapshot;=0A=20=09=09=09=09=09= SetupHistoricSnapshot(snapshot_now,=20txn->tuplecid_hash);=0A+=09=09=09=09= =09SnapBuildSnapIncRefcount(snapshot_now);=0A=20=09=09=09=09=09break;=0A=20= =0A=20=09=09=09=09case=20REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:=0A@@=20= -2547,16=20+2512,26=20@@=20ReorderBufferProcessTXN(ReorderBuffer=20*rb,=20= ReorderBufferTXN=20*txn,=0A=20=09=09=09=09=09{=0A=20=09=09=09=09=09=09= command_id=20=3D=20change->data.command_id;=0A=20=0A-=09=09=09=09=09=09= if=20(!snapshot_now->copied)=0A+=09=09=09=09=09=09= TeardownHistoricSnapshot(false);=0A+=0A+=09=09=09=09=09=09/*=0A+=09=09=09= =09=09=09=20*=20Construct=20a=20new=20snapshot=20with=20the=20new=20= command=20ID.=0A+=09=09=09=09=09=09=20*=0A+=09=09=09=09=09=09=20*=20If=20= this=20is=20the=20only=20reference=20to=20the=20snapshot,=20and=0A+=09=09= =09=09=09=09=20*=20it's=20a=20"copied"=20snapshot=20that=20already=20= contains=20all=0A+=09=09=09=09=09=09=20*=20the=20replayed=20= transaction's=20XIDs=20(curxnct=20>=200),=20we=0A+=09=09=09=09=09=09=20*=20= can=20take=20a=20shortcut=20and=20update=20the=20snapshot's=0A+=09=09=09=09= =09=09=20*=20command=20ID=20in=20place.=0A+=09=09=09=09=09=09=20*/=0A+=09= =09=09=09=09=09if=20(snapshot_now->refcount=20=3D=3D=201=20&&=20= snapshot_now->curxcnt=20>=200)=0A+=09=09=09=09=09=09=09= snapshot_now->curcid=20=3D=20command_id;=0A+=09=09=09=09=09=09else=0A=20=09= =09=09=09=09=09{=0A-=09=09=09=09=09=09=09/*=20we=20don't=20use=20the=20= global=20one=20anymore=20*/=0A+=09=09=09=09=09=09=09= SnapBuildSnapDecRefcount(snapshot_now);=0A=20=09=09=09=09=09=09=09= snapshot_now=20=3D=20ReorderBufferCopySnap(rb,=20snapshot_now,=0A=20=09=09= =09=09=09=09=09=09=09=09=09=09=09=09=09=09=20txn,=20command_id);=0A=20=09= =09=09=09=09=09}=0A=20=0A-=09=09=09=09=09=09snapshot_now->curcid=20=3D=20= command_id;=0A-=0A-=09=09=09=09=09=09TeardownHistoricSnapshot(false);=0A=20= =09=09=09=09=09=09SetupHistoricSnapshot(snapshot_now,=20= txn->tuplecid_hash);=0A=20=09=09=09=09=09}=0A=20=0A@@=20-2646,11=20= +2621,11=20@@=20ReorderBufferProcessTXN(ReorderBuffer=20*rb,=20= ReorderBufferTXN=20*txn,=0A=20=09=09=20*/=0A=20=09=09if=20(streaming)=0A=20= =09=09=09ReorderBufferSaveTXNSnapshot(rb,=20txn,=20snapshot_now,=20= command_id);=0A-=09=09else=20if=20(snapshot_now->copied)=0A-=09=09=09= ReorderBufferFreeSnap(rb,=20snapshot_now);=0A=20=0A=20=09=09/*=20cleanup=20= */=0A=20=09=09TeardownHistoricSnapshot(false);=0A+=09=09= SnapBuildSnapDecRefcount(snapshot_now);=0A+=09=09snapshot_now=20=3D=20= NULL;=0A=20=0A=20=09=09/*=0A=20=09=09=20*=20Aborting=20the=20current=20= (sub-)transaction=20as=20a=20whole=20has=20the=20right=0A@@=20-2703,6=20= +2678,11=20@@=20ReorderBufferProcessTXN(ReorderBuffer=20*rb,=20= ReorderBufferTXN=20*txn,=0A=20=0A=20=09=09= TeardownHistoricSnapshot(true);=0A=20=0A+=09=09/*=0A+=09=09=20*=20don't=20= decrement=20the=20refcount=20on=20snapshot_now=20yet,=20we=20still=20use=20= it=0A+=09=09=20*=20in=20the=20ReorderBufferResetTXN()=20call=20below.=0A= +=09=09=20*/=0A+=0A=20=09=09/*=0A=20=09=09=20*=20Force=20cache=20= invalidation=20to=20happen=20outside=20of=20a=20valid=20transaction=0A=20= =09=09=20*=20to=20prevent=20catalog=20access=20as=20we=20just=20caught=20= an=20error.=0A@@=20-2751,9=20+2731,15=20@@=20= ReorderBufferProcessTXN(ReorderBuffer=20*rb,=20ReorderBufferTXN=20*txn,=0A= =20=09=09=09ReorderBufferResetTXN(rb,=20txn,=20snapshot_now,=0A=20=09=09=09= =09=09=09=09=09=20=20command_id,=20prev_lsn,=0A=20=09=09=09=09=09=09=09=09= =20=20specinsert);=0A+=0A+=09=09=09= SnapBuildSnapDecRefcount(snapshot_now);=0A+=09=09=09snapshot_now=20=3D=20= NULL;=0A=20=09=09}=0A=20=09=09else=0A=20=09=09{=0A+=09=09=09= SnapBuildSnapDecRefcount(snapshot_now);=0A+=09=09=09snapshot_now=20=3D=20= NULL;=0A+=0A=20=09=09=09ReorderBufferCleanupTXN(rb,=20txn);=0A=20=09=09=09= MemoryContextSwitchTo(ecxt);=0A=20=09=09=09PG_RE_THROW();=0A@@=20-4256,8=20= +4242,7=20@@=20ReorderBufferStreamTXN(ReorderBuffer=20*rb,=20= ReorderBufferTXN=20*txn)=0A=20=09=09=09=09=09=09=09=09=09=09=09=20txn,=20= command_id);=0A=20=0A=20=09=09/*=20Free=20the=20previously=20copied=20= snapshot.=20*/=0A-=09=09Assert(txn->snapshot_now->copied);=0A-=09=09= ReorderBufferFreeSnap(rb,=20txn->snapshot_now);=0A+=09=09= SnapBuildSnapDecRefcount(txn->snapshot_now);=0A=20=09=09= txn->snapshot_now=20=3D=20NULL;=0A=20=09}=0A=20=0A@@=20-4647,7=20+4632,7=20= @@=20ReorderBufferRestoreChange(ReorderBuffer=20*rb,=20ReorderBufferTXN=20= *txn,=0A=20=09=09=09=09newsnap->committed_xids=20=3D=20(TransactionId=20= *)=0A=20=09=09=09=09=09(((char=20*)=20newsnap)=20+=20= sizeof(HistoricMVCCSnapshotData));=0A=20=09=09=09=09newsnap->curxip=20=3D=20= newsnap->committed_xids=20+=20newsnap->xcnt;=0A-=09=09=09=09= newsnap->copied=20=3D=20true;=0A+=09=09=09=09newsnap->refcount=20=3D=20= 1;=0A=20=09=09=09=09break;=0A=20=09=09=09}=0A=20=09=09=09/*=20the=20base=20= struct=20contains=20all=20the=20data,=20easy=20peasy=20*/=0Adiff=20--git=20= a/src/backend/replication/logical/snapbuild.c=20= b/src/backend/replication/logical/snapbuild.c=0Aindex=20= 7a341418a74..50dca7cb758=20100644=0A---=20= a/src/backend/replication/logical/snapbuild.c=0A+++=20= b/src/backend/replication/logical/snapbuild.c=0A@@=20-157,10=20+157,6=20= @@=20static=20void=20SnapBuildPurgeOlderTxn(SnapBuild=20*builder);=0A=20= /*=20snapshot=20building/manipulation/distribution=20functions=20*/=0A=20= static=20HistoricMVCCSnapshot=20SnapBuildBuildSnapshot(SnapBuild=20= *builder);=0A=20=0A-static=20void=20= SnapBuildFreeSnapshot(HistoricMVCCSnapshot=20snap);=0A-=0A-static=20void=20= SnapBuildSnapIncRefcount(HistoricMVCCSnapshot=20snap);=0A-=0A=20static=20= void=20SnapBuildDistributeNewCatalogSnapshot(SnapBuild=20*builder,=20= XLogRecPtr=20lsn);=0A=20=0A=20static=20inline=20bool=20= SnapBuildXidHasCatalogChanges(SnapBuild=20*builder,=20TransactionId=20= xid,=0A@@=20-245,29=20+241,6=20@@=20FreeSnapshotBuilder(SnapBuild=20= *builder)=0A=20=09MemoryContextDelete(context);=0A=20}=0A=20=0A-/*=0A-=20= *=20Free=20an=20unreferenced=20snapshot=20that=20has=20previously=20been=20= built=20by=20us.=0A-=20*/=0A-static=20void=0A= -SnapBuildFreeSnapshot(HistoricMVCCSnapshot=20snap)=0A-{=0A-=09/*=20make=20= sure=20we=20don't=20get=20passed=20an=20external=20snapshot=20*/=0A-=09= Assert(snap->snapshot_type=20=3D=3D=20SNAPSHOT_HISTORIC_MVCC);=0A-=0A-=09= /*=20make=20sure=20nobody=20modified=20our=20snapshot=20*/=0A-=09= Assert(snap->curcid=20=3D=3D=20FirstCommandId);=0A-=09= Assert(snap->regd_count=20=3D=3D=200);=0A-=0A-=09/*=20slightly=20more=20= likely,=20so=20it's=20checked=20even=20without=20c-asserts=20*/=0A-=09if=20= (snap->copied)=0A-=09=09elog(ERROR,=20"cannot=20free=20a=20copied=20= snapshot");=0A-=0A-=09if=20(snap->refcount)=0A-=09=09elog(ERROR,=20= "cannot=20free=20a=20snapshot=20that's=20in=20use");=0A-=0A-=09= pfree(snap);=0A-}=0A-=0A=20/*=0A=20=20*=20In=20which=20state=20of=20= snapshot=20building=20are=20we?=0A=20=20*/=0A@@=20-310,7=20+283,7=20@@=20= SnapBuildXactNeedsSkip(SnapBuild=20*builder,=20XLogRecPtr=20ptr)=0A=20=20= *=20This=20is=20used=20when=20handing=20out=20a=20snapshot=20to=20some=20= external=20resource=20or=20when=0A=20=20*=20adding=20a=20Snapshot=20as=20= builder->snapshot.=0A=20=20*/=0A-static=20void=0A+void=0A=20= SnapBuildSnapIncRefcount(HistoricMVCCSnapshot=20snap)=0A=20{=0A=20=09= snap->refcount++;=0A@@=20-318,9=20+291,6=20@@=20= SnapBuildSnapIncRefcount(HistoricMVCCSnapshot=20snap)=0A=20=0A=20/*=0A=20= =20*=20Decrease=20refcount=20of=20a=20snapshot=20and=20free=20if=20the=20= refcount=20reaches=20zero.=0A-=20*=0A-=20*=20Externally=20visible,=20so=20= that=20external=20resources=20that=20have=20been=20handed=20an=0A-=20*=20= IncRef'ed=20Snapshot=20can=20adjust=20its=20refcount=20easily.=0A=20=20= */=0A=20void=0A=20SnapBuildSnapDecRefcount(HistoricMVCCSnapshot=20snap)=0A= @@=20-328,19=20+298,12=20@@=20= SnapBuildSnapDecRefcount(HistoricMVCCSnapshot=20snap)=0A=20=09/*=20make=20= sure=20we=20don't=20get=20passed=20an=20external=20snapshot=20*/=0A=20=09= Assert(snap->snapshot_type=20=3D=3D=20SNAPSHOT_HISTORIC_MVCC);=0A=20=0A-=09= /*=20make=20sure=20nobody=20modified=20our=20snapshot=20*/=0A-=09= Assert(snap->curcid=20=3D=3D=20FirstCommandId);=0A-=0A=20=09= Assert(snap->refcount=20>=200);=0A=20=09Assert(snap->regd_count=20=3D=3D=20= 0);=0A=20=0A-=09/*=20slightly=20more=20likely,=20so=20it's=20checked=20= even=20without=20casserts=20*/=0A-=09if=20(snap->copied)=0A-=09=09= elog(ERROR,=20"cannot=20free=20a=20copied=20snapshot");=0A-=0A=20=09= snap->refcount--;=0A=20=09if=20(snap->refcount=20=3D=3D=200)=0A-=09=09= SnapBuildFreeSnapshot(snap);=0A+=09=09pfree(snap);=0A=20}=0A=20=0A=20/*=0A= @@=20-413,7=20+376,6=20@@=20SnapBuildBuildSnapshot(SnapBuild=20*builder)=0A= =20=09snapshot->curxcnt=20=3D=200;=0A=20=09snapshot->curxip=20=3D=20= NULL;=0A=20=0A-=09snapshot->copied=20=3D=20false;=0A=20=09= snapshot->curcid=20=3D=20FirstCommandId;=0A=20=09snapshot->refcount=20=3D=20= 0;=0A=20=09snapshot->regd_count=20=3D=200;=0A@@=20-1037,18=20+999,16=20= @@=20SnapBuildCommitTxn(SnapBuild=20*builder,=20XLogRecPtr=20lsn,=20= TransactionId=20xid,=0A=20=09=09=09= SnapBuildSnapDecRefcount(builder->snapshot);=0A=20=0A=20=09=09= builder->snapshot=20=3D=20SnapBuildBuildSnapshot(builder);=0A+=09=09= SnapBuildSnapIncRefcount(builder->snapshot);=0A=20=0A=20=09=09/*=20we=20= might=20need=20to=20execute=20invalidations,=20add=20snapshot=20*/=0A=20=09= =09if=20(!ReorderBufferXidHasBaseSnapshot(builder->reorder,=20xid))=0A=20= =09=09{=0A-=09=09=09SnapBuildSnapIncRefcount(builder->snapshot);=0A=20=09= =09=09ReorderBufferSetBaseSnapshot(builder->reorder,=20xid,=20lsn,=0A=20=09= =09=09=09=09=09=09=09=09=09=20builder->snapshot);=0A+=09=09=09= SnapBuildSnapIncRefcount(builder->snapshot);=0A=20=09=09}=0A=20=0A-=09=09= /*=20refcount=20of=20the=20snapshot=20builder=20for=20the=20new=20= snapshot=20*/=0A-=09=09SnapBuildSnapIncRefcount(builder->snapshot);=0A-=0A= =20=09=09/*=20add=20a=20new=20catalog=20snapshot=20to=20all=20currently=20= running=20transactions=20*/=0A=20=09=09= SnapBuildDistributeNewCatalogSnapshot(builder,=20lsn);=0A=20=09}=0Adiff=20= --git=20a/src/include/replication/snapbuild.h=20= b/src/include/replication/snapbuild.h=0Aindex=205930ffb55a8..6095013a299=20= 100644=0A---=20a/src/include/replication/snapbuild.h=0A+++=20= b/src/include/replication/snapbuild.h=0A@@=20-70,6=20+70,7=20@@=20extern=20= SnapBuild=20*AllocateSnapshotBuilder(struct=20ReorderBuffer=20*reorder,=0A= =20=09=09=09=09=09=09=09=09=09=09=20=20XLogRecPtr=20two_phase_at);=0A=20= extern=20void=20FreeSnapshotBuilder(SnapBuild=20*builder);=0A=20=0A= +extern=20void=20SnapBuildSnapIncRefcount(HistoricMVCCSnapshot=20snap);=0A= =20extern=20void=20SnapBuildSnapDecRefcount(HistoricMVCCSnapshot=20= snap);=0A=20=0A=20extern=20MVCCSnapshot=20= SnapBuildInitialSnapshot(SnapBuild=20*builder);=0Adiff=20--git=20= a/src/include/utils/snapshot.h=20b/src/include/utils/snapshot.h=0Aindex=20= 93c1f51784f..bca0ad16e68=20100644=0A---=20a/src/include/utils/snapshot.h=0A= +++=20b/src/include/utils/snapshot.h=0A@@=20-218,8=20+218,6=20@@=20= typedef=20struct=20HistoricMVCCSnapshotData=0A=20=0A=20=09CommandId=09= curcid;=09=09=09/*=20in=20my=20xact,=20CID=20<=20curcid=20are=20visible=20= */=0A=20=0A-=09bool=09=09copied;=09=09=09/*=20false=20if=20it's=20a=20= "base"=20snapshot=20*/=0A-=0A=20=09uint32=09=09refcount;=09=09/*=20= refcount=20managed=20by=20snapbuild.c=20=20*/=0A=20=09uint32=09=09= regd_count;=09=09/*=20refcount=20registered=20with=20resource=20owners=20= */=0A=20=0A--=20=0A2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0003-Add-an-explicit-valid-flag-to-MVCCSnapshotData.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0003-Add-an-explicit-valid-flag-to-MVCCSnapshotData.patch" Content-Transfer-Encoding: quoted-printable =46rom=201705639a73555d9b3f5884c7fd90540c268d3db5=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Mon,=2031=20Mar=202025=2023:47:48=20= +0300=0ASubject:=20[PATCH=20v6=2003/12]=20Add=20an=20explicit=20'valid'=20= flag=20to=20MVCCSnapshotData=0A=0AThe=20lifetime=20of=20the=20"static"=20= snapshots=20returned=20by=0AGetTransactionSnapshot(),=20= GetLatestSnapshot()=20and=20GetCatalogSnapshot()=0Ais=20a=20bit=20vague.=20= By=20adding=20an=20explicit=20'valid'=20flag,=20we=20can=20make=20it=0A= more=20clear=20when=20a=20function=20call=20updates=20a=20static=20= snapshot,=20making=20it=0Avalid,=20and=20when=20another=20function=20= makes=20it=20invalid=20again.=20It's=0Acurrently=20only=20used=20in=20= assertions,=20and=20can=20also=20be=20handy=20when=0Adebugging.=0A---=0A=20= src/backend/storage/ipc/procarray.c=20|=20=202=20++=0A=20= src/backend/utils/time/snapmgr.c=20=20=20=20|=2015=20+++++++++++++++=0A=20= src/include/utils/snapshot.h=20=20=20=20=20=20=20=20|=20=201=20+=0A=203=20= files=20changed,=2018=20insertions(+)=0A=0Adiff=20--git=20= a/src/backend/storage/ipc/procarray.c=20= b/src/backend/storage/ipc/procarray.c=0Aindex=20535755614a9..ba5ed8960dd=20= 100644=0A---=20a/src/backend/storage/ipc/procarray.c=0A+++=20= b/src/backend/storage/ipc/procarray.c=0A@@=20-2135,6=20+2135,7=20@@=20= GetSnapshotDataReuse(MVCCSnapshot=20snapshot)=0A=20=09= snapshot->active_count=20=3D=200;=0A=20=09snapshot->regd_count=20=3D=20= 0;=0A=20=09snapshot->copied=20=3D=20false;=0A+=09snapshot->valid=20=3D=20= true;=0A=20=0A=20=09return=20true;=0A=20}=0A@@=20-2514,6=20+2515,7=20@@=20= GetSnapshotData(MVCCSnapshot=20snapshot)=0A=20=09snapshot->active_count=20= =3D=200;=0A=20=09snapshot->regd_count=20=3D=200;=0A=20=09= snapshot->copied=20=3D=20false;=0A+=09snapshot->valid=20=3D=20true;=0A=20= =0A=20=09return=20snapshot;=0A=20}=0Adiff=20--git=20= a/src/backend/utils/time/snapmgr.c=20b/src/backend/utils/time/snapmgr.c=0A= index=2078adb6d575a..69ed86b2101=20100644=0A---=20= a/src/backend/utils/time/snapmgr.c=0A+++=20= b/src/backend/utils/time/snapmgr.c=0A@@=20-447,6=20+447,7=20@@=20= InvalidateCatalogSnapshot(void)=0A=20=09{=0A=20=09=09= pairingheap_remove(&RegisteredSnapshots,=20&CatalogSnapshot->ph_node);=0A= =20=09=09CatalogSnapshot=20=3D=20NULL;=0A+=09=09= CatalogSnapshotData.valid=20=3D=20false;=0A=20=09=09SnapshotResetXmin();=0A= =20=09}=0A=20}=0A@@=20-611,6=20+612,7=20@@=20= CopyMVCCSnapshot(MVCCSnapshot=20snapshot)=0A=20=09newsnap->regd_count=20= =3D=200;=0A=20=09newsnap->active_count=20=3D=200;=0A=20=09= newsnap->copied=20=3D=20true;=0A+=09newsnap->valid=20=3D=20true;=0A=20=09= newsnap->snapXactCompletionCount=20=3D=200;=0A=20=0A=20=09/*=20setup=20= XID=20array=20*/=0A@@=20-652,6=20+654,7=20@@=20= FreeMVCCSnapshot(MVCCSnapshot=20snapshot)=0A=20=09= Assert(snapshot->regd_count=20=3D=3D=200);=0A=20=09= Assert(snapshot->active_count=20=3D=3D=200);=0A=20=09= Assert(snapshot->copied);=0A+=09Assert(snapshot->valid);=0A=20=0A=20=09= pfree(snapshot);=0A=20}=0A@@=20-688,6=20+691,7=20@@=20= PushActiveSnapshotWithLevel(Snapshot=20snapshot,=20int=20snap_level)=0A=20= =0A=20=09Assert(snapshot->snapshot_type=20=3D=3D=20SNAPSHOT_MVCC);=0A=20=09= origsnap=20=3D=20&snapshot->mvcc;=0A+=09Assert(origsnap->valid);=0A=20=0A= =20=09Assert(ActiveSnapshot=20=3D=3D=20NULL=20||=20snap_level=20>=3D=20= ActiveSnapshot->as_level);=0A=20=0A@@=20-847,6=20+851,7=20@@=20= RegisterSnapshotOnOwner(Snapshot=20orig_snapshot,=20ResourceOwner=20= owner)=0A=20=0A=20=09Assert(orig_snapshot->snapshot_type=20=3D=3D=20= SNAPSHOT_MVCC);=0A=20=09snapshot=20=3D=20&orig_snapshot->mvcc;=0A+=09= Assert(snapshot->valid);=0A=20=0A=20=09/*=20Static=20snapshot?=20=20= Create=20a=20persistent=20copy=20*/=0A=20=09snapshot=20=3D=20= snapshot->copied=20?=20snapshot=20:=20CopyMVCCSnapshot(snapshot);=0A@@=20= -968,6=20+973,15=20@@=20SnapshotResetXmin(void)=0A=20{=0A=20=09= MVCCSnapshot=20minSnapshot;=0A=20=0A+=09/*=0A+=09=20*=20These=20static=20= snapshots=20are=20not=20in=20the=20RegisteredSnapshots=20list,=20so=20we=0A= +=09=20*=20might=20advance=20MyProc->xmin=20past=20their=20xmin.=20(Note=20= that=20in=20case=20of=0A+=09=20*=20IsolationUsesXactSnapshot()=20=3D=3D=20= true,=20CurrentSnapshot=20points=20to=20the=20copy=0A+=09=20*=20in=20= FirstSnapshot=20rather=20than=20CurrentSnapshotData.)=0A+=09=20*/=0A+=09= CurrentSnapshotData.valid=20=3D=20false;=0A+=09= SecondarySnapshotData.valid=20=3D=20false;=0A+=0A=20=09if=20= (ActiveSnapshot=20!=3D=20NULL)=0A=20=09=09return;=0A=20=0A@@=20-1871,6=20= +1885,7=20@@=20RestoreSnapshot(char=20*start_address)=0A=20=09= snapshot->regd_count=20=3D=200;=0A=20=09snapshot->active_count=20=3D=20= 0;=0A=20=09snapshot->copied=20=3D=20true;=0A+=09snapshot->valid=20=3D=20= true;=0A=20=0A=20=09return=20snapshot;=0A=20}=0Adiff=20--git=20= a/src/include/utils/snapshot.h=20b/src/include/utils/snapshot.h=0Aindex=20= bca0ad16e68..1697c6df856=20100644=0A---=20a/src/include/utils/snapshot.h=0A= +++=20b/src/include/utils/snapshot.h=0A@@=20-161,6=20+161,7=20@@=20= typedef=20struct=20MVCCSnapshotData=0A=20=0A=20=09bool=09=09= takenDuringRecovery;=09/*=20recovery-shaped=20snapshot?=20*/=0A=20=09= bool=09=09copied;=09=09=09/*=20false=20if=20it's=20a=20static=20snapshot=20= */=0A+=09bool=09=09valid;=09=09=09/*=20is=20this=20snapshot=20valid?=20= */=0A=20=0A=20=09CommandId=09curcid;=09=09=09/*=20in=20my=20xact,=20CID=20= <=20curcid=20are=20visible=20*/=0A=20=0A--=20=0A2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0004-Replace-static-snapshot-pointers-with-the-valid-f.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0004-Replace-static-snapshot-pointers-with-the-valid-f.patch" Content-Transfer-Encoding: quoted-printable =46rom=208cc814dc2e9fef8feda7cca9a0f2591c371b8ece=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Mon,=2031=20Mar=202025=2021:44:43=20= +0300=0ASubject:=20[PATCH=20v6=2004/12]=20Replace=20static=20snapshot=20= pointers=20with=20the=20'valid'=0A=20flags=0A=0APreviously,=20we=20used=20= the=20pointers=20like=20SecondarySnapshot=20and=0ACatalogSnapshot=20to=20= indicate=20whether=20the=20corresponding=20static=20snapshot=0Ais=20= valid=20or=20not,=20but=20now=20that=20we=20have=20an=20explicit=20flag=20= in=0AMVCCSnapshotData=20for=20that,=20we=20replace=20checks=20like=20= "SecondarySnapshot=0A!=3D=20NULL"=20with=20= "SecondarySnapshotData.valid",=20and=20get=20rid=20of=20the=0Aseparate=20= pointer=20variables.=0A=0AThe=20situation=20with=20CurrentSnapshot=20was=20= a=20bit=20more=0Acomplicated.=20Usually,=20it=20pointed=20to=20= CurrentSnapshotData,=20but=20could=0Aalso=20point=20to=20the=20palloc'd=20= FirstXactSnapshot.=20This=20gets=20rid=20of=20the=0Apalloc'd=20= FirstXactSnapshot,=20and=20instead=20we=20just=20refrain=20from=20= modifying=0ACurrentSnapshotData=20when=20in=20a=20serializable=20= transaction.=0A---=0A=20src/backend/utils/time/snapmgr.c=20|=20147=20= +++++++++++++++----------------=0A=201=20file=20changed,=2070=20= insertions(+),=2077=20deletions(-)=0A=0Adiff=20--git=20= a/src/backend/utils/time/snapmgr.c=20b/src/backend/utils/time/snapmgr.c=0A= index=2069ed86b2101..ea1e7d17b04=20100644=0A---=20= a/src/backend/utils/time/snapmgr.c=0A+++=20= b/src/backend/utils/time/snapmgr.c=0A@@=20-67,8=20+67,8=20@@=0A=20=20*=20= In=20addition=20to=20snapshots=20pushed=20to=20the=20active=20snapshot=20= stack,=20a=20snapshot=0A=20=20*=20can=20be=20registered=20with=20a=20= resource=20owner.=0A=20=20*=0A-=20*=20The=20FirstXactSnapshot,=20if=20= any,=20is=20treated=20a=20bit=20specially:=20we=20increment=20its=0A-=20= *=20regd_count=20and=20list=20it=20in=20RegisteredSnapshots,=20but=20= this=20reference=20is=20not=0A+=20*=20If=20FirstXactSnapshotRegistered=20= is=20set,=20we=20increment=20the=20static=0A+=20*=20= CurrentSnapshotData's=20regd_count=20and=20list=20it=20in=20= RegisteredSnapshots,=20but=20this=20reference=20is=20not=0A=20=20*=20= tracked=20by=20a=20resource=20owner.=20We=20used=20to=20use=20the=20= TopTransactionResourceOwner=0A=20=20*=20to=20track=20this=20snapshot=20= reference,=20but=20that=20introduces=20logical=20circularity=0A=20=20*=20= and=20thus=20makes=20it=20impossible=20to=20clean=20up=20in=20a=20sane=20= fashion.=20=20It's=20better=20to=0A@@=20-145,9=20+145,6=20@@=20= SnapshotData=20SnapshotAnyData=20=3D=20{SNAPSHOT_ANY};=0A=20SnapshotData=20= SnapshotToastData=20=3D=20{SNAPSHOT_TOAST};=0A=20=0A=20/*=20Pointers=20= to=20valid=20snapshots=20*/=0A-static=20MVCCSnapshot=20CurrentSnapshot=20= =3D=20NULL;=0A-static=20MVCCSnapshot=20SecondarySnapshot=20=3D=20NULL;=0A= -static=20MVCCSnapshot=20CatalogSnapshot=20=3D=20NULL;=0A=20static=20= HistoricMVCCSnapshot=20HistoricSnapshot=20=3D=20NULL;=0A=20=0A=20/*=0A@@=20= -196,7=20+193,7=20@@=20bool=09=09FirstSnapshotSet=20=3D=20false;=0A=20=20= *=20FirstSnapshotSet=20in=20combination=20with=20= IsolationUsesXactSnapshot(),=20because=0A=20=20*=20GUC=20may=20be=20= reset=20before=20us,=20changing=20the=20value=20of=20= IsolationUsesXactSnapshot.=0A=20=20*/=0A-static=20MVCCSnapshot=20= FirstXactSnapshot=20=3D=20NULL;=0A+static=20bool=20= FirstXactSnapshotRegistered=20=3D=20false;=0A=20=0A=20/*=20Define=20= pathname=20of=20exported-snapshot=20files=20*/=0A=20#define=20= SNAPSHOT_EXPORT_DIR=20"pg_snapshots"=0A@@=20-288,7=20+285,7=20@@=20= GetTransactionSnapshot(void)=0A=20=09=09InvalidateCatalogSnapshot();=0A=20= =0A=20=09=09Assert(pairingheap_is_empty(&RegisteredSnapshots));=0A-=09=09= Assert(FirstXactSnapshot=20=3D=3D=20NULL);=0A+=09=09= Assert(!FirstXactSnapshotRegistered);=0A=20=0A=20=09=09if=20= (IsInParallelMode())=0A=20=09=09=09elog(ERROR,=0A@@=20-296,42=20+293,44=20= @@=20GetTransactionSnapshot(void)=0A=20=0A=20=09=09/*=0A=20=09=09=20*=20= In=20transaction-snapshot=20mode,=20the=20first=20snapshot=20must=20live=20= until=0A-=09=09=20*=20end=20of=20xact=20regardless=20of=20what=20the=20= caller=20does=20with=20it,=20so=20we=20must=0A-=09=09=20*=20make=20a=20= copy=20of=20it=20rather=20than=20returning=20CurrentSnapshotData=0A-=09=09= =20*=20directly.=20=20Furthermore,=20if=20we're=20running=20in=20= serializable=20mode,=0A-=09=09=20*=20predicate.c=20needs=20to=20wrap=20= the=20snapshot=20fetch=20in=20its=20own=20processing.=0A+=09=09=20*=20= end=20of=20xact=20regardless=20of=20what=20the=20caller=20does=20with=20= it,=20so=20we=20keep=0A+=09=09=20*=20it=20in=20RegisteredSnapshots=20= even=20though=20it's=20not=20tracked=20by=20any=0A+=09=09=20*=20resource=20= owner.=20=20Furthermore,=20if=20we're=20running=20in=20serializable=0A+=09= =09=20*=20mode,=20predicate.c=20needs=20to=20wrap=20the=20snapshot=20= fetch=20in=20its=20own=0A+=09=09=20*=20processing.=0A=20=09=09=20*/=0A=20= =09=09if=20(IsolationUsesXactSnapshot())=0A=20=09=09{=0A=20=09=09=09/*=20= First,=20create=20the=20snapshot=20in=20CurrentSnapshotData=20*/=0A=20=09= =09=09if=20(IsolationIsSerializable())=0A-=09=09=09=09CurrentSnapshot=20= =3D=20GetSerializableTransactionSnapshot(&CurrentSnapshotData);=0A+=09=09= =09=09GetSerializableTransactionSnapshot(&CurrentSnapshotData);=0A=20=09=09= =09else=0A-=09=09=09=09CurrentSnapshot=20=3D=20= GetSnapshotData(&CurrentSnapshotData);=0A-=0A-=09=09=09/*=20Make=20a=20= saved=20copy=20*/=0A-=09=09=09CurrentSnapshot=20=3D=20= CopyMVCCSnapshot(CurrentSnapshot);=0A-=09=09=09FirstXactSnapshot=20=3D=20= CurrentSnapshot;=0A-=09=09=09/*=20Mark=20it=20as=20"registered"=20in=20= FirstXactSnapshot=20*/=0A-=09=09=09FirstXactSnapshot->regd_count++;=0A-=09= =09=09pairingheap_add(&RegisteredSnapshots,=20= &FirstXactSnapshot->ph_node);=0A+=09=09=09=09= GetSnapshotData(&CurrentSnapshotData);=0A+=0A+=09=09=09/*=20Mark=20it=20= as=20"registered"=20*/=0A+=09=09=09CurrentSnapshotData.regd_count++;=0A+=09= =09=09FirstXactSnapshotRegistered=20=3D=20true;=0A+=09=09=09= pairingheap_add(&RegisteredSnapshots,=20&CurrentSnapshotData.ph_node);=0A= =20=09=09}=0A=20=09=09else=0A-=09=09=09CurrentSnapshot=20=3D=20= GetSnapshotData(&CurrentSnapshotData);=0A+=09=09=09= GetSnapshotData(&CurrentSnapshotData);=0A=20=0A=20=09=09FirstSnapshotSet=20= =3D=20true;=0A-=09=09return=20(Snapshot)=20CurrentSnapshot;=0A+=09=09= return=20(Snapshot)=20&CurrentSnapshotData;=0A=20=09}=0A=20=0A=20=09if=20= (IsolationUsesXactSnapshot())=0A-=09=09return=20(Snapshot)=20= CurrentSnapshot;=0A+=09{=0A+=09=09Assert(CurrentSnapshotData.valid);=0A+=09= =09return=20(Snapshot)=20&CurrentSnapshotData;=0A+=09}=0A=20=0A=20=09/*=20= Don't=20allow=20catalog=20snapshot=20to=20be=20older=20than=20xact=20= snapshot.=20*/=0A=20=09InvalidateCatalogSnapshot();=0A=20=0A-=09= CurrentSnapshot=20=3D=20GetSnapshotData(&CurrentSnapshotData);=0A+=09= GetSnapshotData(&CurrentSnapshotData);=0A=20=0A-=09return=20(Snapshot)=20= CurrentSnapshot;=0A+=09return=20(Snapshot)=20&CurrentSnapshotData;=0A=20= }=0A=20=0A=20/*=0A@@=20-360,9=20+359,9=20@@=20GetLatestSnapshot(void)=0A=20= =09if=20(!FirstSnapshotSet)=0A=20=09=09return=20= GetTransactionSnapshot();=0A=20=0A-=09SecondarySnapshot=20=3D=20= GetSnapshotData(&SecondarySnapshotData);=0A+=09= GetSnapshotData(&SecondarySnapshotData);=0A=20=0A-=09return=20(Snapshot)=20= SecondarySnapshot;=0A+=09return=20(Snapshot)=20&SecondarySnapshotData;=0A= =20}=0A=20=0A=20/*=0A@@=20-402,15=20+401,15=20@@=20= GetNonHistoricCatalogSnapshot(Oid=20relid)=0A=20=09=20*=20scan=20a=20= relation=20for=20which=20neither=20catcache=20nor=20snapshot=20= invalidations=0A=20=09=20*=20are=20sent,=20we=20must=20refresh=20the=20= snapshot=20every=20time.=0A=20=09=20*/=0A-=09if=20(CatalogSnapshot=20&&=0A= +=09if=20(CatalogSnapshotData.valid=20&&=0A=20=09=09= !RelationInvalidatesSnapshotsOnly(relid)=20&&=0A=20=09=09= !RelationHasSysCache(relid))=0A=20=09=09InvalidateCatalogSnapshot();=0A=20= =0A-=09if=20(CatalogSnapshot=20=3D=3D=20NULL)=0A+=09if=20= (!CatalogSnapshotData.valid)=0A=20=09{=0A=20=09=09/*=20Get=20new=20= snapshot.=20*/=0A-=09=09CatalogSnapshot=20=3D=20= GetSnapshotData(&CatalogSnapshotData);=0A+=09=09= GetSnapshotData(&CatalogSnapshotData);=0A=20=0A=20=09=09/*=0A=20=09=09=20= *=20Make=20sure=20the=20catalog=20snapshot=20will=20be=20accounted=20for=20= in=20decisions=0A@@=20-424,10=20+423,10=20@@=20= GetNonHistoricCatalogSnapshot(Oid=20relid)=0A=20=09=09=20*=20NB:=20it=20= had=20better=20be=20impossible=20for=20this=20to=20throw=20error,=20= since=20the=0A=20=09=09=20*=20CatalogSnapshot=20pointer=20is=20already=20= valid.=0A=20=09=09=20*/=0A-=09=09pairingheap_add(&RegisteredSnapshots,=20= &CatalogSnapshot->ph_node);=0A+=09=09= pairingheap_add(&RegisteredSnapshots,=20&CatalogSnapshotData.ph_node);=0A= =20=09}=0A=20=0A-=09return=20(Snapshot)=20CatalogSnapshot;=0A+=09return=20= (Snapshot)=20&CatalogSnapshotData;=0A=20}=0A=20=0A=20/*=0A@@=20-443,10=20= +442,9=20@@=20GetNonHistoricCatalogSnapshot(Oid=20relid)=0A=20void=0A=20= InvalidateCatalogSnapshot(void)=0A=20{=0A-=09if=20(CatalogSnapshot)=0A+=09= if=20(CatalogSnapshotData.valid)=0A=20=09{=0A-=09=09= pairingheap_remove(&RegisteredSnapshots,=20&CatalogSnapshot->ph_node);=0A= -=09=09CatalogSnapshot=20=3D=20NULL;=0A+=09=09= pairingheap_remove(&RegisteredSnapshots,=20= &CatalogSnapshotData.ph_node);=0A=20=09=09CatalogSnapshotData.valid=20=3D=20= false;=0A=20=09=09SnapshotResetXmin();=0A=20=09}=0A@@=20-465,7=20+463,7=20= @@=20InvalidateCatalogSnapshot(void)=0A=20void=0A=20= InvalidateCatalogSnapshotConditionally(void)=0A=20{=0A-=09if=20= (CatalogSnapshot=20&&=0A+=09if=20(CatalogSnapshotData.valid=20&&=0A=20=09= =09ActiveSnapshot=20=3D=3D=20NULL=20&&=0A=20=09=09= pairingheap_is_singular(&RegisteredSnapshots))=0A=20=09=09= InvalidateCatalogSnapshot();=0A@@=20-481,10=20+479,10=20@@=20= SnapshotSetCommandId(CommandId=20curcid)=0A=20=09if=20= (!FirstSnapshotSet)=0A=20=09=09return;=0A=20=0A-=09if=20= (CurrentSnapshot)=0A-=09=09CurrentSnapshot->curcid=20=3D=20curcid;=0A-=09= if=20(SecondarySnapshot)=0A-=09=09SecondarySnapshot->curcid=20=3D=20= curcid;=0A+=09if=20(CurrentSnapshotData.valid)=0A+=09=09= CurrentSnapshotData.curcid=20=3D=20curcid;=0A+=09if=20= (SecondarySnapshotData.valid)=0A+=09=09SecondarySnapshotData.curcid=20=3D=20= curcid;=0A=20=09/*=20Should=20we=20do=20the=20same=20with=20= CatalogSnapshot?=20*/=0A=20}=0A=20=0A@@=20-507,7=20+505,7=20@@=20= SetTransactionSnapshot(MVCCSnapshot=20sourcesnap,=20VirtualTransactionId=20= *sourcevxid=0A=20=09InvalidateCatalogSnapshot();=0A=20=0A=20=09= Assert(pairingheap_is_empty(&RegisteredSnapshots));=0A-=09= Assert(FirstXactSnapshot=20=3D=3D=20NULL);=0A+=09= Assert(!FirstXactSnapshotRegistered);=0A=20=09= Assert(!HistoricSnapshotActive());=0A=20=0A=20=09/*=0A@@=20-516,28=20= +514,28=20@@=20SetTransactionSnapshot(MVCCSnapshot=20sourcesnap,=20= VirtualTransactionId=20*sourcevxid=0A=20=09=20*=20CurrentSnapshotData's=20= XID=20arrays=20have=20been=20allocated,=20and=20(2)=20to=20update=0A=20=09= =20*=20the=20state=20for=20GlobalVis*.=0A=20=09=20*/=0A-=09= CurrentSnapshot=20=3D=20GetSnapshotData(&CurrentSnapshotData);=0A+=09= GetSnapshotData(&CurrentSnapshotData);=0A=20=0A=20=09/*=0A=20=09=20*=20= Now=20copy=20appropriate=20fields=20from=20the=20source=20snapshot.=0A=20= =09=20*/=0A-=09CurrentSnapshot->xmin=20=3D=20sourcesnap->xmin;=0A-=09= CurrentSnapshot->xmax=20=3D=20sourcesnap->xmax;=0A-=09= CurrentSnapshot->xcnt=20=3D=20sourcesnap->xcnt;=0A+=09= CurrentSnapshotData.xmin=20=3D=20sourcesnap->xmin;=0A+=09= CurrentSnapshotData.xmax=20=3D=20sourcesnap->xmax;=0A+=09= CurrentSnapshotData.xcnt=20=3D=20sourcesnap->xcnt;=0A=20=09= Assert(sourcesnap->xcnt=20<=3D=20GetMaxSnapshotXidCount());=0A=20=09if=20= (sourcesnap->xcnt=20>=200)=0A-=09=09memcpy(CurrentSnapshot->xip,=20= sourcesnap->xip,=0A+=09=09memcpy(CurrentSnapshotData.xip,=20= sourcesnap->xip,=0A=20=09=09=09=20=20=20sourcesnap->xcnt=20*=20= sizeof(TransactionId));=0A-=09CurrentSnapshot->subxcnt=20=3D=20= sourcesnap->subxcnt;=0A+=09CurrentSnapshotData.subxcnt=20=3D=20= sourcesnap->subxcnt;=0A=20=09Assert(sourcesnap->subxcnt=20<=3D=20= GetMaxSnapshotSubxidCount());=0A=20=09if=20(sourcesnap->subxcnt=20>=200)=0A= -=09=09memcpy(CurrentSnapshot->subxip,=20sourcesnap->subxip,=0A+=09=09= memcpy(CurrentSnapshotData.subxip,=20sourcesnap->subxip,=0A=20=09=09=09=20= =20=20sourcesnap->subxcnt=20*=20sizeof(TransactionId));=0A-=09= CurrentSnapshot->suboverflowed=20=3D=20sourcesnap->suboverflowed;=0A-=09= CurrentSnapshot->takenDuringRecovery=20=3D=20= sourcesnap->takenDuringRecovery;=0A+=09CurrentSnapshotData.suboverflowed=20= =3D=20sourcesnap->suboverflowed;=0A+=09= CurrentSnapshotData.takenDuringRecovery=20=3D=20= sourcesnap->takenDuringRecovery;=0A=20=09/*=20NB:=20curcid=20should=20= NOT=20be=20copied,=20it's=20a=20local=20matter=20*/=0A=20=0A-=09= CurrentSnapshot->snapXactCompletionCount=20=3D=200;=0A+=09= CurrentSnapshotData.snapXactCompletionCount=20=3D=200;=0A=20=0A=20=09/*=0A= =20=09=20*=20Now=20we=20have=20to=20fix=20what=20GetSnapshotData=20did=20= with=20MyProc->xmin=20and=0A@@=20-552,13=20+550,13=20@@=20= SetTransactionSnapshot(MVCCSnapshot=20sourcesnap,=20VirtualTransactionId=20= *sourcevxid=0A=20=09=20*/=0A=20=09if=20(sourceproc=20!=3D=20NULL)=0A=20=09= {=0A-=09=09if=20(!ProcArrayInstallRestoredXmin(CurrentSnapshot->xmin,=20= sourceproc))=0A+=09=09if=20= (!ProcArrayInstallRestoredXmin(CurrentSnapshotData.xmin,=20sourceproc))=0A= =20=09=09=09ereport(ERROR,=0A=20=09=09=09=09=09= (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),=0A=20=09=09=09=09=09=20= errmsg("could=20not=20import=20the=20requested=20snapshot"),=0A=20=09=09=09= =09=09=20errdetail("The=20source=20transaction=20is=20not=20running=20= anymore.")));=0A=20=09}=0A-=09else=20if=20= (!ProcArrayInstallImportedXmin(CurrentSnapshot->xmin,=20sourcevxid))=0A+=09= else=20if=20(!ProcArrayInstallImportedXmin(CurrentSnapshotData.xmin,=20= sourcevxid))=0A=20=09=09ereport(ERROR,=0A=20=09=09=09=09= (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),=0A=20=09=09=09=09=20= errmsg("could=20not=20import=20the=20requested=20snapshot"),=0A@@=20= -567,20=20+565,19=20@@=20SetTransactionSnapshot(MVCCSnapshot=20= sourcesnap,=20VirtualTransactionId=20*sourcevxid=0A=20=0A=20=09/*=0A=20=09= =20*=20In=20transaction-snapshot=20mode,=20the=20first=20snapshot=20must=20= live=20until=20end=20of=0A-=09=20*=20xact,=20so=20we=20must=20make=20a=20= copy=20of=20it.=20=20Furthermore,=20if=20we're=20running=20in=0A-=09=20*=20= serializable=20mode,=20predicate.c=20needs=20to=20do=20its=20own=20= processing.=0A+=09=20*=20xact,=20so=20we=20include=20it=20in=20= RegisteredSnapshots.=20=20Furthermore,=20if=20we're=0A+=09=20*=20running=20= in=20serializable=20mode,=20predicate.c=20needs=20to=20do=20its=20own=0A= +=09=20*=20processing.=0A=20=09=20*/=0A=20=09if=20= (IsolationUsesXactSnapshot())=0A=20=09{=0A=20=09=09if=20= (IsolationIsSerializable())=0A-=09=09=09= SetSerializableTransactionSnapshot(CurrentSnapshot,=20sourcevxid,=0A+=09=09= =09SetSerializableTransactionSnapshot(&CurrentSnapshotData,=20= sourcevxid,=0A=20=09=09=09=09=09=09=09=09=09=09=09=20=20=20sourcepid);=0A= -=09=09/*=20Make=20a=20saved=20copy=20*/=0A-=09=09CurrentSnapshot=20=3D=20= CopyMVCCSnapshot(CurrentSnapshot);=0A-=09=09FirstXactSnapshot=20=3D=20= CurrentSnapshot;=0A-=09=09/*=20Mark=20it=20as=20"registered"=20in=20= FirstXactSnapshot=20*/=0A-=09=09FirstXactSnapshot->regd_count++;=0A-=09=09= pairingheap_add(&RegisteredSnapshots,=20&FirstXactSnapshot->ph_node);=0A= +=09=09/*=20Mark=20it=20as=20"registered"=20*/=0A+=09=09= FirstXactSnapshotRegistered=20=3D=20true;=0A+=09=09= CurrentSnapshotData.regd_count++;=0A+=09=09= pairingheap_add(&RegisteredSnapshots,=20&CurrentSnapshotData.ph_node);=0A= =20=09}=0A=20=0A=20=09FirstSnapshotSet=20=3D=20true;=0A@@=20-701,8=20= +698,7=20@@=20PushActiveSnapshotWithLevel(Snapshot=20snapshot,=20int=20= snap_level)=0A=20=09=20*=20Checking=20SecondarySnapshot=20is=20probably=20= useless=20here,=20but=20it=20seems=0A=20=09=20*=20better=20to=20be=20= sure.=0A=20=09=20*/=0A-=09if=20(origsnap=20=3D=3D=20CurrentSnapshot=20||=20= origsnap=20=3D=3D=20SecondarySnapshot=20||=0A-=09=09!origsnap->copied)=0A= +=09if=20(!origsnap->copied)=0A=20=09=09newactive->as_snap=20=3D=20= CopyMVCCSnapshot(origsnap);=0A=20=09else=0A=20=09=09newactive->as_snap=20= =3D=20origsnap;=0A@@=20-974,12=20+970,10=20@@=20SnapshotResetXmin(void)=0A= =20=09MVCCSnapshot=20minSnapshot;=0A=20=0A=20=09/*=0A-=09=20*=20These=20= static=20snapshots=20are=20not=20in=20the=20RegisteredSnapshots=20list,=20= so=20we=0A-=09=20*=20might=20advance=20MyProc->xmin=20past=20their=20= xmin.=20(Note=20that=20in=20case=20of=0A-=09=20*=20= IsolationUsesXactSnapshot()=20=3D=3D=20true,=20CurrentSnapshot=20points=20= to=20the=20copy=0A-=09=20*=20in=20FirstSnapshot=20rather=20than=20= CurrentSnapshotData.)=0A+=09=20*=20Invalidate=20these=20static=20= snapshots=20so=20that=20we=20can=20advance=20xmin.=0A=20=09=20*/=0A-=09= CurrentSnapshotData.valid=20=3D=20false;=0A+=09if=20= (!FirstXactSnapshotRegistered)=0A+=09=09CurrentSnapshotData.valid=20=3D=20= false;=0A=20=09SecondarySnapshotData.valid=20=3D=20false;=0A=20=0A=20=09= if=20(ActiveSnapshot=20!=3D=20NULL)=0A@@=20-1068,13=20+1062,13=20@@=20= AtEOXact_Snapshot(bool=20isCommit,=20bool=20resetXmin)=0A=20=09=20*=20= stacked=20as=20active,=20we=20don't=20want=20the=20code=20below=20to=20= be=20chasing=20through=20a=0A=20=09=20*=20dangling=20pointer.=0A=20=09=20= */=0A-=09if=20(FirstXactSnapshot=20!=3D=20NULL)=0A+=09if=20= (FirstXactSnapshotRegistered)=0A=20=09{=0A-=09=09= Assert(FirstXactSnapshot->regd_count=20>=200);=0A+=09=09= Assert(CurrentSnapshotData.regd_count=20>=200);=0A=20=09=09= Assert(!pairingheap_is_empty(&RegisteredSnapshots));=0A-=09=09= pairingheap_remove(&RegisteredSnapshots,=20&FirstXactSnapshot->ph_node);=0A= +=09=09pairingheap_remove(&RegisteredSnapshots,=20= &CurrentSnapshotData.ph_node);=0A+=09=09FirstXactSnapshotRegistered=20=3D=20= false;=0A=20=09}=0A-=09FirstXactSnapshot=20=3D=20NULL;=0A=20=0A=20=09/*=0A= =20=09=20*=20If=20we=20exported=20any=20snapshots,=20clean=20them=20up.=0A= @@=20-1132,9=20+1126,8=20@@=20AtEOXact_Snapshot(bool=20isCommit,=20bool=20= resetXmin)=0A=20=09ActiveSnapshot=20=3D=20NULL;=0A=20=09= pairingheap_reset(&RegisteredSnapshots);=0A=20=0A-=09CurrentSnapshot=20=3D= =20NULL;=0A-=09SecondarySnapshot=20=3D=20NULL;=0A-=0A+=09= CurrentSnapshotData.valid=20=3D=20false;=0A+=09= SecondarySnapshotData.valid=20=3D=20false;=0A=20=09FirstSnapshotSet=20=3D=20= false;=0A=20=0A=20=09/*=0A@@=20-1695,7=20+1688,7=20@@=20= HaveRegisteredOrActiveSnapshot(void)=0A=20=09=20*=20removed=20at=20any=20= time=20due=20to=20invalidation=20processing.=20If=20explicitly=0A=20=09=20= *=20registered=20more=20than=20one=20snapshot=20has=20to=20be=20in=20= RegisteredSnapshots.=0A=20=09=20*/=0A-=09if=20(CatalogSnapshot=20!=3D=20= NULL=20&&=0A+=09if=20(CatalogSnapshotData.valid=20&&=0A=20=09=09= pairingheap_is_singular(&RegisteredSnapshots))=0A=20=09=09return=20= false;=0A=20=0A--=20=0A2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0005-Make-RestoreSnapshot-register-the-snapshot-with-c.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0005-Make-RestoreSnapshot-register-the-snapshot-with-c.patch" Content-Transfer-Encoding: quoted-printable =46rom=2034b92db816f87fb06d8eff3c07e60c81b322e44d=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Mon,=2031=20Mar=202025=2019:54:39=20= +0300=0ASubject:=20[PATCH=20v6=2005/12]=20Make=20RestoreSnapshot=20= register=20the=20snapshot=20with=0A=20current=20resowner=0A=0AThis=20= simplifies=20the=20next=20commit=0A---=0A=20= src/backend/access/index/indexam.c=20=20=20=20|=201=20-=0A=20= src/backend/access/table/tableam.c=20=20=20=20|=201=20-=0A=20= src/backend/access/transam/parallel.c=20|=204=20++++=0A=20= src/backend/utils/time/snapmgr.c=20=20=20=20=20=20|=208=20+++++++-=0A=20= 4=20files=20changed,=2011=20insertions(+),=203=20deletions(-)=0A=0Adiff=20= --git=20a/src/backend/access/index/indexam.c=20= b/src/backend/access/index/indexam.c=0Aindex=20769170a37d5..8f0ae02221c=20= 100644=0A---=20a/src/backend/access/index/indexam.c=0A+++=20= b/src/backend/access/index/indexam.c=0A@@=20-592,7=20+592,6=20@@=20= index_beginscan_parallel(Relation=20heaprel,=20Relation=20indexrel,=0A=20= =09Assert(RelFileLocatorEquals(indexrel->rd_locator,=20= pscan->ps_indexlocator));=0A=20=0A=20=09snapshot=20=3D=20(Snapshot)=20= RestoreSnapshot(pscan->ps_snapshot_data);=0A-=09snapshot=20=3D=20= RegisterSnapshot(snapshot);=0A=20=09scan=20=3D=20= index_beginscan_internal(indexrel,=20nkeys,=20norderbys,=20snapshot,=0A=20= =09=09=09=09=09=09=09=09=09pscan,=20true);=0A=20=0Adiff=20--git=20= a/src/backend/access/table/tableam.c=20= b/src/backend/access/table/tableam.c=0Aindex=204eb81e40d99..fc823cf84e5=20= 100644=0A---=20a/src/backend/access/table/tableam.c=0A+++=20= b/src/backend/access/table/tableam.c=0A@@=20-175,7=20+175,6=20@@=20= table_beginscan_parallel(Relation=20relation,=20ParallelTableScanDesc=20= pscan)=0A=20=09{=0A=20=09=09/*=20Snapshot=20was=20serialized=20--=20= restore=20it=20*/=0A=20=09=09snapshot=20=3D=20(Snapshot)=20= RestoreSnapshot((char=20*)=20pscan=20+=20pscan->phs_snapshot_off);=0A-=09= =09snapshot=20=3D=20RegisterSnapshot(snapshot);=0A=20=09=09flags=20|=3D=20= SO_TEMP_SNAPSHOT;=0A=20=09}=0A=20=09else=0Adiff=20--git=20= a/src/backend/access/transam/parallel.c=20= b/src/backend/access/transam/parallel.c=0Aindex=20= 8046e14abf7..e13ea57efff=20100644=0A---=20= a/src/backend/access/transam/parallel.c=0A+++=20= b/src/backend/access/transam/parallel.c=0A@@=20-1499,6=20+1499,10=20@@=20= ParallelWorkerMain(Datum=20main_arg)=0A=20=09=09=09=09=09=09=09=20=20=20= fps->parallel_leader_pgproc);=0A=20=09PushActiveSnapshot(asnapshot);=0A=20= =0A+=09UnregisterSnapshot(asnapshot);=0A+=09if=20(tsnapshot=20!=3D=20= asnapshot)=0A+=09=09UnregisterSnapshot(tsnapshot);=0A+=0A=20=09/*=0A=20=09= =20*=20We've=20changed=20which=20tuples=20we=20can=20see,=20and=20must=20= therefore=20invalidate=0A=20=09=20*=20system=20caches.=0Adiff=20--git=20= a/src/backend/utils/time/snapmgr.c=20b/src/backend/utils/time/snapmgr.c=0A= index=20ea1e7d17b04..ef579128d3f=20100644=0A---=20= a/src/backend/utils/time/snapmgr.c=0A+++=20= b/src/backend/utils/time/snapmgr.c=0A@@=20-1823,7=20+1823,7=20@@=20= SerializeSnapshot(MVCCSnapshot=20snapshot,=20char=20*start_address)=0A=20= =20*=09=09Restore=20a=20serialized=20snapshot=20from=20the=20specified=20= address.=0A=20=20*=0A=20=20*=20The=20copy=20is=20palloc'd=20in=20= TopTransactionContext=20and=20has=20initial=20refcounts=20set=0A-=20*=20= to=200.=20=20The=20returned=20snapshot=20has=20the=20copied=20flag=20= set.=0A+=20*=20to=200.=20=20The=20returned=20snapshot=20is=20registered=20= with=20the=20current=20resource=20owner.=0A=20=20*/=0A=20MVCCSnapshot=0A=20= RestoreSnapshot(char=20*start_address)=0A@@=20-1880,6=20+1880,12=20@@=20= RestoreSnapshot(char=20*start_address)=0A=20=09snapshot->copied=20=3D=20= true;=0A=20=09snapshot->valid=20=3D=20true;=0A=20=0A+=09/*=20and=20tell=20= resowner.c=20about=20it,=20just=20like=20RegisterSnapshot()=20*/=0A+=09= ResourceOwnerEnlarge(CurrentResourceOwner);=0A+=09= snapshot->regd_count++;=0A+=09= ResourceOwnerRememberSnapshot(CurrentResourceOwner,=20(Snapshot)=20= snapshot);=0A+=09pairingheap_add(&RegisteredSnapshots,=20= &snapshot->ph_node);=0A+=0A=20=09return=20snapshot;=0A=20}=0A=20=0A--=20=0A= 2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0006-Replace-the-RegisteredSnapshot-pairing-heap-with-.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0006-Replace-the-RegisteredSnapshot-pairing-heap-with-.patch" Content-Transfer-Encoding: quoted-printable =46rom=20db70117e68b6f745c5ab9289e263aede7a068ac7=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Mon,=2031=20Mar=202025=2023:50:55=20= +0300=0ASubject:=20[PATCH=20v6=2006/12]=20Replace=20the=20= RegisteredSnapshot=20pairing=20heap=20with=20a=0A=20linked=20list=0A=0A= Previously,=20we=20kept=20all=20the=20snapshots=20in=20a=20pairing=20= heap,=20so=20that=20we=0Acould=20cheaply=20find=20the=20snapshot=20with=20= the=20smallest=20xmin.=20However,=20we=0Acan=20easily=20use=20a=20= doubly-linked=20list=20instead,=20which=20is=20a=20little=0Asimpler.=20A=20= newly=20acquired=20snapshot's=20xmin=20is=20always=20greater=20than=20or=0A= equal=20to=20that=20of=20any=20previous=20snapshot's,=20so=20we=20can=20= simply=20push=20new=0Asnapshots=20to=20the=20tail=20of=20the=20list,=20= and=20the=20oldest=20xmin=20is=20always=20at=0Athe=20head.=0A=0A= Previously,=20we=20would=20only=20push=20a=20snapshot=20to=20the=20heap=20= when=20it's=0Aregistered=20or=20pushed=20to=20the=20active=20stack,=20= not=20immediately=20when=20the=0AGetSnapshotData()=20was=20called.=20= Because=20of=20that,=20snapshots=20were=0Asometimes=20added=20to=20the=20= heap=20out=20of=20order.=20But=20if=20we=20update=20the=20list=0A= earlier,=20after=20each=20GetSnapshotData()=20call,=20it=20stays=20in=20= order.=20That=0Ameans=20that=20the=20list=20now=20contains=20*all*=20= valid=20snapshots,=20including=20the=0Asnapshots=20that=20are=20in=20the=20= active=20stack,=20and=20the=20static=20CurrentSnapshot=0Aand=20= SecondarySnapshot,=20whenever=20they=20are=20valid.=20(CatalogSnapshot=20= was=0Aalready=20tracked=20by=20the=20heap)=0A---=0A=20= src/backend/utils/time/snapmgr.c=20=20=20=20|=20279=20= +++++++++++++++++-----------=0A=20src/include/access/spgist_private.h=20= |=20=20=201=20+=0A=20src/include/utils/snapshot.h=20=20=20=20=20=20=20=20= |=20=20=206=20+-=0A=203=20files=20changed,=20175=20insertions(+),=20111=20= deletions(-)=0A=0Adiff=20--git=20a/src/backend/utils/time/snapmgr.c=20= b/src/backend/utils/time/snapmgr.c=0Aindex=20ef579128d3f..1c39cc11609=20= 100644=0A---=20a/src/backend/utils/time/snapmgr.c=0A+++=20= b/src/backend/utils/time/snapmgr.c=0A@@=20-67,32=20+67,22=20@@=0A=20=20*=20= In=20addition=20to=20snapshots=20pushed=20to=20the=20active=20snapshot=20= stack,=20a=20snapshot=0A=20=20*=20can=20be=20registered=20with=20a=20= resource=20owner.=0A=20=20*=0A-=20*=20If=20FirstXactSnapshotRegistered=20= is=20set,=20we=20increment=20the=20static=0A-=20*=20= CurrentSnapshotData's=20regd_count=20and=20list=20it=20in=20= RegisteredSnapshots,=20but=20this=20reference=20is=20not=0A-=20*=20= tracked=20by=20a=20resource=20owner.=20We=20used=20to=20use=20the=20= TopTransactionResourceOwner=0A-=20*=20to=20track=20this=20snapshot=20= reference,=20but=20that=20introduces=20logical=20circularity=0A-=20*=20= and=20thus=20makes=20it=20impossible=20to=20clean=20up=20in=20a=20sane=20= fashion.=20=20It's=20better=20to=0A-=20*=20handle=20this=20reference=20= as=20an=20internally-tracked=20registration,=20so=20that=20this=0A-=20*=20= module=20is=20entirely=20lower-level=20than=20ResourceOwners.=0A+=20*=20= Xmin=20tracking=0A+=20*=20-------------=0A=20=20*=0A-=20*=20Likewise,=20= any=20snapshots=20that=20have=20been=20exported=20by=20= pg_export_snapshot=0A-=20*=20have=20regd_count=20=3D=201=20and=20are=20= listed=20in=20RegisteredSnapshots,=20but=20are=20not=0A-=20*=20tracked=20= by=20any=20resource=20owner.=0A+=20*=20All=20valid=20snapshots,=20= whether=20they=20are=20"static",=20included=20the=20active=20stack,=0A+=20= *=20or=20registered=20with=20a=20resource=20owner,=20are=20tracked=20in=20= a=20doubly-linked=20list,=0A+=20*=20ValidSnapshots.=20=20Any=20snapshots=20= that=20have=20been=20exported=20by=0A+=20*=20pg_export_snapshot()=20are=20= also=20listed=20there.=20=20(They=20have=20regd_count=20=3D=201,=0A+=20*=20= even=20though=20they=20are=20not=20tracked=20by=20any=20resource=20= owner).=0A=20=20*=0A-=20*=20Likewise,=20the=20CatalogSnapshot=20is=20= listed=20in=20RegisteredSnapshots=20when=20it=0A-=20*=20is=20valid,=20= but=20is=20not=20tracked=20by=20any=20resource=20owner.=0A-=20*=0A-=20*=20= The=20same=20is=20true=20for=20historic=20snapshots=20used=20during=20= logical=20decoding,=0A-=20*=20their=20lifetime=20is=20managed=20= separately=20(as=20they=20live=20longer=20than=20one=20xact.c=0A-=20*=20= transaction).=0A-=20*=0A-=20*=20These=20arrangements=20let=20us=20reset=20= MyProc->xmin=20when=20there=20are=20no=20snapshots=0A+=20*=20The=20list=20= is=20in=20xmin=20order,=20so=20that=20the=20tail=20always=20contains=20= the=20oldest=0A+=20*=20snapshot.=20=20That=20let=20us=20reset=20= MyProc->xmin=20when=20there=20are=20no=20snapshots=0A=20=20*=20= referenced=20by=20this=20transaction,=20and=20advance=20it=20when=20the=20= one=20with=20oldest=0A-=20*=20Xmin=20is=20no=20longer=20referenced.=20=20= For=20simplicity=20however,=20only=20registered=0A-=20*=20snapshots=20= not=20active=20snapshots=20participate=20in=20tracking=20which=20one=20= is=20oldest;=0A-=20*=20we=20don't=20try=20to=20change=20MyProc->xmin=20= except=20when=20the=20active-snapshot=0A-=20*=20stack=20is=20empty.=0A+=20= *=20Xmin=20is=20no=20longer=20referenced.=0A=20=20*=0A+=20*=20The=20= lifetime=20of=20historic=20snapshots=20used=20during=20logical=20= decoding=20is=20managed=0A+=20*=20separately=20(as=20they=20live=20= longer=20than=20one=20xact.c=20transaction).=0A=20=20*=0A=20=20*=20= Portions=20Copyright=20(c)=201996-2025,=20PostgreSQL=20Global=20= Development=20Group=0A=20=20*=20Portions=20Copyright=20(c)=201994,=20= Regents=20of=20the=20University=20of=20California=0A@@=20-111,7=20+101,6=20= @@=0A=20#include=20"access/transam.h"=0A=20#include=20"access/xact.h"=0A=20= #include=20"datatype/timestamp.h"=0A-#include=20"lib/pairingheap.h"=0A=20= #include=20"miscadmin.h"=0A=20#include=20"port/pg_lfind.h"=0A=20#include=20= "storage/fd.h"=0A@@=20-177,13=20+166,10=20@@=20typedef=20struct=20= ActiveSnapshotElt=0A=20static=20ActiveSnapshotElt=20*ActiveSnapshot=20=3D=20= NULL;=0A=20=0A=20/*=0A-=20*=20Currently=20registered=20Snapshots.=20=20= Ordered=20in=20a=20heap=20by=20xmin,=20so=20that=20we=20can=0A+=20*=20= Currently=20valid=20Snapshots.=20=20Ordered=20in=20a=20heap=20by=20xmin,=20= so=20that=20we=20can=0A=20=20*=20quickly=20find=20the=20one=20with=20= lowest=20xmin,=20to=20advance=20our=20MyProc->xmin.=0A=20=20*/=0A-static=20= int=09xmin_cmp(const=20pairingheap_node=20*a,=20const=20pairingheap_node=20= *b,=0A-=09=09=09=09=09=20void=20*arg);=0A-=0A-static=20pairingheap=20= RegisteredSnapshots=20=3D=20{&xmin_cmp,=20NULL,=20NULL};=0A+static=20= dlist_head=20ValidSnapshots=20=3D=20DLIST_STATIC_INIT(ValidSnapshots);=0A= =20=0A=20/*=20first=20GetTransactionSnapshot=20call=20in=20a=20= transaction?=20*/=0A=20bool=09=09FirstSnapshotSet=20=3D=20false;=0A@@=20= -213,6=20+199,8=20@@=20static=20MVCCSnapshot=20= CopyMVCCSnapshot(MVCCSnapshot=20snapshot);=0A=20static=20void=20= UnregisterSnapshotNoOwner(Snapshot=20snapshot);=0A=20static=20void=20= FreeMVCCSnapshot(MVCCSnapshot=20snapshot);=0A=20static=20void=20= SnapshotResetXmin(void);=0A+static=20void=20= valid_snapshots_push_tail(MVCCSnapshot=20snapshot);=0A+static=20void=20= valid_snapshots_push_out_of_order(MVCCSnapshot=20snapshot);=0A=20=0A=20= /*=20ResourceOwner=20callbacks=20to=20track=20snapshot=20references=20*/=0A= =20static=20void=20ResOwnerReleaseSnapshot(Datum=20res);=0A@@=20-284,7=20= +272,7=20@@=20GetTransactionSnapshot(void)=0A=20=09=09=20*/=0A=20=09=09= InvalidateCatalogSnapshot();=0A=20=0A-=09=09= Assert(pairingheap_is_empty(&RegisteredSnapshots));=0A+=09=09= Assert(dlist_is_empty(&ValidSnapshots));=0A=20=09=09= Assert(!FirstXactSnapshotRegistered);=0A=20=0A=20=09=09if=20= (IsInParallelMode())=0A@@=20-308,12=20+296,13=20@@=20= GetTransactionSnapshot(void)=0A=20=09=09=09=09= GetSnapshotData(&CurrentSnapshotData);=0A=20=0A=20=09=09=09/*=20Mark=20= it=20as=20"registered"=20*/=0A-=09=09=09= CurrentSnapshotData.regd_count++;=0A=20=09=09=09= FirstXactSnapshotRegistered=20=3D=20true;=0A-=09=09=09= pairingheap_add(&RegisteredSnapshots,=20&CurrentSnapshotData.ph_node);=0A= =20=09=09}=0A=20=09=09else=0A+=09=09{=0A=20=09=09=09= GetSnapshotData(&CurrentSnapshotData);=0A+=09=09}=0A+=09=09= valid_snapshots_push_tail(&CurrentSnapshotData);=0A=20=0A=20=09=09= FirstSnapshotSet=20=3D=20true;=0A=20=09=09return=20(Snapshot)=20= &CurrentSnapshotData;=0A@@=20-321,6=20+310,7=20@@=20= GetTransactionSnapshot(void)=0A=20=0A=20=09if=20= (IsolationUsesXactSnapshot())=0A=20=09{=0A+=09=09= Assert(FirstXactSnapshotRegistered);=0A=20=09=09= Assert(CurrentSnapshotData.valid);=0A=20=09=09return=20(Snapshot)=20= &CurrentSnapshotData;=0A=20=09}=0A@@=20-328,7=20+318,10=20@@=20= GetTransactionSnapshot(void)=0A=20=09/*=20Don't=20allow=20catalog=20= snapshot=20to=20be=20older=20than=20xact=20snapshot.=20*/=0A=20=09= InvalidateCatalogSnapshot();=0A=20=0A+=09if=20= (CurrentSnapshotData.valid)=0A+=09=09= dlist_delete(&CurrentSnapshotData.node);=0A=20=09= GetSnapshotData(&CurrentSnapshotData);=0A+=09= valid_snapshots_push_tail(&CurrentSnapshotData);=0A=20=0A=20=09return=20= (Snapshot)=20&CurrentSnapshotData;=0A=20}=0A@@=20-359,7=20+352,10=20@@=20= GetLatestSnapshot(void)=0A=20=09if=20(!FirstSnapshotSet)=0A=20=09=09= return=20GetTransactionSnapshot();=0A=20=0A+=09if=20= (SecondarySnapshotData.valid)=0A+=09=09= dlist_delete(&SecondarySnapshotData.node);=0A=20=09= GetSnapshotData(&SecondarySnapshotData);=0A+=09= valid_snapshots_push_tail(&SecondarySnapshotData);=0A=20=0A=20=09return=20= (Snapshot)=20&SecondarySnapshotData;=0A=20}=0A@@=20-423,7=20+419,7=20@@=20= GetNonHistoricCatalogSnapshot(Oid=20relid)=0A=20=09=09=20*=20NB:=20it=20= had=20better=20be=20impossible=20for=20this=20to=20throw=20error,=20= since=20the=0A=20=09=09=20*=20CatalogSnapshot=20pointer=20is=20already=20= valid.=0A=20=09=09=20*/=0A-=09=09pairingheap_add(&RegisteredSnapshots,=20= &CatalogSnapshotData.ph_node);=0A+=09=09= valid_snapshots_push_tail(&CatalogSnapshotData);=0A=20=09}=0A=20=0A=20=09= return=20(Snapshot)=20&CatalogSnapshotData;=0A@@=20-444,10=20+440,21=20= @@=20InvalidateCatalogSnapshot(void)=0A=20{=0A=20=09if=20= (CatalogSnapshotData.valid)=0A=20=09{=0A-=09=09= pairingheap_remove(&RegisteredSnapshots,=20= &CatalogSnapshotData.ph_node);=0A+=09=09= dlist_delete(&CatalogSnapshotData.node);=0A=20=09=09= CatalogSnapshotData.valid=20=3D=20false;=0A-=09=09SnapshotResetXmin();=0A= =20=09}=0A+=09if=20(!FirstXactSnapshotRegistered=20&&=20= CurrentSnapshotData.valid)=0A+=09{=0A+=09=09= dlist_delete(&CurrentSnapshotData.node);=0A+=09=09= CurrentSnapshotData.valid=20=3D=20false;=0A+=09}=0A+=09if=20= (SecondarySnapshotData.valid)=0A+=09{=0A+=09=09= dlist_delete(&SecondarySnapshotData.node);=0A+=09=09= SecondarySnapshotData.valid=20=3D=20false;=0A+=09}=0A+=0A+=09= SnapshotResetXmin();=0A=20}=0A=20=0A=20/*=0A@@=20-464,8=20+471,7=20@@=20= void=0A=20InvalidateCatalogSnapshotConditionally(void)=0A=20{=0A=20=09if=20= (CatalogSnapshotData.valid=20&&=0A-=09=09ActiveSnapshot=20=3D=3D=20NULL=20= &&=0A-=09=09pairingheap_is_singular(&RegisteredSnapshots))=0A+=09=09= dlist_head_node(&ValidSnapshots)=20=3D=3D=20&CatalogSnapshotData.node)=0A= =20=09=09InvalidateCatalogSnapshot();=0A=20}=0A=20=0A@@=20-504,7=20= +510,6=20@@=20SetTransactionSnapshot(MVCCSnapshot=20sourcesnap,=20= VirtualTransactionId=20*sourcevxid=0A=20=09/*=20Better=20do=20this=20to=20= ensure=20following=20Assert=20succeeds.=20*/=0A=20=09= InvalidateCatalogSnapshot();=0A=20=0A-=09= Assert(pairingheap_is_empty(&RegisteredSnapshots));=0A=20=09= Assert(!FirstXactSnapshotRegistered);=0A=20=09= Assert(!HistoricSnapshotActive());=0A=20=0A@@=20-576,9=20+581,8=20@@=20= SetTransactionSnapshot(MVCCSnapshot=20sourcesnap,=20VirtualTransactionId=20= *sourcevxid=0A=20=09=09=09=09=09=09=09=09=09=09=09=20=20=20sourcepid);=0A= =20=09=09/*=20Mark=20it=20as=20"registered"=20*/=0A=20=09=09= FirstXactSnapshotRegistered=20=3D=20true;=0A-=09=09= CurrentSnapshotData.regd_count++;=0A-=09=09= pairingheap_add(&RegisteredSnapshots,=20&CurrentSnapshotData.ph_node);=0A= =20=09}=0A+=09valid_snapshots_push_tail(&CurrentSnapshotData);=0A=20=0A=20= =09FirstSnapshotSet=20=3D=20true;=0A=20}=0A@@=20-699,7=20+703,10=20@@=20= PushActiveSnapshotWithLevel(Snapshot=20snapshot,=20int=20snap_level)=0A=20= =09=20*=20better=20to=20be=20sure.=0A=20=09=20*/=0A=20=09if=20= (!origsnap->copied)=0A+=09{=0A=20=09=09newactive->as_snap=20=3D=20= CopyMVCCSnapshot(origsnap);=0A+=09=09dlist_insert_after(&origsnap->node,=20= &newactive->as_snap->node);=0A+=09}=0A=20=09else=0A=20=09=09= newactive->as_snap=20=3D=20origsnap;=0A=20=0A@@=20-722,8=20+729,13=20@@=20= PushActiveSnapshotWithLevel(Snapshot=20snapshot,=20int=20snap_level)=0A=20= void=0A=20PushCopiedSnapshot(Snapshot=20snapshot)=0A=20{=0A+=09= MVCCSnapshot=20copy;=0A+=0A=20=09Assert(snapshot->snapshot_type=20=3D=3D=20= SNAPSHOT_MVCC);=0A-=09PushActiveSnapshot((Snapshot)=20= CopyMVCCSnapshot(&snapshot->mvcc));=0A+=0A+=09copy=20=3D=20= CopyMVCCSnapshot(&snapshot->mvcc);=0A+=09= dlist_insert_after(&snapshot->mvcc.node,=20©->node);=0A+=09= PushActiveSnapshot((Snapshot)=20copy);=0A=20}=0A=20=0A=20/*=0A@@=20= -776,7=20+788,10=20@@=20PopActiveSnapshot(void)=0A=20=0A=20=09if=20= (ActiveSnapshot->as_snap->active_count=20=3D=3D=200=20&&=0A=20=09=09= ActiveSnapshot->as_snap->regd_count=20=3D=3D=200)=0A+=09{=0A+=09=09= dlist_delete(&ActiveSnapshot->as_snap->node);=0A=20=09=09= FreeMVCCSnapshot(ActiveSnapshot->as_snap);=0A+=09}=0A=20=0A=20=09= pfree(ActiveSnapshot);=0A=20=09ActiveSnapshot=20=3D=20newstack;=0A@@=20= -850,16=20+865,17=20@@=20RegisterSnapshotOnOwner(Snapshot=20= orig_snapshot,=20ResourceOwner=20owner)=0A=20=09Assert(snapshot->valid);=0A= =20=0A=20=09/*=20Static=20snapshot?=20=20Create=20a=20persistent=20copy=20= */=0A-=09snapshot=20=3D=20snapshot->copied=20?=20snapshot=20:=20= CopyMVCCSnapshot(snapshot);=0A+=09if=20(!snapshot->copied)=0A+=09{=0A+=09= =09snapshot=20=3D=20CopyMVCCSnapshot(snapshot);=0A+=09=09= dlist_insert_after(&orig_snapshot->mvcc.node,=20&snapshot->node);=0A+=09= }=0A=20=0A=20=09/*=20and=20tell=20resowner.c=20about=20it=20*/=0A=20=09= ResourceOwnerEnlarge(owner);=0A=20=09snapshot->regd_count++;=0A=20=09= ResourceOwnerRememberSnapshot(owner,=20(Snapshot)=20snapshot);=0A=20=0A-=09= if=20(snapshot->regd_count=20=3D=3D=201)=0A-=09=09= pairingheap_add(&RegisteredSnapshots,=20&snapshot->ph_node);=0A-=0A=20=09= return=20(Snapshot)=20snapshot;=0A=20}=0A=20=0A@@=20-901,14=20+917,12=20= @@=20UnregisterSnapshotNoOwner(Snapshot=20snapshot)=0A=20=09=09= MVCCSnapshot=20mvccsnap=20=3D=20&snapshot->mvcc;=0A=20=0A=20=09=09= Assert(mvccsnap->regd_count=20>=200);=0A-=09=09= Assert(!pairingheap_is_empty(&RegisteredSnapshots));=0A+=09=09= Assert(!dlist_is_empty(&ValidSnapshots));=0A=20=0A=20=09=09= mvccsnap->regd_count--;=0A-=09=09if=20(mvccsnap->regd_count=20=3D=3D=20= 0)=0A-=09=09=09pairingheap_remove(&RegisteredSnapshots,=20= &mvccsnap->ph_node);=0A-=0A=20=09=09if=20(mvccsnap->regd_count=20=3D=3D=20= 0=20&&=20mvccsnap->active_count=20=3D=3D=200)=0A=20=09=09{=0A+=09=09=09= dlist_delete(&mvccsnap->node);=0A=20=09=09=09FreeMVCCSnapshot(mvccsnap);=0A= =20=09=09=09SnapshotResetXmin();=0A=20=09=09}=0A@@=20-933,24=20+947,6=20= @@=20UnregisterSnapshotNoOwner(Snapshot=20snapshot)=0A=20=09=09= elog(ERROR,=20"registered=20snapshot=20has=20unexpected=20type");=0A=20}=0A= =20=0A-/*=0A-=20*=20Comparison=20function=20for=20RegisteredSnapshots=20= heap.=20=20Snapshots=20are=20ordered=0A-=20*=20by=20xmin,=20so=20that=20= the=20snapshot=20with=20smallest=20xmin=20is=20at=20the=20top.=0A-=20*/=0A= -static=20int=0A-xmin_cmp(const=20pairingheap_node=20*a,=20const=20= pairingheap_node=20*b,=20void=20*arg)=0A-{=0A-=09const=20= MVCCSnapshotData=20*asnap=20=3D=20= pairingheap_const_container(MVCCSnapshotData,=20ph_node,=20a);=0A-=09= const=20MVCCSnapshotData=20*bsnap=20=3D=20= pairingheap_const_container(MVCCSnapshotData,=20ph_node,=20b);=0A-=0A-=09= if=20(TransactionIdPrecedes(asnap->xmin,=20bsnap->xmin))=0A-=09=09return=20= 1;=0A-=09else=20if=20(TransactionIdFollows(asnap->xmin,=20bsnap->xmin))=0A= -=09=09return=20-1;=0A-=09else=0A-=09=09return=200;=0A-}=0A-=0A=20/*=0A=20= =20*=20SnapshotResetXmin=0A=20=20*=0A@@=20-972,21=20+968,27=20@@=20= SnapshotResetXmin(void)=0A=20=09/*=0A=20=09=20*=20Invalidate=20these=20= static=20snapshots=20so=20that=20we=20can=20advance=20xmin.=0A=20=09=20= */=0A-=09if=20(!FirstXactSnapshotRegistered)=0A+=09if=20= (!FirstXactSnapshotRegistered=20&&=20CurrentSnapshotData.valid)=0A+=09{=0A= +=09=09dlist_delete(&CurrentSnapshotData.node);=0A=20=09=09= CurrentSnapshotData.valid=20=3D=20false;=0A-=09= SecondarySnapshotData.valid=20=3D=20false;=0A+=09}=0A+=09if=20= (SecondarySnapshotData.valid)=0A+=09{=0A+=09=09= dlist_delete(&SecondarySnapshotData.node);=0A+=09=09= SecondarySnapshotData.valid=20=3D=20false;=0A+=09}=0A=20=0A=20=09if=20= (ActiveSnapshot=20!=3D=20NULL)=0A=20=09=09return;=0A=20=0A-=09if=20= (pairingheap_is_empty(&RegisteredSnapshots))=0A+=09if=20= (dlist_is_empty(&ValidSnapshots))=0A=20=09{=0A=20=09=09MyProc->xmin=20=3D=20= TransactionXmin=20=3D=20InvalidTransactionId;=0A=20=09=09return;=0A=20=09= }=0A=20=0A-=09minSnapshot=20=3D=20= pairingheap_container(MVCCSnapshotData,=20ph_node,=0A-=09=09=09=09=09=09=09= =09=09=09pairingheap_first(&RegisteredSnapshots));=0A+=09minSnapshot=20=3D= =20dlist_head_element(MVCCSnapshotData,=20node,=20&ValidSnapshots);=0A=20= =0A=20=09if=20(TransactionIdPrecedes(MyProc->xmin,=20minSnapshot->xmin))=0A= =20=09=09MyProc->xmin=20=3D=20TransactionXmin=20=3D=20minSnapshot->xmin;=0A= @@=20-1035,7=20+1037,10=20@@=20AtSubAbort_Snapshot(int=20level)=0A=20=0A=20= =09=09if=20(ActiveSnapshot->as_snap->active_count=20=3D=3D=200=20&&=0A=20= =09=09=09ActiveSnapshot->as_snap->regd_count=20=3D=3D=200)=0A+=09=09{=0A= +=09=09=09dlist_delete(&ActiveSnapshot->as_snap->node);=0A=20=09=09=09= FreeMVCCSnapshot(ActiveSnapshot->as_snap);=0A+=09=09}=0A=20=0A=20=09=09= /*=20and=20free=20the=20stack=20element=20*/=0A=20=09=09= pfree(ActiveSnapshot);=0A@@=20-1053,23=20+1058,6=20@@=20= AtSubAbort_Snapshot(int=20level)=0A=20void=0A=20AtEOXact_Snapshot(bool=20= isCommit,=20bool=20resetXmin)=0A=20{=0A-=09/*=0A-=09=20*=20In=20= transaction-snapshot=20mode=20we=20must=20release=20our=20= privately-managed=0A-=09=20*=20reference=20to=20the=20transaction=20= snapshot.=20=20We=20must=20remove=20it=20from=0A-=09=20*=20= RegisteredSnapshots=20to=20keep=20the=20check=20below=20happy.=20=20But=20= we=20don't=20bother=0A-=09=20*=20to=20do=20FreeMVCCSnapshot,=20for=20two=20= reasons:=20the=20memory=20will=20go=20away=20with=0A-=09=20*=20= TopTransactionContext=20anyway,=20and=20if=20someone=20has=20left=20the=20= snapshot=0A-=09=20*=20stacked=20as=20active,=20we=20don't=20want=20the=20= code=20below=20to=20be=20chasing=20through=20a=0A-=09=20*=20dangling=20= pointer.=0A-=09=20*/=0A-=09if=20(FirstXactSnapshotRegistered)=0A-=09{=0A= -=09=09Assert(CurrentSnapshotData.regd_count=20>=200);=0A-=09=09= Assert(!pairingheap_is_empty(&RegisteredSnapshots));=0A-=09=09= pairingheap_remove(&RegisteredSnapshots,=20= &CurrentSnapshotData.ph_node);=0A-=09=09FirstXactSnapshotRegistered=20=3D=20= false;=0A-=09}=0A-=0A=20=09/*=0A=20=09=20*=20If=20we=20exported=20any=20= snapshots,=20clean=20them=20up.=0A=20=09=20*/=0A@@=20-1082,8=20+1070,8=20= @@=20AtEOXact_Snapshot(bool=20isCommit,=20bool=20resetXmin)=0A=20=09=09=20= *=20it's=20too=20late=20to=20abort=20the=20transaction,=20and=20(2)=20= leaving=20a=20leaked=0A=20=09=09=20*=20file=20around=20has=20little=20= real=20consequence=20anyway.=0A=20=09=09=20*=0A-=09=09=20*=20We=20also=20= need=20to=20remove=20the=20snapshots=20from=20RegisteredSnapshots=20to=0A= -=09=09=20*=20prevent=20a=20warning=20below.=0A+=09=09=20*=20We=20also=20= need=20to=20remove=20the=20snapshots=20from=20ValidSnapshots=20to=20= prevent=0A+=09=09=20*=20a=20warning=20below.=0A=20=09=09=20*=0A=20=09=09=20= *=20As=20with=20the=20FirstXactSnapshot,=20we=20don't=20need=20to=20free=20= resources=20of=0A=20=09=09=20*=20the=20snapshot=20itself=20as=20it=20= will=20go=20away=20with=20the=20memory=20context.=0A@@=20-1096,22=20= +1084,35=20@@=20AtEOXact_Snapshot(bool=20isCommit,=20bool=20resetXmin)=0A= =20=09=09=09=09elog(WARNING,=20"could=20not=20unlink=20file=20\"%s\":=20= %m",=0A=20=09=09=09=09=09=20esnap->snapfile);=0A=20=0A-=09=09=09= pairingheap_remove(&RegisteredSnapshots,=0A-=09=09=09=09=09=09=09=20=20=20= &esnap->snapshot->ph_node);=0A+=09=09=09= dlist_delete(&esnap->snapshot->node);=0A=20=09=09}=0A=20=0A=20=09=09= exportedSnapshots=20=3D=20NIL;=0A=20=09}=0A=20=0A-=09/*=20Drop=20catalog=20= snapshot=20if=20any=20*/=0A-=09InvalidateCatalogSnapshot();=0A+=09/*=20= Drop=20all=20static=20snapshot=20*/=0A+=09if=20= (CatalogSnapshotData.valid)=0A+=09{=0A+=09=09= dlist_delete(&CatalogSnapshotData.node);=0A+=09=09= CatalogSnapshotData.valid=20=3D=20false;=0A+=09}=0A+=09if=20= (CurrentSnapshotData.valid)=0A+=09{=0A+=09=09= dlist_delete(&CurrentSnapshotData.node);=0A+=09=09= CurrentSnapshotData.valid=20=3D=20false;=0A+=09}=0A+=09if=20= (SecondarySnapshotData.valid)=0A+=09{=0A+=09=09= dlist_delete(&SecondarySnapshotData.node);=0A+=09=09= SecondarySnapshotData.valid=20=3D=20false;=0A+=09}=0A=20=0A=20=09/*=20On=20= commit,=20complain=20about=20leftover=20snapshots=20*/=0A=20=09if=20= (isCommit)=0A=20=09{=0A=20=09=09ActiveSnapshotElt=20*active;=0A=20=0A-=09= =09if=20(!pairingheap_is_empty(&RegisteredSnapshots))=0A+=09=09if=20= (!dlist_is_empty(&ValidSnapshots))=0A=20=09=09=09elog(WARNING,=20= "registered=20snapshots=20seem=20to=20remain=20after=20cleanup");=0A=20=0A= =20=09=09/*=20complain=20about=20unpopped=20active=20snapshots=20*/=0A@@=20= -1124,11=20+1125,12=20@@=20AtEOXact_Snapshot(bool=20isCommit,=20bool=20= resetXmin)=0A=20=09=20*=20it'll=20go=20away=20with=20= TopTransactionContext.=0A=20=09=20*/=0A=20=09ActiveSnapshot=20=3D=20= NULL;=0A-=09pairingheap_reset(&RegisteredSnapshots);=0A+=09= dlist_init(&ValidSnapshots);=0A=20=0A=20=09CurrentSnapshotData.valid=20=3D= =20false;=0A=20=09SecondarySnapshotData.valid=20=3D=20false;=0A=20=09= FirstSnapshotSet=20=3D=20false;=0A+=09FirstXactSnapshotRegistered=20=3D=20= false;=0A=20=0A=20=09/*=0A=20=09=20*=20During=20normal=20commit=20= processing,=20we=20call=20ProcArrayEndTransaction()=20to=0A@@=20-1151,6=20= +1153,7=20@@=20AtEOXact_Snapshot(bool=20isCommit,=20bool=20resetXmin)=0A=20= char=20*=0A=20ExportSnapshot(MVCCSnapshot=20snapshot)=0A=20{=0A+=09= MVCCSnapshot=20orig_snapshot;=0A=20=09TransactionId=20topXid;=0A=20=09= TransactionId=20*children;=0A=20=09ExportedSnapshot=20*esnap;=0A@@=20= -1213,7=20+1216,8=20@@=20ExportSnapshot(MVCCSnapshot=20snapshot)=0A=20=09= =20*=20ensure=20that=20the=20snapshot's=20xmin=20is=20honored=20for=20= the=20rest=20of=20the=0A=20=09=20*=20transaction.=0A=20=09=20*/=0A-=09= snapshot=20=3D=20CopyMVCCSnapshot(snapshot);=0A+=09orig_snapshot=20=3D=20= snapshot;=0A+=09snapshot=20=3D=20CopyMVCCSnapshot(orig_snapshot);=0A=20=0A= =20=09oldcxt=20=3D=20MemoryContextSwitchTo(TopTransactionContext);=0A=20=09= esnap=20=3D=20(ExportedSnapshot=20*)=20palloc(sizeof(ExportedSnapshot));=0A= @@=20-1223,7=20+1227,7=20@@=20ExportSnapshot(MVCCSnapshot=20snapshot)=0A=20= =09MemoryContextSwitchTo(oldcxt);=0A=20=0A=20=09snapshot->regd_count++;=0A= -=09pairingheap_add(&RegisteredSnapshots,=20&snapshot->ph_node);=0A+=09= dlist_insert_after(&orig_snapshot->node,=20&snapshot->node);=0A=20=0A=20=09= /*=0A=20=09=20*=20Fill=20buf=20with=20a=20text=20serialization=20of=20= the=20snapshot,=20plus=20identification=0A@@=20-1653,7=20+1657,7=20@@=20= DeleteAllExportedSnapshotFiles(void)=0A=20=0A=20/*=0A=20=20*=20= ThereAreNoPriorRegisteredSnapshots=0A-=20*=09=09Is=20the=20registered=20= snapshot=20count=20less=20than=20or=20equal=20to=20one?=0A+=20*=09=09Are=20= there=20any=20snapshots=20other=20than=20the=20current=20active=20= snapshot?=0A=20=20*=0A=20=20*=20Don't=20use=20this=20to=20settle=20= important=20decisions.=20=20While=20zero=20registrations=20and=0A=20=20*=20= no=20ActiveSnapshot=20would=20confirm=20a=20certain=20idleness,=20the=20= system=20makes=20no=0A@@=20-1662,11=20+1666,25=20@@=20= DeleteAllExportedSnapshotFiles(void)=0A=20bool=0A=20= ThereAreNoPriorRegisteredSnapshots(void)=0A=20{=0A-=09if=20= (pairingheap_is_empty(&RegisteredSnapshots)=20||=0A-=09=09= pairingheap_is_singular(&RegisteredSnapshots))=0A-=09=09return=20true;=0A= +=09dlist_iter=09iter;=0A=20=0A-=09return=20false;=0A+=09= dlist_foreach(iter,=20&ValidSnapshots)=0A+=09{=0A+=09=09MVCCSnapshot=20= cur=20=3D=20dlist_container(MVCCSnapshotData,=20node,=20iter.cur);=0A+=0A= +=09=09if=20(FirstXactSnapshotRegistered)=0A+=09=09{=0A+=09=09=09= Assert(CurrentSnapshotData.valid);=0A+=09=09=09if=20(cur=20!=3D=20= &CurrentSnapshotData)=0A+=09=09=09=09continue;=0A+=09=09}=0A+=09=09if=20= (ActiveSnapshot=20&&=20cur=20=3D=3D=20ActiveSnapshot->as_snap)=0A+=09=09=09= continue;=0A+=0A+=09=09return=20false;=0A+=09}=0A+=0A+=09return=20true;=0A= =20}=0A=20=0A=20/*=0A@@=20-1684,15=20+1702,18=20@@=20= HaveRegisteredOrActiveSnapshot(void)=0A=20=09=09return=20true;=0A=20=0A=20= =09/*=0A-=09=20*=20The=20catalog=20snapshot=20is=20in=20= RegisteredSnapshots=20when=20valid,=20but=20can=20be=0A+=09=20*=20The=20= catalog=20snapshot=20is=20in=20ValidSnapshots=20when=20valid,=20but=20= can=20be=0A=20=09=20*=20removed=20at=20any=20time=20due=20to=20= invalidation=20processing.=20If=20explicitly=0A-=09=20*=20registered=20= more=20than=20one=20snapshot=20has=20to=20be=20in=20RegisteredSnapshots.=0A= +=09=20*=20registered=20more=20than=20one=20snapshot=20has=20to=20be=20= in=20ValidSnapshots.=0A=20=09=20*/=0A=20=09if=20= (CatalogSnapshotData.valid=20&&=0A-=09=09= pairingheap_is_singular(&RegisteredSnapshots))=0A+=09=09= dlist_head_node(&ValidSnapshots)=20=3D=3D=20&CatalogSnapshotData.node=20= &&=0A+=09=09dlist_tail_node(&ValidSnapshots)=20=3D=3D=20= &CatalogSnapshotData.node)=0A+=09{=0A=20=09=09return=20false;=0A+=09}=0A=20= =0A-=09return=20!pairingheap_is_empty(&RegisteredSnapshots);=0A+=09= return=20!dlist_is_empty(&ValidSnapshots);=0A=20}=0A=20=0A=20=0A@@=20= -1884,7=20+1905,7=20@@=20RestoreSnapshot(char=20*start_address)=0A=20=09= ResourceOwnerEnlarge(CurrentResourceOwner);=0A=20=09= snapshot->regd_count++;=0A=20=09= ResourceOwnerRememberSnapshot(CurrentResourceOwner,=20(Snapshot)=20= snapshot);=0A-=09pairingheap_add(&RegisteredSnapshots,=20= &snapshot->ph_node);=0A+=09valid_snapshots_push_out_of_order(snapshot);=0A= =20=0A=20=09return=20snapshot;=0A=20}=0A@@=20-2015,3=20+2036,45=20@@=20= ResOwnerReleaseSnapshot(Datum=20res)=0A=20{=0A=20=09= UnregisterSnapshotNoOwner((Snapshot)=20DatumGetPointer(res));=0A=20}=0A+=0A= +=0A+/*=20Helper=20functions=20to=20manipulate=20the=20ValidSnapshots=20= list=20*/=0A+=0A+/*=20dlist_push_tail,=20with=20assertion=20that=20the=20= list=20stays=20ordered=20by=20xmin=20*/=0A+static=20void=0A= +valid_snapshots_push_tail(MVCCSnapshot=20snapshot)=0A+{=0A+#ifdef=20= USE_ASSERT_CHECKING=0A+=09if=20(!dlist_is_empty(&ValidSnapshots))=0A+=09= {=0A+=09=09MVCCSnapshot=20tail=20=3D=20= dlist_tail_element(MVCCSnapshotData,=20node,=20&ValidSnapshots);=0A+=0A+=09= =09Assert(TransactionIdFollowsOrEquals(snapshot->xmin,=20tail->xmin));=0A= +=09}=0A+#endif=0A+=09dlist_push_tail(&ValidSnapshots,=20= &snapshot->node);=0A+}=0A+=0A+/*=0A+=20*=20Add=20an=20entry=20to=20the=20= right=20position=20in=20the=20list,=20keeping=20it=20ordered=20by=20= xmin.=0A+=20*=0A+=20*=20This=20is=20O(n),=20but=20that's=20OK=20because=20= it's=20only=20used=20in=20rare=20occasions,=20when=0A+=20*=20the=20list=20= is=20small.=0A+=20*/=0A+static=20void=0A= +valid_snapshots_push_out_of_order(MVCCSnapshot=20snapshot)=0A+{=0A+=09= dlist_iter=09iter;=0A+=0A+=09dlist_foreach(iter,=20&ValidSnapshots)=0A+=09= {=0A+=09=09MVCCSnapshot=20cur=20=3D=20dlist_container(MVCCSnapshotData,=20= node,=20iter.cur);=0A+=0A+=09=09if=20= (TransactionIdFollowsOrEquals(snapshot->xmin,=20cur->xmin))=0A+=09=09{=0A= +=09=09=09dlist_insert_after(&cur->node,=20&snapshot->node);=0A+=09=09=09= return;=0A+=09=09}=0A+=09}=0A+=09dlist_push_tail(&ValidSnapshots,=20= &snapshot->node);=0A+}=0Adiff=20--git=20= a/src/include/access/spgist_private.h=20= b/src/include/access/spgist_private.h=0Aindex=20cb43a278f46..27ed1d77c9b=20= 100644=0A---=20a/src/include/access/spgist_private.h=0A+++=20= b/src/include/access/spgist_private.h=0A@@=20-17,6=20+17,7=20@@=0A=20= #include=20"access/itup.h"=0A=20#include=20"access/spgist.h"=0A=20= #include=20"catalog/pg_am_d.h"=0A+#include=20"lib/pairingheap.h"=0A=20= #include=20"nodes/tidbitmap.h"=0A=20#include=20"storage/buf.h"=0A=20= #include=20"utils/geo_decls.h"=0Adiff=20--git=20= a/src/include/utils/snapshot.h=20b/src/include/utils/snapshot.h=0Aindex=20= 1697c6df856..44b3b20f73c=20100644=0A---=20a/src/include/utils/snapshot.h=0A= +++=20b/src/include/utils/snapshot.h=0A@@=20-13,7=20+13,7=20@@=0A=20= #ifndef=20SNAPSHOT_H=0A=20#define=20SNAPSHOT_H=0A=20=0A-#include=20= "lib/pairingheap.h"=0A+#include=20"lib/ilist.h"=0A=20=0A=20=0A=20/*=0A@@=20= -169,8=20+169,8=20@@=20typedef=20struct=20MVCCSnapshotData=0A=20=09=20*=20= Book-keeping=20information,=20used=20by=20the=20snapshot=20manager=0A=20=09= =20*/=0A=20=09uint32=09=09active_count;=09/*=20refcount=20on=20= ActiveSnapshot=20stack=20*/=0A-=09uint32=09=09regd_count;=09=09/*=20= refcount=20on=20RegisteredSnapshots=20*/=0A-=09pairingheap_node=20= ph_node;=09/*=20link=20in=20the=20RegisteredSnapshots=20heap=20*/=0A+=09= uint32=09=09regd_count;=09=09/*=20refcount=20of=20registrations=20in=20= resowners=20*/=0A+=09dlist_node=09node;=09=09=09/*=20link=20in=20= ValidSnapshots=20*/=0A=20=0A=20=09/*=0A=20=09=20*=20The=20transaction=20= completion=20count=20at=20the=20time=20GetSnapshotData()=20built=0A--=20=0A= 2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0007-Split-MVCCSnapshot-into-inner-and-outer-parts.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0007-Split-MVCCSnapshot-into-inner-and-outer-parts.patch" Content-Transfer-Encoding: quoted-printable =46rom=2005443030201d59216b3125d51c641b68decd4379=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Mon,=2031=20Mar=202025=2021:46:54=20= +0300=0ASubject:=20[PATCH=20v6=2007/12]=20Split=20MVCCSnapshot=20into=20= inner=20and=20outer=20parts=0A=0ASplit=20MVCCSnapshot=20into=20two=20= parts:=20inner=20struct=20to=20hold=20the=20xmin,=20xmax=0Aand=20XID=20= arrays=20that=20determine=20which=20transactions=20are=20visible,=20and=20= an=0Aouter=20shell=20that=20includes=20the=20command=20ID=20and=20a=20= pointer=20to=20the=20inner=0Astruct.=20That=20way,=20the=20inner=20= struct=20can=20be=20shared=20by=20snapshots=20derived=0Afrom=20the=20= same=20original=20snapshot,=20just=20with=20different=20command=20IDs.=0A= =0AThe=20inner=20struct,=20MVCCSnapshotShared,=20is=20reference=20= counted=20separately=0Aso=20that=20we=20can=20avoid=20copying=20it=20= when=20pushing=20or=20registering=20a=20snapshot=0Afor=20the=20first=20= time.=20Also,=20GetMVCCSnapshotData()=20can=20reuse=20it=20more=0A= aggressively:=20we=20always=20keep=20a=20pointer=20to=20the=20latest=20= shared=20struct=0A(latestSnapshotShared),=20and=20GetMVCCSnapshotData()=20= always=20tries=20to=0Areuse=20the=20same=20latest=20snapshot,=20= regardless=20of=20whether=20it=20was=20called=0Afrom=20= GetTransactionSnapshot(),=20GetLatestSnapshot(),=20or=0A= GetCatalogSnapshot().=20That=20avoids=20unnecessary=20copying.=20= Snapshots=20are=0Ausually=20small=20so=20that=20it=20doesn't=20matter,=20= but=20it=20can=20help=20in=20extreme=0Acases=20where=20you=20have=20= thousands=20of=20(sub-)XIDs=20in=20progress.=0A=0ANow=20that=20the=20= shared=20inner=20structs=20are=20reference=20counted,=20it=20seems=0A= unnecessary=20to=20reference=20count=20the=20outer=20MVCCSnapshots=0A= separately.=20That=20means=20that=20RegisterSnapshot()=20always=20makes=20= a=20new=0Apalloc'd=20copy=20of=20the=20outer=20struct,=20but=20that's=20= pretty=20small.=20The=0AActiveSnapshot=20stack=20entries=20now=20embed=20= the=20outer=20struct=20directly,=20so=0Athe=20'active_count'=20is=20gone=20= too.=0A=0AThe=20ValidSnapshots=20list=20now=20tracks=20the=20shared=20= structs=20rather=20than=20the=0Aouter=20snapshots.=20That's=20sufficient=20= for=20finding=20the=20oldest=20xmin,=20but=20if=0Awe=20ever=20wanted=20= to=20also=20know=20the=20oldest=20command=20ID=20in=20use,=20we'd=20need=20= to=0Atrack=20the=20outer=20structs=20instead.=0A---=0A=20= contrib/amcheck/verify_heapam.c=20=20=20=20=20=20=20=20=20=20=20=20=20|=20= =20=202=20+-=0A=20contrib/amcheck/verify_nbtree.c=20=20=20=20=20=20=20=20= =20=20=20=20=20|=20=20=202=20+-=0A=20src/backend/access/heap/heapam.c=20=20= =20=20=20=20=20=20=20=20=20=20|=20=20=202=20+-=0A=20= src/backend/access/heap/heapam_handler.c=20=20=20=20|=20=20=202=20+-=0A=20= src/backend/access/heap/heapam_visibility.c=20|=20=2018=20+-=0A=20= src/backend/access/spgist/spgvacuum.c=20=20=20=20=20=20=20|=20=20=202=20= +-=0A=20src/backend/access/transam/README=20=20=20=20=20=20=20=20=20=20=20= |=20=2026=20+-=0A=20src/backend/catalog/pg_inherits.c=20=20=20=20=20=20=20= =20=20=20=20|=20=20=206=20+-=0A=20src/backend/commands/async.c=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20=20=202=20+-=0A=20= src/backend/commands/indexcmds.c=20=20=20=20=20=20=20=20=20=20=20=20|=20=20= =204=20+-=0A=20src/backend/commands/tablecmds.c=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=202=20+-=0A=20src/backend/executor/execMain.c=20=20=20=20= =20=20=20=20=20=20=20=20=20|=20=2012=20+-=0A=20= src/backend/executor/execParallel.c=20=20=20=20=20=20=20=20=20|=20=20=20= 3=20+-=0A=20src/backend/partitioning/partdesc.c=20=20=20=20=20=20=20=20=20= |=20=20=202=20+-=0A=20src/backend/replication/logical/snapbuild.c=20|=20=20= 40=20+-=0A=20src/backend/replication/walsender.c=20=20=20=20=20=20=20=20=20= |=20=20=202=20+-=0A=20src/backend/storage/ipc/procarray.c=20=20=20=20=20=20= =20=20=20|=20138=20+++--=0A=20src/backend/storage/lmgr/predicate.c=20=20=20= =20=20=20=20=20|=20109=20++--=0A=20src/backend/utils/adt/xid8funcs.c=20=20= =20=20=20=20=20=20=20=20=20|=20=20=208=20+-=0A=20= src/backend/utils/time/snapmgr.c=20=20=20=20=20=20=20=20=20=20=20=20|=20= 605=20++++++++++----------=0A=20src/include/access/transam.h=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20|=20=20=204=20+-=0A=20= src/include/storage/predicate.h=20=20=20=20=20=20=20=20=20=20=20=20=20|=20= =20=208=20+-=0A=20src/include/storage/proc.h=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20=20=202=20+-=0A=20= src/include/storage/procarray.h=20=20=20=20=20=20=20=20=20=20=20=20=20|=20= =20=202=20+-=0A=20src/include/utils/snapmgr.h=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20|=20=2011=20+-=0A=20src/include/utils/snapshot.h=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=2051=20+-=0A=20= src/tools/pgindent/typedefs.list=20=20=20=20=20=20=20=20=20=20=20=20|=20=20= =202=20+=0A=2027=20files=20changed,=20536=20insertions(+),=20531=20= deletions(-)=0A=0Adiff=20--git=20a/contrib/amcheck/verify_heapam.c=20= b/contrib/amcheck/verify_heapam.c=0Aindex=206665cafc179..d7f0b772f94=20= 100644=0A---=20a/contrib/amcheck/verify_heapam.c=0A+++=20= b/contrib/amcheck/verify_heapam.c=0A@@=20-310,7=20+310,7=20@@=20= verify_heapam(PG_FUNCTION_ARGS)=0A=20=09=20*=20Any=20xmin=20newer=20than=20= the=20xmin=20of=20our=20snapshot=20can't=20become=20all-visible=0A=20=09=20= *=20while=20we're=20running.=0A=20=09=20*/=0A-=09ctx.safe_xmin=20=3D=20= GetTransactionSnapshot()->mvcc.xmin;=0A+=09ctx.safe_xmin=20=3D=20= GetTransactionSnapshot()->mvcc.shared->xmin;=0A=20=0A=20=09/*=0A=20=09=20= *=20If=20we=20report=20corruption=20when=20not=20examining=20some=20= individual=20attribute,=0Adiff=20--git=20= a/contrib/amcheck/verify_nbtree.c=20b/contrib/amcheck/verify_nbtree.c=0A= index=20e90b4a2ad5a..d77ded4cc40=20100644=0A---=20= a/contrib/amcheck/verify_nbtree.c=0A+++=20= b/contrib/amcheck/verify_nbtree.c=0A@@=20-458,7=20+458,7=20@@=20= bt_check_every_level(Relation=20rel,=20Relation=20heaprel,=20bool=20= heapkeyspace,=0A=20=09=09=09=20*/=0A=20=09=09=09if=20= (IsolationUsesXactSnapshot()=20&&=20rel->rd_index->indcheckxmin=20&&=0A=20= =09=09=09=09= !TransactionIdPrecedes(HeapTupleHeaderGetXmin(rel->rd_indextuple->t_data),= =0A-=09=09=09=09=09=09=09=09=09=20=20=20snapshot->mvcc.xmin))=0A+=09=09=09= =09=09=09=09=09=09=20=20=20snapshot->mvcc.shared->xmin))=0A=20=09=09=09=09= ereport(ERROR,=0A=20=09=09=09=09=09=09= (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),=0A=20=09=09=09=09=09=09=20= errmsg("index=20\"%s\"=20cannot=20be=20verified=20using=20transaction=20= snapshot",=0Adiff=20--git=20a/src/backend/access/heap/heapam.c=20= b/src/backend/access/heap/heapam.c=0Aindex=200cfa100cbd1..0615ffa2bd1=20= 100644=0A---=20a/src/backend/access/heap/heapam.c=0A+++=20= b/src/backend/access/heap/heapam.c=0A@@=20-606,7=20+606,7=20@@=20= heap_prepare_pagescan(TableScanDesc=20sscan)=0A=20=09=20*=20tuple=20for=20= visibility=20the=20hard=20way.=0A=20=09=20*/=0A=20=09all_visible=20=3D=20= PageIsAllVisible(page)=20&&=0A-=09=09(snapshot->snapshot_type=20!=3D=20= SNAPSHOT_MVCC=20||=20!snapshot->mvcc.takenDuringRecovery);=0A+=09=09= (snapshot->snapshot_type=20!=3D=20SNAPSHOT_MVCC=20||=20= !snapshot->mvcc.shared->takenDuringRecovery);=0A=20=09check_serializable=20= =3D=0A=20=09=09= CheckForSerializableConflictOutNeeded(scan->rs_base.rs_rd,=20snapshot);=0A= =20=0Adiff=20--git=20a/src/backend/access/heap/heapam_handler.c=20= b/src/backend/access/heap/heapam_handler.c=0Aindex=20= fce657f00f6..b9a5b38dd08=20100644=0A---=20= a/src/backend/access/heap/heapam_handler.c=0A+++=20= b/src/backend/access/heap/heapam_handler.c=0A@@=20-2308,7=20+2308,7=20@@=20= heapam_scan_sample_next_tuple(TableScanDesc=20scan,=20SampleScanState=20= *scanstate,=0A=20=0A=20=09page=20=3D=20(Page)=20= BufferGetPage(hscan->rs_cbuf);=0A=20=09all_visible=20=3D=20= PageIsAllVisible(page)=20&&=0A-=09=09(scan->rs_snapshot->snapshot_type=20= !=3D=20SNAPSHOT_MVCC=20||=20= !scan->rs_snapshot->mvcc.takenDuringRecovery);=0A+=09=09= (scan->rs_snapshot->snapshot_type=20!=3D=20SNAPSHOT_MVCC=20||=20= !scan->rs_snapshot->mvcc.shared->takenDuringRecovery);=0A=20=09maxoffset=20= =3D=20PageGetMaxOffsetNumber(page);=0A=20=0A=20=09for=20(;;)=0Adiff=20= --git=20a/src/backend/access/heap/heapam_visibility.c=20= b/src/backend/access/heap/heapam_visibility.c=0Aindex=20= f5d69b558f1..07f155498d4=20100644=0A---=20= a/src/backend/access/heap/heapam_visibility.c=0A+++=20= b/src/backend/access/heap/heapam_visibility.c=0A@@=20-19,7=20+19,7=20@@=0A= =20=20*=20That=20fixes=20that=20problem,=20but=20it=20also=20means=20= there=20is=20a=20window=20where=0A=20=20*=20TransactionIdIsInProgress=20= and=20TransactionIdDidCommit=20will=20both=20return=20true.=0A=20=20*=20= If=20we=20check=20only=20TransactionIdDidCommit,=20we=20could=20consider=20= a=20tuple=0A-=20*=20committed=20when=20a=20later=20GetSnapshotData=20= call=20will=20still=20think=20the=0A+=20*=20committed=20when=20a=20later=20= GetMVCCSnapshotData=20call=20will=20still=20think=20the=0A=20=20*=20= originating=20transaction=20is=20in=20progress,=20which=20leads=20to=20= application-level=0A=20=20*=20inconsistency.=20=20The=20upshot=20is=20= that=20we=20gotta=20check=20TransactionIdIsInProgress=0A=20=20*=20first=20= in=20all=20code=20paths,=20except=20for=20a=20few=20cases=20where=20we=20= are=20looking=20at=0A@@=20-969,7=20+969,7=20@@=20= HeapTupleSatisfiesMVCC(HeapTuple=20htup,=20MVCCSnapshot=20snapshot,=0A=20= =09=20*=20get=20invalidated=20while=20it's=20still=20in=20use,=20and=20= this=20is=20a=20convenient=20place=0A=20=09=20*=20to=20check=20for=20= that.=0A=20=09=20*/=0A-=09Assert(snapshot->regd_count=20>=200=20||=20= snapshot->active_count=20>=200);=0A+=09Assert(snapshot->kind=20=3D=3D=20= SNAPSHOT_ACTIVE=20||=20snapshot->kind=20=3D=3D=20SNAPSHOT_REGISTERED);=0A= =20=0A=20=09Assert(ItemPointerIsValid(&htup->t_self));=0A=20=09= Assert(htup->t_tableOid=20!=3D=20InvalidOid);=0A@@=20-986,7=20+986,7=20= @@=20HeapTupleSatisfiesMVCC(HeapTuple=20htup,=20MVCCSnapshot=20snapshot,=0A= =20=0A=20=09=09=09if=20(TransactionIdIsCurrentTransactionId(xvac))=0A=20=09= =09=09=09return=20false;=0A-=09=09=09if=20(!XidInMVCCSnapshot(xvac,=20= snapshot))=0A+=09=09=09if=20(!XidInMVCCSnapshot(xvac,=20= snapshot->shared))=0A=20=09=09=09{=0A=20=09=09=09=09if=20= (TransactionIdDidCommit(xvac))=0A=20=09=09=09=09{=0A@@=20-1005,7=20= +1005,7=20@@=20HeapTupleSatisfiesMVCC(HeapTuple=20htup,=20MVCCSnapshot=20= snapshot,=0A=20=0A=20=09=09=09if=20= (!TransactionIdIsCurrentTransactionId(xvac))=0A=20=09=09=09{=0A-=09=09=09= =09if=20(XidInMVCCSnapshot(xvac,=20snapshot))=0A+=09=09=09=09if=20= (XidInMVCCSnapshot(xvac,=20snapshot->shared))=0A=20=09=09=09=09=09return=20= false;=0A=20=09=09=09=09if=20(TransactionIdDidCommit(xvac))=0A=20=09=09=09= =09=09SetHintBits(tuple,=20buffer,=20HEAP_XMIN_COMMITTED,=0A@@=20-1060,7=20= +1060,7=20@@=20HeapTupleSatisfiesMVCC(HeapTuple=20htup,=20MVCCSnapshot=20= snapshot,=0A=20=09=09=09else=0A=20=09=09=09=09return=20false;=09/*=20= deleted=20before=20scan=20started=20*/=0A=20=09=09}=0A-=09=09else=20if=20= (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple),=20snapshot))=0A+=09=09= else=20if=20(XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple),=20= snapshot->shared))=0A=20=09=09=09return=20false;=0A=20=09=09else=20if=20= (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))=0A=20=09=09=09= SetHintBits(tuple,=20buffer,=20HEAP_XMIN_COMMITTED,=0A@@=20-1077,7=20= +1077,7=20@@=20HeapTupleSatisfiesMVCC(HeapTuple=20htup,=20MVCCSnapshot=20= snapshot,=0A=20=09{=0A=20=09=09/*=20xmin=20is=20committed,=20but=20maybe=20= not=20according=20to=20our=20snapshot=20*/=0A=20=09=09if=20= (!HeapTupleHeaderXminFrozen(tuple)=20&&=0A-=09=09=09= XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple),=20snapshot))=0A+=09=09= =09XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple),=20= snapshot->shared))=0A=20=09=09=09return=20false;=09=09/*=20treat=20as=20= still=20in=20progress=20*/=0A=20=09}=0A=20=0A@@=20-1108,7=20+1108,7=20@@=20= HeapTupleSatisfiesMVCC(HeapTuple=20htup,=20MVCCSnapshot=20snapshot,=0A=20= =09=09=09else=0A=20=09=09=09=09return=20false;=09/*=20deleted=20before=20= scan=20started=20*/=0A=20=09=09}=0A-=09=09if=20(XidInMVCCSnapshot(xmax,=20= snapshot))=0A+=09=09if=20(XidInMVCCSnapshot(xmax,=20snapshot->shared))=0A= =20=09=09=09return=20true;=0A=20=09=09if=20= (TransactionIdDidCommit(xmax))=0A=20=09=09=09return=20false;=09=09/*=20= updating=20transaction=20committed=20*/=0A@@=20-1126,7=20+1126,7=20@@=20= HeapTupleSatisfiesMVCC(HeapTuple=20htup,=20MVCCSnapshot=20snapshot,=0A=20= =09=09=09=09return=20false;=09/*=20deleted=20before=20scan=20started=20= */=0A=20=09=09}=0A=20=0A-=09=09if=20= (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple),=20snapshot))=0A+=09=09= if=20(XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple),=20= snapshot->shared))=0A=20=09=09=09return=20true;=0A=20=0A=20=09=09if=20= (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))=0A@@=20= -1144,7=20+1144,7=20@@=20HeapTupleSatisfiesMVCC(HeapTuple=20htup,=20= MVCCSnapshot=20snapshot,=0A=20=09else=0A=20=09{=0A=20=09=09/*=20xmax=20= is=20committed,=20but=20maybe=20not=20according=20to=20our=20snapshot=20= */=0A-=09=09if=20(XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple),=20= snapshot))=0A+=09=09if=20= (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple),=20= snapshot->shared))=0A=20=09=09=09return=20true;=09=09/*=20treat=20as=20= still=20in=20progress=20*/=0A=20=09}=0A=20=0Adiff=20--git=20= a/src/backend/access/spgist/spgvacuum.c=20= b/src/backend/access/spgist/spgvacuum.c=0Aindex=20= 850ad36cd0a..0a8d7b0a0d6=20100644=0A---=20= a/src/backend/access/spgist/spgvacuum.c=0A+++=20= b/src/backend/access/spgist/spgvacuum.c=0A@@=20-808,7=20+808,7=20@@=20= spgvacuumscan(spgBulkDeleteState=20*bds)=0A=20=09/*=20Finish=20setting=20= up=20spgBulkDeleteState=20*/=0A=20=09initSpGistState(&bds->spgstate,=20= index);=0A=20=09bds->pendingList=20=3D=20NULL;=0A-=09bds->myXmin=20=3D=20= GetActiveSnapshot()->mvcc.xmin;=0A+=09bds->myXmin=20=3D=20= GetActiveSnapshot()->mvcc.shared->xmin;=0A=20=09bds->lastFilledBlock=20=3D= =20SPGIST_LAST_FIXED_BLKNO;=0A=20=0A=20=09/*=0Adiff=20--git=20= a/src/backend/access/transam/README=20= b/src/backend/access/transam/README=0Aindex=20231106270fd..81792f0eab3=20= 100644=0A---=20a/src/backend/access/transam/README=0A+++=20= b/src/backend/access/transam/README=0A@@=20-231,7=20+231,7=20@@=20we=20= must=20ensure=20consistency=20about=20the=20commit=20order=20of=20= transactions.=0A=20For=20example,=20suppose=20an=20UPDATE=20in=20xact=20= A=20is=20blocked=20by=20xact=20B's=20prior=0A=20update=20of=20the=20same=20= row,=20and=20xact=20B=20is=20doing=20commit=20while=20xact=20C=20gets=20= a=0A=20snapshot.=20=20Xact=20A=20can=20complete=20and=20commit=20as=20= soon=20as=20B=20releases=20its=20locks.=0A-If=20xact=20C's=20= GetSnapshotData=20sees=20xact=20B=20as=20still=20running,=20then=20it=20= had=0A+If=20xact=20C's=20GetMVCCSnapshotData=20sees=20xact=20B=20as=20= still=20running,=20then=20it=20had=0A=20better=20see=20xact=20A=20as=20= still=20running=20as=20well,=20or=20it=20will=20be=20able=20to=20see=20= two=0A=20tuple=20versions=20-=20one=20deleted=20by=20xact=20B=20and=20= one=20inserted=20by=20xact=20A.=20=20Another=0A=20reason=20why=20this=20= would=20be=20bad=20is=20that=20C=20would=20see=20(in=20the=20row=20= inserted=20by=20A)=0A@@=20-248,8=20+248,8=20@@=20with=20snapshot-taking:=20= we=20do=20not=20allow=20any=20transaction=20to=20exit=20the=20set=20of=0A= =20running=20transactions=20while=20a=20snapshot=20is=20being=20taken.=20= =20(This=20rule=20is=0A=20stronger=20than=20necessary=20for=20= consistency,=20but=20is=20relatively=20simple=20to=0A=20enforce,=20and=20= it=20assists=20with=20some=20other=20issues=20as=20explained=20below.)=20= =20The=0A-implementation=20of=20this=20is=20that=20GetSnapshotData=20= takes=20the=20ProcArrayLock=20in=0A-shared=20mode=20(so=20that=20= multiple=20backends=20can=20take=20snapshots=20in=20parallel),=0A= +implementation=20of=20this=20is=20that=20GetMVCCSnapshotData=20takes=20= the=20ProcArrayLock=0A+in=20shared=20mode=20(so=20that=20multiple=20= backends=20can=20take=20snapshots=20in=20parallel),=0A=20but=20= ProcArrayEndTransaction=20must=20take=20the=20ProcArrayLock=20in=20= exclusive=20mode=0A=20while=20clearing=20the=20ProcGlobal->xids[]=20= entry=20at=20transaction=20end=20(either=0A=20commit=20or=20abort).=20= (To=20reduce=20context=20switching,=20when=20multiple=20transactions=0A= @@=20-257,7=20+257,7=20@@=20commit=20nearly=20simultaneously,=20we=20= have=20one=20backend=20take=20ProcArrayLock=20and=0A=20clear=20the=20= XIDs=20of=20multiple=20processes=20at=20once.)=0A=20=0A=20= ProcArrayEndTransaction=20also=20holds=20the=20lock=20while=20advancing=20= the=20shared=0A-latestCompletedXid=20variable.=20=20This=20allows=20= GetSnapshotData=20to=20use=0A+latestCompletedXid=20variable.=20=20This=20= allows=20GetMVCCSnapshotData=20to=20use=0A=20latestCompletedXid=20+=201=20= as=20xmax=20for=20its=20snapshot:=20there=20can=20be=20no=0A=20= transaction=20>=3D=20this=20xid=20value=20that=20the=20snapshot=20needs=20= to=20consider=20as=0A=20completed.=0A@@=20-301,7=20+301,7=20@@=20if=20it=20= currently=20has=20no=20live=20snapshots=20(eg,=20if=20it's=20between=20= transactions=20or=0A=20hasn't=20yet=20set=20a=20snapshot=20for=20a=20new=20= transaction).=20=20ComputeXidHorizons=20takes=0A=20the=20MIN()=20of=20= the=20valid=20xmin=20fields.=20=20It=20does=20this=20with=20only=20= shared=20lock=20on=0A=20ProcArrayLock,=20which=20means=20there=20is=20a=20= potential=20race=20condition=20against=20other=0A-backends=20doing=20= GetSnapshotData=20concurrently:=20we=20must=20be=20certain=20that=20a=0A= +backends=20doing=20GetMVCCSnapshotData=20concurrently:=20we=20must=20be=20= certain=20that=20a=0A=20concurrent=20backend=20that=20is=20about=20to=20= set=20its=20xmin=20does=20not=20compute=20an=20xmin=0A=20less=20than=20= what=20ComputeXidHorizons=20determines.=20=20We=20ensure=20that=20by=20= including=0A=20all=20the=20active=20XIDs=20into=20the=20MIN()=20= calculation,=20along=20with=20the=20valid=20xmins.=0A@@=20-310,27=20= +310,27=20@@=20ensures=20that=20concurrent=20holders=20of=20shared=20= ProcArrayLock=20will=20compute=20the=0A=20same=20minimum=20of=20= currently-active=20XIDs:=20no=20xact,=20in=20particular=20not=20the=0A=20= oldest,=20can=20exit=20while=20we=20hold=20shared=20ProcArrayLock.=20=20= So=0A=20ComputeXidHorizons's=20view=20of=20the=20minimum=20active=20XID=20= will=20be=20the=20same=20as=20that=0A-of=20any=20concurrent=20= GetSnapshotData,=20and=20so=20it=20can't=20produce=20an=20overestimate.=0A= +of=20any=20concurrent=20GetMVCCSnapshotData,=20and=20so=20it=20can't=20= produce=20an=20overestimate.=0A=20If=20there=20is=20no=20active=20= transaction=20at=20all,=20ComputeXidHorizons=20uses=0A=20= latestCompletedXid=20+=201,=20which=20is=20a=20lower=20bound=20for=20the=20= xmin=20that=20might=0A-be=20computed=20by=20concurrent=20or=20later=20= GetSnapshotData=20calls.=20=20(We=20know=20that=20no=0A+be=20computed=20= by=20concurrent=20or=20later=20GetMVCCSnapshotData=20calls.=20=20(We=20= know=20that=20no=0A=20XID=20less=20than=20this=20could=20be=20about=20to=20= appear=20in=20the=20ProcArray,=20because=20of=20the=0A=20XidGenLock=20= interlock=20discussed=20above.)=0A=20=0A-As=20GetSnapshotData=20is=20= performance=20critical,=20it=20does=20not=20perform=20an=20accurate=0A= +As=20GetMVCCSnapshotData=20is=20performance=20critical,=20it=20does=20= not=20perform=20an=20accurate=0A=20oldest-xmin=20calculation=20(it=20= used=20to,=20until=20v14).=20The=20contents=20of=20a=20snapshot=0A=20= only=20depend=20on=20the=20xids=20of=20other=20backends,=20not=20their=20= xmin.=20As=20backend's=20xmin=0A-changes=20much=20more=20often=20than=20= its=20xid,=20having=20GetSnapshotData=20look=20at=20xmins=0A+changes=20= much=20more=20often=20than=20its=20xid,=20having=20GetMVCCSnapshotData=20= look=20at=20xmins=0A=20can=20lead=20to=20a=20lot=20of=20unnecessary=20= cacheline=20ping-pong.=20=20Instead=0A-GetSnapshotData=20updates=20= approximate=20thresholds=20(one=20that=20guarantees=20that=20all=0A= -deleted=20rows=20older=20than=20it=20can=20be=20removed,=20another=20= determining=20that=20deleted=0A+GetMVCCSnapshotData=20updates=20= approximate=20thresholds=20(one=20that=20guarantees=20that=0A+all=20= deleted=20rows=20older=20than=20it=20can=20be=20removed,=20another=20= determining=20that=20deleted=0A=20rows=20newer=20than=20it=20can=20not=20= be=20removed).=20GlobalVisTest*=20uses=20those=20thresholds=0A=20to=20= make=20invisibility=20decision,=20falling=20back=20to=20= ComputeXidHorizons=20if=0A=20necessary.=0A=20=0A=20Note=20that=20while=20= it=20is=20certain=20that=20two=20concurrent=20executions=20of=0A= -GetSnapshotData=20will=20compute=20the=20same=20xmin=20for=20their=20= own=20snapshots,=20there=20is=0A-no=20such=20guarantee=20for=20the=20= horizons=20computed=20by=20ComputeXidHorizons.=20=20This=20is=0A= +GetMVCCSnapshotData=20will=20compute=20the=20same=20xmin=20for=20their=20= own=20snapshots,=20there=0A+is=20no=20such=20guarantee=20for=20the=20= horizons=20computed=20by=20ComputeXidHorizons.=20=20This=20is=0A=20= because=20we=20allow=20XID-less=20transactions=20to=20clear=20their=20= MyProc->xmin=0A=20asynchronously=20(without=20taking=20ProcArrayLock),=20= so=20one=20execution=20might=20see=0A=20what=20had=20been=20the=20oldest=20= xmin,=20and=20another=20not.=20=20This=20is=20OK=20since=20the=0Adiff=20= --git=20a/src/backend/catalog/pg_inherits.c=20= b/src/backend/catalog/pg_inherits.c=0Aindex=20b658601bf77..f1148dbe4a3=20= 100644=0A---=20a/src/backend/catalog/pg_inherits.c=0A+++=20= b/src/backend/catalog/pg_inherits.c=0A@@=20-143,12=20+143,12=20@@=20= find_inheritance_children_extended(Oid=20parentrelId,=20bool=20= omit_detached,=0A=20=09=09=09if=20(omit_detached=20&&=20= ActiveSnapshotSet())=0A=20=09=09=09{=0A=20=09=09=09=09TransactionId=20= xmin;=0A-=09=09=09=09Snapshot=09snap;=0A+=09=09=09=09MVCCSnapshot=20= snap;=0A=20=0A=20=09=09=09=09xmin=20=3D=20= HeapTupleHeaderGetXmin(inheritsTuple->t_data);=0A-=09=09=09=09snap=20=3D=20= GetActiveSnapshot();=0A+=09=09=09=09snap=20=3D=20(MVCCSnapshot)=20= GetActiveSnapshot();=0A=20=0A-=09=09=09=09if=20(!XidInMVCCSnapshot(xmin,=20= (MVCCSnapshot)=20snap))=0A+=09=09=09=09if=20(!XidInMVCCSnapshot(xmin,=20= snap->shared))=0A=20=09=09=09=09{=0A=20=09=09=09=09=09if=20= (detached_xmin)=0A=20=09=09=09=09=09{=0Adiff=20--git=20= a/src/backend/commands/async.c=20b/src/backend/commands/async.c=0Aindex=20= 1ffb6f5fa70..037ca6c5444=20100644=0A---=20a/src/backend/commands/async.c=0A= +++=20b/src/backend/commands/async.c=0A@@=20-2043,7=20+2043,7=20@@=20= asyncQueueProcessPageEntries(volatile=20QueuePosition=20*current,=0A=20=09= =09/*=20Ignore=20messages=20destined=20for=20other=20databases=20*/=0A=20= =09=09if=20(qe->dboid=20=3D=3D=20MyDatabaseId)=0A=20=09=09{=0A-=09=09=09= if=20(XidInMVCCSnapshot(qe->xid,=20(MVCCSnapshot)=20snapshot))=0A+=09=09=09= if=20(XidInMVCCSnapshot(qe->xid,=20((MVCCSnapshot)=20snapshot)->shared))=0A= =20=09=09=09{=0A=20=09=09=09=09/*=0A=20=09=09=09=09=20*=20The=20source=20= transaction=20is=20still=20in=20progress,=20so=20we=20can't=0Adiff=20= --git=20a/src/backend/commands/indexcmds.c=20= b/src/backend/commands/indexcmds.c=0Aindex=20da3e02398bb..7fa044f6f1c=20= 100644=0A---=20a/src/backend/commands/indexcmds.c=0A+++=20= b/src/backend/commands/indexcmds.c=0A@@=20-1761,7=20+1761,7=20@@=20= DefineIndex(Oid=20tableId,=0A=20=09=20*=20they=20must=20wait=20for.=20=20= But=20first,=20save=20the=20snapshot's=20xmin=20to=20use=20as=0A=20=09=20= *=20limitXmin=20for=20GetCurrentVirtualXIDs().=0A=20=09=20*/=0A-=09= limitXmin=20=3D=20snapshot->mvcc.xmin;=0A+=09limitXmin=20=3D=20= snapshot->mvcc.shared->xmin;=0A=20=0A=20=09PopActiveSnapshot();=0A=20=09= UnregisterSnapshot(snapshot);=0A@@=20-4156,7=20+4156,7=20@@=20= ReindexRelationConcurrently(const=20ReindexStmt=20*stmt,=20Oid=20= relationOid,=20const=20Rein=0A=20=09=09=20*=20We=20can=20now=20do=20away=20= with=20our=20active=20snapshot,=20we=20still=20need=20to=20save=0A=20=09=09= =20*=20the=20xmin=20limit=20to=20wait=20for=20older=20snapshots.=0A=20=09= =09=20*/=0A-=09=09limitXmin=20=3D=20snapshot->mvcc.xmin;=0A+=09=09= limitXmin=20=3D=20snapshot->mvcc.shared->xmin;=0A=20=0A=20=09=09= PopActiveSnapshot();=0A=20=09=09UnregisterSnapshot(snapshot);=0Adiff=20= --git=20a/src/backend/commands/tablecmds.c=20= b/src/backend/commands/tablecmds.c=0Aindex=20c55b5a7a014..9aca810f9d5=20= 100644=0A---=20a/src/backend/commands/tablecmds.c=0A+++=20= b/src/backend/commands/tablecmds.c=0A@@=20-20797,7=20+20797,7=20@@=20= ATExecDetachPartitionFinalize(Relation=20rel,=20RangeVar=20*name)=0A=20=09= =20*=20all=20such=20queries=20are=20complete=20(otherwise=20we=20would=20= present=20them=20with=20an=0A=20=09=20*=20inconsistent=20view=20of=20= catalogs).=0A=20=09=20*/=0A-=09WaitForOlderSnapshots(snap->mvcc.xmin,=20= false);=0A+=09WaitForOlderSnapshots(snap->mvcc.shared->xmin,=20false);=0A= =20=0A=20=09DetachPartitionFinalize(rel,=20partRel,=20true,=20= InvalidOid);=0A=20=0Adiff=20--git=20a/src/backend/executor/execMain.c=20= b/src/backend/executor/execMain.c=0Aindex=202da848970be..9ee10050873=20= 100644=0A---=20a/src/backend/executor/execMain.c=0A+++=20= b/src/backend/executor/execMain.c=0A@@=20-157,8=20+157,8=20@@=20= standard_ExecutorStart(QueryDesc=20*queryDesc,=20int=20eflags)=0A=20=09= Assert(queryDesc=20!=3D=20NULL);=0A=20=09Assert(queryDesc->estate=20=3D=3D= =20NULL);=0A=20=0A-=09/*=20caller=20must=20ensure=20the=20query's=20= snapshot=20is=20active=20*/=0A-=09Assert(GetActiveSnapshot()=20=3D=3D=20= queryDesc->snapshot);=0A+=09/*=20ensure=20the=20query's=20snapshot=20is=20= active=20*/=0A+=09PushActiveSnapshot(queryDesc->snapshot);=0A=20=0A=20=09= /*=0A=20=09=20*=20If=20the=20transaction=20is=20read-only,=20we=20need=20= to=20check=20if=20any=20writes=20are=0A@@=20-272,6=20+272,8=20@@=20= standard_ExecutorStart(QueryDesc=20*queryDesc,=20int=20eflags)=0A=20=0A=20= =09MemoryContextSwitchTo(oldcontext);=0A=20=0A+=09PopActiveSnapshot();=0A= +=0A=20=09return=20ExecPlanStillValid(queryDesc->estate);=0A=20}=0A=20=0A= @@=20-390,8=20+392,8=20@@=20standard_ExecutorRun(QueryDesc=20*queryDesc,=0A= =20=09Assert(!estate->es_aborted);=0A=20=09= Assert(!(estate->es_top_eflags=20&=20EXEC_FLAG_EXPLAIN_ONLY));=0A=20=0A-=09= /*=20caller=20must=20ensure=20the=20query's=20snapshot=20is=20active=20= */=0A-=09Assert(GetActiveSnapshot()=20=3D=3D=20estate->es_snapshot);=0A+=09= /*=20ensure=20the=20query's=20snapshot=20is=20active=20*/=0A+=09= PushActiveSnapshot(estate->es_snapshot);=0A=20=0A=20=09/*=0A=20=09=20*=20= Switch=20into=20per-query=20memory=20context=0A@@=20-455,6=20+457,8=20@@=20= standard_ExecutorRun(QueryDesc=20*queryDesc,=0A=20=09=09= InstrStopNode(queryDesc->totaltime,=20estate->es_processed);=0A=20=0A=20=09= MemoryContextSwitchTo(oldcontext);=0A+=0A+=09PopActiveSnapshot();=0A=20}=0A= =20=0A=20/*=20= ----------------------------------------------------------------=0Adiff=20= --git=20a/src/backend/executor/execParallel.c=20= b/src/backend/executor/execParallel.c=0Aindex=2039c990ae638..af3f8f28144=20= 100644=0A---=20a/src/backend/executor/execParallel.c=0A+++=20= b/src/backend/executor/execParallel.c=0A@@=20-737,7=20+737,8=20@@=20= ExecInitParallelPlan(PlanState=20*planstate,=20EState=20*estate,=0A=20=09= =20*=20worker,=20which=20uses=20it=20to=20set=20es_snapshot.=20=20Make=20= sure=20we=20don't=20set=0A=20=09=20*=20es_snapshot=20differently=20in=20= the=20child.=0A=20=09=20*/=0A-=09Assert(GetActiveSnapshot()=20=3D=3D=20= estate->es_snapshot);=0A+=09Assert(((MVCCSnapshot)=20= GetActiveSnapshot())->shared=20=3D=3D=20((MVCCSnapshot)=20= estate->es_snapshot)->shared);=0A+=09Assert(((MVCCSnapshot)=20= GetActiveSnapshot())->curcid=20=3D=3D=20((MVCCSnapshot)=20= estate->es_snapshot)->curcid);=0A=20=0A=20=09/*=20Everyone's=20had=20a=20= chance=20to=20ask=20for=20space,=20so=20now=20create=20the=20DSM.=20*/=0A= =20=09InitializeParallelDSM(pcxt);=0Adiff=20--git=20= a/src/backend/partitioning/partdesc.c=20= b/src/backend/partitioning/partdesc.c=0Aindex=207c15c634181..c5000b37b87=20= 100644=0A---=20a/src/backend/partitioning/partdesc.c=0A+++=20= b/src/backend/partitioning/partdesc.c=0A@@=20-102,7=20+102,7=20@@=20= RelationGetPartitionDesc(Relation=20rel,=20bool=20omit_detached)=0A=20=09= =09Assert(TransactionIdIsValid(rel->rd_partdesc_nodetached_xmin));=0A=20=09= =09activesnap=20=3D=20GetActiveSnapshot();=0A=20=0A-=09=09if=20= (!XidInMVCCSnapshot(rel->rd_partdesc_nodetached_xmin,=20= &activesnap->mvcc))=0A+=09=09if=20= (!XidInMVCCSnapshot(rel->rd_partdesc_nodetached_xmin,=20= activesnap->mvcc.shared))=0A=20=09=09=09return=20= rel->rd_partdesc_nodetached;=0A=20=09}=0A=20=0Adiff=20--git=20= a/src/backend/replication/logical/snapbuild.c=20= b/src/backend/replication/logical/snapbuild.c=0Aindex=20= 50dca7cb758..3c94a62cdf6=20100644=0A---=20= a/src/backend/replication/logical/snapbuild.c=0A+++=20= b/src/backend/replication/logical/snapbuild.c=0A@@=20-389,6=20+389,12=20= @@=20SnapBuildBuildSnapshot(SnapBuild=20*builder)=0A=20=20*=0A=20=20*=20= The=20snapshot=20will=20be=20usable=20directly=20in=20current=20= transaction=20or=20exported=0A=20=20*=20for=20loading=20in=20different=20= transaction.=0A+=20*=0A+=20*=20XXX:=20The=20snapshot=20manager=20doesn't=20= know=20anything=20about=20the=20returned=0A+=20*=20snapshot.=20=20It=20= does=20not=20hold=20back=20MyProc->xmin,=20nor=20is=20it=20registered=20= with=0A+=20*=20any=20resource=20owner.=20=20There's=20also=20no=20good=20= way=20to=20free=20it,=20but=20leaking=20it=20is=0A+=20*=20acceptable=20= for=20the=20current=20usage=20where=20only=20one=20snapshot=20is=20build=20= for=20the=0A+=20*=20whole=20session.=0A=20=20*/=0A=20MVCCSnapshot=0A=20= SnapBuildInitialSnapshot(SnapBuild=20*builder)=0A@@=20-440,11=20+446,14=20= @@=20SnapBuildInitialSnapshot(SnapBuild=20*builder)=0A=20=09MyProc->xmin=20= =3D=20historicsnap->xmin;=0A=20=0A=20=09/*=20allocate=20in=20transaction=20= context=20*/=0A-=09mvccsnap=20=3D=20palloc(sizeof(MVCCSnapshotData)=20+=20= sizeof(TransactionId)=20*=20GetMaxSnapshotXidCount());=0A+=09mvccsnap=20= =3D=20palloc(sizeof(MVCCSnapshotData));=0A+=09mvccsnap->kind=20=3D=20= SNAPSHOT_STATIC;=0A+=09mvccsnap->shared=20=3D=20= AllocMVCCSnapshotShared();=0A+=09mvccsnap->shared->refcount=20=3D=201;=0A= =20=09mvccsnap->snapshot_type=20=3D=20SNAPSHOT_MVCC;=0A-=09= mvccsnap->xmin=20=3D=20historicsnap->xmin;=0A-=09mvccsnap->xmax=20=3D=20= historicsnap->xmax;=0A-=09mvccsnap->xip=20=3D=20(TransactionId=20*)=20= ((char=20*)=20mvccsnap=20+=20sizeof(MVCCSnapshotData));=0A+=09= mvccsnap->shared->xmin=20=3D=20historicsnap->xmin;=0A+=09= mvccsnap->shared->xmax=20=3D=20historicsnap->xmax;=0A+=09= mvccsnap->shared->xip=20=3D=20(TransactionId=20*)=20((char=20*)=20= mvccsnap->shared=20+=20sizeof(MVCCSnapshotData));=0A=20=0A=20=09/*=0A=20=09= =20*=20snapbuild.c=20builds=20transactions=20in=20an=20"inverted"=20= manner,=20which=20means=20it=0A@@=20-470,23=20+479,20=20@@=20= SnapBuildInitialSnapshot(SnapBuild=20*builder)=0A=20=09=09=09=09=09=09= (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),=0A=20=09=09=09=09=09=09=20= errmsg("initial=20slot=20snapshot=20too=20large")));=0A=20=0A-=09=09=09= mvccsnap->xip[newxcnt++]=20=3D=20xid;=0A+=09=09=09= mvccsnap->shared->xip[newxcnt++]=20=3D=20xid;=0A=20=09=09}=0A=20=0A=20=09= =09TransactionIdAdvance(xid);=0A=20=09}=0A-=09mvccsnap->xcnt=20=3D=20= newxcnt;=0A+=09mvccsnap->shared->xcnt=20=3D=20newxcnt;=0A=20=0A=20=09/*=20= Initialize=20remaining=20MVCCSnapshot=20fields=20*/=0A-=09= mvccsnap->subxip=20=3D=20NULL;=0A-=09mvccsnap->subxcnt=20=3D=200;=0A-=09= mvccsnap->suboverflowed=20=3D=20false;=0A-=09= mvccsnap->takenDuringRecovery=20=3D=20false;=0A-=09mvccsnap->copied=20=3D=20= true;=0A+=09mvccsnap->shared->subxip=20=3D=20NULL;=0A+=09= mvccsnap->shared->subxcnt=20=3D=200;=0A+=09= mvccsnap->shared->suboverflowed=20=3D=20false;=0A+=09= mvccsnap->shared->takenDuringRecovery=20=3D=20false;=0A+=09= mvccsnap->shared->snapXactCompletionCount=20=3D=200;=0A=20=09= mvccsnap->curcid=20=3D=20FirstCommandId;=0A-=09mvccsnap->active_count=20= =3D=200;=0A-=09mvccsnap->regd_count=20=3D=200;=0A-=09= mvccsnap->snapXactCompletionCount=20=3D=200;=0A=20=0A=20=09= pfree(historicsnap);=0A=20=0A@@=20-528,13=20+534,13=20@@=20= SnapBuildExportSnapshot(SnapBuild=20*builder)=0A=20=09=20*=20now=20that=20= we've=20built=20a=20plain=20snapshot,=20make=20it=20active=20and=20use=20= the=0A=20=09=20*=20normal=20mechanisms=20for=20exporting=20it=0A=20=09=20= */=0A-=09snapname=20=3D=20ExportSnapshot(snap);=0A+=09snapname=20=3D=20= ExportSnapshot(snap->shared);=0A=20=0A=20=09ereport(LOG,=0A=20=09=09=09= (errmsg_plural("exported=20logical=20decoding=20snapshot:=20\"%s\"=20= with=20%u=20transaction=20ID",=0A=20=09=09=09=09=09=09=20=20=20"exported=20= logical=20decoding=20snapshot:=20\"%s\"=20with=20%u=20transaction=20= IDs",=0A-=09=09=09=09=09=09=20=20=20snap->xcnt,=0A-=09=09=09=09=09=09=20=20= =20snapname,=20snap->xcnt)));=0A+=09=09=09=09=09=09=20=20=20= snap->shared->xcnt,=0A+=09=09=09=09=09=09=20=20=20snapname,=20= snap->shared->xcnt)));=0A=20=09return=20snapname;=0A=20}=0A=20=0Adiff=20= --git=20a/src/backend/replication/walsender.c=20= b/src/backend/replication/walsender.c=0Aindex=201a7a35e25eb..513449ea9de=20= 100644=0A---=20a/src/backend/replication/walsender.c=0A+++=20= b/src/backend/replication/walsender.c=0A@@=20-2620,7=20+2620,7=20@@=20= ProcessStandbyHSFeedbackMessage(void)=0A=20=0A=20=09/*=0A=20=09=20*=20= Set=20the=20WalSender's=20xmin=20equal=20to=20the=20standby's=20= requested=20xmin,=20so=20that=0A-=09=20*=20the=20xmin=20will=20be=20= taken=20into=20account=20by=20GetSnapshotData()=20/=0A+=09=20*=20the=20= xmin=20will=20be=20taken=20into=20account=20by=20GetMVCCSnapshotData()=20= /=0A=20=09=20*=20ComputeXidHorizons().=20=20This=20will=20hold=20back=20= the=20removal=20of=20dead=20rows=20and=0A=20=09=20*=20thereby=20prevent=20= the=20generation=20of=20cleanup=20conflicts=20on=20the=20standby=0A=20=09= =20*=20server.=0Adiff=20--git=20a/src/backend/storage/ipc/procarray.c=20= b/src/backend/storage/ipc/procarray.c=0Aindex=20ba5ed8960dd..819649741f6=20= 100644=0A---=20a/src/backend/storage/ipc/procarray.c=0A+++=20= b/src/backend/storage/ipc/procarray.c=0A@@=20-62,6=20+62,7=20@@=0A=20= #include=20"storage/procarray.h"=0A=20#include=20"utils/acl.h"=0A=20= #include=20"utils/builtins.h"=0A+#include=20"utils/memutils.h"=0A=20= #include=20"utils/rel.h"=0A=20#include=20"utils/snapmgr.h"=0A=20=0A@@=20= -105,7=20+106,7=20@@=20typedef=20struct=20ProcArrayStruct=0A=20=20*=20= MVCC=20semantics:=20If=20the=20deleted=20row's=20xmax=20is=20not=20= considered=20to=20be=20running=0A=20=20*=20by=20anyone,=20the=20row=20= can=20be=20removed.=0A=20=20*=0A-=20*=20To=20avoid=20slowing=20down=20= GetSnapshotData(),=20we=20don't=20calculate=20a=20precise=0A+=20*=20To=20= avoid=20slowing=20down=20GetMVCCSnapshotData(),=20we=20don't=20calculate=20= a=20precise=0A=20=20*=20cutoff=20XID=20while=20building=20a=20snapshot=20= (looking=20at=20the=20frequently=20changing=0A=20=20*=20xmins=20scales=20= badly).=20Instead=20we=20compute=20two=20boundaries=20while=20building=20= the=0A=20=20*=20snapshot:=0A@@=20-159,7=20+160,7=20@@=20typedef=20struct=20= ProcArrayStruct=0A=20=20*=0A=20=20*=20The=20boundaries=20are=20= FullTransactionIds=20instead=20of=20TransactionIds=20to=20avoid=0A=20=20= *=20wraparound=20dangers.=20There=20e.g.=20would=20otherwise=20exist=20= no=20procarray=20state=20to=0A-=20*=20prevent=20maybe_needed=20to=20= become=20old=20enough=20after=20the=20GetSnapshotData()=0A+=20*=20= prevent=20maybe_needed=20to=20become=20old=20enough=20after=20the=20= GetMVCCSnapshotData()=0A=20=20*=20call.=0A=20=20*=0A=20=20*=20The=20= typedef=20is=20in=20the=20header.=0A@@=20-386,7=20+387,7=20@@=20= ProcArrayShmemSize(void)=0A=20=09/*=0A=20=09=20*=20During=20Hot=20= Standby=20processing=20we=20have=20a=20data=20structure=20called=0A=20=09= =20*=20KnownAssignedXids,=20created=20in=20shared=20memory.=20Local=20= data=20structures=20are=0A-=09=20*=20also=20created=20in=20various=20= backends=20during=20GetSnapshotData(),=0A+=09=20*=20also=20created=20in=20= various=20backends=20during=20GetMVCCSnapshotData(),=0A=20=09=20*=20= TransactionIdIsInProgress()=20and=20GetRunningTransactionData().=20All=20= of=20the=0A=20=09=20*=20main=20structures=20created=20in=20those=20= functions=20must=20be=20identically=20sized,=0A=20=09=20*=20since=20we=20= may=20at=20times=20copy=20the=20whole=20of=20the=20data=20structures=20= around.=20We=0A@@=20-938,7=20+939,7=20@@=20= ProcArrayClearTransaction(PGPROC=20*proc)=0A=20=0A=20=09/*=0A=20=09=20*=20= Need=20to=20increment=20completion=20count=20even=20though=20transaction=20= hasn't=0A-=09=20*=20really=20committed=20yet.=20The=20reason=20for=20= that=20is=20that=20GetSnapshotData()=0A+=09=20*=20really=20committed=20= yet.=20The=20reason=20for=20that=20is=20that=20GetMVCCSnapshotData()=0A=20= =09=20*=20omits=20the=20xid=20of=20the=20current=20transaction,=20thus=20= without=20the=20increment=20we=0A=20=09=20*=20otherwise=20could=20end=20= up=20reusing=20the=20snapshot=20later.=20Which=20would=20be=20bad,=0A=20=09= =20*=20because=20it=20might=20not=20count=20the=20prepared=20transaction=20= as=20running.=0A@@=20-2083,7=20+2084,7=20@@=20= GetMaxSnapshotSubxidCount(void)=0A=20}=0A=20=0A=20/*=0A-=20*=20Helper=20= function=20for=20GetSnapshotData()=20that=20checks=20if=20the=20bulk=20= of=20the=0A+=20*=20Helper=20function=20for=20GetMVCCSnapshotData()=20= that=20checks=20if=20the=20bulk=20of=20the=0A=20=20*=20visibility=20= information=20in=20the=20snapshot=20is=20still=20valid.=20If=20so,=20it=20= updates=0A=20=20*=20the=20fields=20that=20need=20to=20change=20and=20= returns=20true.=20Otherwise=20it=20returns=0A=20=20*=20false.=0A@@=20= -2092,7=20+2093,7=20@@=20GetMaxSnapshotSubxidCount(void)=0A=20=20*=20= least=20in=20the=20case=20we=20already=20hold=20a=20snapshot),=20but=20= that's=20for=20another=20day.=0A=20=20*/=0A=20static=20bool=0A= -GetSnapshotDataReuse(MVCCSnapshot=20snapshot)=0A= +GetMVCCSnapshotDataReuse(MVCCSnapshotShared=20snapshot)=0A=20{=0A=20=09= uint64=09=09curXactCompletionCount;=0A=20=0A@@=20-2112,17=20+2113,18=20= @@=20GetSnapshotDataReuse(MVCCSnapshot=20snapshot)=0A=20=09=20*=20= contents:=0A=20=09=20*=0A=20=09=20*=20As=20explained=20in=20= transam/README,=20the=20set=20of=20xids=20considered=20running=20by=0A-=09= =20*=20GetSnapshotData()=20cannot=20change=20while=20ProcArrayLock=20is=20= held.=20Snapshot=0A-=09=20*=20contents=20only=20depend=20on=20= transactions=20with=20xids=20and=20xactCompletionCount=0A-=09=20*=20is=20= incremented=20whenever=20a=20transaction=20with=20an=20xid=20finishes=20= (while=0A-=09=20*=20holding=20ProcArrayLock=20exclusively).=20Thus=20the=20= xactCompletionCount=20check=0A-=09=20*=20ensures=20we=20would=20detect=20= if=20the=20snapshot=20would=20have=20changed.=0A+=09=20*=20= GetMVCCSnapshotData()=20cannot=20change=20while=20ProcArrayLock=20is=20= held.=0A+=09=20*=20Snapshot=20contents=20only=20depend=20on=20= transactions=20with=20xids=20and=0A+=09=20*=20xactCompletionCount=20is=20= incremented=20whenever=20a=20transaction=20with=20an=20xid=0A+=09=20*=20= finishes=20(while=20holding=20ProcArrayLock=20exclusively).=20Thus=20the=0A= +=09=20*=20xactCompletionCount=20check=20ensures=20we=20would=20detect=20= if=20the=20snapshot=20would=0A+=09=20*=20have=20changed.=0A=20=09=20*=0A=20= =09=20*=20As=20the=20snapshot=20contents=20are=20the=20same=20as=20it=20= was=20before,=20it=20is=20safe=20to=0A=20=09=20*=20re-enter=20the=20= snapshot's=20xmin=20into=20the=20PGPROC=20array.=20None=20of=20the=20= rows=0A=20=09=20*=20visible=20under=20the=20snapshot=20could=20already=20= have=20been=20removed=20(that'd=0A=20=09=20*=20require=20the=20set=20of=20= running=20transactions=20to=20change)=20and=20it=20fulfills=20the=0A-=09=20= *=20requirement=20that=20concurrent=20GetSnapshotData()=20calls=20yield=20= the=20same=0A+=09=20*=20requirement=20that=20concurrent=20= GetMVCCSnapshotData()=20calls=20yield=20the=20same=0A=20=09=20*=20xmin.=0A= =20=09=20*/=0A=20=09if=20(!TransactionIdIsValid(MyProc->xmin))=0A@@=20= -2131,17=20+2133,11=20@@=20GetSnapshotDataReuse(MVCCSnapshot=20snapshot)=0A= =20=09RecentXmin=20=3D=20snapshot->xmin;=0A=20=09= Assert(TransactionIdPrecedesOrEquals(TransactionXmin,=20RecentXmin));=0A=20= =0A-=09snapshot->curcid=20=3D=20GetCurrentCommandId(false);=0A-=09= snapshot->active_count=20=3D=200;=0A-=09snapshot->regd_count=20=3D=200;=0A= -=09snapshot->copied=20=3D=20false;=0A-=09snapshot->valid=20=3D=20true;=0A= -=0A=20=09return=20true;=0A=20}=0A=20=0A=20/*=0A-=20*=20GetSnapshotData=20= --=20returns=20information=20about=20running=20transactions.=0A+=20*=20= GetMVCCSnapshotData=20--=20returns=20information=20about=20running=20= transactions.=0A=20=20*=0A=20=20*=20The=20returned=20snapshot=20includes=20= xmin=20(lowest=20still-running=20xact=20ID),=0A=20=20*=20xmax=20(highest=20= completed=20xact=20ID=20+=201),=20and=20a=20list=20of=20running=20xact=20= IDs=0A@@=20-2168,12=20+2164,9=20@@=20GetSnapshotDataReuse(MVCCSnapshot=20= snapshot)=0A=20=20*=0A=20=20*=20And=20try=20to=20advance=20the=20bounds=20= of=20GlobalVis{Shared,Catalog,Data,Temp}Rels=0A=20=20*=20for=20the=20= benefit=20of=20the=20GlobalVisTest*=20family=20of=20functions.=0A-=20*=0A= -=20*=20Note:=20this=20function=20should=20probably=20not=20be=20called=20= with=20an=20argument=20that's=0A-=20*=20not=20statically=20allocated=20= (see=20xip=20allocation=20below).=0A=20=20*/=0A-MVCCSnapshot=0A= -GetSnapshotData(MVCCSnapshot=20snapshot)=0A+MVCCSnapshotShared=0A= +GetMVCCSnapshotData(void)=0A=20{=0A=20=09ProcArrayStruct=20*arrayP=20=3D=20= procArray;=0A=20=09TransactionId=20*other_xids=20=3D=20ProcGlobal->xids;=0A= @@=20-2187,43=20+2180,34=20@@=20GetSnapshotData(MVCCSnapshot=20snapshot)=0A= =20=09int=09=09=09mypgxactoff;=0A=20=09TransactionId=20myxid;=0A=20=09= uint64=09=09curXactCompletionCount;=0A+=09MVCCSnapshotShared=20snapshot;=0A= =20=0A=20=09TransactionId=20replication_slot_xmin=20=3D=20= InvalidTransactionId;=0A=20=09TransactionId=20= replication_slot_catalog_xmin=20=3D=20InvalidTransactionId;=0A=20=0A-=09= Assert(snapshot=20!=3D=20NULL);=0A-=0A-=09/*=0A-=09=20*=20Allocating=20= space=20for=20maxProcs=20xids=20is=20usually=20overkill;=20numProcs=20= would=0A-=09=20*=20be=20sufficient.=20=20But=20it=20seems=20better=20to=20= do=20the=20malloc=20while=20not=20holding=0A-=09=20*=20the=20lock,=20so=20= we=20can't=20look=20at=20numProcs.=20=20Likewise,=20we=20allocate=20much=0A= -=09=20*=20more=20subxip=20storage=20than=20is=20probably=20needed.=0A+=09= /*---=0A+=09=20*=20Allocate=20an=20MVCCSnapshotShared=20struct.=20=20= There=20are=20three=20cases:=0A+=09=20*=0A+=09=20*=201.=20No=20= transactions=20have=20completed=20since=20the=20last=20call:=20we=20can=20= reuse=20the=0A+=09=20*=20=20=20=20latest=20snapshot=20information.=20=20= See=20GetMVCCSnapshotDataReuse().=0A+=09=20*=0A+=09=20*=202.=20Need=20to=20= recalculate=20the=20snapshot,=20and=20'latestSnapshotShared'=20is=20not=0A= +=09=20*=20=20=20=20currently=20in=20use=20by=20any=20snapshot.=20=20We=20= can=20overwrite=20its=20contents.=0A+=09=20*=0A+=09=20*=203.=20Need=20to=20= recalculate=20the=20XID=20list=20and=20'latestSnapshotShared'=20is=20= still=0A+=09=20*=20=20=20=20in=20use.=20=20We=20need=20to=20allocate=20a=20= new=20MVCCSnapshotShared=20struct.=0A=20=09=20*=0A-=09=20*=20This=20does=20= open=20a=20possibility=20for=20avoiding=20repeated=20malloc/free:=20= since=0A-=09=20*=20maxProcs=20does=20not=20change=20at=20runtime,=20we=20= can=20simply=20reuse=20the=20previous=0A-=09=20*=20xip=20arrays=20if=20= any.=20=20(This=20relies=20on=20the=20fact=20that=20all=20callers=20pass=0A= -=09=20*=20static=20SnapshotData=20structs.)=0A+=09=20*=20We=20don't=20= know=20if=20'latestSnapshotShared'=20can=20be=20reused=20before=20we=20= acquire=0A+=09=20*=20the=20lock,=20but=20if=20we=20do=20need=20to=20= allocate,=20we=20want=20to=20do=20it=20before=0A+=09=20*=20acquiring=20= the=20lock.=20=20Therefore,=20we=20always=20make=20the=20allocation=20if=20= we=0A+=09=20*=20might=20need=20it=20and=20if=20it=20turns=20out=20to=20= have=20been=20unnecessary,=20we=20stash=0A+=09=20*=20away=20the=20= allocated=20struct=20in=20'spareSnapshotShared'=20to=20be=20reused=20on=20= next=0A+=09=20*=20call.=20=20This=20way,=20the=20unnecessary=20= allocation=20is=20very=20cheap.=0A=20=09=20*/=0A-=09if=20(snapshot->xip=20= =3D=3D=20NULL)=0A-=09{=0A-=09=09/*=0A-=09=09=20*=20First=20call=20for=20= this=20snapshot.=20Snapshot=20is=20same=20size=20whether=20or=20not=0A-=09= =09=20*=20we=20are=20in=20recovery,=20see=20later=20comments.=0A-=09=09=20= */=0A-=09=09snapshot->xip=20=3D=20(TransactionId=20*)=0A-=09=09=09= malloc(GetMaxSnapshotXidCount()=20*=20sizeof(TransactionId));=0A-=09=09= if=20(snapshot->xip=20=3D=3D=20NULL)=0A-=09=09=09ereport(ERROR,=0A-=09=09= =09=09=09(errcode(ERRCODE_OUT_OF_MEMORY),=0A-=09=09=09=09=09=20= errmsg("out=20of=20memory")));=0A-=09=09Assert(snapshot->subxip=20=3D=3D=20= NULL);=0A-=09=09snapshot->subxip=20=3D=20(TransactionId=20*)=0A-=09=09=09= malloc(GetMaxSnapshotSubxidCount()=20*=20sizeof(TransactionId));=0A-=09=09= if=20(snapshot->subxip=20=3D=3D=20NULL)=0A-=09=09=09ereport(ERROR,=0A-=09= =09=09=09=09(errcode(ERRCODE_OUT_OF_MEMORY),=0A-=09=09=09=09=09=20= errmsg("out=20of=20memory")));=0A-=09}=0A+=09if=20(latestSnapshotShared=20= &&=20latestSnapshotShared->refcount=20=3D=3D=200)=0A+=09=09snapshot=20=3D=20= latestSnapshotShared;=09/*=20case=201=20or=202=20*/=0A+=09else=0A+=09=09= snapshot=20=3D=20AllocMVCCSnapshotShared();=09/*=20case=201=20or=203=20= */=0A=20=0A=20=09/*=0A=20=09=20*=20It=20is=20sufficient=20to=20get=20= shared=20lock=20on=20ProcArrayLock,=20even=20if=20we=20are=0A@@=20= -2231,10=20+2215,14=20@@=20GetSnapshotData(MVCCSnapshot=20snapshot)=0A=20= =09=20*/=0A=20=09LWLockAcquire(ProcArrayLock,=20LW_SHARED);=0A=20=0A-=09= if=20(GetSnapshotDataReuse(snapshot))=0A+=09if=20(latestSnapshotShared=20= &&=20GetMVCCSnapshotDataReuse(latestSnapshotShared))=0A=20=09{=0A=20=09=09= LWLockRelease(ProcArrayLock);=0A-=09=09return=20snapshot;=0A+=0A+=09=09= /*=20if=20we=20made=20an=20allocation,=20stash=20it=20away=20for=20next=20= call=20*/=0A+=09=09if=20(snapshot=20!=3D=20latestSnapshotShared)=0A+=09=09= =09spareSnapshotShared=20=3D=20snapshot;=0A+=09=09return=20= latestSnapshotShared;=0A=20=09}=0A=20=0A=20=09latest_completed=20=3D=20= TransamVariables->latestCompletedXid;=0A@@=20-2506,16=20+2494,18=20@@=20= GetSnapshotData(MVCCSnapshot=20snapshot)=0A=20=09snapshot->suboverflowed=20= =3D=20suboverflowed;=0A=20=09snapshot->snapXactCompletionCount=20=3D=20= curXactCompletionCount;=0A=20=0A-=09snapshot->curcid=20=3D=20= GetCurrentCommandId(false);=0A-=0A=20=09/*=0A-=09=20*=20This=20is=20a=20= new=20snapshot,=20so=20set=20both=20refcounts=20are=20zero,=20and=20mark=20= it=20as=0A-=09=20*=20not=20copied=20in=20persistent=20memory.=0A+=09=20*=20= If=20we=20allocated=20a=20new=20struct=20for=20this,=20remember=20that=20= it=20is=20the=20latest=0A+=09=20*=20now=20and=20adjust=20the=20refcounts=20= accordingly.=0A=20=09=20*/=0A-=09snapshot->active_count=20=3D=200;=0A-=09= snapshot->regd_count=20=3D=200;=0A-=09snapshot->copied=20=3D=20false;=0A= -=09snapshot->valid=20=3D=20true;=0A+=09if=20(snapshot=20!=3D=20= latestSnapshotShared)=0A+=09{=0A+=09=09Assert(snapshot->refcount=20=3D=3D=20= 0);=0A+=0A+=09=09if=20(latestSnapshotShared=20&&=20= latestSnapshotShared->refcount=20=3D=3D=200)=0A+=09=09=09= FreeMVCCSnapshotShared(latestSnapshotShared);=0A+=09=09= latestSnapshotShared=20=3D=20snapshot;=0A+=09}=0A=20=0A=20=09return=20= snapshot;=0A=20}=0A@@=20-2585,10=20+2575,10=20@@=20= ProcArrayInstallImportedXmin(TransactionId=20xmin,=0A=20=09=09=09= continue;=0A=20=0A=20=09=09/*=0A-=09=09=20*=20We're=20good.=20=20Install=20= the=20new=20xmin.=20=20As=20in=20GetSnapshotData,=20set=0A+=09=09=20*=20= We're=20good.=20=20Install=20the=20new=20xmin.=20=20As=20in=20= GetMVCCSnapshotData,=20set=0A=20=09=09=20*=20TransactionXmin=20too.=20=20= (Note=20that=20because=20snapmgr.c=20called=0A-=09=09=20*=20= GetSnapshotData=20first,=20we'll=20be=20overwriting=20a=20valid=20xmin=20= here,=20so=0A-=09=09=20*=20we=20don't=20check=20that.)=0A+=09=09=20*=20= GetMVCCSnapshotData=20first,=20we'll=20be=20overwriting=20a=20valid=20= xmin=20here,=0A+=09=09=20*=20so=20we=20don't=20check=20that.)=0A=20=09=09= =20*/=0A=20=09=09MyProc->xmin=20=3D=20TransactionXmin=20=3D=20xmin;=0A=20= =0A@@=20-2659,7=20+2649,7=20@@=20= ProcArrayInstallRestoredXmin(TransactionId=20xmin,=20PGPROC=20*proc)=0A=20= /*=0A=20=20*=20GetRunningTransactionData=20--=20returns=20information=20= about=20running=20transactions.=0A=20=20*=0A-=20*=20Similar=20to=20= GetSnapshotData=20but=20returns=20more=20information.=20We=20include=0A+=20= *=20Similar=20to=20GetMVCCSnapshotData=20but=20returns=20more=20= information.=20We=20include=0A=20=20*=20all=20PGPROCs=20with=20an=20= assigned=20TransactionId,=20even=20VACUUM=20processes=20and=0A=20=20*=20= prepared=20transactions.=0A=20=20*=0A@@=20-2681,7=20+2671,7=20@@=20= ProcArrayInstallRestoredXmin(TransactionId=20xmin,=20PGPROC=20*proc)=0A=20= =20*=20entries=20here=20to=20not=20hold=20on=20ProcArrayLock=20more=20= than=20necessary.=0A=20=20*=0A=20=20*=20We=20don't=20worry=20about=20= updating=20other=20counters,=20we=20want=20to=20keep=20this=20as=0A-=20*=20= simple=20as=20possible=20and=20leave=20GetSnapshotData()=20as=20the=20= primary=20code=20for=0A+=20*=20simple=20as=20possible=20and=20leave=20= GetMVCCSnapshotData()=20as=20the=20primary=20code=20for=0A=20=20*=20that=20= bookkeeping.=0A=20=20*=0A=20=20*=20Note=20that=20if=20any=20transaction=20= has=20overflowed=20its=20cached=20subtransactions=0A@@=20-2866,8=20= +2856,8=20@@=20GetRunningTransactionData(void)=0A=20/*=0A=20=20*=20= GetOldestActiveTransactionId()=0A=20=20*=0A-=20*=20Similar=20to=20= GetSnapshotData=20but=20returns=20just=20oldestActiveXid.=20We=20include=0A= -=20*=20all=20PGPROCs=20with=20an=20assigned=20TransactionId,=20even=20= VACUUM=20processes.=0A+=20*=20Similar=20to=20GetMVCCSnapshotData=20but=20= returns=20just=20oldestActiveXid.=20We=0A+=20*=20include=20all=20PGPROCs=20= with=20an=20assigned=20TransactionId,=20even=20VACUUM=20processes.=0A=20=20= *=20We=20look=20at=20all=20databases,=20though=20there=20is=20no=20need=20= to=20include=20WALSender=0A=20=20*=20since=20this=20has=20no=20effect=20= on=20hot=20standby=20conflicts.=0A=20=20*=0A@@=20-2875,7=20+2865,7=20@@=20= GetRunningTransactionData(void)=0A=20=20*=20KnownAssignedXids.=0A=20=20*=0A= =20=20*=20We=20don't=20worry=20about=20updating=20other=20counters,=20we=20= want=20to=20keep=20this=20as=0A-=20*=20simple=20as=20possible=20and=20= leave=20GetSnapshotData()=20as=20the=20primary=20code=20for=0A+=20*=20= simple=20as=20possible=20and=20leave=20GetMVCCSnapshotData()=20as=20the=20= primary=20code=20for=0A=20=20*=20that=20bookkeeping.=0A=20=20*/=0A=20= TransactionId=0A@@=20-4356,7=20+4346,7=20@@=20= FullXidRelativeTo(FullTransactionId=20rel,=20TransactionId=20xid)=0A=20=20= *=20During=20hot=20standby=20we=20do=20not=20fret=20too=20much=20about=20= the=20distinction=20between=0A=20=20*=20top-level=20XIDs=20and=20= subtransaction=20XIDs.=20We=20store=20both=20together=20in=20the=0A=20=20= *=20KnownAssignedXids=20list.=20=20In=20backends,=20this=20is=20copied=20= into=20snapshots=20in=0A-=20*=20GetSnapshotData(),=20taking=20advantage=20= of=20the=20fact=20that=20XidInMVCCSnapshot()=0A+=20*=20= GetMVCCSnapshotData(),=20taking=20advantage=20of=20the=20fact=20that=20= XidInMVCCSnapshot()=0A=20=20*=20doesn't=20care=20about=20the=20= distinction=20either.=20=20Subtransaction=20XIDs=20are=0A=20=20*=20= effectively=20treated=20as=20top-level=20XIDs=20and=20in=20the=20typical=20= case=20pg_subtrans=0A=20=20*=20links=20are=20*not*=20maintained=20(which=20= does=20not=20affect=20visibility).=0Adiff=20--git=20= a/src/backend/storage/lmgr/predicate.c=20= b/src/backend/storage/lmgr/predicate.c=0Aindex=20= dd52782ff22..edc6b9de7ca=20100644=0A---=20= a/src/backend/storage/lmgr/predicate.c=0A+++=20= b/src/backend/storage/lmgr/predicate.c=0A@@=20-449,10=20+449,10=20@@=20= static=20void=20SerialSetActiveSerXmin(TransactionId=20xid);=0A=20=0A=20= static=20uint32=20predicatelock_hash(const=20void=20*key,=20Size=20= keysize);=0A=20static=20void=20SummarizeOldestCommittedSxact(void);=0A= -static=20MVCCSnapshot=20GetSafeSnapshot(MVCCSnapshot=20origSnapshot);=0A= -static=20MVCCSnapshot=20= GetSerializableTransactionSnapshotInt(MVCCSnapshot=20snapshot,=0A-=09=09=09= =09=09=09=09=09=09=09=09=09=09=09=20=20VirtualTransactionId=20= *sourcevxid,=0A-=09=09=09=09=09=09=09=09=09=09=09=09=09=09=20=20int=20= sourcepid);=0A+static=20MVCCSnapshotShared=20GetSafeSnapshot(void);=0A= +static=20MVCCSnapshotShared=20= GetSerializableTransactionSnapshotInt(VirtualTransactionId=20= *sourcevxid,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09= TransactionId=20sourcexmin,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09=09= =09=09int=20sourcepid);=0A=20static=20bool=20PredicateLockExists(const=20= PREDICATELOCKTARGETTAG=20*targettag);=0A=20static=20bool=20= GetParentPredicateLockTag(const=20PREDICATELOCKTARGETTAG=20*tag,=0A=20=09= =09=09=09=09=09=09=09=09=20=20PREDICATELOCKTARGETTAG=20*parent);=0A@@=20= -1542,25=20+1542,20=20@@=20SummarizeOldestCommittedSxact(void)=0A=20=20*=0A= =20=20*=09=09As=20with=20GetSerializableTransactionSnapshot=20(which=20= this=20is=20a=20subroutine=0A=20=20*=09=09for),=20the=20passed-in=20= Snapshot=20pointer=20should=20reference=20a=20static=20data=0A-=20*=09=09= area=20that=20can=20safely=20be=20passed=20to=20GetSnapshotData.=0A+=20*=09= =09area=20that=20can=20safely=20be=20passed=20to=20GetMVCCSnapshotData.=0A= =20=20*/=0A-static=20MVCCSnapshot=0A-GetSafeSnapshot(MVCCSnapshot=20= origSnapshot)=0A+static=20MVCCSnapshotShared=0A+GetSafeSnapshot(void)=0A=20= {=0A-=09MVCCSnapshot=20snapshot;=0A+=09MVCCSnapshotShared=20snapshot;=0A=20= =0A=20=09Assert(XactReadOnly=20&&=20XactDeferrable);=0A=20=0A=20=09while=20= (true)=0A=20=09{=0A-=09=09/*=0A-=09=09=20*=20= GetSerializableTransactionSnapshotInt=20is=20going=20to=20call=0A-=09=09=20= *=20GetSnapshotData,=20so=20we=20need=20to=20provide=20it=20the=20static=20= snapshot=20area=0A-=09=09=20*=20our=20caller=20passed=20to=20us.=20=20= The=20pointer=20returned=20is=20actually=20the=20same=0A-=09=09=20*=20= one=20passed=20to=20it,=20but=20we=20avoid=20assuming=20that=20here.=0A-=09= =09=20*/=0A-=09=09snapshot=20=3D=20= GetSerializableTransactionSnapshotInt(origSnapshot,=0A-=09=09=09=09=09=09= =09=09=09=09=09=09=09=09=20NULL,=20InvalidPid);=0A+=09=09snapshot=20=3D=20= GetSerializableTransactionSnapshotInt(NULL,=0A+=09=09=09=09=09=09=09=09=09= =09=09=09=09=09=20InvalidTransactionId,=0A+=09=09=09=09=09=09=09=09=09=09= =09=09=09=09=20InvalidPid);=0A=20=0A=20=09=09if=20(MySerializableXact=20= =3D=3D=20InvalidSerializableXact)=0A=20=09=09=09return=20snapshot;=09/*=20= no=20concurrent=20r/w=20xacts;=20it's=20safe=20*/=0A@@=20-1663,13=20= +1658,11=20@@=20GetSafeSnapshotBlockingPids(int=20blocked_pid,=20int=20= *output,=20int=20output_size)=0A=20=20*=20Make=20sure=20we=20have=20a=20= SERIALIZABLEXACT=20reference=20in=20MySerializableXact.=0A=20=20*=20It=20= should=20be=20current=20for=20this=20process=20and=20be=20contained=20in=20= PredXact.=0A=20=20*=0A-=20*=20The=20passed-in=20Snapshot=20pointer=20= should=20reference=20a=20static=20data=20area=20that=0A-=20*=20can=20= safely=20be=20passed=20to=20GetSnapshotData.=20=20The=20return=20value=20= is=20actually=0A-=20*=20always=20this=20same=20pointer;=20no=20new=20= snapshot=20data=20structure=20is=20allocated=0A-=20*=20within=20this=20= function.=0A+=20*=20This=20calls=20GetMVCCSnapshotData=20to=20do=20the=20= heavy=20lifting,=20but=20also=20sets=20up=0A+=20*=20shared=20memory=20= data=20structures=20specific=20to=20serializable=20transactions.=0A=20=20= */=0A-MVCCSnapshot=0A-GetSerializableTransactionSnapshot(MVCCSnapshot=20= snapshot)=0A+MVCCSnapshotShared=0A= +GetSerializableTransactionSnapshotData(void)=0A=20{=0A=20=09= Assert(IsolationIsSerializable());=0A=20=0A@@=20-1692,26=20+1685,25=20@@=20= GetSerializableTransactionSnapshot(MVCCSnapshot=20snapshot)=0A=20=09=20*=20= thereby=20avoid=20all=20SSI=20overhead=20once=20it's=20running.=0A=20=09=20= */=0A=20=09if=20(XactReadOnly=20&&=20XactDeferrable)=0A-=09=09return=20= GetSafeSnapshot(snapshot);=0A+=09=09return=20GetSafeSnapshot();=0A=20=0A= -=09return=20GetSerializableTransactionSnapshotInt(snapshot,=0A-=09=09=09= =09=09=09=09=09=09=09=09=09=20NULL,=20InvalidPid);=0A+=09return=20= GetSerializableTransactionSnapshotInt(NULL,=20InvalidTransactionId,=20= InvalidPid);=0A=20}=0A=20=0A=20/*=0A=20=20*=20Import=20a=20snapshot=20to=20= be=20used=20for=20the=20current=20transaction.=0A=20=20*=0A-=20*=20This=20= is=20nearly=20the=20same=20as=20GetSerializableTransactionSnapshot,=20= except=20that=0A-=20*=20we=20don't=20take=20a=20new=20snapshot,=20but=20= rather=20use=20the=20data=20we're=20handed.=0A+=20*=20This=20is=20nearly=20= the=20same=20as=20GetSerializableTransactionSnapshotData,=20except=0A+=20= *=20that=20we=20don't=20take=20a=20new=20snapshot,=20but=20rather=20use=20= the=20data=20we're=20handed.=0A=20=20*=0A=20=20*=20The=20caller=20must=20= have=20verified=20that=20the=20snapshot=20came=20from=20a=20serializable=0A= =20=20*=20transaction;=20and=20if=20we're=20read-write,=20the=20source=20= transaction=20must=20not=20be=0A=20=20*=20read-only.=0A=20=20*/=0A=20= void=0A-SetSerializableTransactionSnapshot(MVCCSnapshot=20snapshot,=0A-=09= =09=09=09=09=09=09=09=20=20=20VirtualTransactionId=20*sourcevxid,=0A-=09=09= =09=09=09=09=09=09=20=20=20int=20sourcepid)=0A= +SetSerializableTransactionSnapshotData(MVCCSnapshotShared=20snapshot,=0A= +=09=09=09=09=09=09=09=09=09=20=20=20VirtualTransactionId=20*sourcevxid,=0A= +=09=09=09=09=09=09=09=09=09=20=20=20int=20sourcepid)=0A=20{=0A=20=09= Assert(IsolationIsSerializable());=0A=20=0A@@=20-1737,28=20+1729,29=20@@=20= SetSerializableTransactionSnapshot(MVCCSnapshot=20snapshot,=0A=20=09=09=09= =09(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),=0A=20=09=09=09=09=20= errmsg("a=20snapshot-importing=20transaction=20must=20not=20be=20READ=20= ONLY=20DEFERRABLE")));=0A=20=0A-=09(void)=20= GetSerializableTransactionSnapshotInt(snapshot,=20sourcevxid,=0A-=09=09=09= =09=09=09=09=09=09=09=09=09=20sourcepid);=0A+=09(void)=20= GetSerializableTransactionSnapshotInt(sourcevxid,=20snapshot->xmin,=20= sourcepid);=0A=20}=0A=20=0A=20/*=0A=20=20*=20Guts=20of=20= GetSerializableTransactionSnapshot=0A=20=20*=0A=20=20*=20If=20sourcevxid=20= is=20valid,=20this=20is=20actually=20an=20import=20operation=20and=20we=20= should=0A-=20*=20skip=20calling=20GetSnapshotData,=20because=20the=20= snapshot=20contents=20are=20already=0A+=20*=20skip=20calling=20= GetMVCCSnapshotData,=20because=20the=20snapshot=20contents=20are=20= already=0A=20=20*=20loaded=20up.=20=20HOWEVER:=20to=20avoid=20race=20= conditions,=20we=20must=20check=20that=20the=0A=20=20*=20source=20xact=20= is=20still=20running=20after=20we=20acquire=20SerializableXactHashLock.=0A= =20=20*=20We=20do=20that=20by=20calling=20ProcArrayInstallImportedXmin.=0A= =20=20*/=0A-static=20MVCCSnapshot=0A= -GetSerializableTransactionSnapshotInt(MVCCSnapshot=20snapshot,=0A-=09=09= =09=09=09=09=09=09=09=20=20VirtualTransactionId=20*sourcevxid,=0A+static=20= MVCCSnapshotShared=0A= +GetSerializableTransactionSnapshotInt(VirtualTransactionId=20= *sourcevxid,=0A+=09=09=09=09=09=09=09=09=09=20=20TransactionId=20= sourcexmin,=0A=20=09=09=09=09=09=09=09=09=09=20=20int=20sourcepid)=0A=20= {=0A=20=09PGPROC=09=20=20=20*proc;=0A=20=09VirtualTransactionId=20vxid;=0A= =20=09SERIALIZABLEXACT=20*sxact,=0A=20=09=09=09=20=20=20*othersxact;=0A+=09= MVCCSnapshotShared=20snapshot;=0A+=09TransactionId=20xmin;=0A=20=0A=20=09= /*=20We=20only=20do=20this=20for=20serializable=20transactions.=20=20= Once.=20*/=0A=20=09Assert(MySerializableXact=20=3D=3D=20= InvalidSerializableXact);=0A@@=20-1783,7=20+1776,7=20@@=20= GetSerializableTransactionSnapshotInt(MVCCSnapshot=20snapshot,=0A=20=09=20= *=0A=20=09=20*=20We=20must=20hold=20SerializableXactHashLock=20when=20= taking/checking=20the=20snapshot=0A=20=09=20*=20to=20avoid=20race=20= conditions,=20for=20much=20the=20same=20reasons=20that=0A-=09=20*=20= GetSnapshotData=20takes=20the=20ProcArrayLock.=20=20Since=20we=20might=20= have=20to=0A+=09=20*=20GetMVCCSnapshotData=20takes=20the=20= ProcArrayLock.=20=20Since=20we=20might=20have=20to=0A=20=09=20*=20= release=20SerializableXactHashLock=20to=20call=20= SummarizeOldestCommittedSxact,=0A=20=09=20*=20this=20means=20we=20have=20= to=20create=20the=20sxact=20first,=20which=20is=20a=20bit=20annoying=0A=20= =09=20*=20(in=20particular,=20an=20elog(ERROR)=20in=20procarray.c=20= would=20cause=20us=20to=20leak=0A@@=20-1807,16=20+1800,24=20@@=20= GetSerializableTransactionSnapshotInt(MVCCSnapshot=20snapshot,=0A=20=0A=20= =09/*=20Get=20the=20snapshot,=20or=20check=20that=20it's=20safe=20to=20= use=20*/=0A=20=09if=20(!sourcevxid)=0A-=09=09snapshot=20=3D=20= GetSnapshotData(snapshot);=0A-=09else=20if=20= (!ProcArrayInstallImportedXmin(snapshot->xmin,=20sourcevxid))=0A=20=09{=0A= -=09=09ReleasePredXact(sxact);=0A-=09=09= LWLockRelease(SerializableXactHashLock);=0A-=09=09ereport(ERROR,=0A-=09=09= =09=09(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),=0A-=09=09=09=09= =20errmsg("could=20not=20import=20the=20requested=20snapshot"),=0A-=09=09= =09=09=20errdetail("The=20source=20process=20with=20PID=20%d=20is=20not=20= running=20anymore.",=0A-=09=09=09=09=09=09=20=20=20sourcepid)));=0A+=09=09= snapshot=20=3D=20GetMVCCSnapshotData();=0A+=09=09xmin=20=3D=20= snapshot->xmin;=0A+=09}=0A+=09else=0A+=09{=0A+=09=09if=20= (!ProcArrayInstallImportedXmin(sourcexmin,=20sourcevxid))=0A+=09=09{=0A+=09= =09=09ReleasePredXact(sxact);=0A+=09=09=09= LWLockRelease(SerializableXactHashLock);=0A+=09=09=09ereport(ERROR,=0A+=09= =09=09=09=09(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),=0A+=09=09= =09=09=09=20errmsg("could=20not=20import=20the=20requested=20snapshot"),=0A= +=09=09=09=09=09=20errdetail("The=20source=20process=20with=20PID=20%d=20= is=20not=20running=20anymore.",=0A+=09=09=09=09=09=09=09=20=20=20= sourcepid)));=0A+=09=09}=0A+=09=09snapshot=20=3D=20NULL;=0A+=09=09xmin=20= =3D=20sourcexmin;=0A=20=09}=0A=20=0A=20=09/*=0A@@=20-1848,7=20+1849,7=20= @@=20GetSerializableTransactionSnapshotInt(MVCCSnapshot=20snapshot,=0A=20= =09dlist_init(&(sxact->possibleUnsafeConflicts));=0A=20=09sxact->topXid=20= =3D=20GetTopTransactionIdIfAny();=0A=20=09sxact->finishedBefore=20=3D=20= InvalidTransactionId;=0A-=09sxact->xmin=20=3D=20snapshot->xmin;=0A+=09= sxact->xmin=20=3D=20xmin;=0A=20=09sxact->pid=20=3D=20MyProcPid;=0A=20=09= sxact->pgprocno=20=3D=20MyProcNumber;=0A=20=09= dlist_init(&sxact->predicateLocks);=0A@@=20-1902,18=20+1903,18=20@@=20= GetSerializableTransactionSnapshotInt(MVCCSnapshot=20snapshot,=0A=20=09= if=20(!TransactionIdIsValid(PredXact->SxactGlobalXmin))=0A=20=09{=0A=20=09= =09Assert(PredXact->SxactGlobalXminCount=20=3D=3D=200);=0A-=09=09= PredXact->SxactGlobalXmin=20=3D=20snapshot->xmin;=0A+=09=09= PredXact->SxactGlobalXmin=20=3D=20xmin;=0A=20=09=09= PredXact->SxactGlobalXminCount=20=3D=201;=0A-=09=09= SerialSetActiveSerXmin(snapshot->xmin);=0A+=09=09= SerialSetActiveSerXmin(xmin);=0A=20=09}=0A-=09else=20if=20= (TransactionIdEquals(snapshot->xmin,=20PredXact->SxactGlobalXmin))=0A+=09= else=20if=20(TransactionIdEquals(xmin,=20PredXact->SxactGlobalXmin))=0A=20= =09{=0A=20=09=09Assert(PredXact->SxactGlobalXminCount=20>=200);=0A=20=09=09= PredXact->SxactGlobalXminCount++;=0A=20=09}=0A=20=09else=0A=20=09{=0A-=09= =09Assert(TransactionIdFollows(snapshot->xmin,=20= PredXact->SxactGlobalXmin));=0A+=09=09Assert(TransactionIdFollows(xmin,=20= PredXact->SxactGlobalXmin));=0A=20=09}=0A=20=0A=20=09MySerializableXact=20= =3D=20sxact;=0A@@=20-3968,13=20+3969,13=20@@=20= XidIsConcurrent(TransactionId=20xid)=0A=20=0A=20=09snap=20=3D=20= (MVCCSnapshot)=20GetTransactionSnapshot();=0A=20=0A-=09if=20= (TransactionIdPrecedes(xid,=20snap->xmin))=0A+=09if=20= (TransactionIdPrecedes(xid,=20snap->shared->xmin))=0A=20=09=09return=20= false;=0A=20=0A-=09if=20(TransactionIdFollowsOrEquals(xid,=20= snap->xmax))=0A+=09if=20(TransactionIdFollowsOrEquals(xid,=20= snap->shared->xmax))=0A=20=09=09return=20true;=0A=20=0A-=09return=20= pg_lfind32(xid,=20snap->xip,=20snap->xcnt);=0A+=09return=20= pg_lfind32(xid,=20snap->shared->xip,=20snap->shared->xcnt);=0A=20}=0A=20=0A= =20bool=0Adiff=20--git=20a/src/backend/utils/adt/xid8funcs.c=20= b/src/backend/utils/adt/xid8funcs.c=0Aindex=20d4aa8ef9e4e..eef632390cb=20= 100644=0A---=20a/src/backend/utils/adt/xid8funcs.c=0A+++=20= b/src/backend/utils/adt/xid8funcs.c=0A@@=20-380,7=20+380,7=20@@=20= pg_current_snapshot(PG_FUNCTION_ARGS)=0A=20=09=09elog(ERROR,=20"no=20= active=20snapshot=20set");=0A=20=0A=20=09/*=20allocate=20*/=0A-=09nxip=20= =3D=20cur->xcnt;=0A+=09nxip=20=3D=20cur->shared->xcnt;=0A=20=09snap=20=3D=20= palloc(PG_SNAPSHOT_SIZE(nxip));=0A=20=0A=20=09/*=0A@@=20-389,12=20= +389,12=20@@=20pg_current_snapshot(PG_FUNCTION_ARGS)=0A=20=09=20*=20= advance=20past=20any=20of=20these=20XIDs.=20=20Hence,=20these=20XIDs=20= remain=20allowable=0A=20=09=20*=20relative=20to=20next_fxid.=0A=20=09=20= */=0A-=09snap->xmin=20=3D=20FullTransactionIdFromAllowableAt(next_fxid,=20= cur->xmin);=0A-=09snap->xmax=20=3D=20= FullTransactionIdFromAllowableAt(next_fxid,=20cur->xmax);=0A+=09= snap->xmin=20=3D=20FullTransactionIdFromAllowableAt(next_fxid,=20= cur->shared->xmin);=0A+=09snap->xmax=20=3D=20= FullTransactionIdFromAllowableAt(next_fxid,=20cur->shared->xmax);=0A=20=09= snap->nxip=20=3D=20nxip;=0A=20=09for=20(i=20=3D=200;=20i=20<=20nxip;=20= i++)=0A=20=09=09snap->xip[i]=20=3D=0A-=09=09=09= FullTransactionIdFromAllowableAt(next_fxid,=20cur->xip[i]);=0A+=09=09=09= FullTransactionIdFromAllowableAt(next_fxid,=20cur->shared->xip[i]);=0A=20= =0A=20=09/*=0A=20=09=20*=20We=20want=20them=20guaranteed=20to=20be=20in=20= ascending=20order.=20=20This=20also=20removes=0Adiff=20--git=20= a/src/backend/utils/time/snapmgr.c=20b/src/backend/utils/time/snapmgr.c=0A= index=201c39cc11609..5f9f2b9d8b2=20100644=0A---=20= a/src/backend/utils/time/snapmgr.c=0A+++=20= b/src/backend/utils/time/snapmgr.c=0A@@=20-122,9=20+122,6=20@@=0A=20=20*=20= special-purpose=20code=20(say,=20RI=20checking.)=20=20CatalogSnapshot=20= points=20to=20an=0A=20=20*=20MVCC=20snapshot=20intended=20to=20be=20used=20= for=20catalog=20scans;=20we=20must=20invalidate=20it=0A=20=20*=20= whenever=20a=20system=20catalog=20change=20occurs.=0A-=20*=0A-=20*=20= These=20SnapshotData=20structs=20are=20static=20to=20simplify=20memory=20= allocation=0A-=20*=20(see=20the=20hack=20in=20GetSnapshotData=20to=20= avoid=20repeated=20malloc/free).=0A=20=20*/=0A=20static=20= MVCCSnapshotData=20CurrentSnapshotData=20=3D=20{SNAPSHOT_MVCC};=0A=20= static=20MVCCSnapshotData=20SecondarySnapshotData=20=3D=20= {SNAPSHOT_MVCC};=0A@@=20-137,7=20+134,7=20@@=20SnapshotData=20= SnapshotToastData=20=3D=20{SNAPSHOT_TOAST};=0A=20static=20= HistoricMVCCSnapshot=20HistoricSnapshot=20=3D=20NULL;=0A=20=0A=20/*=0A-=20= *=20These=20are=20updated=20by=20GetSnapshotData.=20=20We=20initialize=20= them=20this=20way=0A+=20*=20These=20are=20updated=20by=20= GetMVCCSnapshotData.=20=20We=20initialize=20them=20this=20way=0A=20=20*=20= for=20the=20convenience=20of=20TransactionIdIsInProgress:=20even=20in=20= bootstrap=0A=20=20*=20mode,=20we=20don't=20want=20it=20to=20say=20that=20= BootstrapTransactionId=20is=20in=20progress.=0A=20=20*/=0A@@=20-150,14=20= +147,12=20@@=20static=20HTAB=20*tuplecid_data=20=3D=20NULL;=0A=20/*=0A=20= =20*=20Elements=20of=20the=20active=20snapshot=20stack.=0A=20=20*=0A-=20= *=20Each=20element=20here=20accounts=20for=20exactly=20one=20= active_count=20on=20SnapshotData.=0A-=20*=0A=20=20*=20NB:=20the=20code=20= assumes=20that=20elements=20in=20this=20list=20are=20in=20non-increasing=0A= =20=20*=20order=20of=20as_level;=20also,=20the=20list=20must=20be=20= NULL-terminated.=0A=20=20*/=0A=20typedef=20struct=20ActiveSnapshotElt=0A=20= {=0A-=09MVCCSnapshot=20as_snap;=0A+=09MVCCSnapshotData=20as_snap;=0A=20=09= int=09=09=09as_level;=0A=20=09struct=20ActiveSnapshotElt=20*as_next;=0A=20= }=20ActiveSnapshotElt;=0A@@=20-188,19=20+183,23=20@@=20static=20bool=20= FirstXactSnapshotRegistered=20=3D=20false;=0A=20typedef=20struct=20= ExportedSnapshot=0A=20{=0A=20=09char=09=20=20=20*snapfile;=0A-=09= MVCCSnapshot=20snapshot;=0A+=09MVCCSnapshotShared=20snapshot;=0A=20}=20= ExportedSnapshot;=0A=20=0A=20/*=20Current=20xact's=20exported=20= snapshots=20(a=20list=20of=20ExportedSnapshot=20structs)=20*/=0A=20= static=20List=20*exportedSnapshots=20=3D=20NIL;=0A=20=0A= +MVCCSnapshotShared=20latestSnapshotShared=20=3D=20NULL;=0A= +MVCCSnapshotShared=20spareSnapshotShared=20=3D=20NULL;=0A+=0A=20/*=20= Prototypes=20for=20local=20functions=20*/=0A-static=20MVCCSnapshot=20= CopyMVCCSnapshot(MVCCSnapshot=20snapshot);=0A+static=20void=20= UpdateStaticMVCCSnapshot(MVCCSnapshot=20snapshot,=20MVCCSnapshotShared=20= shared);=0A=20static=20void=20UnregisterSnapshotNoOwner(Snapshot=20= snapshot);=0A-static=20void=20FreeMVCCSnapshot(MVCCSnapshot=20snapshot);=0A= =20static=20void=20SnapshotResetXmin(void);=0A-static=20void=20= valid_snapshots_push_tail(MVCCSnapshot=20snapshot);=0A-static=20void=20= valid_snapshots_push_out_of_order(MVCCSnapshot=20snapshot);=0A+static=20= void=20ReleaseMVCCSnapshotShared(MVCCSnapshotShared=20shared);=0A+static=20= void=20valid_snapshots_push_tail(MVCCSnapshotShared=20snapshot);=0A= +static=20void=20valid_snapshots_push_out_of_order(MVCCSnapshotShared=20= snapshot);=0A+=0A=20=0A=20/*=20ResourceOwner=20callbacks=20to=20track=20= snapshot=20references=20*/=0A=20static=20void=20= ResOwnerReleaseSnapshot(Datum=20res);=0A@@=20-266,6=20+265,8=20@@=20= GetTransactionSnapshot(void)=0A=20=09/*=20First=20call=20in=20= transaction?=20*/=0A=20=09if=20(!FirstSnapshotSet)=0A=20=09{=0A+=09=09= MVCCSnapshotShared=20shared;=0A+=0A=20=09=09/*=0A=20=09=09=20*=20Don't=20= allow=20catalog=20snapshot=20to=20be=20older=20than=20xact=20snapshot.=20= =20Must=0A=20=09=09=20*=20do=20this=20first=20to=20allow=20the=20= empty-heap=20Assert=20to=20succeed.=0A@@=20-287,23=20+288,18=20@@=20= GetTransactionSnapshot(void)=0A=20=09=09=20*=20mode,=20predicate.c=20= needs=20to=20wrap=20the=20snapshot=20fetch=20in=20its=20own=0A=20=09=09=20= *=20processing.=0A=20=09=09=20*/=0A+=09=09if=20= (IsolationIsSerializable())=0A+=09=09=09shared=20=3D=20= GetSerializableTransactionSnapshotData();=0A+=09=09else=0A+=09=09=09= shared=20=3D=20GetMVCCSnapshotData();=0A+=0A+=09=09= UpdateStaticMVCCSnapshot(&CurrentSnapshotData,=20shared);=0A+=0A=20=09=09= if=20(IsolationUsesXactSnapshot())=0A=20=09=09{=0A-=09=09=09/*=20First,=20= create=20the=20snapshot=20in=20CurrentSnapshotData=20*/=0A-=09=09=09if=20= (IsolationIsSerializable())=0A-=09=09=09=09= GetSerializableTransactionSnapshot(&CurrentSnapshotData);=0A-=09=09=09= else=0A-=09=09=09=09GetSnapshotData(&CurrentSnapshotData);=0A-=0A-=09=09=09= /*=20Mark=20it=20as=20"registered"=20*/=0A+=09=09=09/*=20keep=20it=20*/=0A= =20=09=09=09FirstXactSnapshotRegistered=20=3D=20true;=0A=20=09=09}=0A-=09= =09else=0A-=09=09{=0A-=09=09=09GetSnapshotData(&CurrentSnapshotData);=0A= -=09=09}=0A-=09=09valid_snapshots_push_tail(&CurrentSnapshotData);=0A-=0A= =20=09=09FirstSnapshotSet=20=3D=20true;=0A=20=09=09return=20(Snapshot)=20= &CurrentSnapshotData;=0A=20=09}=0A@@=20-318,14=20+314,31=20@@=20= GetTransactionSnapshot(void)=0A=20=09/*=20Don't=20allow=20catalog=20= snapshot=20to=20be=20older=20than=20xact=20snapshot.=20*/=0A=20=09= InvalidateCatalogSnapshot();=0A=20=0A-=09if=20= (CurrentSnapshotData.valid)=0A-=09=09= dlist_delete(&CurrentSnapshotData.node);=0A-=09= GetSnapshotData(&CurrentSnapshotData);=0A-=09= valid_snapshots_push_tail(&CurrentSnapshotData);=0A-=0A+=09= UpdateStaticMVCCSnapshot(&CurrentSnapshotData,=20GetMVCCSnapshotData());=0A= =20=09return=20(Snapshot)=20&CurrentSnapshotData;=0A=20}=0A=20=0A+/*=0A+=20= *=20Update=20a=20static=20snapshot=20with=20the=20given=20shared=20= struct.=0A+=20*=0A+=20*=20If=20the=20static=20snapshot=20is=20previously=20= valid,=20release=20its=20old=20'shared'=0A+=20*=20struct=20first.=0A+=20= */=0A+static=20void=0A+UpdateStaticMVCCSnapshot(MVCCSnapshot=20snapshot,=20= MVCCSnapshotShared=20shared)=0A+{=0A+=09/*=20Replace=20the=20'shared'=20= struct=20*/=0A+=09if=20(snapshot->shared)=0A+=09=09= ReleaseMVCCSnapshotShared(snapshot->shared);=0A+=09snapshot->shared=20=3D=20= shared;=0A+=09snapshot->shared->refcount++;=0A+=09if=20= (snapshot->shared->refcount=20=3D=3D=201)=0A+=09=09= valid_snapshots_push_tail(shared);=0A+=0A+=09snapshot->curcid=20=3D=20= GetCurrentCommandId(false);=0A+=09snapshot->valid=20=3D=20true;=0A+}=0A+=0A= =20/*=0A=20=20*=20GetLatestSnapshot=0A=20=20*=09=09Get=20a=20snapshot=20= that=20is=20up-to-date=20as=20of=20the=20current=20instant,=0A@@=20= -352,10=20+365,7=20@@=20GetLatestSnapshot(void)=0A=20=09if=20= (!FirstSnapshotSet)=0A=20=09=09return=20GetTransactionSnapshot();=0A=20=0A= -=09if=20(SecondarySnapshotData.valid)=0A-=09=09= dlist_delete(&SecondarySnapshotData.node);=0A-=09= GetSnapshotData(&SecondarySnapshotData);=0A-=09= valid_snapshots_push_tail(&SecondarySnapshotData);=0A+=09= UpdateStaticMVCCSnapshot(&SecondarySnapshotData,=20= GetMVCCSnapshotData());=0A=20=0A=20=09return=20(Snapshot)=20= &SecondarySnapshotData;=0A=20}=0A@@=20-405,7=20+415,7=20@@=20= GetNonHistoricCatalogSnapshot(Oid=20relid)=0A=20=09if=20= (!CatalogSnapshotData.valid)=0A=20=09{=0A=20=09=09/*=20Get=20new=20= snapshot.=20*/=0A-=09=09GetSnapshotData(&CatalogSnapshotData);=0A+=09=09= UpdateStaticMVCCSnapshot(&CatalogSnapshotData,=20GetMVCCSnapshotData());=0A= =20=0A=20=09=09/*=0A=20=09=09=20*=20Make=20sure=20the=20catalog=20= snapshot=20will=20be=20accounted=20for=20in=20decisions=0A@@=20-419,7=20= +429,6=20@@=20GetNonHistoricCatalogSnapshot(Oid=20relid)=0A=20=09=09=20*=20= NB:=20it=20had=20better=20be=20impossible=20for=20this=20to=20throw=20= error,=20since=20the=0A=20=09=09=20*=20CatalogSnapshot=20pointer=20is=20= already=20valid.=0A=20=09=09=20*/=0A-=09=09= valid_snapshots_push_tail(&CatalogSnapshotData);=0A=20=09}=0A=20=0A=20=09= return=20(Snapshot)=20&CatalogSnapshotData;=0A@@=20-440,17=20+449,20=20= @@=20InvalidateCatalogSnapshot(void)=0A=20{=0A=20=09if=20= (CatalogSnapshotData.valid)=0A=20=09{=0A-=09=09= dlist_delete(&CatalogSnapshotData.node);=0A+=09=09= ReleaseMVCCSnapshotShared(CatalogSnapshotData.shared);=0A+=09=09= CatalogSnapshotData.shared=20=3D=20NULL;=0A=20=09=09= CatalogSnapshotData.valid=20=3D=20false;=0A=20=09}=0A=20=09if=20= (!FirstXactSnapshotRegistered=20&&=20CurrentSnapshotData.valid)=0A=20=09= {=0A-=09=09dlist_delete(&CurrentSnapshotData.node);=0A+=09=09= ReleaseMVCCSnapshotShared(CurrentSnapshotData.shared);=0A+=09=09= CurrentSnapshotData.shared=20=3D=20NULL;=0A=20=09=09= CurrentSnapshotData.valid=20=3D=20false;=0A=20=09}=0A=20=09if=20= (SecondarySnapshotData.valid)=0A=20=09{=0A-=09=09= dlist_delete(&SecondarySnapshotData.node);=0A+=09=09= ReleaseMVCCSnapshotShared(SecondarySnapshotData.shared);=0A+=09=09= SecondarySnapshotData.shared=20=3D=20NULL;=0A=20=09=09= SecondarySnapshotData.valid=20=3D=20false;=0A=20=09}=0A=20=0A@@=20= -465,13=20+477,14=20@@=20InvalidateCatalogSnapshot(void)=0A=20=20*=20= want=20to=20continue=20holding=20the=20catalog=20snapshot=20if=20it=20= might=20mean=20that=20the=0A=20=20*=20global=20xmin=20horizon=20can't=20= advance.=20=20However,=20if=20there=20are=20other=20snapshots=0A=20=20*=20= still=20active=20or=20registered,=20the=20catalog=20snapshot=20isn't=20= likely=20to=20be=20the=0A-=20*=20oldest=20one,=20so=20we=20might=20as=20= well=20keep=20it.=0A+=20*=20oldest=20one,=20so=20we=20might=20as=20well=20= keep=20it.=20XXX=0A=20=20*/=0A=20void=0A=20= InvalidateCatalogSnapshotConditionally(void)=0A=20{=0A=20=09if=20= (CatalogSnapshotData.valid=20&&=0A-=09=09= dlist_head_node(&ValidSnapshots)=20=3D=3D=20&CatalogSnapshotData.node)=0A= +=09=09dlist_tail_node(&ValidSnapshots)=20=3D=3D=20= &CatalogSnapshotData.shared->node=20&&=0A+=09=09= CatalogSnapshotData.shared->refcount=20=3D=3D=201)=0A=20=09=09= InvalidateCatalogSnapshot();=0A=20}=0A=20=0A@@=20-501,7=20+514,7=20@@=20= SnapshotSetCommandId(CommandId=20curcid)=0A=20=20*=20in=20= GetTransactionSnapshot.=0A=20=20*/=0A=20static=20void=0A= -SetTransactionSnapshot(MVCCSnapshot=20sourcesnap,=20= VirtualTransactionId=20*sourcevxid,=0A= +SetTransactionSnapshot(MVCCSnapshotShared=20sourcesnap,=20= VirtualTransactionId=20*sourcevxid,=0A=20=09=09=09=09=09=20=20=20int=20= sourcepid,=20PGPROC=20*sourceproc)=0A=20{=0A=20=09/*=20Caller=20should=20= have=20checked=20this=20already=20*/=0A@@=20-512,38=20+525,25=20@@=20= SetTransactionSnapshot(MVCCSnapshot=20sourcesnap,=20VirtualTransactionId=20= *sourcevxid=0A=20=0A=20=09Assert(!FirstXactSnapshotRegistered);=0A=20=09= Assert(!HistoricSnapshotActive());=0A+=09Assert(sourcesnap->refcount=20>=20= 0);=0A=20=0A=20=09/*=0A=20=09=20*=20Even=20though=20we=20are=20not=20= going=20to=20use=20the=20snapshot=20it=20computes,=20we=20must=0A-=09=20= *=20call=20GetSnapshotData,=20for=20two=20reasons:=20(1)=20to=20be=20= sure=20that=0A-=09=20*=20CurrentSnapshotData's=20XID=20arrays=20have=20= been=20allocated,=20and=20(2)=20to=20update=0A-=09=20*=20the=20state=20= for=20GlobalVis*.=0A+=09=20*=20call=20GetMVCCSnapshotData=20to=20update=20= the=20state=20for=20GlobalVis*.=0A=20=09=20*/=0A-=09= GetSnapshotData(&CurrentSnapshotData);=0A+=09= UpdateStaticMVCCSnapshot(&CurrentSnapshotData,=20GetMVCCSnapshotData());=0A= =20=0A=20=09/*=0A=20=09=20*=20Now=20copy=20appropriate=20fields=20from=20= the=20source=20snapshot.=0A=20=09=20*/=0A-=09CurrentSnapshotData.xmin=20= =3D=20sourcesnap->xmin;=0A-=09CurrentSnapshotData.xmax=20=3D=20= sourcesnap->xmax;=0A-=09CurrentSnapshotData.xcnt=20=3D=20= sourcesnap->xcnt;=0A-=09Assert(sourcesnap->xcnt=20<=3D=20= GetMaxSnapshotXidCount());=0A-=09if=20(sourcesnap->xcnt=20>=200)=0A-=09=09= memcpy(CurrentSnapshotData.xip,=20sourcesnap->xip,=0A-=09=09=09=20=20=20= sourcesnap->xcnt=20*=20sizeof(TransactionId));=0A-=09= CurrentSnapshotData.subxcnt=20=3D=20sourcesnap->subxcnt;=0A-=09= Assert(sourcesnap->subxcnt=20<=3D=20GetMaxSnapshotSubxidCount());=0A-=09= if=20(sourcesnap->subxcnt=20>=200)=0A-=09=09= memcpy(CurrentSnapshotData.subxip,=20sourcesnap->subxip,=0A-=09=09=09=20=20= =20sourcesnap->subxcnt=20*=20sizeof(TransactionId));=0A-=09= CurrentSnapshotData.suboverflowed=20=3D=20sourcesnap->suboverflowed;=0A-=09= CurrentSnapshotData.takenDuringRecovery=20=3D=20= sourcesnap->takenDuringRecovery;=0A-=09/*=20NB:=20curcid=20should=20NOT=20= be=20copied,=20it's=20a=20local=20matter=20*/=0A+=09= ReleaseMVCCSnapshotShared(CurrentSnapshotData.shared);=0A+=09= CurrentSnapshotData.shared=20=3D=20sourcesnap;=0A+=09= CurrentSnapshotData.shared->refcount++;=0A=20=0A-=09= CurrentSnapshotData.snapXactCompletionCount=20=3D=200;=0A+=09/*=20NB:=20= curcid=20should=20NOT=20be=20copied,=20it's=20a=20local=20matter=20*/=0A=20= =0A=20=09/*=0A-=09=20*=20Now=20we=20have=20to=20fix=20what=20= GetSnapshotData=20did=20with=20MyProc->xmin=20and=0A+=09=20*=20Now=20we=20= have=20to=20fix=20what=20GetMVCCSnapshotData=20did=20with=20MyProc->xmin=20= and=0A=20=09=20*=20TransactionXmin.=20=20There=20is=20a=20race=20= condition:=20to=20make=20sure=20we=20are=20not=0A=20=09=20*=20causing=20= the=20global=20xmin=20to=20go=20backwards,=20we=20have=20to=20test=20= that=20the=0A=20=09=20*=20source=20transaction=20is=20still=20running,=20= and=20that=20has=20to=20be=20done=0A@@=20-555,13=20+555,13=20@@=20= SetTransactionSnapshot(MVCCSnapshot=20sourcesnap,=20VirtualTransactionId=20= *sourcevxid=0A=20=09=20*/=0A=20=09if=20(sourceproc=20!=3D=20NULL)=0A=20=09= {=0A-=09=09if=20(!ProcArrayInstallRestoredXmin(CurrentSnapshotData.xmin,=20= sourceproc))=0A+=09=09if=20= (!ProcArrayInstallRestoredXmin(CurrentSnapshotData.shared->xmin,=20= sourceproc))=0A=20=09=09=09ereport(ERROR,=0A=20=09=09=09=09=09= (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),=0A=20=09=09=09=09=09=20= errmsg("could=20not=20import=20the=20requested=20snapshot"),=0A=20=09=09=09= =09=09=20errdetail("The=20source=20transaction=20is=20not=20running=20= anymore.")));=0A=20=09}=0A-=09else=20if=20= (!ProcArrayInstallImportedXmin(CurrentSnapshotData.xmin,=20sourcevxid))=0A= +=09else=20if=20= (!ProcArrayInstallImportedXmin(CurrentSnapshotData.shared->xmin,=20= sourcevxid))=0A=20=09=09ereport(ERROR,=0A=20=09=09=09=09= (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),=0A=20=09=09=09=09=20= errmsg("could=20not=20import=20the=20requested=20snapshot"),=0A@@=20= -577,96=20+577,22=20@@=20SetTransactionSnapshot(MVCCSnapshot=20= sourcesnap,=20VirtualTransactionId=20*sourcevxid=0A=20=09if=20= (IsolationUsesXactSnapshot())=0A=20=09{=0A=20=09=09if=20= (IsolationIsSerializable())=0A-=09=09=09= SetSerializableTransactionSnapshot(&CurrentSnapshotData,=20sourcevxid,=0A= -=09=09=09=09=09=09=09=09=09=09=09=20=20=20sourcepid);=0A-=09=09/*=20= Mark=20it=20as=20"registered"=20*/=0A+=09=09=09= SetSerializableTransactionSnapshotData(CurrentSnapshotData.shared,=0A+=09= =09=09=09=09=09=09=09=09=09=09=09=20=20=20sourcevxid,=20sourcepid);=0A+=09= =09/*=20keep=20it=20*/=0A=20=09=09FirstXactSnapshotRegistered=20=3D=20= true;=0A=20=09}=0A-=09valid_snapshots_push_tail(&CurrentSnapshotData);=0A= =20=0A=20=09FirstSnapshotSet=20=3D=20true;=0A=20}=0A=20=0A-/*=0A-=20*=20= CopyMVCCSnapshot=0A-=20*=09=09Copy=20the=20given=20snapshot.=0A-=20*=0A-=20= *=20The=20copy=20is=20palloc'd=20in=20TopTransactionContext=20and=20has=20= initial=20refcounts=20set=0A-=20*=20to=200.=20=20The=20returned=20= snapshot=20has=20the=20copied=20flag=20set.=0A-=20*/=0A-static=20= MVCCSnapshot=0A-CopyMVCCSnapshot(MVCCSnapshot=20snapshot)=0A-{=0A-=09= MVCCSnapshot=20newsnap;=0A-=09Size=09=09subxipoff;=0A-=09Size=09=09size;=0A= -=0A-=09/*=20We=20allocate=20any=20XID=20arrays=20needed=20in=20the=20= same=20palloc=20block.=20*/=0A-=09size=20=3D=20subxipoff=20=3D=20= sizeof(MVCCSnapshotData)=20+=0A-=09=09snapshot->xcnt=20*=20= sizeof(TransactionId);=0A-=09if=20(snapshot->subxcnt=20>=200)=0A-=09=09= size=20+=3D=20snapshot->subxcnt=20*=20sizeof(TransactionId);=0A-=0A-=09= newsnap=20=3D=20(MVCCSnapshot)=20= MemoryContextAlloc(TopTransactionContext,=20size);=0A-=09memcpy(newsnap,=20= snapshot,=20sizeof(MVCCSnapshotData));=0A-=0A-=09newsnap->regd_count=20=3D= =200;=0A-=09newsnap->active_count=20=3D=200;=0A-=09newsnap->copied=20=3D=20= true;=0A-=09newsnap->valid=20=3D=20true;=0A-=09= newsnap->snapXactCompletionCount=20=3D=200;=0A-=0A-=09/*=20setup=20XID=20= array=20*/=0A-=09if=20(snapshot->xcnt=20>=200)=0A-=09{=0A-=09=09= newsnap->xip=20=3D=20(TransactionId=20*)=20(newsnap=20+=201);=0A-=09=09= memcpy(newsnap->xip,=20snapshot->xip,=0A-=09=09=09=20=20=20= snapshot->xcnt=20*=20sizeof(TransactionId));=0A-=09}=0A-=09else=0A-=09=09= newsnap->xip=20=3D=20NULL;=0A-=0A-=09/*=0A-=09=20*=20Setup=20subXID=20= array.=20Don't=20bother=20to=20copy=20it=20if=20it=20had=20overflowed,=0A= -=09=20*=20though,=20because=20it's=20not=20used=20anywhere=20in=20that=20= case.=20Except=20if=20it's=20a=0A-=09=20*=20snapshot=20taken=20during=20= recovery;=20all=20the=20top-level=20XIDs=20are=20in=20subxip=20as=0A-=09=20= *=20well=20in=20that=20case,=20so=20we=20mustn't=20lose=20them.=0A-=09=20= */=0A-=09if=20(snapshot->subxcnt=20>=200=20&&=0A-=09=09= (!snapshot->suboverflowed=20||=20snapshot->takenDuringRecovery))=0A-=09{=0A= -=09=09newsnap->subxip=20=3D=20(TransactionId=20*)=20((char=20*)=20= newsnap=20+=20subxipoff);=0A-=09=09memcpy(newsnap->subxip,=20= snapshot->subxip,=0A-=09=09=09=20=20=20snapshot->subxcnt=20*=20= sizeof(TransactionId));=0A-=09}=0A-=09else=0A-=09=09newsnap->subxip=20=3D=20= NULL;=0A-=0A-=09return=20newsnap;=0A-}=0A-=0A-/*=0A-=20*=20= FreeMVCCSnapshot=0A-=20*=09=09Free=20the=20memory=20associated=20with=20= a=20snapshot.=0A-=20*/=0A-static=20void=0A-FreeMVCCSnapshot(MVCCSnapshot=20= snapshot)=0A-{=0A-=09Assert(snapshot->regd_count=20=3D=3D=200);=0A-=09= Assert(snapshot->active_count=20=3D=3D=200);=0A-=09= Assert(snapshot->copied);=0A-=09Assert(snapshot->valid);=0A-=0A-=09= pfree(snapshot);=0A-}=0A-=0A=20/*=0A=20=20*=20PushActiveSnapshot=0A=20=20= *=09=09Set=20the=20given=20snapshot=20as=20the=20current=20active=20= snapshot=0A=20=20*=0A=20=20*=20If=20the=20passed=20snapshot=20is=20a=20= statically-allocated=20one,=20or=20it=20is=20possibly=0A=20=20*=20= subject=20to=20a=20future=20command=20counter=20update,=20create=20a=20= new=20long-lived=20copy=0A-=20*=20with=20active=20refcount=3D1.=20=20= Otherwise,=20only=20increment=20the=20refcount.=0A+=20*=20with=20active=20= refcount=3D1.=20=20Otherwise,=20only=20increment=20the=20refcount.=20XXX=0A= =20=20*=0A=20=20*=20Only=20regular=20MVCC=20snaphots=20can=20be=20used=20= as=20the=20active=20snapshot.=0A=20=20*/=0A@@=20-697,24=20+623,13=20@@=20= PushActiveSnapshotWithLevel(Snapshot=20snapshot,=20int=20snap_level)=0A=20= =09Assert(ActiveSnapshot=20=3D=3D=20NULL=20||=20snap_level=20>=3D=20= ActiveSnapshot->as_level);=0A=20=0A=20=09newactive=20=3D=20= MemoryContextAlloc(TopTransactionContext,=20sizeof(ActiveSnapshotElt));=0A= -=0A-=09/*=0A-=09=20*=20Checking=20SecondarySnapshot=20is=20probably=20= useless=20here,=20but=20it=20seems=0A-=09=20*=20better=20to=20be=20sure.=0A= -=09=20*/=0A-=09if=20(!origsnap->copied)=0A-=09{=0A-=09=09= newactive->as_snap=20=3D=20CopyMVCCSnapshot(origsnap);=0A-=09=09= dlist_insert_after(&origsnap->node,=20&newactive->as_snap->node);=0A-=09= }=0A-=09else=0A-=09=09newactive->as_snap=20=3D=20origsnap;=0A+=09= memcpy(&newactive->as_snap,=20origsnap,=20sizeof(MVCCSnapshotData));=0A+=09= newactive->as_snap.kind=20=3D=20SNAPSHOT_ACTIVE;=0A+=09= newactive->as_snap.shared->refcount++;=0A=20=0A=20=09newactive->as_next=20= =3D=20ActiveSnapshot;=0A=20=09newactive->as_level=20=3D=20snap_level;=0A=20= =0A-=09newactive->as_snap->active_count++;=0A-=0A=20=09ActiveSnapshot=20= =3D=20newactive;=0A=20}=0A=20=0A@@=20-729,20=20+644,20=20@@=20= PushActiveSnapshotWithLevel(Snapshot=20snapshot,=20int=20snap_level)=0A=20= void=0A=20PushCopiedSnapshot(Snapshot=20snapshot)=0A=20{=0A-=09= MVCCSnapshot=20copy;=0A-=0A=20=09Assert(snapshot->snapshot_type=20=3D=3D=20= SNAPSHOT_MVCC);=0A=20=0A-=09copy=20=3D=20= CopyMVCCSnapshot(&snapshot->mvcc);=0A-=09= dlist_insert_after(&snapshot->mvcc.node,=20©->node);=0A-=09= PushActiveSnapshot((Snapshot)=20copy);=0A+=09/*=0A+=09=20*=20This=20used=20= to=20be=20different=20from=20PushActiveSnapshot,=20but=20these=20days=0A= +=09=20*=20PushActiveSnapshot=20creates=20a=20copy=20too=20and=20there's=20= no=20difference.=0A+=09=20*/=0A+=09PushActiveSnapshot(snapshot);=0A=20}=0A= =20=0A=20/*=0A=20=20*=20UpdateActiveSnapshotCommandId=0A=20=20*=0A=20=20= *=20Update=20the=20current=20CID=20of=20the=20active=20snapshot.=20=20= This=20can=20only=20be=20applied=0A-=20*=20to=20a=20snapshot=20that=20is=20= not=20referenced=20elsewhere.=0A+=20*=20to=20a=20snapshot=20that=20is=20= not=20referenced=20elsewhere.=20XXX=0A=20=20*/=0A=20void=0A=20= UpdateActiveSnapshotCommandId(void)=0A@@=20-751,8=20+666,6=20@@=20= UpdateActiveSnapshotCommandId(void)=0A=20=09=09=09=09curcid;=0A=20=0A=20=09= Assert(ActiveSnapshot=20!=3D=20NULL);=0A-=09= Assert(ActiveSnapshot->as_snap->active_count=20=3D=3D=201);=0A-=09= Assert(ActiveSnapshot->as_snap->regd_count=20=3D=3D=200);=0A=20=0A=20=09= /*=0A=20=09=20*=20Don't=20allow=20modification=20of=20the=20active=20= snapshot=20during=20parallel=0A@@=20-762,11=20+675,12=20@@=20= UpdateActiveSnapshotCommandId(void)=0A=20=09=20*=20= CommandCounterIncrement,=20but=20there=20are=20a=20few=20places=20that=20= call=20this=0A=20=09=20*=20directly,=20so=20we=20put=20an=20additional=20= guard=20here.=0A=20=09=20*/=0A-=09save_curcid=20=3D=20= ActiveSnapshot->as_snap->curcid;=0A+=09save_curcid=20=3D=20= ActiveSnapshot->as_snap.curcid;=0A=20=09curcid=20=3D=20= GetCurrentCommandId(false);=0A=20=09if=20(IsInParallelMode()=20&&=20= save_curcid=20!=3D=20curcid)=0A=20=09=09elog(ERROR,=20"cannot=20modify=20= commandid=20in=20active=20snapshot=20during=20a=20parallel=20= operation");=0A-=09ActiveSnapshot->as_snap->curcid=20=3D=20curcid;=0A+=0A= +=09ActiveSnapshot->as_snap.curcid=20=3D=20curcid;=0A=20}=0A=20=0A=20/*=0A= @@=20-782,16=20+696,7=20@@=20PopActiveSnapshot(void)=0A=20=0A=20=09= newstack=20=3D=20ActiveSnapshot->as_next;=0A=20=0A-=09= Assert(ActiveSnapshot->as_snap->active_count=20>=200);=0A-=0A-=09= ActiveSnapshot->as_snap->active_count--;=0A-=0A-=09if=20= (ActiveSnapshot->as_snap->active_count=20=3D=3D=200=20&&=0A-=09=09= ActiveSnapshot->as_snap->regd_count=20=3D=3D=200)=0A-=09{=0A-=09=09= dlist_delete(&ActiveSnapshot->as_snap->node);=0A-=09=09= FreeMVCCSnapshot(ActiveSnapshot->as_snap);=0A-=09}=0A+=09= ReleaseMVCCSnapshotShared(ActiveSnapshot->as_snap.shared);=0A=20=0A=20=09= pfree(ActiveSnapshot);=0A=20=09ActiveSnapshot=20=3D=20newstack;=0A@@=20= -808,7=20+713,7=20@@=20GetActiveSnapshot(void)=0A=20{=0A=20=09= Assert(ActiveSnapshot=20!=3D=20NULL);=0A=20=0A-=09return=20(Snapshot)=20= ActiveSnapshot->as_snap;=0A+=09return=20(Snapshot)=20= &ActiveSnapshot->as_snap;=0A=20}=0A=20=0A=20/*=0A@@=20-844,7=20+749,7=20= @@=20RegisterSnapshot(Snapshot=20snapshot)=0A=20Snapshot=0A=20= RegisterSnapshotOnOwner(Snapshot=20orig_snapshot,=20ResourceOwner=20= owner)=0A=20{=0A-=09MVCCSnapshot=20snapshot;=0A+=09MVCCSnapshot=20= newsnap;=0A=20=0A=20=09if=20(orig_snapshot=20=3D=3D=20InvalidSnapshot)=0A= =20=09=09return=20InvalidSnapshot;=0A@@=20-861,22=20+766,19=20@@=20= RegisterSnapshotOnOwner(Snapshot=20orig_snapshot,=20ResourceOwner=20= owner)=0A=20=09}=0A=20=0A=20=09Assert(orig_snapshot->snapshot_type=20=3D=3D= =20SNAPSHOT_MVCC);=0A-=09snapshot=20=3D=20&orig_snapshot->mvcc;=0A-=09= Assert(snapshot->valid);=0A+=09Assert(orig_snapshot->mvcc.valid);=0A=20=0A= -=09/*=20Static=20snapshot?=20=20Create=20a=20persistent=20copy=20*/=0A-=09= if=20(!snapshot->copied)=0A-=09{=0A-=09=09snapshot=20=3D=20= CopyMVCCSnapshot(snapshot);=0A-=09=09= dlist_insert_after(&orig_snapshot->mvcc.node,=20&snapshot->node);=0A-=09= }=0A+=09/*=20Create=20a=20copy=20*/=0A+=09newsnap=20=3D=20= MemoryContextAlloc(TopTransactionContext,=20sizeof(MVCCSnapshotData));=0A= +=09memcpy(newsnap,=20&orig_snapshot->mvcc,=20sizeof(MVCCSnapshotData));=0A= +=09newsnap->kind=20=3D=20SNAPSHOT_REGISTERED;=0A+=09= newsnap->shared->refcount++;=0A=20=0A=20=09/*=20and=20tell=20resowner.c=20= about=20it=20*/=0A=20=09ResourceOwnerEnlarge(owner);=0A-=09= snapshot->regd_count++;=0A-=09ResourceOwnerRememberSnapshot(owner,=20= (Snapshot)=20snapshot);=0A+=09ResourceOwnerRememberSnapshot(owner,=20= (Snapshot)=20newsnap);=0A=20=0A-=09return=20(Snapshot)=20snapshot;=0A+=09= return=20(Snapshot)=20newsnap;=0A=20}=0A=20=0A=20/*=0A@@=20-914,18=20= +816,12=20@@=20UnregisterSnapshotNoOwner(Snapshot=20snapshot)=0A=20{=0A=20= =09if=20(snapshot->snapshot_type=20=3D=3D=20SNAPSHOT_MVCC)=0A=20=09{=0A-=09= =09MVCCSnapshot=20mvccsnap=20=3D=20&snapshot->mvcc;=0A-=0A-=09=09= Assert(mvccsnap->regd_count=20>=200);=0A+=09=09= Assert(snapshot->mvcc.kind=20=3D=3D=20SNAPSHOT_REGISTERED);=0A=20=09=09= Assert(!dlist_is_empty(&ValidSnapshots));=0A=20=0A-=09=09= mvccsnap->regd_count--;=0A-=09=09if=20(mvccsnap->regd_count=20=3D=3D=200=20= &&=20mvccsnap->active_count=20=3D=3D=200)=0A-=09=09{=0A-=09=09=09= dlist_delete(&mvccsnap->node);=0A-=09=09=09FreeMVCCSnapshot(mvccsnap);=0A= -=09=09=09SnapshotResetXmin();=0A-=09=09}=0A+=09=09= ReleaseMVCCSnapshotShared(snapshot->mvcc.shared);=0A+=09=09= pfree(snapshot);=0A+=09=09SnapshotResetXmin();=0A=20=09}=0A=20=09else=20= if=20(snapshot->snapshot_type=20=3D=3D=20SNAPSHOT_HISTORIC_MVCC)=0A=20=09= {=0A@@=20-963,19=20+859,21=20@@=20UnregisterSnapshotNoOwner(Snapshot=20= snapshot)=0A=20static=20void=0A=20SnapshotResetXmin(void)=0A=20{=0A-=09= MVCCSnapshot=20minSnapshot;=0A+=09MVCCSnapshotShared=20minSnapshot;=0A=20= =0A=20=09/*=0A=20=09=20*=20Invalidate=20these=20static=20snapshots=20so=20= that=20we=20can=20advance=20xmin.=0A=20=09=20*/=0A=20=09if=20= (!FirstXactSnapshotRegistered=20&&=20CurrentSnapshotData.valid)=0A=20=09= {=0A-=09=09dlist_delete(&CurrentSnapshotData.node);=0A+=09=09= ReleaseMVCCSnapshotShared(CurrentSnapshotData.shared);=0A+=09=09= CurrentSnapshotData.shared=20=3D=20NULL;=0A=20=09=09= CurrentSnapshotData.valid=20=3D=20false;=0A=20=09}=0A=20=09if=20= (SecondarySnapshotData.valid)=0A=20=09{=0A-=09=09= dlist_delete(&SecondarySnapshotData.node);=0A+=09=09= ReleaseMVCCSnapshotShared(SecondarySnapshotData.shared);=0A+=09=09= SecondarySnapshotData.shared=20=3D=20NULL;=0A=20=09=09= SecondarySnapshotData.valid=20=3D=20false;=0A=20=09}=0A=20=0A@@=20-988,7=20= +886,7=20@@=20SnapshotResetXmin(void)=0A=20=09=09return;=0A=20=09}=0A=20=0A= -=09minSnapshot=20=3D=20dlist_head_element(MVCCSnapshotData,=20node,=20= &ValidSnapshots);=0A+=09minSnapshot=20=3D=20= dlist_head_element(MVCCSnapshotSharedData,=20node,=20&ValidSnapshots);=0A= =20=0A=20=09if=20(TransactionIdPrecedes(MyProc->xmin,=20= minSnapshot->xmin))=0A=20=09=09MyProc->xmin=20=3D=20TransactionXmin=20=3D=20= minSnapshot->xmin;=0A@@=20-1028,21=20+926,7=20@@=20= AtSubAbort_Snapshot(int=20level)=0A=20=0A=20=09=09next=20=3D=20= ActiveSnapshot->as_next;=0A=20=0A-=09=09/*=0A-=09=09=20*=20Decrement=20= the=20snapshot's=20active=20count.=20=20If=20it's=20still=20registered=20= or=0A-=09=09=20*=20marked=20as=20active=20by=20an=20outer=20= subtransaction,=20we=20can't=20free=20it=20yet.=0A-=09=09=20*/=0A-=09=09= Assert(ActiveSnapshot->as_snap->active_count=20>=3D=201);=0A-=09=09= ActiveSnapshot->as_snap->active_count=20-=3D=201;=0A-=0A-=09=09if=20= (ActiveSnapshot->as_snap->active_count=20=3D=3D=200=20&&=0A-=09=09=09= ActiveSnapshot->as_snap->regd_count=20=3D=3D=200)=0A-=09=09{=0A-=09=09=09= dlist_delete(&ActiveSnapshot->as_snap->node);=0A-=09=09=09= FreeMVCCSnapshot(ActiveSnapshot->as_snap);=0A-=09=09}=0A-=0A-=09=09/*=20= and=20free=20the=20stack=20element=20*/=0A+=09=09= ReleaseMVCCSnapshotShared(ActiveSnapshot->as_snap.shared);=0A=20=09=09= pfree(ActiveSnapshot);=0A=20=0A=20=09=09ActiveSnapshot=20=3D=20next;=0A= @@=20-1058,6=20+942,8=20@@=20AtSubAbort_Snapshot(int=20level)=0A=20void=0A= =20AtEOXact_Snapshot(bool=20isCommit,=20bool=20resetXmin)=0A=20{=0A+=09= dlist_mutable_iter=20iter;=0A+=0A=20=09/*=0A=20=09=20*=20If=20we=20= exported=20any=20snapshots,=20clean=20them=20up.=0A=20=09=20*/=0A@@=20= -1084,7=20+970,7=20@@=20AtEOXact_Snapshot(bool=20isCommit,=20bool=20= resetXmin)=0A=20=09=09=09=09elog(WARNING,=20"could=20not=20unlink=20file=20= \"%s\":=20%m",=0A=20=09=09=09=09=09=20esnap->snapfile);=0A=20=0A-=09=09=09= dlist_delete(&esnap->snapshot->node);=0A+=09=09=09= ReleaseMVCCSnapshotShared(esnap->snapshot);=0A=20=09=09}=0A=20=0A=20=09=09= exportedSnapshots=20=3D=20NIL;=0A@@=20-1093,17=20+979,20=20@@=20= AtEOXact_Snapshot(bool=20isCommit,=20bool=20resetXmin)=0A=20=09/*=20Drop=20= all=20static=20snapshot=20*/=0A=20=09if=20(CatalogSnapshotData.valid)=0A=20= =09{=0A-=09=09dlist_delete(&CatalogSnapshotData.node);=0A+=09=09= ReleaseMVCCSnapshotShared(CatalogSnapshotData.shared);=0A+=09=09= CatalogSnapshotData.shared=20=3D=20NULL;=0A=20=09=09= CatalogSnapshotData.valid=20=3D=20false;=0A=20=09}=0A=20=09if=20= (CurrentSnapshotData.valid)=0A=20=09{=0A-=09=09= dlist_delete(&CurrentSnapshotData.node);=0A+=09=09= ReleaseMVCCSnapshotShared(CurrentSnapshotData.shared);=0A+=09=09= CurrentSnapshotData.shared=20=3D=20NULL;=0A=20=09=09= CurrentSnapshotData.valid=20=3D=20false;=0A=20=09}=0A=20=09if=20= (SecondarySnapshotData.valid)=0A=20=09{=0A-=09=09= dlist_delete(&SecondarySnapshotData.node);=0A+=09=09= ReleaseMVCCSnapshotShared(SecondarySnapshotData.shared);=0A+=09=09= SecondarySnapshotData.shared=20=3D=20NULL;=0A=20=09=09= SecondarySnapshotData.valid=20=3D=20false;=0A=20=09}=0A=20=0A@@=20= -1124,11=20+1013,23=20@@=20AtEOXact_Snapshot(bool=20isCommit,=20bool=20= resetXmin)=0A=20=09=20*=20And=20reset=20our=20state.=20=20We=20don't=20= need=20to=20free=20the=20memory=20explicitly=20--=0A=20=09=20*=20it'll=20= go=20away=20with=20TopTransactionContext.=0A=20=09=20*/=0A-=09= ActiveSnapshot=20=3D=20NULL;=0A-=09dlist_init(&ValidSnapshots);=0A+=09= dlist_foreach_modify(iter,=20&ValidSnapshots)=0A+=09{=0A+=09=09= MVCCSnapshotShared=20cur=20=3D=20dlist_container(MVCCSnapshotSharedData,=20= node,=20iter.cur);=0A=20=0A-=09CurrentSnapshotData.valid=20=3D=20false;=0A= -=09SecondarySnapshotData.valid=20=3D=20false;=0A+=09=09= dlist_delete(iter.cur);=0A+=09=09cur->refcount=20=3D=200;=0A+=09=09if=20= (cur=20=3D=3D=20latestSnapshotShared)=0A+=09=09{=0A+=09=09=09/*=20keep=20= it=20*/=0A+=09=09}=0A+=09=09else=20if=20(spareSnapshotShared=20=3D=3D=20= NULL)=0A+=09=09=09spareSnapshotShared=20=3D=20cur;=0A+=09=09else=0A+=09=09= =09pfree(cur);=0A+=09}=0A+=0A+=09ActiveSnapshot=20=3D=20NULL;=0A=20=09= FirstSnapshotSet=20=3D=20false;=0A=20=09FirstXactSnapshotRegistered=20=3D=20= false;=0A=20=0A@@=20-1151,9=20+1052,8=20@@=20AtEOXact_Snapshot(bool=20= isCommit,=20bool=20resetXmin)=0A=20=20*=09=09snapshot.=0A=20=20*/=0A=20= char=20*=0A-ExportSnapshot(MVCCSnapshot=20snapshot)=0A= +ExportSnapshot(MVCCSnapshotShared=20snapshot)=0A=20{=0A-=09MVCCSnapshot=20= orig_snapshot;=0A=20=09TransactionId=20topXid;=0A=20=09TransactionId=20= *children;=0A=20=09ExportedSnapshot=20*esnap;=0A@@=20-1214,21=20+1114,16=20= @@=20ExportSnapshot(MVCCSnapshot=20snapshot)=0A=20=09=20*=20Copy=20the=20= snapshot=20into=20TopTransactionContext,=20add=20it=20to=20the=0A=20=09=20= *=20exportedSnapshots=20list,=20and=20mark=20it=20pseudo-registered.=20=20= We=20do=20this=20to=0A=20=09=20*=20ensure=20that=20the=20snapshot's=20= xmin=20is=20honored=20for=20the=20rest=20of=20the=0A-=09=20*=20= transaction.=0A+=09=20*=20transaction.=20XXX=0A=20=09=20*/=0A-=09= orig_snapshot=20=3D=20snapshot;=0A-=09snapshot=20=3D=20= CopyMVCCSnapshot(orig_snapshot);=0A-=0A=20=09oldcxt=20=3D=20= MemoryContextSwitchTo(TopTransactionContext);=0A=20=09esnap=20=3D=20= (ExportedSnapshot=20*)=20palloc(sizeof(ExportedSnapshot));=0A=20=09= esnap->snapfile=20=3D=20pstrdup(path);=0A=20=09esnap->snapshot=20=3D=20= snapshot;=0A+=09snapshot->refcount++;=0A=20=09exportedSnapshots=20=3D=20= lappend(exportedSnapshots,=20esnap);=0A=20=09= MemoryContextSwitchTo(oldcxt);=0A=20=0A-=09snapshot->regd_count++;=0A-=09= dlist_insert_after(&orig_snapshot->node,=20&snapshot->node);=0A-=0A=20=09= /*=0A=20=09=20*=20Fill=20buf=20with=20a=20text=20serialization=20of=20= the=20snapshot,=20plus=20identification=0A=20=09=20*=20data=20about=20= this=20transaction.=20=20The=20format=20expected=20by=20ImportSnapshot=20= is=0A@@=20-1248,8=20+1143,8=20@@=20ExportSnapshot(MVCCSnapshot=20= snapshot)=0A=20=09/*=0A=20=09=20*=20We=20must=20include=20our=20own=20= top=20transaction=20ID=20in=20the=20top-xid=20data,=20since=0A=20=09=20*=20= by=20definition=20we=20will=20still=20be=20running=20when=20the=20= importing=20transaction=0A-=09=20*=20adopts=20the=20snapshot,=20but=20= GetSnapshotData=20never=20includes=20our=20own=20XID=20in=0A-=09=20*=20= the=20snapshot.=20=20(There=20must,=20therefore,=20be=20enough=20room=20= to=20add=20it.)=0A+=09=20*=20adopts=20the=20snapshot,=20but=20= GetMVCCSnapshotData=20never=20includes=20our=20own=20XID=0A+=09=20*=20in=20= the=20snapshot.=20=20(There=20must,=20therefore,=20be=20enough=20room=20= to=20add=20it.)=0A=20=09=20*=0A=20=09=20*=20However,=20it=20could=20be=20= that=20our=20topXid=20is=20after=20the=20xmax,=20in=20which=20case=0A=20=09= =20*=20we=20shouldn't=20include=20it=20because=20xip[]=20members=20are=20= expected=20to=20be=20before=0A@@=20-1334,7=20+1229,7=20@@=20= pg_export_snapshot(PG_FUNCTION_ARGS)=0A=20{=0A=20=09char=09=20=20=20= *snapshotName;=0A=20=0A-=09snapshotName=20=3D=20= ExportSnapshot((MVCCSnapshot)=20GetActiveSnapshot());=0A+=09snapshotName=20= =3D=20ExportSnapshot(((MVCCSnapshot)=20GetActiveSnapshot())->shared);=0A=20= =09PG_RETURN_TEXT_P(cstring_to_text(snapshotName));=0A=20}=0A=20=0A@@=20= -1438,7=20+1333,7=20@@=20ImportSnapshot(const=20char=20*idstr)=0A=20=09= Oid=09=09=09src_dbid;=0A=20=09int=09=09=09src_isolevel;=0A=20=09bool=09=09= src_readonly;=0A-=09MVCCSnapshotData=20snapshot;=0A+=09= MVCCSnapshotShared=20snapshot;=0A=20=0A=20=09/*=0A=20=09=20*=20Must=20be=20= at=20top=20level=20of=20a=20fresh=20transaction.=20=20Note=20in=20= particular=20that=0A@@=20-1508,8=20+1403,6=20@@=20ImportSnapshot(const=20= char=20*idstr)=0A=20=09/*=0A=20=09=20*=20Construct=20a=20snapshot=20= struct=20by=20parsing=20the=20file=20content.=0A=20=09=20*/=0A-=09= memset(&snapshot,=200,=20sizeof(snapshot));=0A-=0A=20=09= parseVxidFromText("vxid:",=20&filebuf,=20path,=20&src_vxid);=0A=20=09= src_pid=20=3D=20parseIntFromText("pid:",=20&filebuf,=20path);=0A=20=09/*=20= we=20abuse=20parseXidFromText=20a=20bit=20here=20...=20*/=0A@@=20= -1517,12=20+1410,11=20@@=20ImportSnapshot(const=20char=20*idstr)=0A=20=09= src_isolevel=20=3D=20parseIntFromText("iso:",=20&filebuf,=20path);=0A=20=09= src_readonly=20=3D=20parseIntFromText("ro:",=20&filebuf,=20path);=0A=20=0A= -=09snapshot.snapshot_type=20=3D=20SNAPSHOT_MVCC;=0A-=0A-=09= snapshot.xmin=20=3D=20parseXidFromText("xmin:",=20&filebuf,=20path);=0A-=09= snapshot.xmax=20=3D=20parseXidFromText("xmax:",=20&filebuf,=20path);=0A+=09= snapshot=20=3D=20AllocMVCCSnapshotShared();=0A+=09snapshot->xmin=20=3D=20= parseXidFromText("xmin:",=20&filebuf,=20path);=0A+=09snapshot->xmax=20=3D=20= parseXidFromText("xmax:",=20&filebuf,=20path);=0A=20=0A-=09snapshot.xcnt=20= =3D=20xcnt=20=3D=20parseIntFromText("xcnt:",=20&filebuf,=20path);=0A+=09= snapshot->xcnt=20=3D=20xcnt=20=3D=20parseIntFromText("xcnt:",=20= &filebuf,=20path);=0A=20=0A=20=09/*=20sanity-check=20the=20xid=20count=20= before=20palloc=20*/=0A=20=09if=20(xcnt=20<=200=20||=20xcnt=20>=20= GetMaxSnapshotXidCount())=0A@@=20-1530,15=20+1422,15=20@@=20= ImportSnapshot(const=20char=20*idstr)=0A=20=09=09=09=09= (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),=0A=20=09=09=09=09=20= errmsg("invalid=20snapshot=20data=20in=20file=20\"%s\"",=20path)));=0A=20= =0A-=09snapshot.xip=20=3D=20(TransactionId=20*)=20palloc(xcnt=20*=20= sizeof(TransactionId));=0A+=09snapshot->xip=20=3D=20(TransactionId=20*)=20= palloc(xcnt=20*=20sizeof(TransactionId));=0A=20=09for=20(i=20=3D=200;=20= i=20<=20xcnt;=20i++)=0A-=09=09snapshot.xip[i]=20=3D=20= parseXidFromText("xip:",=20&filebuf,=20path);=0A+=09=09snapshot->xip[i]=20= =3D=20parseXidFromText("xip:",=20&filebuf,=20path);=0A=20=0A-=09= snapshot.suboverflowed=20=3D=20parseIntFromText("sof:",=20&filebuf,=20= path);=0A+=09snapshot->suboverflowed=20=3D=20parseIntFromText("sof:",=20= &filebuf,=20path);=0A=20=0A-=09if=20(!snapshot.suboverflowed)=0A+=09if=20= (!snapshot->suboverflowed)=0A=20=09{=0A-=09=09snapshot.subxcnt=20=3D=20= xcnt=20=3D=20parseIntFromText("sxcnt:",=20&filebuf,=20path);=0A+=09=09= snapshot->subxcnt=20=3D=20xcnt=20=3D=20parseIntFromText("sxcnt:",=20= &filebuf,=20path);=0A=20=0A=20=09=09/*=20sanity-check=20the=20xid=20= count=20before=20palloc=20*/=0A=20=09=09if=20(xcnt=20<=200=20||=20xcnt=20= >=20GetMaxSnapshotSubxidCount())=0A@@=20-1546,17=20+1438,19=20@@=20= ImportSnapshot(const=20char=20*idstr)=0A=20=09=09=09=09=09= (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),=0A=20=09=09=09=09=09=20= errmsg("invalid=20snapshot=20data=20in=20file=20\"%s\"",=20path)));=0A=20= =0A-=09=09snapshot.subxip=20=3D=20(TransactionId=20*)=20palloc(xcnt=20*=20= sizeof(TransactionId));=0A+=09=09snapshot->subxip=20=3D=20(TransactionId=20= *)=20palloc(xcnt=20*=20sizeof(TransactionId));=0A=20=09=09for=20(i=20=3D=20= 0;=20i=20<=20xcnt;=20i++)=0A-=09=09=09snapshot.subxip[i]=20=3D=20= parseXidFromText("sxp:",=20&filebuf,=20path);=0A+=09=09=09= snapshot->subxip[i]=20=3D=20parseXidFromText("sxp:",=20&filebuf,=20= path);=0A=20=09}=0A=20=09else=0A=20=09{=0A-=09=09snapshot.subxcnt=20=3D=20= 0;=0A-=09=09snapshot.subxip=20=3D=20NULL;=0A+=09=09snapshot->subxcnt=20=3D= =200;=0A=20=09}=0A=20=0A-=09snapshot.takenDuringRecovery=20=3D=20= parseIntFromText("rec:",=20&filebuf,=20path);=0A+=09= snapshot->takenDuringRecovery=20=3D=20parseIntFromText("rec:",=20= &filebuf,=20path);=0A+=0A+=09snapshot->refcount=20=3D=201;=0A+=09= valid_snapshots_push_out_of_order(snapshot);=0A=20=0A=20=09/*=0A=20=09=20= *=20Do=20some=20additional=20sanity=20checking,=20just=20to=20protect=20= ourselves.=20=20We=0A@@=20-1565,8=20+1459,8=20@@=20ImportSnapshot(const=20= char=20*idstr)=0A=20=09=20*/=0A=20=09if=20= (!VirtualTransactionIdIsValid(src_vxid)=20||=0A=20=09=09= !OidIsValid(src_dbid)=20||=0A-=09=09= !TransactionIdIsNormal(snapshot.xmin)=20||=0A-=09=09= !TransactionIdIsNormal(snapshot.xmax))=0A+=09=09= !TransactionIdIsNormal(snapshot->xmin)=20||=0A+=09=09= !TransactionIdIsNormal(snapshot->xmax))=0A=20=09=09ereport(ERROR,=0A=20=09= =09=09=09(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),=0A=20=09=09=09=09= =20errmsg("invalid=20snapshot=20data=20in=20file=20\"%s\"",=20path)));=0A= @@=20-1604,7=20+1498,7=20@@=20ImportSnapshot(const=20char=20*idstr)=0A=20= =09=09=09=09=20errmsg("cannot=20import=20a=20snapshot=20from=20a=20= different=20database")));=0A=20=0A=20=09/*=20OK,=20install=20the=20= snapshot=20*/=0A-=09SetTransactionSnapshot(&snapshot,=20&src_vxid,=20= src_pid,=20NULL);=0A+=09SetTransactionSnapshot(snapshot,=20&src_vxid,=20= src_pid,=20NULL);=0A=20}=0A=20=0A=20/*=0A@@=20-1670,18=20+1564,21=20@@=20= ThereAreNoPriorRegisteredSnapshots(void)=0A=20=0A=20=09= dlist_foreach(iter,=20&ValidSnapshots)=0A=20=09{=0A-=09=09MVCCSnapshot=20= cur=20=3D=20dlist_container(MVCCSnapshotData,=20node,=20iter.cur);=0A+=09= =09MVCCSnapshotShared=20cur=20=3D=0A+=09=09=09= dlist_container(MVCCSnapshotSharedData,=20node,=20iter.cur);=0A+=09=09= uint32=09=09allowedcount=20=3D=200;=0A=20=0A=20=09=09if=20= (FirstXactSnapshotRegistered)=0A=20=09=09{=0A=20=09=09=09= Assert(CurrentSnapshotData.valid);=0A-=09=09=09if=20(cur=20!=3D=20= &CurrentSnapshotData)=0A-=09=09=09=09continue;=0A+=09=09=09if=20(cur=20= =3D=3D=20CurrentSnapshotData.shared)=0A+=09=09=09=09allowedcount++;=0A=20= =09=09}=0A-=09=09if=20(ActiveSnapshot=20&&=20cur=20=3D=3D=20= ActiveSnapshot->as_snap)=0A-=09=09=09continue;=0A+=09=09if=20= (ActiveSnapshot=20&&=20cur=20=3D=3D=20ActiveSnapshot->as_snap.shared)=0A= +=09=09=09allowedcount++;=0A=20=0A-=09=09return=20false;=0A+=09=09if=20= (cur->refcount=20!=3D=20allowedcount)=0A+=09=09=09return=20false;=0A=20=09= }=0A=20=0A=20=09return=20true;=0A@@=20-1707,8=20+1604,9=20@@=20= HaveRegisteredOrActiveSnapshot(void)=0A=20=09=20*=20registered=20more=20= than=20one=20snapshot=20has=20to=20be=20in=20ValidSnapshots.=0A=20=09=20= */=0A=20=09if=20(CatalogSnapshotData.valid=20&&=0A-=09=09= dlist_head_node(&ValidSnapshots)=20=3D=3D=20&CatalogSnapshotData.node=20= &&=0A-=09=09dlist_tail_node(&ValidSnapshots)=20=3D=3D=20= &CatalogSnapshotData.node)=0A+=09=09CatalogSnapshotData.shared->refcount=20= =3D=3D=201=20&&=0A+=09=09dlist_head_node(&ValidSnapshots)=20=3D=3D=20= &CatalogSnapshotData.shared->node=20&&=0A+=09=09= dlist_tail_node(&ValidSnapshots)=20=3D=3D=20= &CatalogSnapshotData.shared->node)=0A=20=09{=0A=20=09=09return=20false;=0A= =20=09}=0A@@=20-1775,11=20+1673,11=20@@=20= EstimateSnapshotSpace(MVCCSnapshot=20snapshot)=0A=20=0A=20=09/*=20We=20= allocate=20any=20XID=20arrays=20needed=20in=20the=20same=20palloc=20= block.=20*/=0A=20=09size=20=3D=20= add_size(sizeof(SerializedSnapshotData),=0A-=09=09=09=09=09= mul_size(snapshot->xcnt,=20sizeof(TransactionId)));=0A-=09if=20= (snapshot->subxcnt=20>=200=20&&=0A-=09=09(!snapshot->suboverflowed=20||=20= snapshot->takenDuringRecovery))=0A+=09=09=09=09=09= mul_size(snapshot->shared->xcnt,=20sizeof(TransactionId)));=0A+=09if=20= (snapshot->shared->subxcnt=20>=200=20&&=0A+=09=09= (!snapshot->shared->suboverflowed=20||=20= snapshot->shared->takenDuringRecovery))=0A=20=09=09size=20=3D=20= add_size(size,=0A-=09=09=09=09=09=09mul_size(snapshot->subxcnt,=20= sizeof(TransactionId)));=0A+=09=09=09=09=09=09= mul_size(snapshot->shared->subxcnt,=20sizeof(TransactionId)));=0A=20=0A=20= =09return=20size;=0A=20}=0A@@=20-1794,15=20+1692,15=20@@=20= SerializeSnapshot(MVCCSnapshot=20snapshot,=20char=20*start_address)=0A=20= {=0A=20=09SerializedSnapshotData=20serialized_snapshot;=0A=20=0A-=09= Assert(snapshot->subxcnt=20>=3D=200);=0A+=09= Assert(snapshot->shared->subxcnt=20>=3D=200);=0A=20=0A=20=09/*=20Copy=20= all=20required=20fields=20*/=0A-=09serialized_snapshot.xmin=20=3D=20= snapshot->xmin;=0A-=09serialized_snapshot.xmax=20=3D=20snapshot->xmax;=0A= -=09serialized_snapshot.xcnt=20=3D=20snapshot->xcnt;=0A-=09= serialized_snapshot.subxcnt=20=3D=20snapshot->subxcnt;=0A-=09= serialized_snapshot.suboverflowed=20=3D=20snapshot->suboverflowed;=0A-=09= serialized_snapshot.takenDuringRecovery=20=3D=20= snapshot->takenDuringRecovery;=0A+=09serialized_snapshot.xmin=20=3D=20= snapshot->shared->xmin;=0A+=09serialized_snapshot.xmax=20=3D=20= snapshot->shared->xmax;=0A+=09serialized_snapshot.xcnt=20=3D=20= snapshot->shared->xcnt;=0A+=09serialized_snapshot.subxcnt=20=3D=20= snapshot->shared->subxcnt;=0A+=09serialized_snapshot.suboverflowed=20=3D=20= snapshot->shared->suboverflowed;=0A+=09= serialized_snapshot.takenDuringRecovery=20=3D=20= snapshot->shared->takenDuringRecovery;=0A=20=09= serialized_snapshot.curcid=20=3D=20snapshot->curcid;=0A=20=0A=20=09/*=0A= @@=20-1810,7=20+1708,7=20@@=20SerializeSnapshot(MVCCSnapshot=20snapshot,=20= char=20*start_address)=0A=20=09=20*=20taken=20during=20recovery=20-=20in=20= that=20case,=20top-level=20XIDs=20are=20in=20subxip=20as=0A=20=09=20*=20= well,=20and=20we=20mustn't=20lose=20them.=0A=20=09=20*/=0A-=09if=20= (serialized_snapshot.suboverflowed=20&&=20= !snapshot->takenDuringRecovery)=0A+=09if=20= (serialized_snapshot.suboverflowed=20&&=20= !snapshot->shared->takenDuringRecovery)=0A=20=09=09= serialized_snapshot.subxcnt=20=3D=200;=0A=20=0A=20=09/*=20Copy=20struct=20= to=20possibly-unaligned=20buffer=20*/=0A@@=20-1818,10=20+1716,10=20@@=20= SerializeSnapshot(MVCCSnapshot=20snapshot,=20char=20*start_address)=0A=20= =09=09=20=20=20&serialized_snapshot,=20sizeof(SerializedSnapshotData));=0A= =20=0A=20=09/*=20Copy=20XID=20array=20*/=0A-=09if=20(snapshot->xcnt=20>=20= 0)=0A+=09if=20(snapshot->shared->xcnt=20>=200)=0A=20=09=09= memcpy((TransactionId=20*)=20(start_address=20+=0A=20=09=09=09=09=09=09=09= =09=20=20sizeof(SerializedSnapshotData)),=0A-=09=09=09=20=20=20= snapshot->xip,=20snapshot->xcnt=20*=20sizeof(TransactionId));=0A+=09=09=09= =20=20=20snapshot->shared->xip,=20snapshot->shared->xcnt=20*=20= sizeof(TransactionId));=0A=20=0A=20=09/*=0A=20=09=20*=20Copy=20SubXID=20= array.=20Don't=20bother=20to=20copy=20it=20if=20it=20had=20overflowed,=0A= @@=20-1832,10=20+1730,10=20@@=20SerializeSnapshot(MVCCSnapshot=20= snapshot,=20char=20*start_address)=0A=20=09if=20= (serialized_snapshot.subxcnt=20>=200)=0A=20=09{=0A=20=09=09Size=09=09= subxipoff=20=3D=20sizeof(SerializedSnapshotData)=20+=0A-=09=09=09= snapshot->xcnt=20*=20sizeof(TransactionId);=0A+=09=09=09= snapshot->shared->xcnt=20*=20sizeof(TransactionId);=0A=20=0A=20=09=09= memcpy((TransactionId=20*)=20(start_address=20+=20subxipoff),=0A-=09=09=09= =20=20=20snapshot->subxip,=20snapshot->subxcnt=20*=20= sizeof(TransactionId));=0A+=09=09=09=20=20=20snapshot->shared->subxip,=20= snapshot->shared->subxcnt=20*=20sizeof(TransactionId));=0A=20=09}=0A=20}=0A= =20=0A@@=20-1863,49=20+1761,46=20@@=20RestoreSnapshot(char=20= *start_address)=0A=20=09size=20=3D=20sizeof(MVCCSnapshotData)=0A=20=09=09= +=20serialized_snapshot.xcnt=20*=20sizeof(TransactionId)=0A=20=09=09+=20= serialized_snapshot.subxcnt=20*=20sizeof(TransactionId);=0A+=09= Assert(serialized_snapshot.xcnt=20<=3D=20GetMaxSnapshotXidCount());=0A+=09= Assert(serialized_snapshot.subxcnt=20<=3D=20= GetMaxSnapshotSubxidCount());=0A=20=0A=20=09/*=20Copy=20all=20required=20= fields=20*/=0A=20=09snapshot=20=3D=20(MVCCSnapshot)=20= MemoryContextAlloc(TopTransactionContext,=20size);=0A=20=09= snapshot->snapshot_type=20=3D=20SNAPSHOT_MVCC;=0A-=09snapshot->xmin=20=3D=20= serialized_snapshot.xmin;=0A-=09snapshot->xmax=20=3D=20= serialized_snapshot.xmax;=0A-=09snapshot->xip=20=3D=20NULL;=0A-=09= snapshot->xcnt=20=3D=20serialized_snapshot.xcnt;=0A-=09snapshot->subxip=20= =3D=20NULL;=0A-=09snapshot->subxcnt=20=3D=20serialized_snapshot.subxcnt;=0A= -=09snapshot->suboverflowed=20=3D=20serialized_snapshot.suboverflowed;=0A= -=09snapshot->takenDuringRecovery=20=3D=20= serialized_snapshot.takenDuringRecovery;=0A+=09snapshot->kind=20=3D=20= SNAPSHOT_REGISTERED;=0A+=09snapshot->shared=20=3D=20= AllocMVCCSnapshotShared();=0A+=09snapshot->shared->xmin=20=3D=20= serialized_snapshot.xmin;=0A+=09snapshot->shared->xmax=20=3D=20= serialized_snapshot.xmax;=0A+=09snapshot->shared->xcnt=20=3D=20= serialized_snapshot.xcnt;=0A+=09snapshot->shared->subxcnt=20=3D=20= serialized_snapshot.subxcnt;=0A+=09snapshot->shared->suboverflowed=20=3D=20= serialized_snapshot.suboverflowed;=0A+=09= snapshot->shared->takenDuringRecovery=20=3D=20= serialized_snapshot.takenDuringRecovery;=0A+=09= snapshot->shared->snapXactCompletionCount=20=3D=200;=0A+=0A+=09= snapshot->shared->refcount=20=3D=201;=0A+=09= valid_snapshots_push_out_of_order(snapshot->shared);=0A+=0A=20=09= snapshot->curcid=20=3D=20serialized_snapshot.curcid;=0A-=09= snapshot->snapXactCompletionCount=20=3D=200;=0A=20=0A=20=09/*=20Copy=20= XIDs,=20if=20present.=20*/=0A=20=09if=20(serialized_snapshot.xcnt=20>=20= 0)=0A=20=09{=0A-=09=09snapshot->xip=20=3D=20(TransactionId=20*)=20= (snapshot=20+=201);=0A-=09=09memcpy(snapshot->xip,=20serialized_xids,=0A= +=09=09memcpy(snapshot->shared->xip,=20serialized_xids,=0A=20=09=09=09=20= =20=20serialized_snapshot.xcnt=20*=20sizeof(TransactionId));=0A=20=09}=0A= =20=0A=20=09/*=20Copy=20SubXIDs,=20if=20present.=20*/=0A=20=09if=20= (serialized_snapshot.subxcnt=20>=200)=0A=20=09{=0A-=09=09= snapshot->subxip=20=3D=20((TransactionId=20*)=20(snapshot=20+=201))=20+=0A= -=09=09=09serialized_snapshot.xcnt;=0A-=09=09memcpy(snapshot->subxip,=20= serialized_xids=20+=20serialized_snapshot.xcnt,=0A+=09=09= memcpy(snapshot->shared->subxip,=20serialized_xids=20+=20= serialized_snapshot.xcnt,=0A=20=09=09=09=20=20=20= serialized_snapshot.subxcnt=20*=20sizeof(TransactionId));=0A=20=09}=0A=20= =0A-=09/*=20Set=20the=20copied=20flag=20so=20that=20the=20caller=20will=20= set=20refcounts=20correctly.=20*/=0A-=09snapshot->regd_count=20=3D=200;=0A= -=09snapshot->active_count=20=3D=200;=0A-=09snapshot->copied=20=3D=20= true;=0A=20=09snapshot->valid=20=3D=20true;=0A=20=0A=20=09/*=20and=20= tell=20resowner.c=20about=20it,=20just=20like=20RegisterSnapshot()=20*/=0A= =20=09ResourceOwnerEnlarge(CurrentResourceOwner);=0A-=09= snapshot->regd_count++;=0A=20=09= ResourceOwnerRememberSnapshot(CurrentResourceOwner,=20(Snapshot)=20= snapshot);=0A-=09valid_snapshots_push_out_of_order(snapshot);=0A=20=0A=20= =09return=20snapshot;=0A=20}=0A@@=20-1919,21=20+1814,21=20@@=20= RestoreSnapshot(char=20*start_address)=0A=20void=0A=20= RestoreTransactionSnapshot(MVCCSnapshot=20snapshot,=20void=20= *source_pgproc)=0A=20{=0A-=09SetTransactionSnapshot(snapshot,=20NULL,=20= InvalidPid,=20source_pgproc);=0A+=09= SetTransactionSnapshot(snapshot->shared,=20NULL,=20InvalidPid,=20= source_pgproc);=0A=20}=0A=20=0A=20/*=0A=20=20*=20XidInMVCCSnapshot=0A=20=20= *=09=09Is=20the=20given=20XID=20still-in-progress=20according=20to=20the=20= snapshot?=0A=20=20*=0A-=20*=20Note:=20GetSnapshotData=20never=20stores=20= either=20top=20xid=20or=20subxids=20of=20our=20own=0A-=20*=20backend=20= into=20a=20snapshot,=20so=20these=20xids=20will=20not=20be=20reported=20= as=20"running"=0A-=20*=20by=20this=20function.=20=20This=20is=20OK=20for=20= current=20uses,=20because=20we=20always=20check=0A-=20*=20= TransactionIdIsCurrentTransactionId=20first,=20except=20when=20it's=20= known=20the=0A-=20*=20XID=20could=20not=20be=20ours=20anyway.=0A+=20*=20= Note:=20GetMVCCSnapshotData=20never=20stores=20either=20top=20xid=20or=20= subxids=20of=20our=20own=0A+=20*=20backend=20into=20a=20snapshot,=20so=20= these=20xids=20will=20not=20be=20reported=20as=20"running"=20by=0A+=20*=20= this=20function.=20=20This=20is=20OK=20for=20current=20uses,=20because=20= we=20always=20check=0A+=20*=20TransactionIdIsCurrentTransactionId=20= first,=20except=20when=20it's=20known=20the=20XID=0A+=20*=20could=20not=20= be=20ours=20anyway.=0A=20=20*/=0A=20bool=0A= -XidInMVCCSnapshot(TransactionId=20xid,=20MVCCSnapshot=20snapshot)=0A= +XidInMVCCSnapshot(TransactionId=20xid,=20MVCCSnapshotShared=20snapshot)=0A= =20{=0A=20=09/*=0A=20=09=20*=20Make=20a=20quick=20range=20check=20to=20= eliminate=20most=20XIDs=20without=20looking=20at=20the=0A@@=20-2029,6=20= +1924,84=20@@=20XidInMVCCSnapshot(TransactionId=20xid,=20MVCCSnapshot=20= snapshot)=0A=20=09return=20false;=0A=20}=0A=20=0A+/*=0A+=20*=20Allocate=20= an=20MVCCSnapshotShared=20struct=0A+=20*=0A+=20*=20The=20'xip'=20and=20= 'subxip'=20arrays=20are=20allocated=20so=20that=20they=20can=20hold=20= the=20max=0A+=20*=20number=20of=20XIDs.=20That's=20usually=20overkill,=20= but=20it=20allows=20us=20to=20do=20the=0A+=20*=20allocation=20while=20= not=20holding=20ProcArrayLock.=0A+=20*=0A+=20*=20MVCCSnapshotShared=20= structs=20are=20kept=20in=20TopMemoryContext=20and=20refcounted.=0A+=20*=20= The=20refcount=20is=20initially=20zero,=20the=20caller=20is=20expected=20= to=20increment=20it.=0A+=20*/=0A+MVCCSnapshotShared=0A= +AllocMVCCSnapshotShared(void)=0A+{=0A+=09MemoryContext=20save_cxt;=0A+=09= MVCCSnapshotShared=20shared;=0A+=09size_t=09=09size;=0A+=09char=09=20=20=20= *p;=0A+=0A+=09/*=0A+=09=20*=20To=20reduce=20alloc/free=20overhead=20in=20= GetMVCCSnapshotData(),=20we=20have=20a=0A+=09=20*=20single-element=20= pool.=0A+=09=20*/=0A+=09if=20(spareSnapshotShared)=0A+=09{=0A+=09=09= shared=20=3D=20spareSnapshotShared;=0A+=09=09spareSnapshotShared=20=3D=20= NULL;=0A+=09=09return=20shared;=0A+=09}=0A+=0A+=09save_cxt=20=3D=20= MemoryContextSwitchTo(TopMemoryContext);=0A+=0A+=09size=20=3D=20= sizeof(MVCCSnapshotSharedData)=20+=0A+=09=09GetMaxSnapshotXidCount()=20*=20= sizeof(TransactionId)=20+=0A+=09=09GetMaxSnapshotSubxidCount()=20*=20= sizeof(TransactionId);=0A+=09p=20=3D=20palloc(size);=0A+=0A+=09shared=20= =3D=20(MVCCSnapshotShared)=20p;=0A+=09p=20+=3D=20= sizeof(MVCCSnapshotSharedData);=0A+=09shared->xip=20=3D=20(TransactionId=20= *)=20p;=0A+=09p=20+=3D=20GetMaxSnapshotXidCount()=20*=20= sizeof(TransactionId);=0A+=09shared->subxip=20=3D=20(TransactionId=20*)=20= p;=0A+=0A+=09shared->snapXactCompletionCount=20=3D=200;=0A+=09= shared->refcount=20=3D=200;=0A+=0A+=09MemoryContextSwitchTo(save_cxt);=0A= +=0A+=09return=20shared;=0A+}=0A+=0A+/*=0A+=20*=20Decrement=20the=20= refcount=20on=20an=20MVCCSnapshotShared=20struct,=20freeing=20it=20if=20= it=0A+=20*=20reaches=20zero.=0A+=20*/=0A+static=20void=0A= +ReleaseMVCCSnapshotShared(MVCCSnapshotShared=20shared)=0A+{=0A+=09= Assert(shared->refcount=20>=200);=0A+=09shared->refcount--;=0A+=0A+=09if=20= (shared->refcount=20=3D=3D=200)=0A+=09{=0A+=09=09= dlist_delete(&shared->node);=0A+=09=09if=20(shared=20!=3D=20= latestSnapshotShared)=0A+=09=09=09FreeMVCCSnapshotShared(shared);=0A+=09= }=0A+}=0A+=0A+void=0A+FreeMVCCSnapshotShared(MVCCSnapshotShared=20= shared)=0A+{=0A+=09Assert(shared->refcount=20=3D=3D=200);=0A+=09if=20= (spareSnapshotShared=20=3D=3D=20NULL)=0A+=09=09spareSnapshotShared=20=3D=20= shared;=0A+=09else=0A+=09=09pfree(shared);=0A+}=0A+=0A=20/*=20= ResourceOwner=20callbacks=20*/=0A=20=0A=20static=20void=0A@@=20-2042,12=20= +2015,13=20@@=20ResOwnerReleaseSnapshot(Datum=20res)=0A=20=0A=20/*=20= dlist_push_tail,=20with=20assertion=20that=20the=20list=20stays=20= ordered=20by=20xmin=20*/=0A=20static=20void=0A= -valid_snapshots_push_tail(MVCCSnapshot=20snapshot)=0A= +valid_snapshots_push_tail(MVCCSnapshotShared=20snapshot)=0A=20{=0A=20= #ifdef=20USE_ASSERT_CHECKING=0A=20=09if=20= (!dlist_is_empty(&ValidSnapshots))=0A=20=09{=0A-=09=09MVCCSnapshot=20= tail=20=3D=20dlist_tail_element(MVCCSnapshotData,=20node,=20= &ValidSnapshots);=0A+=09=09MVCCSnapshotShared=20tail=20=3D=0A+=09=09=09= dlist_tail_element(MVCCSnapshotSharedData,=20node,=20&ValidSnapshots);=0A= =20=0A=20=09=09Assert(TransactionIdFollowsOrEquals(snapshot->xmin,=20= tail->xmin));=0A=20=09}=0A@@=20-2062,13=20+2036,14=20@@=20= valid_snapshots_push_tail(MVCCSnapshot=20snapshot)=0A=20=20*=20the=20= list=20is=20small.=0A=20=20*/=0A=20static=20void=0A= -valid_snapshots_push_out_of_order(MVCCSnapshot=20snapshot)=0A= +valid_snapshots_push_out_of_order(MVCCSnapshotShared=20snapshot)=0A=20{=0A= =20=09dlist_iter=09iter;=0A=20=0A=20=09dlist_foreach(iter,=20= &ValidSnapshots)=0A=20=09{=0A-=09=09MVCCSnapshot=20cur=20=3D=20= dlist_container(MVCCSnapshotData,=20node,=20iter.cur);=0A+=09=09= MVCCSnapshotShared=20cur=20=3D=0A+=09=09=09= dlist_container(MVCCSnapshotSharedData,=20node,=20iter.cur);=0A=20=0A=20=09= =09if=20(TransactionIdFollowsOrEquals(snapshot->xmin,=20cur->xmin))=0A=20= =09=09{=0Adiff=20--git=20a/src/include/access/transam.h=20= b/src/include/access/transam.h=0Aindex=207d82cd2eb56..e71c660118e=20= 100644=0A---=20a/src/include/access/transam.h=0A+++=20= b/src/include/access/transam.h=0A@@=20-242,8=20+242,8=20@@=20typedef=20= struct=20TransamVariablesData=0A=20=09=20*=20Number=20of=20top-level=20= transactions=20with=20xids=20(i.e.=20which=20may=20have=0A=20=09=20*=20= modified=20the=20database)=20that=20completed=20in=20some=20form=20since=20= the=20start=20of=0A=20=09=20*=20the=20server.=20This=20currently=20is=20= solely=20used=20to=20check=20whether=0A-=09=20*=20GetSnapshotData()=20= needs=20to=20recompute=20the=20contents=20of=20the=20snapshot,=20or=0A-=09= =20*=20not.=20There=20are=20likely=20other=20users=20of=20this.=20=20= Always=20above=201.=0A+=09=20*=20GetMVCCSnapshotData()=20needs=20to=20= recompute=20the=20contents=20of=20the=20snapshot,=0A+=09=20*=20or=20not.=20= There=20are=20likely=20other=20users=20of=20this.=20=20Always=20above=20= 1.=0A=20=09=20*/=0A=20=09uint64=09=09xactCompletionCount;=0A=20=0Adiff=20= --git=20a/src/include/storage/predicate.h=20= b/src/include/storage/predicate.h=0Aindex=206a78dfeac96..e68862576ee=20= 100644=0A---=20a/src/include/storage/predicate.h=0A+++=20= b/src/include/storage/predicate.h=0A@@=20-47,10=20+47,10=20@@=20extern=20= void=20CheckPointPredicate(void);=0A=20extern=20bool=20= PageIsPredicateLocked(Relation=20relation,=20BlockNumber=20blkno);=0A=20=0A= =20/*=20predicate=20lock=20maintenance=20*/=0A-extern=20MVCCSnapshot=20= GetSerializableTransactionSnapshot(MVCCSnapshot=20snapshot);=0A-extern=20= void=20SetSerializableTransactionSnapshot(MVCCSnapshot=20snapshot,=0A-=09= =09=09=09=09=09=09=09=09=09=09=20=20=20VirtualTransactionId=20= *sourcevxid,=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20int=20= sourcepid);=0A+extern=20MVCCSnapshotShared=20= GetSerializableTransactionSnapshotData(void);=0A+extern=20void=20= SetSerializableTransactionSnapshotData(MVCCSnapshotShared=20snapshot,=0A= +=09=09=09=09=09=09=09=09=09=09=09=09=20=20=20VirtualTransactionId=20= *sourcevxid,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=20=20=20int=20= sourcepid);=0A=20extern=20void=20= RegisterPredicateLockingXid(TransactionId=20xid);=0A=20extern=20void=20= PredicateLockRelation(Relation=20relation,=20Snapshot=20snapshot);=0A=20= extern=20void=20PredicateLockPage(Relation=20relation,=20BlockNumber=20= blkno,=20Snapshot=20snapshot);=0Adiff=20--git=20= a/src/include/storage/proc.h=20b/src/include/storage/proc.h=0Aindex=20= f51b03d3822..46b58a17489=20100644=0A---=20a/src/include/storage/proc.h=0A= +++=20b/src/include/storage/proc.h=0A@@=20-324,7=20+324,7=20@@=20extern=20= PGDLLIMPORT=20PGPROC=20*MyProc;=0A=20=20*=20Adding/Removing=20an=20entry=20= into=20the=20procarray=20requires=20holding=20*both*=0A=20=20*=20= ProcArrayLock=20and=20XidGenLock=20in=20exclusive=20mode=20(in=20that=20= order).=20Both=20are=0A=20=20*=20needed=20because=20the=20dense=20arrays=20= (see=20below)=20are=20accessed=20from=0A-=20*=20GetNewTransactionId()=20= and=20GetSnapshotData(),=20and=20we=20don't=20want=20to=20add=0A+=20*=20= GetNewTransactionId()=20and=20GetMVCCSnapshotData(),=20and=20we=20don't=20= want=20to=20add=0A=20=20*=20further=20contention=20by=20both=20using=20= the=20same=20lock.=20Adding/Removing=20a=20procarray=0A=20=20*=20entry=20= is=20much=20less=20frequent.=0A=20=20*=0Adiff=20--git=20= a/src/include/storage/procarray.h=20b/src/include/storage/procarray.h=0A= index=207f5727c2586..8eedc2d6b9f=20100644=0A---=20= a/src/include/storage/procarray.h=0A+++=20= b/src/include/storage/procarray.h=0A@@=20-44,7=20+44,7=20@@=20extern=20= void=20KnownAssignedTransactionIdsIdleMaintenance(void);=0A=20extern=20= int=09GetMaxSnapshotXidCount(void);=0A=20extern=20int=09= GetMaxSnapshotSubxidCount(void);=0A=20=0A-extern=20MVCCSnapshot=20= GetSnapshotData(MVCCSnapshot=20snapshot);=0A+extern=20MVCCSnapshotShared=20= GetMVCCSnapshotData(void);=0A=20=0A=20extern=20bool=20= ProcArrayInstallImportedXmin(TransactionId=20xmin,=0A=20=09=09=09=09=09=09= =09=09=09=09=20VirtualTransactionId=20*sourcevxid);=0Adiff=20--git=20= a/src/include/utils/snapmgr.h=20b/src/include/utils/snapmgr.h=0Aindex=20= 1f627ff966d..36c6043740f=20100644=0A---=20a/src/include/utils/snapmgr.h=0A= +++=20b/src/include/utils/snapmgr.h=0A@@=20-56,6=20+56,13=20@@=20extern=20= PGDLLIMPORT=20SnapshotData=20SnapshotToastData;=0A=20=09= ((snapshot)->snapshot_type=20=3D=3D=20SNAPSHOT_MVCC=20||=20\=0A=20=09=20= (snapshot)->snapshot_type=20=3D=3D=20SNAPSHOT_HISTORIC_MVCC)=0A=20=0A+/*=20= exported=20so=20that=20GetMVCCSnapshotData()=20can=20access=20these=20*/=0A= +extern=20MVCCSnapshotShared=20latestSnapshotShared;=0A+extern=20= MVCCSnapshotShared=20spareSnapshotShared;=0A+=0A+extern=20= MVCCSnapshotShared=20AllocMVCCSnapshotShared(void);=0A+extern=20void=20= FreeMVCCSnapshotShared(MVCCSnapshotShared=20shared);=0A+=0A=20extern=20= Snapshot=20GetTransactionSnapshot(void);=0A=20extern=20Snapshot=20= GetLatestSnapshot(void);=0A=20extern=20void=20= SnapshotSetCommandId(CommandId=20curcid);=0A@@=20-89,7=20+96,7=20@@=20= extern=20void=20WaitForOlderSnapshots(TransactionId=20limitXmin,=20bool=20= progress);=0A=20extern=20bool=20= ThereAreNoPriorRegisteredSnapshots(void);=0A=20extern=20bool=20= HaveRegisteredOrActiveSnapshot(void);=0A=20=0A-extern=20char=20= *ExportSnapshot(MVCCSnapshot=20snapshot);=0A+extern=20char=20= *ExportSnapshot(MVCCSnapshotShared=20snapshot);=0A=20=0A=20/*=0A=20=20*=20= These=20live=20in=20procarray.c=20because=20they're=20intimately=20= linked=20to=20the=0A@@=20-105,7=20+112,7=20@@=20extern=20bool=20= GlobalVisCheckRemovableFullXid(Relation=20rel,=20FullTransactionId=20= fxid)=0A=20/*=0A=20=20*=20Utility=20functions=20for=20implementing=20= visibility=20routines=20in=20table=20AMs.=0A=20=20*/=0A-extern=20bool=20= XidInMVCCSnapshot(TransactionId=20xid,=20MVCCSnapshot=20snapshot);=0A= +extern=20bool=20XidInMVCCSnapshot(TransactionId=20xid,=20= MVCCSnapshotShared=20snapshot);=0A=20=0A=20/*=20Support=20for=20catalog=20= timetravel=20for=20logical=20decoding=20*/=0A=20struct=20HTAB;=0Adiff=20= --git=20a/src/include/utils/snapshot.h=20b/src/include/utils/snapshot.h=0A= index=2044b3b20f73c..193366ce052=20100644=0A---=20= a/src/include/utils/snapshot.h=0A+++=20b/src/include/utils/snapshot.h=0A= @@=20-119,17=20+119,44=20@@=20typedef=20enum=20SnapshotType=0A=20=09= SNAPSHOT_NON_VACUUMABLE,=0A=20}=20SnapshotType;=0A=20=0A+typedef=20= struct=20MVCCSnapshotSharedData=20*MVCCSnapshotShared;=0A+=0A+typedef=20= enum=20MVCCSnapshotKind=0A+{=0A+=09SNAPSHOT_STATIC,=0A+=09= SNAPSHOT_ACTIVE,=0A+=09SNAPSHOT_REGISTERED,=0A+}=20MVCCSnapshotKind;=0A+=0A= =20/*=0A=20=20*=20Struct=20representing=20a=20normal=20MVCC=20snapshot.=0A= =20=20*=0A=20=20*=20MVCC=20snapshots=20come=20in=20two=20variants:=20= those=20taken=20during=20recovery=20in=20hot=0A=20=20*=20standby=20mode,=20= and=20"normal"=20MVCC=20snapshots.=20=20They=20are=20distinguished=20by=0A= -=20*=20takenDuringRecovery.=0A+=20*=20shared->takenDuringRecovery.=0A=20= =20*/=0A=20typedef=20struct=20MVCCSnapshotData=0A=20{=0A=20=09= SnapshotType=20snapshot_type;=20/*=20type=20of=20snapshot,=20must=20be=20= first=20*/=0A=20=0A+=09/*=0A+=09=20*=20Most=20fields=20are=20in=20this=20= separate=20struct=20which=20can=20be=20reused=20and=20shared=0A+=09=20*=20= between=20snapshots=20that=20only=20differ=20in=20the=20command=20ID.=20=20= It=20is=20reference=0A+=09=20*=20counted=20separately.=0A+=09=20*/=0A+=09= MVCCSnapshotShared=20shared;=0A+=0A+=09CommandId=09curcid;=09=09=09/*=20= in=20my=20xact,=20CID=20<=20curcid=20are=20visible=20*/=0A+=0A+=09/*=0A+=09= =20*=20Book-keeping=20information,=20used=20by=20the=20snapshot=20= manager=0A+=09=20*/=0A+=09MVCCSnapshotKind=20kind;=0A+=09bool=09=09= valid;=0A+}=20MVCCSnapshotData;=0A+=0A+typedef=20struct=20= MVCCSnapshotSharedData=0A+{=0A=20=09/*=0A=20=09=20*=20An=20MVCC=20= snapshot=20can=20never=20see=20the=20effects=20of=20XIDs=20>=3D=20xmax.=20= It=20can=20see=0A=20=09=20*=20the=20effects=20of=20all=20older=20XIDs=20= except=20those=20listed=20in=20the=20snapshot.=20xmin=0A@@=20-160,25=20= +187,17=20@@=20typedef=20struct=20MVCCSnapshotData=0A=20=09bool=09=09= suboverflowed;=09/*=20has=20the=20subxip=20array=20overflowed?=20*/=0A=20= =0A=20=09bool=09=09takenDuringRecovery;=09/*=20recovery-shaped=20= snapshot?=20*/=0A-=09bool=09=09copied;=09=09=09/*=20false=20if=20it's=20= a=20static=20snapshot=20*/=0A-=09bool=09=09valid;=09=09=09/*=20is=20this=20= snapshot=20valid?=20*/=0A-=0A-=09CommandId=09curcid;=09=09=09/*=20in=20= my=20xact,=20CID=20<=20curcid=20are=20visible=20*/=0A-=0A-=09/*=0A-=09=20= *=20Book-keeping=20information,=20used=20by=20the=20snapshot=20manager=0A= -=09=20*/=0A-=09uint32=09=09active_count;=09/*=20refcount=20on=20= ActiveSnapshot=20stack=20*/=0A-=09uint32=09=09regd_count;=09=09/*=20= refcount=20of=20registrations=20in=20resowners=20*/=0A-=09dlist_node=09= node;=09=09=09/*=20link=20in=20ValidSnapshots=20*/=0A=20=0A=20=09/*=0A-=09= =20*=20The=20transaction=20completion=20count=20at=20the=20time=20= GetSnapshotData()=20built=0A-=09=20*=20this=20snapshot.=20Allows=20to=20= avoid=20re-computing=20static=20snapshots=20when=20no=0A-=09=20*=20= transactions=20completed=20since=20the=20last=20GetSnapshotData().=0A+=09= =20*=20The=20transaction=20completion=20count=20at=20the=20time=20= GetMVCCSnapshotData()=0A+=09=20*=20built=20this=20snapshot.=20Allows=20= to=20avoid=20re-computing=20static=20snapshots=20when=0A+=09=20*=20no=20= transactions=20completed=20since=20the=20last=20GetMVCCSnapshotData().=0A= =20=09=20*/=0A=20=09uint64=09=09snapXactCompletionCount;=0A-}=20= MVCCSnapshotData;=0A+=0A+=09uint32=09=09refcount;=0A+=09dlist_node=09= node;=09=09=09/*=20link=20in=20ValidSnapshots=20*/=0A+}=20= MVCCSnapshotSharedData;=0A=20=0A=20typedef=20struct=20MVCCSnapshotData=20= *MVCCSnapshot;=0A=20=0Adiff=20--git=20a/src/tools/pgindent/typedefs.list=20= b/src/tools/pgindent/typedefs.list=0Aindex=20c8ed18cf580..990c83c902a=20= 100644=0A---=20a/src/tools/pgindent/typedefs.list=0A+++=20= b/src/tools/pgindent/typedefs.list=0A@@=20-1636,6=20+1636,8=20@@=20= MINIDUMP_TYPE=0A=20MJEvalResult=0A=20MTTargetRelLookup=0A=20= MVCCSnapshotData=0A+MVCCSnapshotKind=0A+MVCCSnapshotSharedData=0A=20= MVDependencies=0A=20MVDependency=0A=20MVNDistinct=0A--=20=0A2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0008-XXX-add-perf-test.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0008-XXX-add-perf-test.patch" Content-Transfer-Encoding: quoted-printable =46rom=20511f67bc9579c5fcec923fa0fcb20370547561f2=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Mon,=2031=20Mar=202025=2022:29:44=20= +0300=0ASubject:=20[PATCH=20v6=2008/12]=20XXX:=20add=20perf=20test=0A=0A= This=20is=20not=20intended=20to=20be=20merged.=20But=20it's=20been=20= useful=20to=20have=20this=0Ain=20the=20tree=20for=20some=20quick=20perf=20= testing=20during=20development.=0A=0ATo=20run=20it,=20I've=20used:=0A=0A= (cd=20build-release=20&&=20ninja=20&&=20=20rm=20-rf=20tmp_install=20&&=20= meson=20test=20--suite=20setup=20--suite=20test_misc;=20grep=20TEST=20= testrun/test_misc/000_csn_perf/log/regress_log_000_csn_perf=20)=0A=0AIt=20= runs=20the=20other=20test_misc=20tests=20concurrently,=20but=20they=20= finish=20a=20lot=0Afaster=20so=20they=20don't=20affect=20the=20results=20= much.=0A---=0A=20src/test/modules/test_misc/meson.build=20=20=20=20=20=20= =20|=20=20=201=20+=0A=20src/test/modules/test_misc/t/000_csn_perf.pl=20|=20= 337=20+++++++++++++++++++=0A=202=20files=20changed,=20338=20= insertions(+)=0A=20create=20mode=20100644=20= src/test/modules/test_misc/t/000_csn_perf.pl=0A=0Adiff=20--git=20= a/src/test/modules/test_misc/meson.build=20= b/src/test/modules/test_misc/meson.build=0Aindex=20= 9c50de7efb0..1c385123448=20100644=0A---=20= a/src/test/modules/test_misc/meson.build=0A+++=20= b/src/test/modules/test_misc/meson.build=0A@@=20-9,6=20+9,7=20@@=20tests=20= +=3D=20{=0A=20=20=20=20=20=20=20=20'enable_injection_points':=20= get_option('injection_points')=20?=20'yes'=20:=20'no',=0A=20=20=20=20=20= },=0A=20=20=20=20=20'tests':=20[=0A+=20=20=20=20=20=20= 't/000_csn_perf.pl',=0A=20=20=20=20=20=20=20= 't/001_constraint_validation.pl',=0A=20=20=20=20=20=20=20= 't/002_tablespace.pl',=0A=20=20=20=20=20=20=20't/003_check_guc.pl',=0A= diff=20--git=20a/src/test/modules/test_misc/t/000_csn_perf.pl=20= b/src/test/modules/test_misc/t/000_csn_perf.pl=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..3915878a407=0A---=20/dev/null=0A+++=20= b/src/test/modules/test_misc/t/000_csn_perf.pl=0A@@=20-0,0=20+1,337=20@@=0A= +=0A+#=20Copyright=20(c)=202021-2024,=20PostgreSQL=20Global=20= Development=20Group=0A+=0A+#=20Verify=20that=20ALTER=20TABLE=20optimizes=20= certain=20operations=20as=20expected=0A+=0A+use=20strict;=0A+use=20= warnings=20FATAL=20=3D>=20'all';=0A+use=20PostgreSQL::Test::Cluster;=0A= +use=20PostgreSQL::Test::Utils;=0A+use=20Test::More;=0A+use=20= Time::HiRes=20qw(time);=0A+=0A+my=20$duration=20=3D=2015;=20#=20seconds=0A= +my=20$miniterations=20=3D=203;=0A+=0A+#=20Initialize=20a=20test=20= cluster=0A+my=20$primary=20=3D=20= PostgreSQL::Test::Cluster->new('primary');=0A+$primary->init();=0A+#=20= Turn=20message=20level=20up=20to=20DEBUG1=20so=20that=20we=20get=20the=20= messages=20we=20want=20to=20see=0A= +$primary->append_conf('postgresql.conf',=20'max_wal_senders=20=3D=20= 5');=0A+$primary->append_conf('postgresql.conf',=20'wal_level=3Dreplica');= =0A+$primary->append_conf('postgresql.conf',=20'max_connections=20=3D=20= 1005');=0A+$primary->start;=0A+$primary->backup('bkp');=0A+=0A+my=20= $replica=20=3D=20PostgreSQL::Test::Cluster->new('replica');=0A= +$replica->init_from_backup($primary,=20'bkp',=20has_streaming=20=3D>=20= 1);=0A+$replica->append_conf('postgresql.conf',=20"shared_buffers=3D'1=20= GB'");=0A+$replica->start;=0A+=0A+sub=20wait_catchup=0A+{=0A+=09my=20= ($primary,=20$replica)=20=3D=20@_;=0A+=09=0A+=09my=20$primary_lsn=20=3D=0A= +=09=20=20$primary->safe_psql('postgres',=20"SELECT=20= pg_current_wal_lsn()");=0A+=09my=20$caughtup_query=20=3D=0A+=09=20=20= "SELECT=20'$primary_lsn'::pg_lsn=20<=3D=20pg_last_wal_replay_lsn()";=0A+=09= $replica->poll_query_until('postgres',=20$caughtup_query)=0A+=09=20=20or=20= die=20"Timed=20out=20while=20waiting=20for=20standby=20to=20catch=20up";=0A= +}=0A+=0A+sub=20repeat_and_time_sql=0A+{=0A+=20=20=09my=20($name,=20= $node,=20$sql)=20=3D=20@_;=0A+=0A+=09my=20$session=20=3D=20=20= $node->background_psql('postgres',=20on_error_die=20=3D>=201);=0A+=09= $session->query_safe("SET=20max_parallel_workers_per_gather=3D0");=0A+=0A= +=09my=20$iterations=20=3D=200;=0A+=0A+=09my=20$now;=0A+=09my=20= $elapsed;=0A+=20=20=20=20my=20$begin_time=20=3D=20time();=0A+=09while=20= (1)=20{=0A+=09=09$session->query_safe($sql);=0A+=09=09$now=20=3D=20= time();=0A+=09=09$iterations=20=3D=20$iterations=20+=201;=0A+=0A+=09=09= $elapsed=20=3D=20$now=20-=20$begin_time;=0A+=09=09if=20($elapsed=20>=20= $duration=20&&=20$iterations=20>=3D=20$miniterations)=20{=0A+=09=09=09= last;=0A+=09=09}=0A+=09}=0A+=0A+=09my=20$periter=20=3D=20$elapsed=20/=20= $iterations;=0A+=0A+=09pass=20("TEST=20$name:=20$elapsed=20s,=20= $iterations=20iterations,=20$periter=20s=20/=20iteration");=0A+}=0A+=0A+=0A= +$primary->safe_psql('postgres',=20"CREATE=20TABLE=20little=20(i=20= int);");=0A+$primary->safe_psql('postgres',=20"INSERT=20INTO=20little=20= VALUES=20(1);");=0A+=0A+sub=20consume_xids=0A+{=0A+=09my=20($node)=20=3D=20= @_;=0A+=0A+=09my=20$session=20=3D=20$node->background_psql('postgres',=20= on_error_die=20=3D>=201);=0A+=09for(my=20$i=20=3D=200;=20$i=20<=2020;=20= $i++)=20{=0A+=09=09$session->query_safe(q{do=20$$=0A+=20=20begin=0A+=20=20= =20=20for=20i=20in=201..50=20loop=0A+=20=20=20=20=20=20begin=0A+=20=20=20= =20=20=20=20=20DELETE=20from=20little;=0A+=20=20=20=20=20=20=20=20= perform=201=20/=200;=0A+=20=20=20=20=20=20exception=0A+=20=20=20=20=20=20= =20=20when=20division_by_zero=20then=20perform=200=20/*=20do=20nothing=20= */;=0A+=20=20=20=20=20=20=20=20when=20others=20then=20raise=20'fail:=20= %',=20sqlerrm;=0A+=20=20=20=20=20=20end;=0A+=20=20=20=20end=20loop;=0A+=20= =20end=0A+$$;});=0A+=09}=0A+=09$session->quit;=0A+}=0A+=0A+#=20TEST=20= few-xacts=0A+#=0A+#=20Cycle=20through=204=20different=20top-level=20XIDs=0A= +#=0A+#=201001,=201002,=201003,=201004,=201001,=201002,=201003,=201004,=20= ...=0A+#=0A+if=20(1)=0A+{=0A+=09$primary->safe_psql('postgres',=20= 'CREATE=20TABLE=20tbl(i=20int)');=0A+=09$primary->safe_psql('postgres',=20= "INSERT=20INTO=20tbl=20SELECT=20g=20FROM=20generate_series(1,=20100000)=20= g;");=0A+=09$primary->safe_psql('postgres',=20"VACUUM=20FREEZE=20tbl;");=0A= +=0A+=09my=20@primary_sessions=20=3D=20();=0A+=09my=20$num_connections=20= =3D=204;=0A+=09for(my=20$i=20=3D=200;=20$i=20<=20$num_connections;=20= $i++)=20{=0A+=09=09my=20$primary_session=20=3D=20=20= $primary->background_psql('postgres',=20on_error_die=20=3D>=201);=0A+=09=09= $primary_session->query_safe("BEGIN;");=0A+=09=09= $primary_session->query_safe("DELETE=20FROM=20tbl=20WHERE=20i=20%=20= $num_connections=20=3D=20$i;");=0A+=09=09push(@primary_sessions,=20= $primary_session);=0A+=09}=0A+=0A+=09#=20Consume=20one=20more=20XID,=20= to=20bump=20up=20"last=20committed=20XID"=0A+=09= $primary->safe_psql('postgres',=20"select=20txid_current()");=0A+=0A+=09= wait_catchup($primary,=20$replica);=0A+=0A+=09= repeat_and_time_sql("few-xacts",=20$replica,=20"select=20count(*)=20from=20= tbl");=0A+=0A+=09for(my=20$i=20=3D=200;=20$i=20<=20$num_connections;=20= $i++)=20{=0A+=09=09$primary_sessions[$i]->quit;=0A+=09}=0A+=09= $primary->safe_psql('postgres',=20"DROP=20TABLE=20tbl");=0A+}=0A+=0A+#=20= TEST=20many-xacts=0A+#=0A+#=20like=20few-xacts,=20but=20we=20cycle=20= through=20100=20different=20XIDs=20instead=20of=204.=0A+#=0A+#=201001,=20= 1002,=201003,=20...=201100,=201001,=201002,=201003,=20...=201100=20=20= ....=0A+#=0A+if=20(1)=0A+{=0A+=09$primary->safe_psql('postgres',=20= 'CREATE=20TABLE=20tbl(i=20int)');=0A+=09$primary->safe_psql('postgres',=20= "INSERT=20INTO=20tbl=20SELECT=20g=20FROM=20generate_series(1,=20100000)=20= g;");=0A+=09$primary->safe_psql('postgres',=20"VACUUM=20FREEZE=20tbl;");=0A= +=0A+=09my=20@primary_sessions=20=3D=20();=0A+=09my=20$num_connections=20= =3D=20100;=0A+=09for(my=20$i=20=3D=200;=20$i=20<=20$num_connections;=20= $i++)=20{=0A+=09=09my=20$primary_session=20=3D=20=20= $primary->background_psql('postgres',=20on_error_die=20=3D>=201);=0A+=09=09= $primary_session->query_safe("BEGIN;");=0A+=09=09= $primary_session->query_safe("DELETE=20FROM=20tbl=20WHERE=20i=20%=20= $num_connections=20=3D=20$i;");=0A+=09=09push(@primary_sessions,=20= $primary_session);=0A+=09}=0A+=0A+=09#=20Consume=20one=20more=20XID,=20= to=20bump=20up=20"last=20committed=20XID"=0A+=09= $primary->safe_psql('postgres',=20"select=20txid_current()");=0A+=0A+=09= wait_catchup($primary,=20$replica);=0A+=0A+=09= repeat_and_time_sql("many-xacts",=20$replica,=20"select=20count(*)=20= from=20tbl");=0A+=0A+=09for(my=20$i=20=3D=200;=20$i=20<=20= $num_connections;=20$i++)=20{=0A+=09=09$primary_sessions[$i]->quit;=0A+=09= }=0A+=09$primary->safe_psql('postgres',=20"DROP=20TABLE=20tbl");=0A+}=0A= +=0A+#=20TEST=20many-xacts-wide-apart=0A+#=0A+#=20like=20many-xacts,=20= but=20the=20XIDs=20are=20more=20spread=20out,=20so=20that=20they=20don't=20= fit=20in=20the=0A+#=20SLRU=20caches.=0A+#=0A+#=201000,=202000,=203000,=20= 4000,=20....=0A+if=20(1)=0A+{=0A+=09$primary->safe_psql('postgres',=20= 'CREATE=20TABLE=20tbl(i=20int)');=0A+=09$primary->safe_psql('postgres',=20= "INSERT=20INTO=20tbl=20SELECT=20g=20FROM=20generate_series(1,=20100000)=20= g;");=0A+=09$primary->safe_psql('postgres',=20"VACUUM=20FREEZE=20tbl;");=0A= +=0A+=09my=20@primary_sessions=20=3D=20();=0A+=09my=20$num_connections=20= =3D=20100;=0A+=09for(my=20$i=20=3D=200;=20$i=20<=20$num_connections;=20= $i++)=20{=0A+=09=09my=20$primary_session=20=3D=20=20= $primary->background_psql('postgres',=20on_error_die=20=3D>=201);=0A+=0A= +=09=09consume_xids($primary);=0A+=0A+=09=09= $primary_session->query_safe("BEGIN;");=0A+=09=09= $primary_session->query_safe("DELETE=20FROM=20tbl=20WHERE=20i=20%=20= $num_connections=20=3D=20$i;");=0A+=09=09push(@primary_sessions,=20= $primary_session);=0A+=09}=0A+=0A+=09#=20Consume=20one=20more=20XID,=20= to=20bump=20up=20"last=20committed=20XID"=0A+=09= $primary->safe_psql('postgres',=20"select=20txid_current()");=0A+=0A+=09= wait_catchup($primary,=20$replica);=0A+=0A+=09= repeat_and_time_sql("many-xacts-wide-apart",=20$replica,=20"select=20= count(*)=20from=20tbl");=0A+=0A+=09for(my=20$i=20=3D=200;=20$i=20<=20= $num_connections;=20$i++)=20{=0A+=09=09$primary_sessions[$i]->quit;=0A+=09= }=0A+=09$primary->safe_psql('postgres',=20"DROP=20TABLE=20tbl");=0A+}=0A= +=0A+#=20TEST:=20few-subxacts=0A+if=20(1)=0A+{=0A+=09= $primary->safe_psql('postgres',=20'CREATE=20TABLE=20tbl(i=20int)');=0A+=09= $primary->safe_psql('postgres',=20"INSERT=20INTO=20tbl=20SELECT=20g=20= FROM=20generate_series(1,=20100000)=20g;");=0A+=09= $primary->safe_psql('postgres',=20"VACUUM=20FREEZE=20tbl;");=0A+=0A+=09= my=20$primary_session=20=3D=20=20$primary->background_psql('postgres',=20= on_error_die=20=3D>=201);=0A+=09$primary_session->query_safe("BEGIN;");=0A= +=09my=20$num_subxacts=20=3D=204;=0A+=09for(my=20$i=20=3D=200;=20$i=20<=20= $num_subxacts;=20$i++)=20{=0A+=09=09= $primary_session->query_safe("savepoint=20sp$i;");=0A+=09=09= $primary_session->query_safe("DELETE=20FROM=20tbl=20WHERE=20i=20%=20= $num_subxacts=20=3D=20$i;");=0A+=09=09= $primary_session->query_safe("release=20savepoint=20sp$i;");=0A+=09}=0A+=0A= +=09#=20Consume=20one=20more=20XID,=20to=20bump=20up=20"last=20committed=20= XID"=0A+=09$primary->safe_psql('postgres',=20"select=20txid_current()");=0A= +=0A+=09wait_catchup($primary,=20$replica);=0A+=0A+=09= repeat_and_time_sql("few-subxacts",=20$replica,=20"select=20count(*)=20= from=20tbl");=0A+=0A+=09$primary_session->quit;=0A+=09= $primary->safe_psql('postgres',=20"DROP=20TABLE=20tbl");=0A+}=0A+=0A+=0A= +#=20TEST:=20many-subxacts=0A+if=20(1)=0A+{=0A+=09= $primary->safe_psql('postgres',=20'CREATE=20TABLE=20tbl(i=20int)');=0A+=09= $primary->safe_psql('postgres',=20"INSERT=20INTO=20tbl=20SELECT=20g=20= FROM=20generate_series(1,=20100000)=20g;");=0A+=09= $primary->safe_psql('postgres',=20"VACUUM=20FREEZE=20tbl;");=0A+=0A+=09= my=20$primary_session=20=3D=20=20$primary->background_psql('postgres',=20= on_error_die=20=3D>=201);=0A+=09$primary_session->query_safe("BEGIN;");=0A= +=09my=20$num_subxacts=20=3D=201000;=0A+=09for(my=20$i=20=3D=200;=20$i=20= <=20$num_subxacts;=20$i++)=20{=0A+=09=09= $primary_session->query_safe("savepoint=20sp$i;");=0A+=09=09= $primary_session->query_safe("DELETE=20FROM=20tbl=20WHERE=20i=20%=20= $num_subxacts=20=3D=20$i;");=0A+=09=09= $primary_session->query_safe("release=20savepoint=20sp$i;");=0A+=09}=0A+=0A= +=09#=20Consume=20one=20more=20XID,=20to=20bump=20up=20"last=20committed=20= XID"=0A+=09$primary->safe_psql('postgres',=20"select=20txid_current()");=0A= +=0A+=09wait_catchup($primary,=20$replica);=0A+=0A+=09= repeat_and_time_sql("many-subxacts",=20$replica,=20"select=20count(*)=20= from=20tbl");=0A+=0A+=09$primary_session->quit;=0A+=09= $primary->safe_psql('postgres',=20"DROP=20TABLE=20tbl");=0A+}=0A+=0A+#=20= TEST:=20many-subxacts-wide-apart=0A+if=20(1)=0A+{=0A+=09= $primary->safe_psql('postgres',=20'CREATE=20TABLE=20tbl(i=20int)');=0A+=09= $primary->safe_psql('postgres',=20"INSERT=20INTO=20tbl=20SELECT=20g=20= FROM=20generate_series(1,=20100000)=20g;");=0A+=09= $primary->safe_psql('postgres',=20"VACUUM=20FREEZE=20tbl;");=0A+=0A+=09= my=20$primary_session=20=3D=20=20$primary->background_psql('postgres',=20= on_error_die=20=3D>=201);=0A+=09$primary_session->query_safe("BEGIN;");=0A= +=09my=20$num_subxacts=20=3D=201000;=0A+=09for(my=20$i=20=3D=200;=20$i=20= <=20$num_subxacts;=20$i++)=20{=0A+=09=09consume_xids($primary);=0A+=09=09= $primary_session->query_safe("savepoint=20sp$i;");=0A+=09=09= $primary_session->query_safe("DELETE=20FROM=20tbl=20WHERE=20i=20%=20= $num_subxacts=20=3D=20$i;");=0A+=09=09= $primary_session->query_safe("release=20savepoint=20sp$i;");=0A+=09}=0A+=0A= +=09#=20Consume=20one=20more=20XID,=20to=20bump=20up=20"last=20committed=20= XID"=0A+=09$primary->safe_psql('postgres',=20"select=20txid_current()");=0A= +=0A+=09wait_catchup($primary,=20$replica);=0A+=0A+=09= repeat_and_time_sql("many-subxacts-wide-apart",=20$replica,=20"select=20= count(*)=20from=20tbl");=0A+=0A+=09$primary_session->quit;=0A+=09= $primary->safe_psql('postgres',=20"DROP=20TABLE=20tbl");=0A+}=0A+=0A+#=20= TEST:=20insert-all-different-xids=0A+if=20(1)=0A+{=0A+=09= $primary->safe_psql('postgres',=20'CREATE=20TABLE=20tbl(i=20int)');=0A+=0A= +=09my=20@primary_sessions=20=3D=20();=0A+=09my=20$num_connections=20=3D=20= 1000;=0A+=09for(my=20$i=20=3D=200;=20$i=20<=20$num_connections;=20$i++)=20= {=0A+=09=09my=20$primary_session=20=3D=20=20= $primary->background_psql('postgres',=20on_error_die=20=3D>=201);=0A+=09=09= $primary_session->query_safe("BEGIN;");=0A+=09=09= $primary_session->query_safe("INSERT=20INTO=20tbl=20VALUES=20($i)");=0A+=09= =09push(@primary_sessions,=20$primary_session);=0A+=09}=0A+=0A+=09#=20= Consume=20one=20more=20XID,=20to=20bump=20up=20"last=20committed=20XID"=0A= +=09$primary->safe_psql('postgres',=20"select=20txid_current()");=0A+=0A= +=09wait_catchup($primary,=20$replica);=0A+=0A+=09= repeat_and_time_sql("insert-all-different-xids",=20$replica,=20"select=20= count(*)=20from=20tbl");=0A+=0A+=09for(my=20$i=20=3D=200;=20$i=20<=20= $num_connections;=20$i++)=20{=0A+=09=09$primary_sessions[$i]->quit;=0A+=09= }=0A+=09$primary->safe_psql('postgres',=20"DROP=20TABLE=20tbl");=0A+}=0A= +=0A+#=20TEST:=20insert-all-different-subxids=0A+if=20(1)=0A+{=0A+=09= $primary->safe_psql('postgres',=20'CREATE=20TABLE=20tbl(i=20int)');=0A+=09= $primary->safe_psql('postgres',=20"VACUUM=20FREEZE=20tbl;");=0A+=0A+=09= my=20$primary_session=20=3D=20=20$primary->background_psql('postgres',=20= on_error_die=20=3D>=201);=0A+=09$primary_session->query_safe("BEGIN;");=0A= +=09my=20$num_subxacts=20=3D=201000;=0A+=09for(my=20$i=20=3D=200;=20$i=20= <=20$num_subxacts;=20$i++)=20{=0A+=09=09= $primary_session->query_safe("savepoint=20sp$i;=20INSERT=20INTO=20tbl=20= VALUES($i);=20release=20savepoint=20sp$i;");=0A+=09}=0A+=0A+=09#=20= Consume=20one=20more=20XID,=20to=20bump=20up=20"last=20committed=20XID"=0A= +=09$primary->safe_psql('postgres',=20"select=20txid_current()");=0A+=0A= +=09wait_catchup($primary,=20$replica);=0A+=0A+=09= repeat_and_time_sql("insert-all-different-subxids",=20$replica,=20= "select=20count(*)=20from=20tbl");=0A+=0A+=09$primary_session->quit;=0A+=09= $primary->safe_psql('postgres',=20"DROP=20TABLE=20tbl");=0A+}=0A+=0A= +done_testing();=0A--=20=0A2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0009-Use-CSN-snapshots-during-Hot-Standby.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0009-Use-CSN-snapshots-during-Hot-Standby.patch" Content-Transfer-Encoding: quoted-printable =46rom=207fec26347c80d42f0243f0d3328b38c69105a41f=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Tue,=201=20Apr=202025=2000:16:17=20= +0300=0ASubject:=20[PATCH=20v6=2009/12]=20Use=20CSN=20snapshots=20during=20= Hot=20Standby=0A=0AReplace=20the=20known-assigned-XIDs=20mechanism=20= with=20a=20CSN=20log.=20The=20CSN=20log=0A(pg_csn)=20tracks=20the=20= commit=20LSN=20of=20each=20transaction,=20when=20replaying=20the=0AWAL=20= on=20a=20standby.=20It's=20only=20used=20on=20the=20standby,=20and=20is=20= initialized=0Afrom=20scratch=20at=20server=20startup=20like=20= pg_subtrans.=0A=0ABased=20on=200001-CSN-base-snapshot.patch=20from=0A= https://www.postgresql.org/message-id/2020081009525213277261%40highgo.ca.=0A= This=20patch=20has=20a=20long=20lineage,=20various=20CSN=20patches=20= have=20been=20posted=0Awith=20parts=20from=20Stas=20Kelvich,=20Movead=20= Li,=20Ants=20Aasma,=20Heikki=0ALinnakangas,=20Alexander=20Kuzmenkov=0A= ---=0A=20contrib/pg_visibility/pg_visibility.c=20=20=20=20=20=20=20=20=20= |=20=20=20=201=20+=0A=20src/backend/access/rmgrdesc/xactdesc.c=20=20=20=20= =20=20=20=20|=20=20=2026=20-=0A=20src/backend/access/transam/Makefile=20=20= =20=20=20=20=20=20=20=20=20|=20=20=20=201=20+=0A=20= src/backend/access/transam/csn_log.c=20=20=20=20=20=20=20=20=20=20|=20=20= 469=20+++++=0A=20src/backend/access/transam/meson.build=20=20=20=20=20=20= =20=20|=20=20=20=201=20+=0A=20src/backend/access/transam/transam.c=20=20=20= =20=20=20=20=20=20=20|=20=20=20=203=20+=0A=20= src/backend/access/transam/twophase.c=20=20=20=20=20=20=20=20=20|=20=20=20= 34=20+-=0A=20src/backend/access/transam/varsup.c=20=20=20=20=20=20=20=20=20= =20=20|=20=20=20=201=20+=0A=20src/backend/access/transam/xact.c=20=20=20=20= =20=20=20=20=20=20=20=20=20|=20=20138=20+-=0A=20= src/backend/access/transam/xlog.c=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20118=20+-=0A=20src/backend/access/transam/xlogrecovery.c=20=20=20=20= =20|=20=20=2013=20+-=0A=20src/backend/access/transam/xlogutils.c=20=20=20= =20=20=20=20=20|=20=20=20=202=20+-=0A=20src/backend/backup/basebackup.c=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=203=20+=0A=20= src/backend/postmaster/startup.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=20=202=20+-=0A=20src/backend/replication/logical/decode.c=20=20=20= =20=20=20|=20=20=20=208=20-=0A=20= src/backend/replication/logical/snapbuild.c=20=20=20|=20=20=20=202=20+-=0A= =20src/backend/storage/ipc/ipci.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20|=20=20=20=203=20+=0A=20src/backend/storage/ipc/procarray.c=20=20=20= =20=20=20=20=20=20=20=20|=201538=20++---------------=0A=20= src/backend/storage/ipc/standby.c=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20102=20+-=0A=20src/backend/storage/lmgr/lwlock.c=20=20=20=20=20=20=20= =20=20=20=20=20=20|=20=20=20=202=20+=0A=20= .../utils/activity/wait_event_names.txt=20=20=20=20=20=20=20|=20=20=20=20= 1=20+=0A=20src/backend/utils/probes.d=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20=20=20=202=20+=0A=20= src/backend/utils/time/snapmgr.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=2034=20+-=0A=20src/bin/initdb/initdb.c=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=203=20+-=0A=20= src/bin/pg_rewind/filemap.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=20=203=20+=0A=20src/include/access/csn_log.h=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=2030=20+=0A=20= src/include/access/transam.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=20=203=20+=0A=20src/include/access/twophase.h=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=203=20+-=0A=20= src/include/access/xact.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20|=20=20=2012=20+-=0A=20src/include/access/xlogutils.h=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=2033=20+-=0A=20= src/include/storage/lwlock.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=20=202=20+=0A=20src/include/storage/procarray.h=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20=20=2013=20+-=0A=20= src/include/utils/snapshot.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=20=208=20+=0A=2033=20files=20changed,=20821=20= insertions(+),=201793=20deletions(-)=0A=20create=20mode=20100644=20= src/backend/access/transam/csn_log.c=0A=20create=20mode=20100644=20= src/include/access/csn_log.h=0A=0Adiff=20--git=20= a/contrib/pg_visibility/pg_visibility.c=20= b/contrib/pg_visibility/pg_visibility.c=0Aindex=20= d79ef35006b..c5c7a4dd2c3=20100644=0A---=20= a/contrib/pg_visibility/pg_visibility.c=0A+++=20= b/contrib/pg_visibility/pg_visibility.c=0A@@=20-607,6=20+607,7=20@@=20= collect_visibility_data(Oid=20relid,=20bool=20include_pd)=0A=20=20*=20=20= =20=20now=20perform=20minimal=20checking=20on=20a=20standby=20by=20= always=20using=20nextXid,=20this=0A=20=20*=20=20=20=20approach=20is=20= better=20than=20nothing=20and=20will=20at=20least=20catch=20extremely=20= broken=0A=20=20*=20=20=20=20cases=20where=20a=20xid=20is=20in=20the=20= future.=0A+=20*=20=20=20=20XXX=20KnownAssignedXids=20is=20gone.=0A=20=20= *=203.=20Ignore=20walsender=20xmin,=20because=20it=20could=20go=20= backward=20if=20some=20replication=0A=20=20*=20=20=20=20connections=20= don't=20use=20replication=20slots.=0A=20=20*=0Adiff=20--git=20= a/src/backend/access/rmgrdesc/xactdesc.c=20= b/src/backend/access/rmgrdesc/xactdesc.c=0Aindex=20= 715cc1f7bad..56f7bd81780=20100644=0A---=20= a/src/backend/access/rmgrdesc/xactdesc.c=0A+++=20= b/src/backend/access/rmgrdesc/xactdesc.c=0A@@=20-422,17=20+422,6=20@@=20= xact_desc_prepare(StringInfo=20buf,=20uint8=20info,=20xl_xact_prepare=20= *xlrec,=20RepOriginI=0A=20=09=09=09=09=09=09=20= timestamptz_to_str(parsed.origin_timestamp));=0A=20}=0A=20=0A-static=20= void=0A-xact_desc_assignment(StringInfo=20buf,=20xl_xact_assignment=20= *xlrec)=0A-{=0A-=09int=09=09=09i;=0A-=0A-=09appendStringInfoString(buf,=20= "subxacts:");=0A-=0A-=09for=20(i=20=3D=200;=20i=20<=20xlrec->nsubxacts;=20= i++)=0A-=09=09appendStringInfo(buf,=20"=20%u",=20xlrec->xsub[i]);=0A-}=0A= -=0A=20void=0A=20xact_desc(StringInfo=20buf,=20XLogReaderState=20= *record)=0A=20{=0A@@=20-460,18=20+449,6=20@@=20xact_desc(StringInfo=20= buf,=20XLogReaderState=20*record)=0A=20=09=09xact_desc_prepare(buf,=20= XLogRecGetInfo(record),=20xlrec,=0A=20=09=09=09=09=09=09=20=20= XLogRecGetOrigin(record));=0A=20=09}=0A-=09else=20if=20(info=20=3D=3D=20= XLOG_XACT_ASSIGNMENT)=0A-=09{=0A-=09=09xl_xact_assignment=20*xlrec=20=3D=20= (xl_xact_assignment=20*)=20rec;=0A-=0A-=09=09/*=0A-=09=09=20*=20Note=20= that=20we=20ignore=20the=20WAL=20record's=20xid,=20since=20we're=20more=0A= -=09=09=20*=20interested=20in=20the=20top-level=20xid=20that=20issued=20= the=20record=20and=20which=0A-=09=09=20*=20xids=20are=20being=20reported=20= here.=0A-=09=09=20*/=0A-=09=09appendStringInfo(buf,=20"xtop=20%u:=20",=20= xlrec->xtop);=0A-=09=09xact_desc_assignment(buf,=20xlrec);=0A-=09}=0A=20=09= else=20if=20(info=20=3D=3D=20XLOG_XACT_INVALIDATIONS)=0A=20=09{=0A=20=09=09= xl_xact_invals=20*xlrec=20=3D=20(xl_xact_invals=20*)=20rec;=0A@@=20= -503,9=20+480,6=20@@=20xact_identify(uint8=20info)=0A=20=09=09case=20= XLOG_XACT_ABORT_PREPARED:=0A=20=09=09=09id=20=3D=20"ABORT_PREPARED";=0A=20= =09=09=09break;=0A-=09=09case=20XLOG_XACT_ASSIGNMENT:=0A-=09=09=09id=20=3D= =20"ASSIGNMENT";=0A-=09=09=09break;=0A=20=09=09case=20= XLOG_XACT_INVALIDATIONS:=0A=20=09=09=09id=20=3D=20"INVALIDATION";=0A=20=09= =09=09break;=0Adiff=20--git=20a/src/backend/access/transam/Makefile=20= b/src/backend/access/transam/Makefile=0Aindex=20661c55a9db7..2520d77c7c8=20= 100644=0A---=20a/src/backend/access/transam/Makefile=0A+++=20= b/src/backend/access/transam/Makefile=0A@@=20-15,6=20+15,7=20@@=20= include=20$(top_builddir)/src/Makefile.global=0A=20OBJS=20=3D=20\=0A=20=09= clog.o=20\=0A=20=09commit_ts.o=20\=0A+=09csn_log.o=20\=0A=20=09= generic_xlog.o=20\=0A=20=09multixact.o=20\=0A=20=09parallel.o=20\=0Adiff=20= --git=20a/src/backend/access/transam/csn_log.c=20= b/src/backend/access/transam/csn_log.c=0Anew=20file=20mode=20100644=0A= index=2000000000000..40673c8579f=0A---=20/dev/null=0A+++=20= b/src/backend/access/transam/csn_log.c=0A@@=20-0,0=20+1,469=20@@=0A= +/*-----------------------------------------------------------------------= ------=0A+=20*=0A+=20*=20csn_log.c=0A+=20*=09=09Track=20commit=20record=20= LSNs=20of=20finished=20transactions=0A+=20*=0A+=20*=20This=20module=20= provides=20an=20SLRU=20to=20store=20the=20LSN=20of=20the=20commit=20= record=20of=20each=0A+=20*=20transaction.=20CSN=20stands=20for=20Commit=20= Sequence=20Number,=20and=20in=20principle=20we=0A+=20*=20could=20use=20a=20= separate=20counter=20that=20is=20incremented=20at=20every=20commit.=20= For=0A+=20*=20simplicity,=20though,=20we=20use=20the=20commit=20records=20= LSN=20as=20the=20sequence=20number.=0A+=20*=0A+=20*=20Like=20= pg_subtrans,=20this=20mapping=20need=20to=20be=20kept=20only=20for=20= xid's=20greater=20then=0A+=20*=20oldestXmin,=20and=20doesn't=20need=20to=20= be=20preserved=20over=20crashes.=20=20Also,=20this=20is=0A+=20*=20only=20= needed=20in=20hot=20standby=20mode,=20and=20immediately=20after=20= exiting=20hot=20standby=0A+=20*=20mode,=20until=20all=20old=20snapshots=20= taken=20during=20standby=20mode=20are=20gone.=0A+=20*=0A+=20*=20Portions=20= Copyright=20(c)=201996-2018,=20PostgreSQL=20Global=20Development=20Group=0A= +=20*=20Portions=20Copyright=20(c)=201994,=20Regents=20of=20the=20= University=20of=20California=0A+=20*=0A+=20*=20= src/backend/access/transam/csn_log.c=0A+=20*=0A+=20= *-------------------------------------------------------------------------= ----=0A+=20*/=0A+#include=20"postgres.h"=0A+=0A+#include=20= "access/clog.h"=0A+#include=20"access/csn_log.h"=0A+#include=20= "access/slru.h"=0A+#include=20"access/subtrans.h"=0A+#include=20= "access/transam.h"=0A+#include=20"miscadmin.h"=0A+#include=20= "pg_trace.h"=0A+#include=20"utils/snapmgr.h"=0A+=0A+/*=0A+=20*=20Defines=20= for=20CSNLog=20page=20sizes.=20=20A=20page=20is=20the=20same=20BLCKSZ=20= as=20is=20used=0A+=20*=20everywhere=20else=20in=20Postgres.=0A+=20*=0A+=20= *=20Note:=20because=20TransactionIds=20are=2032=20bits=20and=20wrap=20= around=20at=200xFFFFFFFF,=0A+=20*=20CSNLog=20page=20numbering=20also=20= wraps=20around=20at=0A+=20*=200xFFFFFFFF/CSN_LOG_XACTS_PER_PAGE,=20and=20= CSNLog=20segment=20numbering=20at=0A+=20*=20= 0xFFFFFFFF/CLOG_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT.=20=20We=20need=20= take=20no=0A+=20*=20explicit=20notice=20of=20that=20fact=20in=20this=20= module,=20except=20when=20comparing=20segment=0A+=20*=20and=20page=20= numbers=20in=20TruncateCSNLog=20(see=20CSNLogPagePrecedes).=0A+=20*/=0A+=0A= +/*=20We=20store=20the=20commit=20CSN=20for=20each=20xid=20*/=0A+#define=20= CSN_LOG_XACTS_PER_PAGE=20(BLCKSZ=20/=20sizeof(XLogRecPtr))=0A+=0A= +#define=20TransactionIdToPage(xid)=09((xid)=20/=20(TransactionId)=20= CSN_LOG_XACTS_PER_PAGE)=0A+#define=20TransactionIdToPgIndex(xid)=20= ((xid)=20%=20(TransactionId)=20CSN_LOG_XACTS_PER_PAGE)=0A+=0A+#define=20= PgIndexToTransactionId(pageno,=20idx)=20(CSN_LOG_XACTS_PER_PAGE=20*=20= (pageno)=20+=20idx)=0A+=0A+=0A+=0A+/*=0A+=20*=20Link=20to=20= shared-memory=20data=20structures=20for=20CSNLog=20control=0A+=20*/=0A= +static=20SlruCtlData=20CSNLogCtlData;=0A+#define=20CsnlogCtl=20= (&CSNLogCtlData)=0A+=0A+static=20int=09ZeroCSNLogPage(int=20pageno);=0A= +static=20bool=20CSNLogPagePrecedes(int64=20page1,=20int64=20page2);=0A= +static=20void=20CSNLogSetPageStatus(TransactionId=20xid,=20int=20= nsubxids,=0A+=09=09=09=09=09=09=09=09TransactionId=20*subxids,=0A+=09=09=09= =09=09=09=09=09XLogRecPtr=20csn,=20int=20pageno);=0A+static=20void=20= CSNLogSetCSNInSlot(TransactionId=20xid,=20XLogRecPtr=20csn,=0A+=09=09=09=09= =09=09=09=20=20=20int=20slotno);=0A+=0A+=0A+/*=0A+=20*=20Record=20commit=20= LSN=20of=20a=20transaction=20and=20its=20subtransaction=20tree.=0A+=20*=0A= +=20*=20xid=20is=20a=20single=20xid=20to=20set=20status=20for.=20This=20= will=20typically=20be=20the=20top=20level=0A+=20*=20transaction=20ID=20= for=20a=20top=20level=20commit.=0A+=20*=0A+=20*=20subxids=20is=20an=20= array=20of=20xids=20of=20length=20nsubxids,=20in=20logical=20XID=20= order,=0A+=20*=20representing=20subtransactions=20in=20the=20tree=20of=20= XIDs.=20In=20various=20cases=20nsubxids=0A+=20*=20may=20be=20zero.=0A+=20= *=0A+=20*=20commitLsn=20is=20the=20LSN=20of=20the=20commit=20record.=20=20= This=20is=20currently=20never=20called=0A+=20*=20for=20aborted=20= transactions.=0A+=20*/=0A+void=0A+CSNLogSetCSN(TransactionId=20xid,=20= int=20nsubxids,=20TransactionId=20*subxids,=0A+=09=09=09=20XLogRecPtr=20= commitLsn)=0A+{=0A+=09int=09=09=09pageno;=0A+=09int=09=09=09i=20=3D=200;=0A= +=09int=09=09=09offset=20=3D=200;=0A+=0A+=09= Assert(TransactionIdIsValid(xid));=0A+=0A+=09pageno=20=3D=20= TransactionIdToPage(xid);=09/*=20get=20page=20of=20parent=20*/=0A+=09for=20= (;;)=0A+=09{=0A+=09=09int=09=09=09num_on_page=20=3D=200;=0A+=0A+=09=09= while=20(i=20<=20nsubxids=20&&=20TransactionIdToPage(subxids[i])=20=3D=3D=20= pageno)=0A+=09=09{=0A+=09=09=09num_on_page++;=0A+=09=09=09i++;=0A+=09=09= }=0A+=0A+=09=09CSNLogSetPageStatus(xid,=0A+=09=09=09=09=09=09=09= num_on_page,=20subxids=20+=20offset,=0A+=09=09=09=09=09=09=09commitLsn,=20= pageno);=0A+=09=09if=20(i=20>=3D=20nsubxids)=0A+=09=09=09break;=0A+=0A+=09= =09offset=20=3D=20i;=0A+=09=09pageno=20=3D=20= TransactionIdToPage(subxids[offset]);=0A+=09=09xid=20=3D=20= InvalidTransactionId;=0A+=09}=0A+}=0A+=0A+/*=0A+=20*=20Record=20the=20= final=20state=20of=20transaction=20entries=20in=20the=20CSN=20log=20for=20= all=0A+=20*=20entries=20on=20a=20single=20page.=20=20Atomic=20only=20on=20= this=20page.=0A+=20*=0A+=20*=20Otherwise=20API=20is=20same=20as=20= CSNLogSetCSN()=0A+=20*/=0A+static=20void=0A= +CSNLogSetPageStatus(TransactionId=20xid,=20int=20nsubxids,=20= TransactionId=20*subxids,=0A+=09=09=09=09=09XLogRecPtr=20commitLsn,=20= int=20pageno)=0A+{=0A+=09int=09=09=09slotno;=0A+=09int=09=09=09i;=0A+=09= LWLock=09=20=20=20*lock;=0A+=0A+=09lock=20=3D=20= SimpleLruGetBankLock(CsnlogCtl,=20pageno);=0A+=09LWLockAcquire(lock,=20= LW_EXCLUSIVE);=0A+=0A+=09slotno=20=3D=20SimpleLruReadPage(CsnlogCtl,=20= pageno,=20true,=20xid);=0A+=0A+=09/*=20Subtransactions=20first,=20if=20= needed=20...=20*/=0A+=09for=20(i=20=3D=200;=20i=20<=20nsubxids;=20i++)=0A= +=09{=0A+=09=09Assert(CsnlogCtl->shared->page_number[slotno]=20=3D=3D=20= TransactionIdToPage(subxids[i]));=0A+=09=09= CSNLogSetCSNInSlot(subxids[i],=20commitLsn,=20slotno);=0A+=09}=0A+=0A+=09= /*=20...=20then=20the=20main=20transaction=20*/=0A+=09if=20= (TransactionIdIsValid(xid))=0A+=09=09CSNLogSetCSNInSlot(xid,=20= commitLsn,=20slotno);=0A+=0A+=09CsnlogCtl->shared->page_dirty[slotno]=20= =3D=20true;=0A+=0A+=09LWLockRelease(lock);=0A+}=0A+=0A+/*=0A+=20*=20Sets=20= the=20commit=20status=20of=20a=20single=20transaction.=0A+=20*/=0A= +static=20void=0A+CSNLogSetCSNInSlot(TransactionId=20xid,=20XLogRecPtr=20= csn,=20int=20slotno)=0A+{=0A+=09int=09=09=09entryno=20=3D=20= TransactionIdToPgIndex(xid);=0A+=09XLogRecPtr=20*ptr;=0A+=0A+=09ptr=20=3D=20= (XLogRecPtr=20*)=20(CsnlogCtl->shared->page_buffer[slotno]=20+=20entryno=20= *=20sizeof(XLogRecPtr));=0A+=0A+=09*ptr=20=3D=20csn;=0A+}=0A+=0A+/*=0A+=20= *=20Interrogate=20the=20state=20of=20a=20transaction=20in=20the=20log.=0A= +=20*=0A+=20*=20NB:=20this=20is=20a=20low-level=20routine=20and=20is=20= NOT=20the=20preferred=20entry=20point=0A+=20*=20for=20most=20uses;=20= TransactionIdGetXidCSN()=20in=20csn_snapshot.c=20is=20the=0A+=20*=20= intended=20caller.=0A+=20*/=0A+XLogRecPtr=0A= +CSNLogGetCSNByXid(TransactionId=20xid)=0A+{=0A+=09int=09=09=09pageno=20= =3D=20TransactionIdToPage(xid);=0A+=09int=09=09=09entryno=20=3D=20= TransactionIdToPgIndex(xid);=0A+=09int=09=09=09slotno;=0A+=09XLogRecPtr=20= *ptr;=0A+=09XLogRecPtr=09xid_csn;=0A+=0A+=09= Assert(TransactionIdIsValid(xid));=0A+=0A+=09/*=20Can't=20ask=20about=20= stuff=20that=20might=20not=20be=20around=20anymore=20*/=0A+=09= Assert(TransactionIdFollowsOrEquals(xid,=20TransactionXmin));=0A+=0A+=09= /*=20lock=20is=20acquired=20by=20SimpleLruReadPage_ReadOnly=20*/=0A+=0A+=09= slotno=20=3D=20SimpleLruReadPage_ReadOnly(CsnlogCtl,=20pageno,=20xid);=0A= +=09ptr=20=3D=20(XLogRecPtr=20*)=20= (CsnlogCtl->shared->page_buffer[slotno]=20+=20entryno=20*=20= sizeof(XLogRecPtr));=0A+=09xid_csn=20=3D=20*ptr;=0A+=0A+=09= LWLockRelease(SimpleLruGetBankLock(CsnlogCtl,=20pageno));=0A+=0A+=09= return=20xid_csn;=0A+}=0A+=0A+/*=0A+=20*=20Number=20of=20shared=20CSNLog=20= buffers.=0A+=20*/=0A+static=20Size=0A+CSNLogShmemBuffers(void)=0A+{=0A+=09= return=20Min(32,=20Max(16,=20NBuffers=20/=20512));=0A+}=0A+=0A+/*=0A+=20= *=20Reserve=20shared=20memory=20for=20CsnlogCtl.=0A+=20*/=0A+Size=0A= +CSNLogShmemSize(void)=0A+{=0A+=09/*=20FIXME:=20skip=20if=20not=20= InHotStandby?=20*/=0A+=09return=20= SimpleLruShmemSize(CSNLogShmemBuffers(),=200);=0A+}=0A+=0A+/*=0A+=20*=20= Initialization=20of=20shared=20memory=20for=20CSNLog.=0A+=20*/=0A+void=0A= +CSNLogShmemInit(void)=0A+{=0A+=09CsnlogCtl->PagePrecedes=20=3D=20= CSNLogPagePrecedes;=0A+=09SimpleLruInit(CsnlogCtl,=20"CSNLog=20Ctl",=20= CSNLogShmemBuffers(),=200,=0A+=09=09=09=09=20=20"pg_csn",=20= LWTRANCHE_CSN_LOG_BUFFER,=0A+=09=09=09=09=20=20LWTRANCHE_CSN_LOG_SLRU,=20= SYNC_HANDLER_NONE,=20false);=0A+=09SlruPagePrecedesUnitTests(CsnlogCtl,=20= CSN_LOG_XACTS_PER_PAGE);=0A+}=0A+=0A+/*=0A+=20*=20This=20func=20must=20= be=20called=20ONCE=20on=20system=20install.=20=20It=20creates=20the=20= initial=0A+=20*=20CSNLog=20segment.=20=20The=20pg_csn=20directory=20is=20= assumed=20to=20have=20been=0A+=20*=20created=20by=20initdb,=20and=20= CSNLogShmemInit=20must=20have=20been=20called=20already.=0A+=20*=0A+=20*=20= Note:=20it's=20not=20really=20necessary=20to=20create=20the=20initial=20= segment=20now,=0A+=20*=20since=20slru.c=20would=20create=20it=20on=20= first=20write=20anyway.=20=20But=20we=20may=20as=20well=0A+=20*=20do=20= it=20to=20be=20sure=20the=20directory=20is=20set=20up=20correctly.=0A+=20= */=0A+void=0A+BootStrapCSNLog(void)=0A+{=0A+=09int=09=09=09slotno;=0A+=09= LWLock=09=20=20=20*lock;=0A+=0A+=09lock=20=3D=20= SimpleLruGetBankLock(CsnlogCtl,=200);=0A+=09LWLockAcquire(lock,=20= LW_EXCLUSIVE);=0A+=0A+=09/*=20Create=20and=20zero=20the=20first=20page=20= of=20the=20commit=20log=20*/=0A+=09slotno=20=3D=20ZeroCSNLogPage(0);=0A+=0A= +=09/*=20Make=20sure=20it's=20written=20out=20*/=0A+=09= SimpleLruWritePage(CsnlogCtl,=20slotno);=0A+=09= Assert(!CsnlogCtl->shared->page_dirty[slotno]);=0A+=0A+=09= LWLockRelease(lock);=0A+}=0A+=0A+/*=0A+=20*=20Initialize=20(or=20= reinitialize)=20a=20page=20of=20CSNLog=20to=20zeroes.=0A+=20*=0A+=20*=20= The=20page=20is=20not=20actually=20written,=20just=20set=20up=20in=20= shared=20memory.=0A+=20*=20The=20slot=20number=20of=20the=20new=20page=20= is=20returned.=0A+=20*=0A+=20*=20Control=20lock=20must=20be=20held=20at=20= entry,=20and=20will=20be=20held=20at=20exit.=0A+=20*/=0A+static=20int=0A= +ZeroCSNLogPage(int=20pageno)=0A+{=0A+=09return=20= SimpleLruZeroPage(CsnlogCtl,=20pageno);=0A+}=0A+=0A+/*=0A+=20*=20= Initialize=20a=20page=20of=20CSNLog=20based=20on=20pg_xact.=0A+=20*=0A+=20= *=20All=20committed=20transactions=20are=20stamped=20with=20'csn'=0A+=20= */=0A+static=20void=0A+InitCSNLogPage(int=20pageno,=20TransactionId=20= *xid,=20TransactionId=20nextXid,=20XLogRecPtr=20csn)=0A+{=0A+=09= XLogRecPtr=09dummy;=0A+=09int=09=09=09slotno;=0A+=0A+=09slotno=20=3D=20= ZeroCSNLogPage(pageno);=0A+=0A+=09while=20(*xid=20<=20nextXid=20&&=20= TransactionIdToPage(*xid)=20=3D=3D=20pageno)=0A+=09{=0A+=09=09XidStatus=09= status=20=3D=20TransactionIdGetStatus(*xid,=20&dummy);=0A+=0A+=09=09if=20= (status=20=3D=3D=20TRANSACTION_STATUS_COMMITTED=20||=0A+=09=09=09status=20= =3D=3D=20TRANSACTION_STATUS_ABORTED)=0A+=09=09=09= CSNLogSetCSNInSlot(*xid,=20csn,=20slotno);=0A+=0A+=09=09= TransactionIdAdvance(*xid);=0A+=09}=0A+=09SimpleLruZeroPage(CsnlogCtl,=20= pageno);=0A+}=0A+=0A+/*=0A+=20*=20This=20must=20be=20called=20ONCE=20= during=20postmaster=20or=20standalone-backend=20startup,=0A+=20*=20after=20= StartupXLOG=20has=20initialized=20ShmemVariableCache->nextXid,=20and=20= after=0A+=20*=20initializing=20the=20CLOG.=0A+=20*=0A+=20*=20= oldestActiveXID=20is=20the=20oldest=20XID=20of=20any=20prepared=20= transaction,=20or=20nextXid=0A+=20*=20if=20there=20are=20none.=0A+=20*=0A= +=20*=20All=20transactions=20that=20have=20already=20completed=20are=20= marked=20with=20'csn'.=20('csn'=0A+=20*=20is=20supposed=20to=20be=20an=20= "older=20than=20anything=20we'll=20ever=20need=20to=20compare=20with")=0A= +=20*/=0A+void=0A+StartupCSNLog(TransactionId=20oldestActiveXID,=20= XLogRecPtr=20csn)=0A+{=0A+=09TransactionId=20xid;=0A+=09= FullTransactionId=20nextXid;=0A+=09int=09=09=09startPage;=0A+=09int=09=09= =09endPage;=0A+=09LWLock=09=20=20=20*prevlock=20=3D=20NULL;=0A+=09LWLock=09= =20=20=20*lock;=0A+=0A+=09/*=0A+=09=20*=20Since=20we=20don't=20expect=20= pg_csn=20to=20be=20valid=20across=20crashes,=20we=20initialize=0A+=09=20= *=20the=20currently-active=20page(s)=20to=20zeroes=20during=20startup.=20= Whenever=20we=0A+=09=20*=20advance=20into=20a=20new=20page,=20= ExtendCSNLog=20will=20likewise=20zero=20the=20new=20page=0A+=09=20*=20= without=20regard=20to=20whatever=20was=20previously=20on=20disk.=0A+=09=20= */=0A+=09startPage=20=3D=20TransactionIdToPage(oldestActiveXID);=0A+=09= nextXid=20=3D=20TransamVariables->nextXid;=0A+=09endPage=20=3D=20= TransactionIdToPage(XidFromFullTransactionId(nextXid));=0A+=0A+=09= Assert(TransactionIdIsValid(oldestActiveXID));=0A+=09= Assert(FullTransactionIdIsValid(nextXid));=0A+=0A+=09xid=20=3D=20= oldestActiveXID;=0A+=09for=20(;;)=0A+=09{=0A+=09=09lock=20=3D=20= SimpleLruGetBankLock(CsnlogCtl,=20startPage);=0A+=09=09if=20(prevlock=20= !=3D=20lock)=0A+=09=09{=0A+=09=09=09if=20(prevlock)=0A+=09=09=09=09= LWLockRelease(prevlock);=0A+=09=09=09LWLockAcquire(lock,=20= LW_EXCLUSIVE);=0A+=09=09=09prevlock=20=3D=20lock;=0A+=09=09}=0A+=0A+=09=09= InitCSNLogPage(startPage,=20&xid,=20XidFromFullTransactionId(nextXid),=20= csn);=0A+=09=09if=20(startPage=20=3D=3D=20endPage)=0A+=09=09=09break;=0A= +=0A+=09=09startPage++;=0A+=09=09/*=20must=20account=20for=20wraparound=20= */=0A+=09=09if=20(startPage=20>=20TransactionIdToPage(MaxTransactionId))=0A= +=09=09=09startPage=20=3D=200;=0A+=09}=0A+=0A+=09LWLockRelease(lock);=0A= +}=0A+=0A+/*=0A+=20*=20This=20must=20be=20called=20ONCE=20during=20= postmaster=20or=20standalone-backend=20shutdown=0A+=20*/=0A+void=0A= +ShutdownCSNLog(void)=0A+{=0A+=09/*=0A+=09=20*=20Flush=20dirty=20CSNLog=20= pages=20to=20disk.=0A+=09=20*=0A+=09=20*=20This=20is=20not=20actually=20= necessary=20from=20a=20correctness=20point=20of=20view.=20We=20do=0A+=09=20= *=20it=20merely=20as=20a=20debugging=20aid.=0A+=09=20*/=0A+=09= TRACE_POSTGRESQL_CSNLOG_CHECKPOINT_START(false);=0A+=09= SimpleLruWriteAll(CsnlogCtl,=20false);=0A+=09= TRACE_POSTGRESQL_CSNLOG_CHECKPOINT_DONE(false);=0A+}=0A+=0A+/*=0A+=20*=20= Perform=20a=20checkpoint=20---=20either=20during=20shutdown,=20or=20= on-the-fly=0A+=20*/=0A+void=0A+CheckPointCSNLog(void)=0A+{=0A+=09/*=0A+=09= =20*=20Flush=20dirty=20CSNLog=20pages=20to=20disk.=0A+=09=20*=0A+=09=20*=20= This=20is=20not=20actually=20necessary=20from=20a=20correctness=20point=20= of=20view.=20We=20do=0A+=09=20*=20it=20merely=20to=20improve=20the=20= odds=20that=20writing=20of=20dirty=20pages=20is=20done=20by=0A+=09=20*=20= the=20checkpoint=20process=20and=20not=20by=20backends.=0A+=09=20*/=0A+=09= TRACE_POSTGRESQL_CSNLOG_CHECKPOINT_START(true);=0A+=09= SimpleLruWriteAll(CsnlogCtl,=20true);=0A+=09= TRACE_POSTGRESQL_CSNLOG_CHECKPOINT_DONE(true);=0A+}=0A+=0A+/*=0A+=20*=20= Make=20sure=20that=20CSNLog=20has=20room=20for=20a=20newly-allocated=20= XID.=0A+=20*=0A+=20*=20NB:=20this=20is=20called=20while=20holding=20= XidGenLock.=20=20We=20want=20it=20to=20be=20very=20fast=0A+=20*=20most=20= of=20the=20time;=20even=20when=20it's=20not=20so=20fast,=20no=20actual=20= I/O=20need=20happen=0A+=20*=20unless=20we're=20forced=20to=20write=20out=20= a=20dirty=20clog=20or=20xlog=20page=20to=20make=20room=0A+=20*=20in=20= shared=20memory.=0A+=20*/=0A+void=0A+ExtendCSNLog(TransactionId=20= newestXact)=0A+{=0A+=09int64=09=09pageno;=0A+=09LWLock=09=20=20=20*lock;=0A= +=0A+=09/*=0A+=09=20*=20No=20work=20except=20at=20first=20XID=20of=20a=20= page.=20=20But=20beware:=20just=20after=0A+=09=20*=20wraparound,=20the=20= first=20XID=20of=20page=20zero=20is=20FirstNormalTransactionId.=0A+=09=20= */=0A+=09if=20(TransactionIdToPgIndex(newestXact)=20!=3D=200=20&&=0A+=09=09= !TransactionIdEquals(newestXact,=20FirstNormalTransactionId))=0A+=09=09= return;=0A+=0A+=09pageno=20=3D=20TransactionIdToPage(newestXact);=0A+=0A= +=09lock=20=3D=20SimpleLruGetBankLock(CsnlogCtl,=20pageno);=0A+=0A+=09= LWLockAcquire(lock,=20LW_EXCLUSIVE);=0A+=0A+=09/*=20Zero=20the=20page=20= and=20make=20an=20XLOG=20entry=20about=20it=20*/=0A+=09= ZeroCSNLogPage(pageno);=0A+=0A+=09LWLockRelease(lock);=0A+}=0A+=0A+/*=0A= +=20*=20Remove=20all=20CSNLog=20segments=20before=20the=20one=20holding=20= the=20passed=0A+=20*=20transaction=20ID.=0A+=20*=0A+=20*=20This=20is=20= normally=20called=20during=20checkpoint,=20with=20oldestXact=20being=20= the=0A+=20*=20oldest=20TransactionXmin=20of=20any=20running=20= transaction.=0A+=20*/=0A+void=0A+TruncateCSNLog(TransactionId=20= oldestXact)=0A+{=0A+=09int=09=09=09cutoffPage;=0A+=0A+=09/*=0A+=09=20*=20= The=20cutoff=20point=20is=20the=20start=20of=20the=20segment=20= containing=20oldestXact.=20We=0A+=09=20*=20pass=20the=20*page*=20= containing=20oldestXact=20to=20SimpleLruTruncate.=20We=20step=0A+=09=20*=20= back=20one=20transaction=20to=20avoid=20passing=20a=20cutoff=20page=20= that=20hasn't=20been=0A+=09=20*=20created=20yet=20in=20the=20rare=20case=20= that=20oldestXact=20would=20be=20the=20first=20item=20on=0A+=09=20*=20a=20= page=20and=20oldestXact=20=3D=3D=20next=20XID.=20=20In=20that=20case,=20= if=20we=20didn't=20subtract=0A+=09=20*=20one,=20we'd=20trigger=20= SimpleLruTruncate's=20wraparound=20detection.=0A+=09=20*/=0A+=09= TransactionIdRetreat(oldestXact);=0A+=09cutoffPage=20=3D=20= TransactionIdToPage(oldestXact);=0A+=0A+=09SimpleLruTruncate(CsnlogCtl,=20= cutoffPage);=0A+}=0A+=0A+/*=0A+=20*=20Decide=20which=20of=20two=20CSNLog=20= page=20numbers=20is=20"older"=20for=20truncation=20purposes.=0A+=20*=20= Analogous=20to=20CLOGPagePrecedes()=20and=20SubTransPagePrecedes().=0A+=20= */=0A+static=20bool=0A+CSNLogPagePrecedes(int64=20page1,=20int64=20= page2)=0A+{=0A+=09TransactionId=20xid1;=0A+=09TransactionId=20xid2;=0A+=0A= +=09xid1=20=3D=20((TransactionId)=20page1)=20*=20CSN_LOG_XACTS_PER_PAGE;=0A= +=09xid1=20+=3D=20FirstNormalTransactionId=20+=201;=0A+=09xid2=20=3D=20= ((TransactionId)=20page2)=20*=20CSN_LOG_XACTS_PER_PAGE;=0A+=09xid2=20+=3D=20= FirstNormalTransactionId=20+=201;=0A+=0A+=09return=20= (TransactionIdPrecedes(xid1,=20xid2)=20&&=0A+=09=09=09= TransactionIdPrecedes(xid1,=20xid2=20+=20CSN_LOG_XACTS_PER_PAGE=20-=20= 1));=0A+}=0Adiff=20--git=20a/src/backend/access/transam/meson.build=20= b/src/backend/access/transam/meson.build=0Aindex=20= e8ae9b13c8e..e2a3419fc22=20100644=0A---=20= a/src/backend/access/transam/meson.build=0A+++=20= b/src/backend/access/transam/meson.build=0A@@=20-2,6=20+2,7=20@@=0A=20=0A= =20backend_sources=20+=3D=20files(=0A=20=20=20'clog.c',=0A+=20=20= 'csn_log.c',=0A=20=20=20'commit_ts.c',=0A=20=20=20'generic_xlog.c',=0A=20= =20=20'multixact.c',=0Adiff=20--git=20= a/src/backend/access/transam/transam.c=20= b/src/backend/access/transam/transam.c=0Aindex=20= 9a39451a29a..b4c42c0f156=20100644=0A---=20= a/src/backend/access/transam/transam.c=0A+++=20= b/src/backend/access/transam/transam.c=0A@@=20-377,6=20+377,9=20@@=20= TransactionIdLatest(TransactionId=20mainxid,=0A=20=20*=20Also,=20because=20= we=20group=20transactions=20on=20the=20same=20clog=20page=20to=20= conserve=0A=20=20*=20storage,=20we=20might=20return=20the=20LSN=20of=20a=20= later=20transaction=20that=20falls=20into=0A=20=20*=20the=20same=20= group.=0A+=20*=0A+=20*=20XXX:=20Now=20that=20we=20have=20the=20CSN-log,=20= should=20we=20use=20that=20during=20recovery?=20Or=0A+=20*=20rename=20= this=20function=20to=20reduce=20confusion.=0A=20=20*/=0A=20XLogRecPtr=0A=20= TransactionIdGetCommitLSN(TransactionId=20xid)=0Adiff=20--git=20= a/src/backend/access/transam/twophase.c=20= b/src/backend/access/transam/twophase.c=0Aindex=20= 73a80559194..2330632e569=20100644=0A---=20= a/src/backend/access/transam/twophase.c=0A+++=20= b/src/backend/access/transam/twophase.c=0A@@=20-77,6=20+77,7=20@@=0A=20= #include=20=0A=20=0A=20#include=20"access/commit_ts.h"=0A= +#include=20"access/csn_log.h"=0A=20#include=20"access/htup_details.h"=0A= =20#include=20"access/subtrans.h"=0A=20#include=20"access/transam.h"=0A= @@=20-1943,20=20+1944,13=20@@=20restoreTwoPhaseData(void)=0A=20=20*=20= Our=20other=20responsibility=20is=20to=20determine=20and=20return=20the=20= oldest=20valid=20XID=0A=20=20*=20among=20the=20prepared=20xacts=20(if=20= none,=20return=20TransamVariables->nextXid).=0A=20=20*=20This=20is=20= needed=20to=20synchronize=20pg_subtrans=20startup=20properly.=0A-=20*=0A= -=20*=20If=20xids_p=20and=20nxids_p=20are=20not=20NULL,=20pointer=20to=20= a=20palloc'd=20array=20of=20all=0A-=20*=20top-level=20xids=20is=20stored=20= in=20*xids_p.=20The=20number=20of=20entries=20in=20the=20array=0A-=20*=20= is=20returned=20in=20*nxids_p.=0A=20=20*/=0A=20TransactionId=0A= -PrescanPreparedTransactions(TransactionId=20**xids_p,=20int=20*nxids_p)=0A= +PrescanPreparedTransactions(void)=0A=20{=0A=20=09FullTransactionId=20= nextXid=20=3D=20TransamVariables->nextXid;=0A=20=09TransactionId=20= origNextXid=20=3D=20XidFromFullTransactionId(nextXid);=0A=20=09= TransactionId=20result=20=3D=20origNextXid;=0A-=09TransactionId=20*xids=20= =3D=20NULL;=0A-=09int=09=09=09nxids=20=3D=200;=0A-=09int=09=09=09= allocsize=20=3D=200;=0A=20=09int=09=09=09i;=0A=20=0A=20=09= LWLockAcquire(TwoPhaseStateLock,=20LW_EXCLUSIVE);=0A@@=20-1984,34=20= +1978,10=20@@=20PrescanPreparedTransactions(TransactionId=20**xids_p,=20= int=20*nxids_p)=0A=20=09=09if=20(TransactionIdPrecedes(xid,=20result))=0A= =20=09=09=09result=20=3D=20xid;=0A=20=0A-=09=09if=20(xids_p)=0A-=09=09{=0A= -=09=09=09if=20(nxids=20=3D=3D=20allocsize)=0A-=09=09=09{=0A-=09=09=09=09= if=20(nxids=20=3D=3D=200)=0A-=09=09=09=09{=0A-=09=09=09=09=09allocsize=20= =3D=2010;=0A-=09=09=09=09=09xids=20=3D=20palloc(allocsize=20*=20= sizeof(TransactionId));=0A-=09=09=09=09}=0A-=09=09=09=09else=0A-=09=09=09= =09{=0A-=09=09=09=09=09allocsize=20=3D=20allocsize=20*=202;=0A-=09=09=09=09= =09xids=20=3D=20repalloc(xids,=20allocsize=20*=20sizeof(TransactionId));=0A= -=09=09=09=09}=0A-=09=09=09}=0A-=09=09=09xids[nxids++]=20=3D=20xid;=0A-=09= =09}=0A-=0A=20=09=09pfree(buf);=0A=20=09}=0A=20=09= LWLockRelease(TwoPhaseStateLock);=0A=20=0A-=09if=20(xids_p)=0A-=09{=0A-=09= =09*xids_p=20=3D=20xids;=0A-=09=09*nxids_p=20=3D=20nxids;=0A-=09}=0A-=0A=20= =09return=20result;=0A=20}=0A=20=0Adiff=20--git=20= a/src/backend/access/transam/varsup.c=20= b/src/backend/access/transam/varsup.c=0Aindex=20fe895787cb7..a495f1d7899=20= 100644=0A---=20a/src/backend/access/transam/varsup.c=0A+++=20= b/src/backend/access/transam/varsup.c=0A@@=20-15,6=20+15,7=20@@=0A=20=0A=20= #include=20"access/clog.h"=0A=20#include=20"access/commit_ts.h"=0A= +#include=20"access/csn_log.h"=0A=20#include=20"access/subtrans.h"=0A=20= #include=20"access/transam.h"=0A=20#include=20"access/xact.h"=0Adiff=20= --git=20a/src/backend/access/transam/xact.c=20= b/src/backend/access/transam/xact.c=0Aindex=20b885513f765..5250a158145=20= 100644=0A---=20a/src/backend/access/transam/xact.c=0A+++=20= b/src/backend/access/transam/xact.c=0A@@=20-21,6=20+21,7=20@@=0A=20= #include=20=0A=20=0A=20#include=20"access/commit_ts.h"=0A= +#include=20"access/csn_log.h"=0A=20#include=20"access/multixact.h"=0A=20= #include=20"access/parallel.h"=0A=20#include=20"access/subtrans.h"=0A@@=20= -210,7=20+211,6=20@@=20typedef=20struct=20TransactionStateData=0A=20=09= int=09=09=09prevSecContext;=20/*=20previous=20SecurityRestrictionContext=20= */=0A=20=09bool=09=09prevXactReadOnly;=09/*=20entry-time=20xact=20r/o=20= state=20*/=0A=20=09bool=09=09startedInRecovery;=09/*=20did=20we=20start=20= in=20recovery?=20*/=0A-=09bool=09=09didLogXid;=09=09/*=20has=20xid=20= been=20included=20in=20WAL=20record?=20*/=0A=20=09int=09=09=09= parallelModeLevel;=09/*=20Enter/ExitParallelMode=20counter=20*/=0A=20=09= bool=09=09parallelChildXact;=09/*=20is=20any=20parent=20transaction=20= parallel?=20*/=0A=20=09bool=09=09chain;=09=09=09/*=20start=20a=20new=20= block=20after=20this=20one=20*/=0A@@=20-250,13=20+250,6=20@@=20static=20= TransactionStateData=20TopTransactionStateData=20=3D=20{=0A=20=09= .topXidLogged=20=3D=20false,=0A=20};=0A=20=0A-/*=0A-=20*=20= unreportedXids=20holds=20XIDs=20of=20all=20subtransactions=20that=20have=20= not=20yet=20been=0A-=20*=20reported=20in=20an=20XLOG_XACT_ASSIGNMENT=20= record.=0A-=20*/=0A-static=20int=09nUnreportedXids;=0A-static=20= TransactionId=20unreportedXids[PGPROC_MAX_CACHED_SUBXIDS];=0A-=0A=20= static=20TransactionState=20CurrentTransactionState=20=3D=20= &TopTransactionStateData;=0A=20=0A=20/*=0A@@=20-532,18=20+525,6=20@@=20= GetCurrentFullTransactionIdIfAny(void)=0A=20=09return=20= CurrentTransactionState->fullTransactionId;=0A=20}=0A=20=0A-/*=0A-=20*=09= MarkCurrentTransactionIdLoggedIfAny=0A-=20*=0A-=20*=20Remember=20that=20= the=20current=20xid=20-=20if=20it=20is=20assigned=20-=20now=20has=20been=20= wal=20logged.=0A-=20*/=0A-void=0A= -MarkCurrentTransactionIdLoggedIfAny(void)=0A-{=0A-=09if=20= (FullTransactionIdIsValid(CurrentTransactionState->fullTransactionId))=0A= -=09=09CurrentTransactionState->didLogXid=20=3D=20true;=0A-}=0A-=0A=20/*=0A= =20=20*=20IsSubxactTopXidLogPending=0A=20=20*=0A@@=20-636,7=20+617,6=20= @@=20AssignTransactionId(TransactionState=20s)=0A=20{=0A=20=09bool=09=09= isSubXact=20=3D=20(s->parent=20!=3D=20NULL);=0A=20=09ResourceOwner=20= currentOwner;=0A-=09bool=09=09log_unknown_top=20=3D=20false;=0A=20=0A=20=09= /*=20Assert=20that=20caller=20didn't=20screw=20up=20*/=0A=20=09= Assert(!FullTransactionIdIsValid(s->fullTransactionId));=0A@@=20-680,20=20= +660,6=20@@=20AssignTransactionId(TransactionState=20s)=0A=20=09=09= pfree(parents);=0A=20=09}=0A=20=0A-=09/*=0A-=09=20*=20When=20= wal_level=3Dlogical,=20guarantee=20that=20a=20subtransaction's=20xid=20= can=20only=0A-=09=20*=20be=20seen=20in=20the=20WAL=20stream=20if=20its=20= toplevel=20xid=20has=20been=20logged=20before.=0A-=09=20*=20If=20= necessary=20we=20log=20an=20xact_assignment=20record=20with=20fewer=20= than=0A-=09=20*=20PGPROC_MAX_CACHED_SUBXIDS.=20Note=20that=20it=20is=20= fine=20if=20didLogXid=20isn't=20set=0A-=09=20*=20for=20a=20transaction=20= even=20though=20it=20appears=20in=20a=20WAL=20record,=20we=20just=20= might=0A-=09=20*=20superfluously=20log=20something.=20That=20can=20= happen=20when=20an=20xid=20is=20included=0A-=09=20*=20somewhere=20inside=20= a=20wal=20record,=20but=20not=20in=20XLogRecord->xl_xid,=20like=20in=0A-=09= =20*=20xl_standby_locks.=0A-=09=20*/=0A-=09if=20(isSubXact=20&&=20= XLogLogicalInfoActive()=20&&=0A-=09=09= !TopTransactionStateData.didLogXid)=0A-=09=09log_unknown_top=20=3D=20= true;=0A-=0A=20=09/*=0A=20=09=20*=20Generate=20a=20new=20= FullTransactionId=20and=20record=20its=20xid=20in=20PGPROC=20and=0A=20=09= =20*=20pg_subtrans.=0A@@=20-729,59=20+695,6=20@@=20= AssignTransactionId(TransactionState=20s)=0A=20=09= XactLockTableInsert(XidFromFullTransactionId(s->fullTransactionId));=0A=20= =0A=20=09CurrentResourceOwner=20=3D=20currentOwner;=0A-=0A-=09/*=0A-=09=20= *=20Every=20PGPROC_MAX_CACHED_SUBXIDS=20assigned=20transaction=20ids=20= within=20each=0A-=09=20*=20top-level=20transaction=20we=20issue=20a=20= WAL=20record=20for=20the=20assignment.=20We=0A-=09=20*=20include=20the=20= top-level=20xid=20and=20all=20the=20subxids=20that=20have=20not=20yet=20= been=0A-=09=20*=20reported=20using=20XLOG_XACT_ASSIGNMENT=20records.=0A-=09= =20*=0A-=09=20*=20This=20is=20required=20to=20limit=20the=20amount=20of=20= shared=20memory=20required=20in=20a=20hot=0A-=09=20*=20standby=20server=20= to=20keep=20track=20of=20in-progress=20XIDs.=20See=20notes=20for=0A-=09=20= *=20RecordKnownAssignedTransactionIds().=0A-=09=20*=0A-=09=20*=20We=20= don't=20keep=20track=20of=20the=20immediate=20parent=20of=20each=20= subxid,=20only=20the=0A-=09=20*=20top-level=20transaction=20that=20each=20= subxact=20belongs=20to.=20This=20is=20correct=20in=0A-=09=20*=20recovery=20= only=20because=20aborted=20subtransactions=20are=20separately=20WAL=0A-=09= =20*=20logged.=0A-=09=20*=0A-=09=20*=20This=20is=20correct=20even=20for=20= the=20case=20where=20several=20levels=20above=20us=20didn't=0A-=09=20*=20= have=20an=20xid=20assigned=20as=20we=20recursed=20up=20to=20them=20= beforehand.=0A-=09=20*/=0A-=09if=20(isSubXact=20&&=20= XLogStandbyInfoActive())=0A-=09{=0A-=09=09= unreportedXids[nUnreportedXids]=20=3D=20= XidFromFullTransactionId(s->fullTransactionId);=0A-=09=09= nUnreportedXids++;=0A-=0A-=09=09/*=0A-=09=09=20*=20ensure=20this=20test=20= matches=20similar=20one=20in=0A-=09=09=20*=20= RecoverPreparedTransactions()=0A-=09=09=20*/=0A-=09=09if=20= (nUnreportedXids=20>=3D=20PGPROC_MAX_CACHED_SUBXIDS=20||=0A-=09=09=09= log_unknown_top)=0A-=09=09{=0A-=09=09=09xl_xact_assignment=20xlrec;=0A-=0A= -=09=09=09/*=0A-=09=09=09=20*=20xtop=20is=20always=20set=20by=20now=20= because=20we=20recurse=20up=20transaction=0A-=09=09=09=20*=20stack=20to=20= the=20highest=20unassigned=20xid=20and=20then=20come=20back=20down=0A-=09= =09=09=20*/=0A-=09=09=09xlrec.xtop=20=3D=20GetTopTransactionId();=0A-=09=09= =09Assert(TransactionIdIsValid(xlrec.xtop));=0A-=09=09=09xlrec.nsubxacts=20= =3D=20nUnreportedXids;=0A-=0A-=09=09=09XLogBeginInsert();=0A-=09=09=09= XLogRegisterData(&xlrec,=20MinSizeOfXactAssignment);=0A-=09=09=09= XLogRegisterData(unreportedXids,=0A-=09=09=09=09=09=09=09=20= nUnreportedXids=20*=20sizeof(TransactionId));=0A-=0A-=09=09=09(void)=20= XLogInsert(RM_XACT_ID,=20XLOG_XACT_ASSIGNMENT);=0A-=0A-=09=09=09= nUnreportedXids=20=3D=200;=0A-=09=09=09/*=20mark=20top,=20not=20current=20= xact=20as=20having=20been=20logged=20*/=0A-=09=09=09= TopTransactionStateData.didLogXid=20=3D=20true;=0A-=09=09}=0A-=09}=0A=20= }=0A=20=0A=20/*=0A@@=20-1481,11=20+1394,11=20@@=20= RecordTransactionCommit(void)=0A=20=09=20*=20temp=20tables=20will=20be=20= lost=20anyway,=20unlogged=20tables=20will=20be=20truncated=20and=0A=20=09= =20*=20HOT=20pruning=20will=20be=20done=20again=20later.=20(Given=20the=20= foregoing,=20you=20might=0A=20=09=20*=20think=20that=20it=20would=20be=20= unnecessary=20to=20emit=20the=20XLOG=20record=20at=20all=20in=0A-=09=20*=20= this=20case,=20but=20we=20don't=20currently=20try=20to=20do=20that.=20=20= It=20would=20certainly=0A-=09=20*=20cause=20problems=20at=20least=20in=20= Hot=20Standby=20mode,=20where=20the=0A-=09=20*=20KnownAssignedXids=20= machinery=20requires=20tracking=20every=20XID=20assignment.=20=20It=0A-=09= =20*=20might=20be=20OK=20to=20skip=20it=20only=20when=20wal_level=20<=20= replica,=20but=20for=20now=20we=0A-=09=20*=20don't.)=0A+=09=20*=20this=20= case,=20but=20we=20don't=20currently=20try=20to=20do=20that.=20=20It=20= might=20cause=0A+=09=20*=20inefficiencies=20in=20Hot=20Standby=20mode,=20= if=20nothing=20else,=20where=20the=0A+=09=20*=20commit/abort=20records=20= allow=20advancing=20the=20xmin=20horizon=20for=20new=0A+=09=20*=20= snapshots.=20It=20might=20be=20OK=20to=20skip=20it=20only=20when=20= wal_level=20<=20replica,=20but=0A+=09=20*=20for=20now=20we=20don't.)=0A=20= =09=20*=0A=20=09=20*=20However,=20if=20we're=20doing=20cleanup=20of=20= any=20non-temp=20rels=20or=20committing=20any=0A=20=09=20*=20command=20= that=20wanted=20to=20force=20sync=20commit,=20then=20we=20must=20flush=20= XLOG=0A@@=20-1953,13=20+1866,6=20@@=20AtSubAbort_childXids(void)=0A=20=09= s->childXids=20=3D=20NULL;=0A=20=09s->nChildXids=20=3D=200;=0A=20=09= s->maxChildXids=20=3D=200;=0A-=0A-=09/*=0A-=09=20*=20We=20could=20prune=20= the=20unreportedXids=20array=20here.=20But=20we=20don't=20bother.=20That=0A= -=09=20*=20would=20potentially=20reduce=20number=20of=20= XLOG_XACT_ASSIGNMENT=20records=20but=20it=0A-=09=20*=20would=20likely=20= introduce=20more=20CPU=20time=20into=20the=20more=20common=20paths,=20so=20= we=0A-=09=20*=20choose=20not=20to=20do=20that.=0A-=09=20*/=0A=20}=0A=20=0A= =20/*=20----------------------------------------------------------------=0A= @@=20-2142,12=20+2048,6=20@@=20StartTransaction(void)=0A=20=09= currentCommandId=20=3D=20FirstCommandId;=0A=20=09currentCommandIdUsed=20= =3D=20false;=0A=20=0A-=09/*=0A-=09=20*=20initialize=20reported=20xid=20= accounting=0A-=09=20*/=0A-=09nUnreportedXids=20=3D=200;=0A-=09= s->didLogXid=20=3D=20false;=0A-=0A=20=09/*=0A=20=09=20*=20must=20= initialize=20resource-management=20stuff=20first=0A=20=09=20*/=0A@@=20= -6154,7=20+6054,7=20@@=20xact_redo_commit(xl_xact_parsed_commit=20= *parsed,=0A=20=09TransactionTreeSetCommitTsData(xid,=20= parsed->nsubxacts,=20parsed->subxacts,=0A=20=09=09=09=09=09=09=09=09=20=20= =20commit_time,=20origin_id);=0A=20=0A-=09if=20(standbyState=20=3D=3D=20= STANDBY_DISABLED)=0A+=09if=20(!InHotStandby)=0A=20=09{=0A=20=09=09/*=0A=20= =09=09=20*=20Mark=20the=20transaction=20committed=20in=20pg_xact.=0A@@=20= -6174,6=20+6074,12=20@@=20xact_redo_commit(xl_xact_parsed_commit=20= *parsed,=0A=20=09=09=20*/=0A=20=09=09= RecordKnownAssignedTransactionIds(max_xid);=0A=20=0A+=09=09/*=0A+=09=09=20= *=20Mark=20the=20CSNLOG=20first.=20=20The=20transaction=20won't=20become=20= visible=20to=20new=0A+=09=09=20*=20snapshots=20until=20the=20call=20to=20= ProcArrayRecoveryEndTransaction().=0A+=09=09=20*/=0A+=09=09= CSNLogSetCSN(xid,=20parsed->nsubxacts,=20parsed->subxacts,=20lsn);=0A+=0A= =20=09=09/*=0A=20=09=09=20*=20Mark=20the=20transaction=20committed=20in=20= pg_xact.=20We=20use=20async=20commit=0A=20=09=09=20*=20protocol=20during=20= recovery=20to=20provide=20information=20on=20database=0A@@=20-6186,9=20= +6092,9=20@@=20xact_redo_commit(xl_xact_parsed_commit=20*parsed,=0A=20=09= =09TransactionIdAsyncCommitTree(xid,=20parsed->nsubxacts,=20= parsed->subxacts,=20lsn);=0A=20=0A=20=09=09/*=0A-=09=09=20*=20We=20must=20= mark=20clog=20before=20we=20update=20the=20ProcArray.=0A+=09=09=20*=20= Make=20the=20commit=20visible=20to=20new=20snapshots=20in=20the=20= ProcArray.=0A=20=09=09=20*/=0A-=09=09= ExpireTreeKnownAssignedTransactionIds(xid,=20parsed->nsubxacts,=20= parsed->subxacts,=20max_xid);=0A+=09=09= ProcArrayRecoveryEndTransaction(max_xid,=20lsn);=0A=20=0A=20=09=09/*=0A=20= =09=09=20*=20Send=20any=20cache=20invalidations=20attached=20to=20the=20= commit.=20We=20must=0A@@=20-6294,7=20+6200,7=20@@=20= xact_redo_abort(xl_xact_parsed_abort=20*parsed,=20TransactionId=20xid,=0A= =20=09=09=09=09=09=09=09=09=20=20parsed->subxacts);=0A=20=09= AdvanceNextFullTransactionIdPastXid(max_xid);=0A=20=0A-=09if=20= (standbyState=20=3D=3D=20STANDBY_DISABLED)=0A+=09if=20(!InHotStandby)=0A=20= =09{=0A=20=09=09/*=20Mark=20the=20transaction=20aborted=20in=20pg_xact,=20= no=20need=20for=20async=20stuff=20*/=0A=20=09=09= TransactionIdAbortTree(xid,=20parsed->nsubxacts,=20parsed->subxacts);=0A= @@=20-6312,13=20+6218,15=20@@=20xact_redo_abort(xl_xact_parsed_abort=20= *parsed,=20TransactionId=20xid,=0A=20=09=09=20*/=0A=20=09=09= RecordKnownAssignedTransactionIds(max_xid);=0A=20=0A+=09=09/*=20Note:=20= we=20don't=20need=20to=20update=20the=20CSN=20log=20on=20abort.=20*/=0A+=0A= =20=09=09/*=20Mark=20the=20transaction=20aborted=20in=20pg_xact,=20no=20= need=20for=20async=20stuff=20*/=0A=20=09=09TransactionIdAbortTree(xid,=20= parsed->nsubxacts,=20parsed->subxacts);=0A=20=0A=20=09=09/*=0A=20=09=09=20= *=20We=20must=20update=20the=20ProcArray=20after=20we=20have=20marked=20= clog.=0A=20=09=09=20*/=0A-=09=09= ExpireTreeKnownAssignedTransactionIds(xid,=20parsed->nsubxacts,=20= parsed->subxacts,=20max_xid);=0A+=09=09= ProcArrayRecoveryEndTransaction(max_xid,=20lsn);=0A=20=0A=20=09=09/*=0A=20= =09=09=20*=20There=20are=20no=20invalidation=20messages=20to=20send=20or=20= undo.=0A@@=20-6426,14=20+6334,6=20@@=20xact_redo(XLogReaderState=20= *record)=0A=20=09=09=09=09=09=20=20=20XLogRecGetOrigin(record));=0A=20=09= =09LWLockRelease(TwoPhaseStateLock);=0A=20=09}=0A-=09else=20if=20(info=20= =3D=3D=20XLOG_XACT_ASSIGNMENT)=0A-=09{=0A-=09=09xl_xact_assignment=20= *xlrec=20=3D=20(xl_xact_assignment=20*)=20XLogRecGetData(record);=0A-=0A= -=09=09if=20(standbyState=20>=3D=20STANDBY_INITIALIZED)=0A-=09=09=09= ProcArrayApplyXidAssignment(xlrec->xtop,=0A-=09=09=09=09=09=09=09=09=09=09= xlrec->nsubxacts,=20xlrec->xsub);=0A-=09}=0A=20=09else=20if=20(info=20=3D=3D= =20XLOG_XACT_INVALIDATIONS)=0A=20=09{=0A=20=09=09/*=0Adiff=20--git=20= a/src/backend/access/transam/xlog.c=20= b/src/backend/access/transam/xlog.c=0Aindex=20fc30a52d496..cbeac223e1c=20= 100644=0A---=20a/src/backend/access/transam/xlog.c=0A+++=20= b/src/backend/access/transam/xlog.c=0A@@=20-48,6=20+48,7=20@@=0A=20=0A=20= #include=20"access/clog.h"=0A=20#include=20"access/commit_ts.h"=0A= +#include=20"access/csn_log.h"=0A=20#include=20"access/heaptoast.h"=0A=20= #include=20"access/multixact.h"=0A=20#include=20"access/rewriteheap.h"=0A= @@=20-951,8=20+952,6=20@@=20XLogInsertRecord(XLogRecData=20*rdata,=0A=20=0A= =20=09END_CRIT_SECTION();=0A=20=0A-=09= MarkCurrentTransactionIdLoggedIfAny();=0A-=0A=20=09/*=0A=20=09=20*=20= Mark=20top=20transaction=20id=20is=20logged=20(if=20needed)=20so=20that=20= we=20should=20not=20try=0A=20=09=20*=20to=20log=20it=20again=20with=20= the=20next=20WAL=20record=20in=20the=20current=20subtransaction.=0A@@=20= -5230,6=20+5229,7=20@@=20BootStrapXLOG(uint32=20data_checksum_version)=0A= =20=0A=20=09/*=20Bootstrap=20the=20commit=20log,=20too=20*/=0A=20=09= BootStrapCLOG();=0A+=09BootStrapCSNLog();=0A=20=09BootStrapCommitTs();=0A= =20=09BootStrapSUBTRANS();=0A=20=09BootStrapMultiXact();=0A@@=20-5831,16=20= +5831,16=20@@=20StartupXLOG(void)=0A=20=09=09=20*/=0A=20=09=09if=20= (ArchiveRecoveryRequested=20&&=20EnableHotStandby)=0A=20=09=09{=0A-=09=09= =09TransactionId=20*xids;=0A-=09=09=09int=09=09=09nxids;=0A+=09=09=09= FullTransactionId=20latestCompletedXid;=0A=20=0A=20=09=09=09= ereport(DEBUG1,=0A=20=09=09=09=09=09(errmsg_internal("initializing=20for=20= hot=20standby")));=0A+=09=09=09InHotStandby=20=3D=20true;=0A=20=0A=20=09=09= =09InitRecoveryTransactionEnvironment();=0A=20=0A=20=09=09=09if=20= (wasShutdown)=0A-=09=09=09=09oldestActiveXID=20=3D=20= PrescanPreparedTransactions(&xids,=20&nxids);=0A+=09=09=09=09= oldestActiveXID=20=3D=20PrescanPreparedTransactions();=0A=20=09=09=09= else=0A=20=09=09=09=09oldestActiveXID=20=3D=20= checkPoint.oldestActiveXid;=0A=20=09=09=09= Assert(TransactionIdIsValid(oldestActiveXID));=0A@@=20-5855,39=20= +5855,17=20@@=20StartupXLOG(void)=0A=20=09=09=09=20*/=0A=20=09=09=09= StartupSUBTRANS(oldestActiveXID);=0A=20=0A-=09=09=09/*=0A-=09=09=09=20*=20= If=20we're=20beginning=20at=20a=20shutdown=20checkpoint,=20we=20know=20= that=0A-=09=09=09=20*=20nothing=20was=20running=20on=20the=20primary=20= at=20this=20point.=20So=20fake-up=20an=0A-=09=09=09=20*=20empty=20= running-xacts=20record=20and=20use=20that=20here=20and=20now.=20Recover=0A= -=09=09=09=20*=20additional=20standby=20state=20for=20prepared=20= transactions.=0A-=09=09=09=20*/=0A-=09=09=09if=20(wasShutdown)=0A-=09=09=09= {=0A-=09=09=09=09RunningTransactionsData=20running;=0A-=09=09=09=09= TransactionId=20latestCompletedXid;=0A+=09=09=09latestCompletedXid=20=3D=20= checkPoint.nextXid;=0A+=09=09=09= FullTransactionIdRetreat(&latestCompletedXid);=0A+=09=09=09= TransamVariables->latestCompletedXid=20=3D=20latestCompletedXid;=0A=20=0A= -=09=09=09=09/*=20Update=20pg_subtrans=20entries=20for=20any=20prepared=20= transactions=20*/=0A-=09=09=09=09StandbyRecoverPreparedTransactions();=0A= +=09=09=09StartupCSNLog(oldestActiveXID,=20RedoRecPtr);=0A=20=0A-=09=09=09= =09/*=0A-=09=09=09=09=20*=20Construct=20a=20RunningTransactions=20= snapshot=20representing=20a=0A-=09=09=09=09=20*=20shut=20down=20server,=20= with=20only=20prepared=20transactions=20still=0A-=09=09=09=09=20*=20= alive.=20We're=20never=20overflowed=20at=20this=20point=20because=20all=0A= -=09=09=09=09=20*=20subxids=20are=20listed=20with=20their=20parent=20= prepared=20transactions.=0A-=09=09=09=09=20*/=0A-=09=09=09=09= running.xcnt=20=3D=20nxids;=0A-=09=09=09=09running.subxcnt=20=3D=200;=0A= -=09=09=09=09running.subxid_status=20=3D=20SUBXIDS_IN_SUBTRANS;=0A-=09=09= =09=09running.nextXid=20=3D=20= XidFromFullTransactionId(checkPoint.nextXid);=0A-=09=09=09=09= running.oldestRunningXid=20=3D=20oldestActiveXID;=0A-=09=09=09=09= latestCompletedXid=20=3D=20XidFromFullTransactionId(checkPoint.nextXid);=0A= -=09=09=09=09TransactionIdRetreat(latestCompletedXid);=0A-=09=09=09=09= Assert(TransactionIdIsNormal(latestCompletedXid));=0A-=09=09=09=09= running.latestCompletedXid=20=3D=20latestCompletedXid;=0A-=09=09=09=09= running.xids=20=3D=20xids;=0A-=0A-=09=09=09=09= ProcArrayApplyRecoveryInfo(&running);=0A-=09=09=09}=0A+=09=09=09= ProcArrayUpdateOldestRunningXid(oldestActiveXID);=0A+=0A+=09=09=09/*=20= Update=20pg_subtrans=20entries=20for=20any=20prepared=20transactions=20= */=0A+=09=09=09if=20(wasShutdown)=0A+=09=09=09=09= StandbyRecoverPreparedTransactions();=0A=20=09=09}=0A=20=0A=20=09=09/*=0A= @@=20-5971,7=20+5949,7=20@@=20StartupXLOG(void)=0A=20=09=20*=20This=20= information=20is=20not=20quite=20needed=20yet,=20but=20it=20is=20= positioned=20here=20so=0A=20=09=20*=20as=20potential=20problems=20are=20= detected=20before=20any=20on-disk=20change=20is=20done.=0A=20=09=20*/=0A= -=09oldestActiveXID=20=3D=20PrescanPreparedTransactions(NULL,=20NULL);=0A= +=09oldestActiveXID=20=3D=20PrescanPreparedTransactions();=0A=20=0A=20=09= /*=0A=20=09=20*=20Allow=20ordinary=20WAL=20segment=20creation=20before=20= possibly=20switching=20to=20a=20new=0A@@=20-6137,9=20+6115,18=20@@=20= StartupXLOG(void)=0A=20=09=20*=20Start=20up=20subtrans,=20if=20not=20= already=20done=20for=20hot=20standby.=20=20(commit=0A=20=09=20*=20= timestamps=20are=20started=20below,=20if=20necessary.)=0A=20=09=20*/=0A-=09= if=20(standbyState=20=3D=3D=20STANDBY_DISABLED)=0A+=09if=20= (!InHotStandby)=0A+=09{=0A=20=09=09StartupSUBTRANS(oldestActiveXID);=0A=20= =0A+=09=09/*=0A+=09=09=20*=20TODO:=20we=20don't=20need=20to=20update=20= CSN=20log=20from=20now=20on,=20but=20it's=20still=0A+=09=09=20*=20= required=20by=20snapshots=20that=20were=20taken=20before=20recovery=20= ended.=20=20We=0A+=09=09=20*=20just=20let=20it=20be,=20but=20it=20would=20= be=20nice=20to=20truncate=20it=20to=200=20after=20all=0A+=09=09=20*=20= the=20snapshots=20are=20gone.=0A+=09=09=20*/=0A+=09}=0A+=0A=20=09/*=0A=20= =09=20*=20Perform=20end=20of=20recovery=20actions=20for=20any=20SLRUs=20= that=20need=20it.=0A=20=09=20*/=0A@@=20-6225,12=20+6212,12=20@@=20= StartupXLOG(void)=0A=20=09=20*=20Shutdown=20the=20recovery=20= environment.=20=20This=20must=20occur=20after=0A=20=09=20*=20= RecoverPreparedTransactions()=20(see=20notes=20in=20= lock_twophase_recover())=0A=20=09=20*=20and=20after=20switching=20= SharedRecoveryState=20to=20RECOVERY_STATE_DONE=20so=20as=0A-=09=20*=20= any=20session=20building=20a=20snapshot=20will=20not=20rely=20on=20= KnownAssignedXids=20as=0A+=09=20*=20any=20session=20building=20a=20= snapshot=20will=20not=20rely=20on=20the=20CSN=20log=20as=0A=20=09=20*=20= RecoveryInProgress()=20would=20return=20false=20at=20this=20stage.=20=20= This=20is=0A=20=09=20*=20particularly=20critical=20for=20prepared=202PC=20= transactions,=20that=20would=20still=0A=20=09=20*=20need=20to=20be=20= included=20in=20snapshots=20once=20recovery=20has=20ended.=0A=20=09=20*/=0A= -=09if=20(standbyState=20!=3D=20STANDBY_DISABLED)=0A+=09if=20= (InHotStandby)=0A=20=09=09ShutdownRecoveryTransactionEnvironment();=0A=20= =0A=20=09/*=0A@@=20-7002,7=20+6989,7=20@@=20CreateCheckPoint(int=20= flags)=0A=20=09=20*=20starting=20snapshot=20of=20locks=20and=20= transactions.=0A=20=09=20*/=0A=20=09if=20(!shutdown=20&&=20= XLogStandbyInfoActive())=0A-=09=09checkPoint.oldestActiveXid=20=3D=20= GetOldestActiveTransactionId();=0A+=09=09checkPoint.oldestActiveXid=20=3D=20= GetOldestActiveTransactionId(true);=0A=20=09else=0A=20=09=09= checkPoint.oldestActiveXid=20=3D=20InvalidTransactionId;=0A=20=0A@@=20= -7396,6=20+7383,9=20@@=20CreateCheckPoint(int=20flags)=0A=20=09if=20= (!RecoveryInProgress())=0A=20=09=09= TruncateSUBTRANS(GetOldestTransactionIdConsideredRunning());=0A=20=0A+=09= if=20(shutdown)=0A+=09=09= TruncateCSNLog(GetOldestTransactionIdConsideredRunning());=0A+=0A=20=09= /*=20Real=20work=20is=20done;=20log=20and=20update=20stats.=20*/=0A=20=09= LogCheckpointEnd(false);=0A=20=0A@@=20-7567,6=20+7557,7=20@@=20= CheckPointGuts(XLogRecPtr=20checkPointRedo,=20int=20flags)=0A=20=09= TRACE_POSTGRESQL_BUFFER_CHECKPOINT_START(flags);=0A=20=09= CheckpointStats.ckpt_write_t=20=3D=20GetCurrentTimestamp();=0A=20=09= CheckPointCLOG();=0A+=09CheckPointCSNLog();=0A=20=09= CheckPointCommitTs();=0A=20=09CheckPointSUBTRANS();=0A=20=09= CheckPointMultiXact();=0A@@=20-7863,7=20+7854,10=20@@=20= CreateRestartPoint(int=20flags)=0A=20=09=20*=20this=20because=20= StartupSUBTRANS=20hasn't=20been=20called=20yet.=0A=20=09=20*/=0A=20=09if=20= (EnableHotStandby)=0A+=09{=0A=20=09=09= TruncateSUBTRANS(GetOldestTransactionIdConsideredRunning());=0A+=09=09= TruncateCSNLog(GetOldestTransactionIdConsideredRunning());=0A+=09}=0A=20=0A= =20=09/*=20Real=20work=20is=20done;=20log=20and=20update=20stats.=20*/=0A= =20=09LogCheckpointEnd(true);=0A@@=20-8348,41=20+8342,17=20@@=20= xlog_redo(XLogReaderState=20*record)=0A=20=0A=20=09=09/*=0A=20=09=09=20*=20= If=20we=20see=20a=20shutdown=20checkpoint,=20we=20know=20that=20nothing=20= was=20running=0A-=09=09=20*=20on=20the=20primary=20at=20this=20point.=20= So=20fake-up=20an=20empty=20running-xacts=0A-=09=09=20*=20record=20and=20= use=20that=20here=20and=20now.=20Recover=20additional=20standby=20state=0A= -=09=09=20*=20for=20prepared=20transactions.=0A+=09=09=20*=20on=20the=20= primary=20at=20this=20point,=20except=20for=20prepared=20transactions.=0A= =20=09=09=20*/=0A-=09=09if=20(standbyState=20>=3D=20STANDBY_INITIALIZED)=0A= +=09=09if=20(InHotStandby)=0A=20=09=09{=0A-=09=09=09TransactionId=20= *xids;=0A-=09=09=09int=09=09=09nxids;=0A=20=09=09=09TransactionId=20= oldestActiveXID;=0A-=09=09=09TransactionId=20latestCompletedXid;=0A-=09=09= =09RunningTransactionsData=20running;=0A=20=0A-=09=09=09oldestActiveXID=20= =3D=20PrescanPreparedTransactions(&xids,=20&nxids);=0A+=09=09=09= oldestActiveXID=20=3D=20PrescanPreparedTransactions();=0A+=09=09=09= ProcArrayUpdateOldestRunningXid(oldestActiveXID);=0A=20=0A=20=09=09=09/*=20= Update=20pg_subtrans=20entries=20for=20any=20prepared=20transactions=20= */=0A=20=09=09=09StandbyRecoverPreparedTransactions();=0A-=0A-=09=09=09= /*=0A-=09=09=09=20*=20Construct=20a=20RunningTransactions=20snapshot=20= representing=20a=20shut=0A-=09=09=09=20*=20down=20server,=20with=20only=20= prepared=20transactions=20still=20alive.=20We're=0A-=09=09=09=20*=20= never=20overflowed=20at=20this=20point=20because=20all=20subxids=20are=20= listed=0A-=09=09=09=20*=20with=20their=20parent=20prepared=20= transactions.=0A-=09=09=09=20*/=0A-=09=09=09running.xcnt=20=3D=20nxids;=0A= -=09=09=09running.subxcnt=20=3D=200;=0A-=09=09=09running.subxid_status=20= =3D=20SUBXIDS_IN_SUBTRANS;=0A-=09=09=09running.nextXid=20=3D=20= XidFromFullTransactionId(checkPoint.nextXid);=0A-=09=09=09= running.oldestRunningXid=20=3D=20oldestActiveXID;=0A-=09=09=09= latestCompletedXid=20=3D=20XidFromFullTransactionId(checkPoint.nextXid);=0A= -=09=09=09TransactionIdRetreat(latestCompletedXid);=0A-=09=09=09= Assert(TransactionIdIsNormal(latestCompletedXid));=0A-=09=09=09= running.latestCompletedXid=20=3D=20latestCompletedXid;=0A-=09=09=09= running.xids=20=3D=20xids;=0A-=0A-=09=09=09= ProcArrayApplyRecoveryInfo(&running);=0A=20=09=09}=0A=20=0A=20=09=09/*=20= ControlFile->checkPointCopy=20always=20tracks=20the=20latest=20ckpt=20= XID=20*/=0A@@=20-8446,6=20+8416,16=20@@=20xlog_redo(XLogReaderState=20= *record)=0A=20=09=09=09=09=09=09=09=09=20=20checkPoint.oldestXid))=0A=20=09= =09=09SetTransactionIdLimit(checkPoint.oldestXid,=0A=20=09=09=09=09=09=09= =09=09=20=20checkPoint.oldestXidDB);=0A+=0A+=09=09/*=0A+=09=09=20*=20= Remember=20the=20oldest=20XID=20that=20was=20running=20at=20the=20time.=20= =20Normally,=0A+=09=09=20*=20all=20transaction=20aborts=20and=20commits=20= are=20WAL-logged,=20so=20our=0A+=09=09=20*=20oldestRunningXid=20value=20= should=20be=20up-to-date,=20but=20if=20not,=20this=0A+=09=09=20*=20= allows=20us=20to=20resynchronize.=0A+=09=09=20*/=0A+=09=09if=20= (InHotStandby)=0A+=09=09=09= ProcArrayUpdateOldestRunningXid(checkPoint.oldestActiveXid);=0A+=0A=20=09= =09/*=20ControlFile->checkPointCopy=20always=20tracks=20the=20latest=20= ckpt=20XID=20*/=0A=20=09=09LWLockAcquire(ControlFileLock,=20= LW_EXCLUSIVE);=0A=20=09=09ControlFile->checkPointCopy.nextXid=20=3D=20= checkPoint.nextXid;=0Adiff=20--git=20= a/src/backend/access/transam/xlogrecovery.c=20= b/src/backend/access/transam/xlogrecovery.c=0Aindex=20= 0aa3ab59085..b213b8a74dc=20100644=0A---=20= a/src/backend/access/transam/xlogrecovery.c=0A+++=20= b/src/backend/access/transam/xlogrecovery.c=0A@@=20-1978,10=20+1978,9=20= @@=20ApplyWalRecord(XLogReaderState=20*xlogreader,=20XLogRecord=20= *record,=20TimeLineID=20*repl=0A=20=09= SpinLockRelease(&XLogRecoveryCtl->info_lck);=0A=20=0A=20=09/*=0A-=09=20*=20= If=20we=20are=20attempting=20to=20enter=20Hot=20Standby=20mode,=20= process=20XIDs=20we=20see=0A+=09=20*=20In=20Hot=20Standby=20mode,=20= process=20XIDs=20we=20see=0A=20=09=20*/=0A-=09if=20(standbyState=20>=3D=20= STANDBY_INITIALIZED=20&&=0A-=09=09TransactionIdIsValid(record->xl_xid))=0A= +=09if=20(InHotStandby=20&&=20TransactionIdIsValid(record->xl_xid))=0A=20= =09=09RecordKnownAssignedTransactionIds(record->xl_xid);=0A=20=0A=20=09= /*=0A@@=20-2258,7=20+2257,7=20@@=20CheckRecoveryConsistency(void)=0A=20=09= =20*=20run?=20If=20so,=20we=20can=20tell=20postmaster=20that=20the=20= database=20is=20consistent=20now,=0A=20=09=20*=20enabling=20connections.=0A= =20=09=20*/=0A-=09if=20(standbyState=20=3D=3D=20STANDBY_SNAPSHOT_READY=20= &&=0A+=09if=20(InHotStandby=20&&=0A=20=09=09!LocalHotStandbyActive=20&&=0A= =20=09=09reachedConsistency=20&&=0A=20=09=09IsUnderPostmaster)=0A@@=20= -3715,9=20+3714,6=20@@=20WaitForWALToBecomeAvailable(XLogRecPtr=20= RecPtr,=20bool=20randAccess,=0A=20=09=09=09=09=09=09elog(LOG,=20"waiting=20= for=20WAL=20to=20become=20available=20at=20%X/%X",=0A=20=09=09=09=09=09=09= =09=20LSN_FORMAT_ARGS(RecPtr));=0A=20=0A-=09=09=09=09=09=09/*=20Do=20= background=20tasks=20that=20might=20benefit=20us=20later.=20*/=0A-=09=09=09= =09=09=09KnownAssignedTransactionIdsIdleMaintenance();=0A-=0A=20=09=09=09= =09=09=09(void)=20WaitLatch(&XLogRecoveryCtl->recoveryWakeupLatch,=0A=20=09= =09=09=09=09=09=09=09=09=09=20WL_LATCH_SET=20|=20WL_TIMEOUT=20|=0A=20=09=09= =09=09=09=09=09=09=09=09=20WL_EXIT_ON_PM_DEATH,=0A@@=20-3983,9=20+3979,6=20= @@=20WaitForWALToBecomeAvailable(XLogRecPtr=20RecPtr,=20bool=20= randAccess,=0A=20=09=09=09=09=09=09streaming_reply_sent=20=3D=20true;=0A=20= =09=09=09=09=09}=0A=20=0A-=09=09=09=09=09/*=20Do=20any=20background=20= tasks=20that=20might=20benefit=20us=20later.=20*/=0A-=09=09=09=09=09= KnownAssignedTransactionIdsIdleMaintenance();=0A-=0A=20=09=09=09=09=09/*=20= Update=20pg_stat_recovery_prefetch=20before=20sleeping.=20*/=0A=20=09=09=09= =09=09XLogPrefetcherComputeStats(xlogprefetcher);=0A=20=0Adiff=20--git=20= a/src/backend/access/transam/xlogutils.c=20= b/src/backend/access/transam/xlogutils.c=0Aindex=20= c389b27f77d..775e1a926d8=20100644=0A---=20= a/src/backend/access/transam/xlogutils.c=0A+++=20= b/src/backend/access/transam/xlogutils.c=0A@@=20-50,7=20+50,7=20@@=20= bool=09=09ignore_invalid_pages=20=3D=20false;=0A=20bool=09=09InRecovery=20= =3D=20false;=0A=20=0A=20/*=20Are=20we=20in=20Hot=20Standby=20mode?=20= Only=20valid=20in=20startup=20process,=20see=20xlogutils.h=20*/=0A= -HotStandbyState=20standbyState=20=3D=20STANDBY_DISABLED;=0A+bool=09=09= InHotStandby=20=3D=20false;=0A=20=0A=20/*=0A=20=20*=20During=20XLOG=20= replay,=20we=20may=20see=20XLOG=20records=20for=20incremental=20updates=20= of=0Adiff=20--git=20a/src/backend/backup/basebackup.c=20= b/src/backend/backup/basebackup.c=0Aindex=20891637e3a44..f1307ed714c=20= 100644=0A---=20a/src/backend/backup/basebackup.c=0A+++=20= b/src/backend/backup/basebackup.c=0A@@=20-181,6=20+181,9=20@@=20static=20= const=20char=20*const=20excludeDirContents[]=20=3D=0A=20=09/*=20Contents=20= zeroed=20on=20startup,=20see=20StartupSUBTRANS().=20*/=0A=20=09= "pg_subtrans",=0A=20=0A+=09/*=20Contents=20zeroed=20on=20startup,=20see=20= StartupCSNLog().=20*/=0A+=09"pg_csn",=0A+=0A=20=09/*=20end=20of=20list=20= */=0A=20=09NULL=0A=20};=0Adiff=20--git=20= a/src/backend/postmaster/startup.c=20b/src/backend/postmaster/startup.c=0A= index=2027e86cf393f..d04286ab270=20100644=0A---=20= a/src/backend/postmaster/startup.c=0A+++=20= b/src/backend/postmaster/startup.c=0A@@=20-203,7=20+203,7=20@@=20static=20= void=0A=20StartupProcExit(int=20code,=20Datum=20arg)=0A=20{=0A=20=09/*=20= Shutdown=20the=20recovery=20environment=20*/=0A-=09if=20(standbyState=20= !=3D=20STANDBY_DISABLED)=0A+=09if=20(InHotStandby)=0A=20=09=09= ShutdownRecoveryTransactionEnvironment();=0A=20}=0A=20=0Adiff=20--git=20= a/src/backend/replication/logical/decode.c=20= b/src/backend/replication/logical/decode.c=0Aindex=20= 6a428e9720e..808b1d85379=20100644=0A---=20= a/src/backend/replication/logical/decode.c=0A+++=20= b/src/backend/replication/logical/decode.c=0A@@=20-270,14=20+270,6=20@@=20= xact_decode(LogicalDecodingContext=20*ctx,=20XLogRecordBuffer=20*buf)=0A=20= =09=09=09=09DecodeAbort(ctx,=20buf,=20&parsed,=20xid,=20two_phase);=0A=20= =09=09=09=09break;=0A=20=09=09=09}=0A-=09=09case=20XLOG_XACT_ASSIGNMENT:=0A= -=0A-=09=09=09/*=0A-=09=09=09=20*=20We=20assign=20subxact=20to=20the=20= toplevel=20xact=20while=20processing=20each=0A-=09=09=09=20*=20record=20= if=20required.=20=20So,=20we=20don't=20need=20to=20do=20anything=20here.=20= See=0A-=09=09=09=20*=20LogicalDecodingProcessRecord.=0A-=09=09=09=20*/=0A= -=09=09=09break;=0A=20=09=09case=20XLOG_XACT_INVALIDATIONS:=0A=20=09=09=09= {=0A=20=09=09=09=09TransactionId=20xid;=0Adiff=20--git=20= a/src/backend/replication/logical/snapbuild.c=20= b/src/backend/replication/logical/snapbuild.c=0Aindex=20= 3c94a62cdf6..97d278052df=20100644=0A---=20= a/src/backend/replication/logical/snapbuild.c=0A+++=20= b/src/backend/replication/logical/snapbuild.c=0A@@=20-27,7=20+27,7=20@@=0A= =20=20*=20removed.=20This=20is=20achieved=20by=20using=20the=20= replication=20slot=20mechanism.=0A=20=20*=0A=20=20*=20As=20the=20= percentage=20of=20transactions=20modifying=20the=20catalog=20normally=20= is=20fairly=0A-=20*=20small=20in=20comparisons=20to=20ones=20only=20= manipulating=20user=20data,=20we=20keep=20track=20of=0A+=20*=20small=20= in=20comparison=20to=20ones=20only=20manipulating=20user=20data,=20we=20= keep=20track=20of=0A=20=20*=20the=20committed=20catalog=20modifying=20= ones=20inside=20[xmin,=20xmax)=20instead=20of=20keeping=0A=20=20*=20= track=20of=20all=20running=20transactions=20like=20it's=20done=20in=20a=20= normal=20snapshot.=20Note=0A=20=20*=20that=20we're=20generally=20only=20= looking=20at=20transactions=20that=20have=20acquired=20an=0Adiff=20--git=20= a/src/backend/storage/ipc/ipci.c=20b/src/backend/storage/ipc/ipci.c=0A= index=202fa045e6b0f..fc9804b2eab=20100644=0A---=20= a/src/backend/storage/ipc/ipci.c=0A+++=20= b/src/backend/storage/ipc/ipci.c=0A@@=20-16,6=20+16,7=20@@=0A=20=0A=20= #include=20"access/clog.h"=0A=20#include=20"access/commit_ts.h"=0A= +#include=20"access/csn_log.h"=0A=20#include=20"access/multixact.h"=0A=20= #include=20"access/nbtree.h"=0A=20#include=20"access/subtrans.h"=0A@@=20= -122,6=20+123,7=20@@=20CalculateShmemSize(int=20*num_semaphores)=0A=20=09= size=20=3D=20add_size(size,=20XLOGShmemSize());=0A=20=09size=20=3D=20= add_size(size,=20XLogRecoveryShmemSize());=0A=20=09size=20=3D=20= add_size(size,=20CLOGShmemSize());=0A+=09size=20=3D=20add_size(size,=20= CSNLogShmemSize());=0A=20=09size=20=3D=20add_size(size,=20= CommitTsShmemSize());=0A=20=09size=20=3D=20add_size(size,=20= SUBTRANSShmemSize());=0A=20=09size=20=3D=20add_size(size,=20= TwoPhaseShmemSize());=0A@@=20-287,6=20+289,7=20@@=20= CreateOrAttachShmemStructs(void)=0A=20=09XLogPrefetchShmemInit();=0A=20=09= XLogRecoveryShmemInit();=0A=20=09CLOGShmemInit();=0A+=09= CSNLogShmemInit();=0A=20=09CommitTsShmemInit();=0A=20=09= SUBTRANSShmemInit();=0A=20=09MultiXactShmemInit();=0Adiff=20--git=20= a/src/backend/storage/ipc/procarray.c=20= b/src/backend/storage/ipc/procarray.c=0Aindex=20819649741f6..3418ddf5304=20= 100644=0A---=20a/src/backend/storage/ipc/procarray.c=0A+++=20= b/src/backend/storage/ipc/procarray.c=0A@@=20-19,20=20+19,10=20@@=0A=20=20= *=20myProcLocks=20lists.=20=20They=20can=20be=20distinguished=20from=20= regular=20backend=20PGPROCs=0A=20=20*=20at=20need=20by=20checking=20for=20= pid=20=3D=3D=200.=0A=20=20*=0A-=20*=20During=20hot=20standby,=20we=20= also=20keep=20a=20list=20of=20XIDs=20representing=20transactions=0A-=20*=20= that=20are=20known=20to=20be=20running=20on=20the=20primary=20(or=20more=20= precisely,=20were=20running=0A-=20*=20as=20of=20the=20current=20point=20= in=20the=20WAL=20stream).=20=20This=20list=20is=20kept=20in=20the=0A-=20= *=20KnownAssignedXids=20array,=20and=20is=20updated=20by=20watching=20= the=20sequence=20of=0A-=20*=20arriving=20XIDs.=20=20This=20is=20= necessary=20because=20if=20we=20leave=20those=20XIDs=20out=20of=0A-=20*=20= snapshots=20taken=20for=20standby=20queries,=20then=20they=20will=20= appear=20to=20be=20already=0A-=20*=20complete,=20leading=20to=20MVCC=20= failures.=20=20Note=20that=20in=20hot=20standby,=20the=20PGPROC=0A-=20*=20= array=20represents=20standby=20processes,=20which=20by=20definition=20= are=20not=20running=0A-=20*=20transactions=20that=20have=20XIDs.=0A-=20*=0A= -=20*=20It=20is=20perhaps=20possible=20for=20a=20backend=20on=20the=20= primary=20to=20terminate=20without=0A-=20*=20writing=20an=20abort=20= record=20for=20its=20transaction.=20=20While=20that=20shouldn't=20really=0A= -=20*=20happen,=20it=20would=20tie=20up=20KnownAssignedXids=20= indefinitely,=20so=20we=20protect=0A-=20*=20ourselves=20by=20pruning=20= the=20array=20when=20a=20valid=20list=20of=20running=20XIDs=20arrives.=0A= +=20*=20During=20hot=20standby,=20we=20don't=20have=20PGPROC=20entries=20= representing=20transactions=0A+=20*=20running=20in=20the=20primary.=20=20= In=20snapshots=20taken=20during=20recovery,=20the=20snapshot=0A+=20*=20= contains=20a=20Commit-Sequence=20Number=20(CSN)=20which=20is=20used=20to=20= determine=20which=0A+=20*=20XIDs=20are=20still=20considered=20as=20= running=20by=20the=20snapshot.=0A=20=20*=0A=20=20*=20Portions=20= Copyright=20(c)=201996-2025,=20PostgreSQL=20Global=20Development=20Group=0A= =20=20*=20Portions=20Copyright=20(c)=201994,=20Regents=20of=20the=20= University=20of=20California=0A@@=20-47,6=20+37,7=20@@=0A=20=0A=20= #include=20=0A=20=0A+#include=20"access/csn_log.h"=0A=20= #include=20"access/subtrans.h"=0A=20#include=20"access/transam.h"=0A=20= #include=20"access/twophase.h"=0A@@=20-74,22=20+65,8=20@@=20typedef=20= struct=20ProcArrayStruct=0A=20=09int=09=09=09numProcs;=09=09/*=20number=20= of=20valid=20procs=20entries=20*/=0A=20=09int=09=09=09maxProcs;=09=09/*=20= allocated=20size=20of=20procs=20array=20*/=0A=20=0A-=09/*=0A-=09=20*=20= Known=20assigned=20XIDs=20handling=0A-=09=20*/=0A-=09int=09=09=09= maxKnownAssignedXids;=09/*=20allocated=20size=20of=20array=20*/=0A-=09= int=09=09=09numKnownAssignedXids;=09/*=20current=20#=20of=20valid=20= entries=20*/=0A-=09int=09=09=09tailKnownAssignedXids;=09/*=20index=20of=20= oldest=20valid=20element=20*/=0A-=09int=09=09=09headKnownAssignedXids;=09= /*=20index=20of=20newest=20element,=20+=201=20*/=0A-=0A-=09/*=0A-=09=20*=20= Highest=20subxid=20that=20has=20been=20removed=20from=20= KnownAssignedXids=20array=20to=0A-=09=20*=20prevent=20overflow;=20or=20= InvalidTransactionId=20if=20none.=20=20We=20track=20this=20for=0A-=09=20= *=20similar=20reasons=20to=20tracking=20overflowing=20cached=20subxids=20= in=20PGPROC=0A-=09=20*=20entries.=20=20Must=20hold=20exclusive=20= ProcArrayLock=20to=20change=20this,=20and=20shared=0A-=09=20*=20lock=20= to=20read=20it.=0A-=09=20*/=0A-=09TransactionId=20lastOverflowedXid;=0A+=09= /*=20In=20recovery,=20oldest=20XID=20that=20could=20be=20still=20running=20= in=20primary=20*/=0A+=09TransactionId=20oldest_running_primary_xid;=0A=20= =0A=20=09/*=20oldest=20xmin=20of=20any=20replication=20slot=20*/=0A=20=09= TransactionId=20replication_slot_xmin;=0A@@=20-100,6=20+77,21=20@@=20= typedef=20struct=20ProcArrayStruct=0A=20=09int=09=09=09= pgprocnos[FLEXIBLE_ARRAY_MEMBER];=0A=20}=20ProcArrayStruct;=0A=20=0A= +#define=20PROCARRAY_MAXPROCS=09(MaxBackends=20+=20max_prepared_xacts)=0A= +=0A+/*=0A+=20*=20TOTAL_MAX_CACHED_SUBXIDS=20is=20the=20total=20number=20= of=20XIDs=20that=20fits=20in=20the=20proc=0A+=20*=20array,=20as=20top=20= XIDs=20and=20in=20the=20subxids=20caches.=0A+=20*=0A+=20*=20Local=20data=20= structures=20are=20also=20created=20in=20various=20backends=20during=0A+=20= *=20GetSnapshotData(),=20TransactionIdIsInProgress()=20and=0A+=20*=20= GetRunningTransactionData().=20All=20of=20the=20main=20structures=20= created=20in=20those=0A+=20*=20functions=20must=20be=20identically=20= sized,=20since=20we=20may=20at=20times=20copy=20the=20whole=0A+=20*=20of=20= the=20data=20structures=20around.=0A+=20*/=0A+#define=20= TOTAL_MAX_CACHED_SUBXIDS=20\=0A+=09((PGPROC_MAX_CACHED_SUBXIDS=20+=201)=20= *=20PROCARRAY_MAXPROCS)=0A+=0A=20/*=0A=20=20*=20State=20for=20the=20= GlobalVisTest*=20family=20of=20functions.=20Those=20functions=20can=0A=20= =20*=20e.g.=20be=20used=20to=20decide=20if=20a=20deleted=20row=20can=20= be=20removed=20without=20violating=0A@@=20-255,17=20+247,6=20@@=20= typedef=20enum=20GlobalVisHorizonKind=0A=20=09VISHORIZON_TEMP,=0A=20}=20= GlobalVisHorizonKind;=0A=20=0A-/*=0A-=20*=20Reason=20codes=20for=20= KnownAssignedXidsCompress().=0A-=20*/=0A-typedef=20enum=20= KAXCompressReason=0A-{=0A-=09KAX_NO_SPACE,=09=09=09=09/*=20need=20to=20= free=20up=20space=20at=20array=20end=20*/=0A-=09KAX_PRUNE,=09=09=09=09=09= /*=20we=20just=20pruned=20old=20entries=20*/=0A-=09KAX_TRANSACTION_END,=09= =09/*=20we=20just=20committed/removed=20some=20XIDs=20*/=0A-=09= KAX_STARTUP_PROCESS_IDLE,=09/*=20startup=20process=20is=20about=20to=20= sleep=20*/=0A-}=20KAXCompressReason;=0A-=0A=20=0A=20static=20= ProcArrayStruct=20*procArray;=0A=20=0A@@=20-277,19=20+258,10=20@@=20= static=20PGPROC=20*allProcs;=0A=20static=20TransactionId=20= cachedXidIsNotInProgress=20=3D=20InvalidTransactionId;=0A=20=0A=20/*=0A-=20= *=20Bookkeeping=20for=20tracking=20emulated=20transactions=20in=20= recovery=0A+=20*=20Bookkeeping=20for=20tracking=20transactions=20seen=20= during=20recovery=0A=20=20*/=0A-static=20TransactionId=20= *KnownAssignedXids;=0A-static=20bool=20*KnownAssignedXidsValid;=0A=20= static=20TransactionId=20latestObservedXid=20=3D=20InvalidTransactionId;=0A= =20=0A-/*=0A-=20*=20If=20we're=20in=20STANDBY_SNAPSHOT_PENDING=20state,=20= standbySnapshotPendingXmin=20is=0A-=20*=20the=20highest=20xid=20that=20= might=20still=20be=20running=20that=20we=20don't=20have=20in=0A-=20*=20= KnownAssignedXids.=0A-=20*/=0A-static=20TransactionId=20= standbySnapshotPendingXmin;=0A-=0A=20/*=0A=20=20*=20State=20for=20= visibility=20checks=20on=20different=20types=20of=20relations.=20See=20= struct=0A=20=20*=20GlobalVisState=20for=20details.=20As=20shared,=20= catalog,=20normal=20and=20temporary=0A@@=20-316,7=20+288,7=20@@=20static=20= long=20xc_by_my_xact=20=3D=200;=0A=20static=20long=20xc_by_latest_xid=20= =3D=200;=0A=20static=20long=20xc_by_main_xid=20=3D=200;=0A=20static=20= long=20xc_by_child_xid=20=3D=200;=0A-static=20long=20= xc_by_known_assigned=20=3D=200;=0A+static=20long=20xc_during_recovery=20= =3D=200;=0A=20static=20long=20xc_no_overflow=20=3D=200;=0A=20static=20= long=20xc_slow_answer=20=3D=200;=0A=20=0A@@=20-326,7=20+298,7=20@@=20= static=20long=20xc_slow_answer=20=3D=200;=0A=20#define=20= xc_by_latest_xid_inc()=09=09(xc_by_latest_xid++)=0A=20#define=20= xc_by_main_xid_inc()=09=09(xc_by_main_xid++)=0A=20#define=20= xc_by_child_xid_inc()=09=09(xc_by_child_xid++)=0A-#define=20= xc_by_known_assigned_inc()=09(xc_by_known_assigned++)=0A+#define=20= xc_during_recovery_inc()=09(xc_during_recovery++)=0A=20#define=20= xc_no_overflow_inc()=09=09(xc_no_overflow++)=0A=20#define=20= xc_slow_answer_inc()=09=09(xc_slow_answer++)=0A=20=0A@@=20-339,28=20= +311,12=20@@=20static=20void=20DisplayXidCache(void);=0A=20#define=20= xc_by_latest_xid_inc()=09=09((void)=200)=0A=20#define=20= xc_by_main_xid_inc()=09=09((void)=200)=0A=20#define=20= xc_by_child_xid_inc()=09=09((void)=200)=0A-#define=20= xc_by_known_assigned_inc()=09((void)=200)=0A+#define=20= xc_during_recovery_inc()=09((void)=200)=0A=20#define=20= xc_no_overflow_inc()=09=09((void)=200)=0A=20#define=20= xc_slow_answer_inc()=09=09((void)=200)=0A=20#endif=09=09=09=09=09=09=09= /*=20XIDCACHE_DEBUG=20*/=0A=20=0A-/*=20Primitives=20for=20= KnownAssignedXids=20array=20handling=20for=20standby=20*/=0A-static=20= void=20KnownAssignedXidsCompress(KAXCompressReason=20reason,=20bool=20= haveLock);=0A-static=20void=20KnownAssignedXidsAdd(TransactionId=20= from_xid,=20TransactionId=20to_xid,=0A-=09=09=09=09=09=09=09=09=20bool=20= exclusive_lock);=0A-static=20bool=20= KnownAssignedXidsSearch(TransactionId=20xid,=20bool=20remove);=0A-static=20= bool=20KnownAssignedXidExists(TransactionId=20xid);=0A-static=20void=20= KnownAssignedXidsRemove(TransactionId=20xid);=0A-static=20void=20= KnownAssignedXidsRemoveTree(TransactionId=20xid,=20int=20nsubxids,=0A-=09= =09=09=09=09=09=09=09=09=09TransactionId=20*subxids);=0A-static=20void=20= KnownAssignedXidsRemovePreceding(TransactionId=20removeXid);=0A-static=20= int=09KnownAssignedXidsGet(TransactionId=20*xarray,=20TransactionId=20= xmax);=0A-static=20int=09KnownAssignedXidsGetAndSetXmin(TransactionId=20= *xarray,=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20TransactionId=20= *xmin,=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20TransactionId=20xmax);=0A= -static=20TransactionId=20KnownAssignedXidsGetOldestXmin(void);=0A= -static=20void=20KnownAssignedXidsDisplay(int=20trace_level);=0A-static=20= void=20KnownAssignedXidsReset(void);=0A+=0A=20static=20inline=20void=20= ProcArrayEndTransactionInternal(PGPROC=20*proc,=20TransactionId=20= latestXid);=0A=20static=20void=20ProcArrayGroupClearXid(PGPROC=20*proc,=20= TransactionId=20latestXid);=0A=20static=20void=20= MaintainLatestCompletedXid(TransactionId=20latestXid);=0A@@=20-384,31=20= +340,6=20@@=20ProcArrayShmemSize(void)=0A=20=09size=20=3D=20= offsetof(ProcArrayStruct,=20pgprocnos);=0A=20=09size=20=3D=20= add_size(size,=20mul_size(sizeof(int),=20PROCARRAY_MAXPROCS));=0A=20=0A-=09= /*=0A-=09=20*=20During=20Hot=20Standby=20processing=20we=20have=20a=20= data=20structure=20called=0A-=09=20*=20KnownAssignedXids,=20created=20in=20= shared=20memory.=20Local=20data=20structures=20are=0A-=09=20*=20also=20= created=20in=20various=20backends=20during=20GetMVCCSnapshotData(),=0A-=09= =20*=20TransactionIdIsInProgress()=20and=20GetRunningTransactionData().=20= All=20of=20the=0A-=09=20*=20main=20structures=20created=20in=20those=20= functions=20must=20be=20identically=20sized,=0A-=09=20*=20since=20we=20= may=20at=20times=20copy=20the=20whole=20of=20the=20data=20structures=20= around.=20We=0A-=09=20*=20refer=20to=20this=20size=20as=20= TOTAL_MAX_CACHED_SUBXIDS.=0A-=09=20*=0A-=09=20*=20Ideally=20we'd=20only=20= create=20this=20structure=20if=20we=20were=20actually=20doing=20hot=0A-=09= =20*=20standby=20in=20the=20current=20run,=20but=20we=20don't=20know=20= that=20yet=20at=20the=20time=0A-=09=20*=20shared=20memory=20is=20being=20= set=20up.=0A-=09=20*/=0A-#define=20TOTAL_MAX_CACHED_SUBXIDS=20\=0A-=09= ((PGPROC_MAX_CACHED_SUBXIDS=20+=201)=20*=20PROCARRAY_MAXPROCS)=0A-=0A-=09= if=20(EnableHotStandby)=0A-=09{=0A-=09=09size=20=3D=20add_size(size,=0A-=09= =09=09=09=09=09mul_size(sizeof(TransactionId),=0A-=09=09=09=09=09=09=09=09= =20TOTAL_MAX_CACHED_SUBXIDS));=0A-=09=09size=20=3D=20add_size(size,=0A-=09= =09=09=09=09=09mul_size(sizeof(bool),=20TOTAL_MAX_CACHED_SUBXIDS));=0A-=09= }=0A-=0A=20=09return=20size;=0A=20}=0A=20=0A@@=20-435,31=20+366,12=20@@=20= ProcArrayShmemInit(void)=0A=20=09=09=20*/=0A=20=09=09procArray->numProcs=20= =3D=200;=0A=20=09=09procArray->maxProcs=20=3D=20PROCARRAY_MAXPROCS;=0A-=09= =09procArray->maxKnownAssignedXids=20=3D=20TOTAL_MAX_CACHED_SUBXIDS;=0A-=09= =09procArray->numKnownAssignedXids=20=3D=200;=0A-=09=09= procArray->tailKnownAssignedXids=20=3D=200;=0A-=09=09= procArray->headKnownAssignedXids=20=3D=200;=0A-=09=09= procArray->lastOverflowedXid=20=3D=20InvalidTransactionId;=0A=20=09=09= procArray->replication_slot_xmin=20=3D=20InvalidTransactionId;=0A=20=09=09= procArray->replication_slot_catalog_xmin=20=3D=20InvalidTransactionId;=0A= =20=09=09TransamVariables->xactCompletionCount=20=3D=201;=0A=20=09}=0A=20= =0A=20=09allProcs=20=3D=20ProcGlobal->allProcs;=0A-=0A-=09/*=20Create=20= or=20attach=20to=20the=20KnownAssignedXids=20arrays=20too,=20if=20needed=20= */=0A-=09if=20(EnableHotStandby)=0A-=09{=0A-=09=09KnownAssignedXids=20=3D=20= (TransactionId=20*)=0A-=09=09=09ShmemInitStruct("KnownAssignedXids",=0A-=09= =09=09=09=09=09=09mul_size(sizeof(TransactionId),=0A-=09=09=09=09=09=09=09= =09=09=20TOTAL_MAX_CACHED_SUBXIDS),=0A-=09=09=09=09=09=09=09&found);=0A-=09= =09KnownAssignedXidsValid=20=3D=20(bool=20*)=0A-=09=09=09= ShmemInitStruct("KnownAssignedXidsValid",=0A-=09=09=09=09=09=09=09= mul_size(sizeof(bool),=20TOTAL_MAX_CACHED_SUBXIDS),=0A-=09=09=09=09=09=09= =09&found);=0A-=09}=0A=20}=0A=20=0A=20/*=0A@@=20-1023,355=20+935,35=20@@=20= MaintainLatestCompletedXidRecovery(TransactionId=20latestXid)=0A=20void=0A= =20ProcArrayInitRecovery(TransactionId=20initializedUptoXID)=0A=20{=0A-=09= Assert(standbyState=20=3D=3D=20STANDBY_INITIALIZED);=0A+=09= Assert(InHotStandby);=0A=20=09= Assert(TransactionIdIsNormal(initializedUptoXID));=0A=20=0A=20=09/*=0A-=09= =20*=20we=20set=20latestObservedXid=20to=20the=20xid=20SUBTRANS=20has=20= been=20initialized=20up=0A-=09=20*=20to,=20so=20we=20can=20extend=20it=20= from=20that=20point=20onwards=20in=0A-=09=20*=20= RecordKnownAssignedTransactionIds,=20and=20when=20we=20get=20consistent=20= in=0A-=09=20*=20ProcArrayApplyRecoveryInfo().=0A+=09=20*=20we=20set=20= latestObservedXid=20to=20the=20xid=20SUBTRANS=20and=20CSN=20log=20have=20= been=0A+=09=20*=20initialized=20up=20to,=20so=20we=20can=20extend=20it=20= from=20that=20point=20onwards=20whenever=0A+=09=20*=20we=20observe=20new=20= XIDs.=0A=20=09=20*/=0A=20=09latestObservedXid=20=3D=20= initializedUptoXID;=0A=20=09TransactionIdRetreat(latestObservedXid);=0A=20= }=0A=20=0A=20/*=0A-=20*=20ProcArrayApplyRecoveryInfo=20--=20apply=20= recovery=20info=20about=20xids=0A-=20*=0A-=20*=20Takes=20us=20through=20= 3=20states:=20Initialized,=20Pending=20and=20Ready.=0A-=20*=20Normal=20= case=20is=20to=20go=20all=20the=20way=20to=20Ready=20straight=20away,=20= though=20there=0A-=20*=20are=20atypical=20cases=20where=20we=20need=20to=20= take=20it=20in=20steps.=0A-=20*=0A-=20*=20Use=20the=20data=20about=20= running=20transactions=20on=20the=20primary=20to=20create=20the=20= initial=0A-=20*=20state=20of=20KnownAssignedXids.=20We=20also=20use=20= these=20records=20to=20regularly=20prune=0A-=20*=20KnownAssignedXids=20= because=20we=20know=20it=20is=20possible=20that=20some=20transactions=0A= -=20*=20with=20FATAL=20errors=20fail=20to=20write=20abort=20records,=20= which=20could=20cause=20eventual=0A-=20*=20overflow.=0A-=20*=0A-=20*=20= See=20comments=20for=20LogStandbySnapshot().=0A+=20*=20Update=20oldest=20= running=20XID.=20from=20a=20checkpoint=20record.=20This=20allows=20= truncating=0A+=20*=20SUBTRANS=20and=20the=20CSN=20log.=0A=20=20*/=0A=20= void=0A-ProcArrayApplyRecoveryInfo(RunningTransactions=20running)=0A= +ProcArrayUpdateOldestRunningXid(TransactionId=20oldestRunningXID)=0A=20= {=0A-=09TransactionId=20*xids;=0A-=09TransactionId=20advanceNextXid;=0A-=09= int=09=09=09nxids;=0A-=09int=09=09=09i;=0A-=0A-=09Assert(standbyState=20= >=3D=20STANDBY_INITIALIZED);=0A-=09= Assert(TransactionIdIsValid(running->nextXid));=0A-=09= Assert(TransactionIdIsValid(running->oldestRunningXid));=0A-=09= Assert(TransactionIdIsNormal(running->latestCompletedXid));=0A-=0A-=09/*=0A= -=09=20*=20Remove=20stale=20transactions,=20if=20any.=0A-=09=20*/=0A-=09= ExpireOldKnownAssignedTransactionIds(running->oldestRunningXid);=0A-=0A-=09= /*=0A-=09=20*=20Adjust=20TransamVariables->nextXid=20before=20= StandbyReleaseOldLocks(),=0A-=09=20*=20because=20we=20will=20need=20it=20= up=20to=20date=20for=20accessing=20two-phase=20transactions=0A-=09=20*=20= in=20StandbyReleaseOldLocks().=0A-=09=20*/=0A-=09advanceNextXid=20=3D=20= running->nextXid;=0A-=09TransactionIdRetreat(advanceNextXid);=0A-=09= AdvanceNextFullTransactionIdPastXid(advanceNextXid);=0A-=09= Assert(FullTransactionIdIsValid(TransamVariables->nextXid));=0A-=0A=20=09= /*=0A=20=09=20*=20Remove=20stale=20locks,=20if=20any.=0A=20=09=20*/=0A-=09= StandbyReleaseOldLocks(running->oldestRunningXid);=0A-=0A-=09/*=0A-=09=20= *=20If=20our=20snapshot=20is=20already=20valid,=20nothing=20else=20to=20= do...=0A-=09=20*/=0A-=09if=20(standbyState=20=3D=3D=20= STANDBY_SNAPSHOT_READY)=0A-=09=09return;=0A-=0A-=09/*=0A-=09=20*=20If=20= our=20initial=20RunningTransactionsData=20had=20an=20overflowed=20= snapshot=20then=0A-=09=20*=20we=20knew=20we=20were=20missing=20some=20= subxids=20from=20our=20snapshot.=20If=20we=20continue=0A-=09=20*=20to=20= see=20overflowed=20snapshots=20then=20we=20might=20never=20be=20able=20= to=20start=20up,=20so=0A-=09=20*=20we=20make=20another=20test=20to=20see=20= if=20our=20snapshot=20is=20now=20valid.=20We=20know=20that=0A-=09=20*=20= the=20missing=20subxids=20are=20equal=20to=20or=20earlier=20than=20= nextXid.=20After=20we=0A-=09=20*=20initialise=20we=20continue=20to=20= apply=20changes=20during=20recovery,=20so=20once=20the=0A-=09=20*=20= oldestRunningXid=20is=20later=20than=20the=20nextXid=20from=20the=20= initial=20snapshot=20we=0A-=09=20*=20know=20that=20we=20no=20longer=20= have=20missing=20information=20and=20can=20mark=20the=0A-=09=20*=20= snapshot=20as=20valid.=0A-=09=20*/=0A-=09if=20(standbyState=20=3D=3D=20= STANDBY_SNAPSHOT_PENDING)=0A-=09{=0A-=09=09/*=0A-=09=09=20*=20If=20the=20= snapshot=20isn't=20overflowed=20or=20if=20its=20empty=20we=20can=20reset=20= our=0A-=09=09=20*=20pending=20state=20and=20use=20this=20snapshot=20= instead.=0A-=09=09=20*/=0A-=09=09if=20(running->subxid_status=20!=3D=20= SUBXIDS_MISSING=20||=20running->xcnt=20=3D=3D=200)=0A-=09=09{=0A-=09=09=09= /*=0A-=09=09=09=20*=20If=20we=20have=20already=20collected=20known=20= assigned=20xids,=20we=20need=20to=0A-=09=09=09=20*=20throw=20them=20away=20= before=20we=20apply=20the=20recovery=20snapshot.=0A-=09=09=09=20*/=0A-=09= =09=09KnownAssignedXidsReset();=0A-=09=09=09standbyState=20=3D=20= STANDBY_INITIALIZED;=0A-=09=09}=0A-=09=09else=0A-=09=09{=0A-=09=09=09if=20= (TransactionIdPrecedes(standbySnapshotPendingXmin,=0A-=09=09=09=09=09=09=09= =09=09=20=20running->oldestRunningXid))=0A-=09=09=09{=0A-=09=09=09=09= standbyState=20=3D=20STANDBY_SNAPSHOT_READY;=0A-=09=09=09=09elog(DEBUG1,=0A= -=09=09=09=09=09=20"recovery=20snapshots=20are=20now=20enabled");=0A-=09=09= =09}=0A-=09=09=09else=0A-=09=09=09=09elog(DEBUG1,=0A-=09=09=09=09=09=20= "recovery=20snapshot=20waiting=20for=20non-overflowed=20snapshot=20or=20= "=0A-=09=09=09=09=09=20"until=20oldest=20active=20xid=20on=20standby=20= is=20at=20least=20%u=20(now=20%u)",=0A-=09=09=09=09=09=20= standbySnapshotPendingXmin,=0A-=09=09=09=09=09=20= running->oldestRunningXid);=0A-=09=09=09return;=0A-=09=09}=0A-=09}=0A-=0A= -=09Assert(standbyState=20=3D=3D=20STANDBY_INITIALIZED);=0A-=0A-=09/*=0A= -=09=20*=20NB:=20this=20can=20be=20reached=20at=20least=20twice,=20so=20= make=20sure=20new=20code=20can=20deal=0A-=09=20*=20with=20that.=0A-=09=20= */=0A+=09StandbyReleaseOldLocks(oldestRunningXID);=0A=20=0A-=09/*=0A-=09=20= *=20Nobody=20else=20is=20running=20yet,=20but=20take=20locks=20anyhow=0A= -=09=20*/=0A=20=09LWLockAcquire(ProcArrayLock,=20LW_EXCLUSIVE);=0A-=0A-=09= /*=0A-=09=20*=20KnownAssignedXids=20is=20sorted=20so=20we=20cannot=20= just=20add=20the=20xids,=20we=20have=20to=0A-=09=20*=20sort=20them=20= first.=0A-=09=20*=0A-=09=20*=20Some=20of=20the=20new=20xids=20are=20= top-level=20xids=20and=20some=20are=20subtransactions.=0A-=09=20*=20We=20= don't=20call=20SubTransSetParent=20because=20it=20doesn't=20matter=20= yet.=20If=20we=0A-=09=20*=20aren't=20overflowed=20then=20all=20xids=20= will=20fit=20in=20snapshot=20and=20so=20we=20don't=0A-=09=20*=20need=20= subtrans.=20If=20we=20later=20overflow,=20an=20xid=20assignment=20record=20= will=20add=0A-=09=20*=20xids=20to=20subtrans.=20If=20= RunningTransactionsData=20is=20overflowed=20then=20we=0A-=09=20*=20don't=20= have=20enough=20information=20to=20correctly=20update=20subtrans=20= anyway.=0A-=09=20*/=0A-=0A-=09/*=0A-=09=20*=20Allocate=20a=20temporary=20= array=20to=20avoid=20modifying=20the=20array=20passed=20as=0A-=09=20*=20= argument.=0A-=09=20*/=0A-=09xids=20=3D=20palloc(sizeof(TransactionId)=20= *=20(running->xcnt=20+=20running->subxcnt));=0A-=0A-=09/*=0A-=09=20*=20= Add=20to=20the=20temp=20array=20any=20xids=20which=20have=20not=20= already=20completed.=0A-=09=20*/=0A-=09nxids=20=3D=200;=0A-=09for=20(i=20= =3D=200;=20i=20<=20running->xcnt=20+=20running->subxcnt;=20i++)=0A-=09{=0A= -=09=09TransactionId=20xid=20=3D=20running->xids[i];=0A-=0A-=09=09/*=0A-=09= =09=20*=20The=20running-xacts=20snapshot=20can=20contain=20xids=20that=20= were=20still=20visible=0A-=09=09=20*=20in=20the=20procarray=20when=20the=20= snapshot=20was=20taken,=20but=20were=20already=0A-=09=09=20*=20= WAL-logged=20as=20completed.=20They're=20not=20running=20anymore,=20so=20= ignore=0A-=09=09=20*=20them.=0A-=09=09=20*/=0A-=09=09if=20= (TransactionIdDidCommit(xid)=20||=20TransactionIdDidAbort(xid))=0A-=09=09= =09continue;=0A-=0A-=09=09xids[nxids++]=20=3D=20xid;=0A-=09}=0A-=0A-=09= if=20(nxids=20>=200)=0A-=09{=0A-=09=09if=20= (procArray->numKnownAssignedXids=20!=3D=200)=0A-=09=09{=0A-=09=09=09= LWLockRelease(ProcArrayLock);=0A-=09=09=09elog(ERROR,=20= "KnownAssignedXids=20is=20not=20empty");=0A-=09=09}=0A-=0A-=09=09/*=0A-=09= =09=20*=20Sort=20the=20array=20so=20that=20we=20can=20add=20them=20= safely=20into=0A-=09=09=20*=20KnownAssignedXids.=0A-=09=09=20*=0A-=09=09=20= *=20We=20have=20to=20sort=20them=20logically,=20because=20in=20= KnownAssignedXidsAdd=20we=0A-=09=09=20*=20call=20= TransactionIdFollowsOrEquals=20and=20so=20on.=20But=20we=20know=20these=20= XIDs=0A-=09=09=20*=20come=20from=20RUNNING_XACTS,=20which=20means=20= there=20are=20only=20normal=20XIDs=0A-=09=09=20*=20from=20the=20same=20= epoch,=20so=20this=20is=20safe.=0A-=09=09=20*/=0A-=09=09qsort(xids,=20= nxids,=20sizeof(TransactionId),=20xidLogicalComparator);=0A-=0A-=09=09/*=0A= -=09=09=20*=20Add=20the=20sorted=20snapshot=20into=20KnownAssignedXids.=20= =20The=20running-xacts=0A-=09=09=20*=20snapshot=20may=20include=20= duplicated=20xids=20because=20of=20prepared=0A-=09=09=20*=20= transactions,=20so=20ignore=20them.=0A-=09=09=20*/=0A-=09=09for=20(i=20=3D= =200;=20i=20<=20nxids;=20i++)=0A-=09=09{=0A-=09=09=09if=20(i=20>=200=20= &&=20TransactionIdEquals(xids[i=20-=201],=20xids[i]))=0A-=09=09=09{=0A-=09= =09=09=09elog(DEBUG1,=0A-=09=09=09=09=09=20"found=20duplicated=20= transaction=20%u=20for=20KnownAssignedXids=20insertion",=0A-=09=09=09=09=09= =20xids[i]);=0A-=09=09=09=09continue;=0A-=09=09=09}=0A-=09=09=09= KnownAssignedXidsAdd(xids[i],=20xids[i],=20true);=0A-=09=09}=0A-=0A-=09=09= KnownAssignedXidsDisplay(DEBUG3);=0A-=09}=0A-=0A-=09pfree(xids);=0A-=0A-=09= /*=0A-=09=20*=20latestObservedXid=20is=20at=20least=20set=20to=20the=20= point=20where=20SUBTRANS=20was=0A-=09=20*=20started=20up=20to=20(cf.=20= ProcArrayInitRecovery())=20or=20to=20the=20biggest=20xid=0A-=09=20*=20= RecordKnownAssignedTransactionIds()=20was=20called=20for.=20=20= Initialize=0A-=09=20*=20subtrans=20from=20thereon,=20up=20to=20nextXid=20= -=201.=0A-=09=20*=0A-=09=20*=20We=20need=20to=20duplicate=20parts=20of=20= RecordKnownAssignedTransactionId()=20here,=0A-=09=20*=20because=20we've=20= just=20added=20xids=20to=20the=20known=20assigned=20xids=20machinery=20= that=0A-=09=20*=20haven't=20gone=20through=20= RecordKnownAssignedTransactionId().=0A-=09=20*/=0A-=09= Assert(TransactionIdIsNormal(latestObservedXid));=0A-=09= TransactionIdAdvance(latestObservedXid);=0A-=09while=20= (TransactionIdPrecedes(latestObservedXid,=20running->nextXid))=0A-=09{=0A= -=09=09ExtendSUBTRANS(latestObservedXid);=0A-=09=09= TransactionIdAdvance(latestObservedXid);=0A-=09}=0A-=09= TransactionIdRetreat(latestObservedXid);=09/*=20=3D=20running->nextXid=20= -=201=20*/=0A-=0A-=09/*=20----------=0A-=09=20*=20Now=20we've=20got=20= the=20running=20xids=20we=20need=20to=20set=20the=20global=20values=20= that=0A-=09=20*=20are=20used=20to=20track=20snapshots=20as=20they=20= evolve=20further.=0A-=09=20*=0A-=09=20*=20-=20latestCompletedXid=20which=20= will=20be=20the=20xmax=20for=20snapshots=0A-=09=20*=20-=20= lastOverflowedXid=20which=20shows=20whether=20snapshots=20overflow=0A-=09= =20*=20-=20nextXid=0A-=09=20*=0A-=09=20*=20If=20the=20snapshot=20= overflowed,=20then=20we=20still=20initialise=20with=20what=20we=20know,=0A= -=09=20*=20but=20the=20recovery=20snapshot=20isn't=20fully=20valid=20yet=20= because=20we=20know=20there=0A-=09=20*=20are=20some=20subxids=20missing.=20= We=20don't=20know=20the=20specific=20subxids=20that=20are=0A-=09=20*=20= missing,=20so=20conservatively=20assume=20the=20last=20one=20is=20= latestObservedXid.=0A-=09=20*=20----------=0A-=09=20*/=0A-=09if=20= (running->subxid_status=20=3D=3D=20SUBXIDS_MISSING)=0A-=09{=0A-=09=09= standbyState=20=3D=20STANDBY_SNAPSHOT_PENDING;=0A-=0A-=09=09= standbySnapshotPendingXmin=20=3D=20latestObservedXid;=0A-=09=09= procArray->lastOverflowedXid=20=3D=20latestObservedXid;=0A-=09}=0A-=09= else=0A-=09{=0A-=09=09standbyState=20=3D=20STANDBY_SNAPSHOT_READY;=0A-=0A= -=09=09standbySnapshotPendingXmin=20=3D=20InvalidTransactionId;=0A-=0A-=09= =09/*=0A-=09=09=20*=20If=20the=20'xids'=20array=20didn't=20include=20all=20= subtransactions,=20we=20have=20to=0A-=09=09=20*=20mark=20any=20snapshots=20= taken=20as=20overflowed.=0A-=09=09=20*/=0A-=09=09if=20= (running->subxid_status=20=3D=3D=20SUBXIDS_IN_SUBTRANS)=0A-=09=09=09= procArray->lastOverflowedXid=20=3D=20latestObservedXid;=0A-=09=09else=0A= -=09=09{=0A-=09=09=09Assert(running->subxid_status=20=3D=3D=20= SUBXIDS_IN_ARRAY);=0A-=09=09=09procArray->lastOverflowedXid=20=3D=20= InvalidTransactionId;=0A-=09=09}=0A-=09}=0A-=0A-=09/*=0A-=09=20*=20If=20= a=20transaction=20wrote=20a=20commit=20record=20in=20the=20gap=20between=20= taking=20and=0A-=09=20*=20logging=20the=20snapshot=20then=20= latestCompletedXid=20may=20already=20be=20higher=20than=0A-=09=20*=20the=20= value=20from=20the=20snapshot,=20so=20check=20before=20we=20use=20the=20= incoming=20value.=0A-=09=20*=20It=20also=20might=20not=20yet=20be=20set=20= at=20all.=0A-=09=20*/=0A-=09= MaintainLatestCompletedXidRecovery(running->latestCompletedXid);=0A-=0A-=09= /*=0A-=09=20*=20NB:=20No=20need=20to=20increment=20= TransamVariables->xactCompletionCount=20here,=0A-=09=20*=20nobody=20can=20= see=20it=20yet.=0A-=09=20*/=0A-=0A+=09= procArray->oldest_running_primary_xid=20=3D=20oldestRunningXID;=0A=20=09= LWLockRelease(ProcArrayLock);=0A-=0A-=09= KnownAssignedXidsDisplay(DEBUG3);=0A-=09if=20(standbyState=20=3D=3D=20= STANDBY_SNAPSHOT_READY)=0A-=09=09elog(DEBUG1,=20"recovery=20snapshots=20= are=20now=20enabled");=0A-=09else=0A-=09=09elog(DEBUG1,=0A-=09=09=09=20= "recovery=20snapshot=20waiting=20for=20non-overflowed=20snapshot=20or=20= "=0A-=09=09=09=20"until=20oldest=20active=20xid=20on=20standby=20is=20at=20= least=20%u=20(now=20%u)",=0A-=09=09=09=20standbySnapshotPendingXmin,=0A-=09= =09=09=20running->oldestRunningXid);=0A=20}=0A=20=0A-/*=0A-=20*=20= ProcArrayApplyXidAssignment=0A-=20*=09=09Process=20an=20= XLOG_XACT_ASSIGNMENT=20WAL=20record=0A-=20*/=0A-void=0A= -ProcArrayApplyXidAssignment(TransactionId=20topxid,=0A-=09=09=09=09=09=09= =09int=20nsubxids,=20TransactionId=20*subxids)=0A-{=0A-=09TransactionId=20= max_xid;=0A-=09int=09=09=09i;=0A-=0A-=09Assert(standbyState=20>=3D=20= STANDBY_INITIALIZED);=0A-=0A-=09max_xid=20=3D=20= TransactionIdLatest(topxid,=20nsubxids,=20subxids);=0A-=0A-=09/*=0A-=09=20= *=20Mark=20all=20the=20subtransactions=20as=20observed.=0A-=09=20*=0A-=09= =20*=20NOTE:=20This=20will=20fail=20if=20the=20subxid=20contains=20too=20= many=20previously=0A-=09=20*=20unobserved=20xids=20to=20fit=20into=20= known-assigned-xids.=20That=20shouldn't=20happen=0A-=09=20*=20as=20the=20= code=20stands,=20because=20xid-assignment=20records=20should=20never=20= contain=0A-=09=20*=20more=20than=20PGPROC_MAX_CACHED_SUBXIDS=20entries.=0A= -=09=20*/=0A-=09RecordKnownAssignedTransactionIds(max_xid);=0A-=0A-=09/*=0A= -=09=20*=20Notice=20that=20we=20update=20pg_subtrans=20with=20the=20= top-level=20xid,=20rather=20than=0A-=09=20*=20the=20parent=20xid.=20This=20= is=20a=20difference=20between=20normal=20processing=20and=0A-=09=20*=20= recovery,=20yet=20is=20still=20correct=20in=20all=20cases.=20The=20= reason=20is=20that=0A-=09=20*=20subtransaction=20commit=20is=20not=20= marked=20in=20clog=20until=20commit=20processing,=20so=0A-=09=20*=20all=20= aborted=20subtransactions=20have=20already=20been=20clearly=20marked=20= in=20clog.=0A-=09=20*=20As=20a=20result=20we=20are=20able=20to=20refer=20= directly=20to=20the=20top-level=0A-=09=20*=20transaction's=20state=20= rather=20than=20skipping=20through=20all=20the=20intermediate=0A-=09=20*=20= states=20in=20the=20subtransaction=20tree.=20This=20should=20be=20the=20= first=20time=20we=0A-=09=20*=20have=20attempted=20to=20= SubTransSetParent().=0A-=09=20*/=0A-=09for=20(i=20=3D=200;=20i=20<=20= nsubxids;=20i++)=0A-=09=09SubTransSetParent(subxids[i],=20topxid);=0A-=0A= -=09/*=20KnownAssignedXids=20isn't=20maintained=20yet,=20so=20we're=20= done=20for=20now=20*/=0A-=09if=20(standbyState=20=3D=3D=20= STANDBY_INITIALIZED)=0A-=09=09return;=0A-=0A-=09/*=0A-=09=20*=20Uses=20= same=20locking=20as=20transaction=20commit=0A-=09=20*/=0A-=09= LWLockAcquire(ProcArrayLock,=20LW_EXCLUSIVE);=0A-=0A-=09/*=0A-=09=20*=20= Remove=20subxids=20from=20known-assigned-xacts.=0A-=09=20*/=0A-=09= KnownAssignedXidsRemoveTree(InvalidTransactionId,=20nsubxids,=20= subxids);=0A-=0A-=09/*=0A-=09=20*=20Advance=20lastOverflowedXid=20to=20= be=20at=20least=20the=20last=20of=20these=20subxids.=0A-=09=20*/=0A-=09= if=20(TransactionIdPrecedes(procArray->lastOverflowedXid,=20max_xid))=0A= -=09=09procArray->lastOverflowedXid=20=3D=20max_xid;=0A-=0A-=09= LWLockRelease(ProcArrayLock);=0A-}=0A=20=0A=20/*=0A=20=20*=20= TransactionIdIsInProgress=20--=20is=20given=20transaction=20running=20in=20= some=20backend=0A@@=20-1379,23=20+971,24=20@@=20= ProcArrayApplyXidAssignment(TransactionId=20topxid,=0A=20=20*=20Aside=20= from=20some=20shortcuts=20such=20as=20checking=20RecentXmin=20and=20our=20= own=20Xid,=0A=20=20*=20there=20are=20four=20possibilities=20for=20= finding=20a=20running=20transaction:=0A=20=20*=0A-=20*=201.=20The=20= given=20Xid=20is=20a=20main=20transaction=20Id.=20=20We=20will=20find=20= this=20out=20cheaply=0A+=20*=201.=20In=20Hot=20Standby=20mode,=20there=20= are=20no=20transactions=20with=20XIDs=20active=20in=20the=0A+=20*=20= standby.=20Check=20pg_xact=20to=20see=20if=20the=20transaction=20is=20= known=20to=20have=20committed=0A+=20*=20or=20aborted,=20otherwise=20it's=20= considered=20as=20running.=0A+=20*=0A+=20*=202.=20The=20given=20Xid=20is=20= a=20main=20transaction=20Id.=20=20We=20will=20find=20this=20out=20= cheaply=0A=20=20*=20by=20looking=20at=20ProcGlobal->xids.=0A=20=20*=0A-=20= *=202.=20The=20given=20Xid=20is=20one=20of=20the=20cached=20subxact=20= Xids=20in=20the=20PGPROC=20array.=0A+=20*=203.=20The=20given=20Xid=20is=20= one=20of=20the=20cached=20subxact=20Xids=20in=20the=20PGPROC=20array.=0A=20= =20*=20We=20can=20find=20this=20out=20cheaply=20too.=0A=20=20*=0A-=20*=20= 3.=20In=20Hot=20Standby=20mode,=20we=20must=20search=20the=20= KnownAssignedXids=20list=20to=20see=0A-=20*=20if=20the=20Xid=20is=20= running=20on=20the=20primary.=0A-=20*=0A=20=20*=204.=20Search=20the=20= SubTrans=20tree=20to=20find=20the=20Xid's=20topmost=20parent,=20and=20= then=20see=0A-=20*=20if=20that=20is=20running=20according=20to=20= ProcGlobal->xids[]=20or=20KnownAssignedXids.=0A+=20*=20if=20that=20is=20= running=20according=20to=20ProcGlobal->xids[].=0A=20=20*=20This=20is=20= the=20slowest=20way,=20but=20sadly=20it=20has=20to=20be=20done=20always=20= if=20the=20others=0A=20=20*=20failed,=20unless=20we=20see=20that=20the=20= cached=20subxact=20sets=20are=20complete=20(none=20have=0A=20=20*=20= overflowed).=0A=20=20*=0A-=20*=20ProcArrayLock=20has=20to=20be=20held=20= while=20we=20do=201,=202,=203.=20=20If=20we=20save=20the=20top=20Xids=0A= -=20*=20while=20doing=201=20and=203,=20we=20can=20release=20the=20= ProcArrayLock=20while=20we=20do=204.=0A+=20*=20ProcArrayLock=20has=20to=20= be=20held=20while=20we=20do=202=20and=203.=20=20If=20we=20save=20the=20= top=20Xids=0A+=20*=20while=20doing=202=20and=203,=20we=20can=20release=20= the=20ProcArrayLock=20while=20we=20do=204.=0A=20=20*=20This=20buys=20= back=20some=20concurrency=20(and=20we=20can't=20retrieve=20the=20main=20= Xids=20from=0A=20=20*=20ProcGlobal->xids[]=20again=20anyway;=20see=20= GetNewTransactionId).=0A=20=20*/=0A@@=20-1436,6=20+1029,28=20@@=20= TransactionIdIsInProgress(TransactionId=20xid)=0A=20=09=09return=20= false;=0A=20=09}=0A=20=0A+=09/*=0A+=09=20*=20In=20hot=20standby=20mode,=20= check=20pg_xact.=0A+=09=20*=0A+=09=20*=20With=20normal=20non-CSN=20= snapshots,=20you=20must=20be=20careful=20to=20check=0A+=09=20*=20= TransactionIdIsInProgress()=20before=20checking=20pg_xact,=20because=20a=0A= +=09=20*=20transaction=20is=20marked=20as=20committed=20before=20it's=20= removed=20from=20PGPROC.=20But=0A+=09=20*=20during=20recovery,=20we=20= now=20use=20CSN=20snapshots=20so=20I=20think=20that's=20OK.=20See=20the=0A= +=09=20*=20"NOTE"=20at=20the=20top=20of=20heapam_visibility.c.=0A+=09=20= *=0A+=09=20*=20During=20recovery,=20the=20XID=20cannot=20be=20our=20own=20= transaction,=20and=20the=20CSN=0A+=09=20*=20check=20handles=20= subtransactions=20too,=20so=20we=20can=20skip=20the=20rest=20of=20the=0A= +=09=20*=20function.=0A+=09=20*/=0A+=09if=20(RecoveryInProgress())=0A+=09= {=0A+=09=09xc_during_recovery_inc();=0A+=09=09if=20= (TransactionIdDidCommit(xid)=20||=20TransactionIdDidAbort(xid))=0A+=09=09= =09return=20false;=0A+=09=09else=0A+=09=09=09return=20true;=0A+=09}=0A+=0A= =20=09/*=0A=20=09=20*=20Also,=20we=20can=20handle=20our=20own=20= transaction=20(and=20subtransactions)=20without=0A=20=09=20*=20any=20= access=20to=20shared=20memory.=0A@@=20-1452,12=20+1067,7=20@@=20= TransactionIdIsInProgress(TransactionId=20xid)=0A=20=09=20*/=0A=20=09if=20= (xids=20=3D=3D=20NULL)=0A=20=09{=0A-=09=09/*=0A-=09=09=20*=20In=20hot=20= standby=20mode,=20reserve=20enough=20space=20to=20hold=20all=20xids=20in=20= the=0A-=09=09=20*=20known-assigned=20list.=20If=20we=20later=20finish=20= recovery,=20we=20no=20longer=20need=0A-=09=09=20*=20the=20bigger=20= array,=20but=20we=20don't=20bother=20to=20shrink=20it.=0A-=09=09=20*/=0A= -=09=09int=09=09=09maxxids=20=3D=20RecoveryInProgress()=20?=20= TOTAL_MAX_CACHED_SUBXIDS=20:=20arrayP->maxProcs;=0A+=09=09int=09=09=09= maxxids=20=3D=20arrayP->maxProcs;=0A=20=0A=20=09=09xids=20=3D=20= (TransactionId=20*)=20malloc(maxxids=20*=20sizeof(TransactionId));=0A=20=09= =09if=20(xids=20=3D=3D=20NULL)=0A@@=20-1552,33=20+1162,6=20@@=20= TransactionIdIsInProgress(TransactionId=20xid)=0A=20=09=09=09= xids[nxids++]=20=3D=20pxid;=0A=20=09}=0A=20=0A-=09/*=0A-=09=20*=20Step=20= 3:=20in=20hot=20standby=20mode,=20check=20the=20known-assigned-xids=20= list.=20=20XIDs=0A-=09=20*=20in=20the=20list=20must=20be=20treated=20as=20= running.=0A-=09=20*/=0A-=09if=20(RecoveryInProgress())=0A-=09{=0A-=09=09= /*=20none=20of=20the=20PGPROC=20entries=20should=20have=20XIDs=20in=20= hot=20standby=20mode=20*/=0A-=09=09Assert(nxids=20=3D=3D=200);=0A-=0A-=09= =09if=20(KnownAssignedXidExists(xid))=0A-=09=09{=0A-=09=09=09= LWLockRelease(ProcArrayLock);=0A-=09=09=09xc_by_known_assigned_inc();=0A= -=09=09=09return=20true;=0A-=09=09}=0A-=0A-=09=09/*=0A-=09=09=20*=20If=20= the=20KnownAssignedXids=20overflowed,=20we=20have=20to=20check=20= pg_subtrans=0A-=09=09=20*=20too.=20=20Fetch=20all=20xids=20from=20= KnownAssignedXids=20that=20are=20lower=20than=0A-=09=09=20*=20xid,=20= since=20if=20xid=20is=20a=20subtransaction=20its=20parent=20will=20= always=20have=20a=0A-=09=09=20*=20lower=20value.=20=20Note=20we=20will=20= collect=20both=20main=20and=20subXIDs=20here,=20but=0A-=09=09=20*=20= there's=20no=20help=20for=20it.=0A-=09=09=20*/=0A-=09=09if=20= (TransactionIdPrecedesOrEquals(xid,=20procArray->lastOverflowedXid))=0A-=09= =09=09nxids=20=3D=20KnownAssignedXidsGet(xids,=20xid);=0A-=09}=0A-=0A=20=09= LWLockRelease(ProcArrayLock);=0A=20=0A=20=09/*=0A@@=20-1852,8=20+1435,7=20= @@=20ComputeXidHorizons(ComputeXidHorizonsResult=20*h)=0A=20=09=09=20*=20= can't=20be=20tied=20to=20a=20specific=20database.)=0A=20=09=09=20*=0A=20=09= =09=20*=20Also,=20while=20in=20recovery=20we=20cannot=20compute=20an=20= accurate=20per-database=0A-=09=09=20*=20horizon,=20as=20all=20xids=20are=20= managed=20via=20the=20KnownAssignedXids=0A-=09=09=20*=20machinery.=0A+=09= =09=20*=20horizon,=20as=20all=20xids=20are=20managed=20via=20the=20CSN=20= log=20machinery.=0A=20=09=09=20*/=0A=20=09=09if=20(proc->databaseId=20=3D=3D= =20MyDatabaseId=20||=0A=20=09=09=09MyDatabaseId=20=3D=3D=20InvalidOid=20= ||=0A@@=20-1866,11=20+1448,14=20@@=20= ComputeXidHorizons(ComputeXidHorizonsResult=20*h)=0A=20=09}=0A=20=0A=20=09= /*=0A-=09=20*=20If=20in=20recovery=20fetch=20oldest=20xid=20in=20= KnownAssignedXids,=20will=20be=20applied=0A-=09=20*=20after=20lock=20is=20= released.=0A+=09=20*=20If=20in=20recovery=20fetch=20oldest=20xid=20from=20= last=20checkpoint.=0A+=09=20*=0A+=09=20*=20XXX:=20that=20can=20be=20much=20= older=20than=20what=20we=20had=20previously=20with=20the=0A+=09=20*=20= known-assigned-xids=20machinery.=20I=20think=20that's=20OK,=20given=20= what=20this=0A+=09=20*=20function=20is=20used=20for=20during=20recovery?=0A= =20=09=20*/=0A=20=09if=20(in_recovery)=0A-=09=09kaxmin=20=3D=20= KnownAssignedXidsGetOldestXmin();=0A+=09=09kaxmin=20=3D=20= procArray->oldest_running_primary_xid;=0A=20=0A=20=09/*=0A=20=09=20*=20= No=20other=20information=20from=20shared=20state=20is=20needed,=20= release=20the=20lock=0A@@=20-2181,7=20+1766,7=20@@=20= GetMVCCSnapshotData(void)=0A=20=09TransactionId=20myxid;=0A=20=09uint64=09= =09curXactCompletionCount;=0A=20=09MVCCSnapshotShared=20snapshot;=0A-=0A= +=09XLogRecPtr=09csn=20=3D=20InvalidXLogRecPtr;=0A=20=09TransactionId=20= replication_slot_xmin=20=3D=20InvalidTransactionId;=0A=20=09= TransactionId=20replication_slot_catalog_xmin=20=3D=20= InvalidTransactionId;=0A=20=0A@@=20-2355,27=20+1940,8=20@@=20= GetMVCCSnapshotData(void)=0A=20=09else=0A=20=09{=0A=20=09=09/*=0A-=09=09=20= *=20We're=20in=20hot=20standby,=20so=20get=20XIDs=20from=20= KnownAssignedXids.=0A-=09=09=20*=0A-=09=09=20*=20We=20store=20all=20xids=20= directly=20into=20subxip[].=20Here's=20why:=0A-=09=09=20*=0A-=09=09=20*=20= In=20recovery=20we=20don't=20know=20which=20xids=20are=20top-level=20and=20= which=20are=0A-=09=09=20*=20subxacts,=20a=20design=20choice=20that=20= greatly=20simplifies=20xid=20processing.=0A-=09=09=20*=0A-=09=09=20*=20= It=20seems=20like=20we=20would=20want=20to=20try=20to=20put=20xids=20= into=20xip[]=20only,=20but=0A-=09=09=20*=20that=20is=20fairly=20small.=20= We=20would=20either=20need=20to=20make=20that=20bigger=20or=0A-=09=09=20= *=20to=20increase=20the=20rate=20at=20which=20we=20WAL-log=20xid=20= assignment;=20neither=20is=0A-=09=09=20*=20an=20appealing=20choice.=0A-=09= =09=20*=0A-=09=09=20*=20We=20could=20try=20to=20store=20xids=20into=20= xip[]=20first=20and=20then=20into=20subxip[]=0A-=09=09=20*=20if=20there=20= are=20too=20many=20xids.=20That=20only=20works=20if=20the=20snapshot=20= doesn't=0A-=09=09=20*=20overflow=20because=20we=20do=20not=20search=20= subxip[]=20in=20that=20case.=20A=20simpler=0A-=09=09=20*=20way=20is=20to=20= just=20store=20all=20xids=20in=20the=20subxip=20array=20because=20this=20= is=0A-=09=09=20*=20by=20far=20the=20bigger=20array.=20We=20just=20leave=20= the=20xip=20array=20empty.=0A-=09=09=20*=0A-=09=09=20*=20Either=20way=20= we=20need=20to=20change=20the=20way=20XidInMVCCSnapshot()=20works=0A-=09=09= =20*=20depending=20upon=20when=20the=20snapshot=20was=20taken,=20or=20= change=20normal=0A-=09=09=20*=20snapshot=20processing=20so=20it=20= matches.=0A+=09=09=20*=20We're=20in=20hot=20standby,=20so=20get=20the=20= current=20CSN.=20That's=20used=20to=0A+=09=09=20*=20determine=20which=20= transactions=20committed=20before=20this=20snapshot.=0A=20=09=09=20*=0A=20= =09=09=20*=20Note:=20It=20is=20possible=20for=20recovery=20to=20end=20= before=20we=20finish=20taking=0A=20=09=09=20*=20the=20snapshot,=20and=20= for=20newly=20assigned=20transaction=20ids=20to=20be=20added=20to=0A@@=20= -2383,14=20+1949,17=20@@=20GetMVCCSnapshotData(void)=0A=20=09=09=20*=20= those=20newly=20added=20transaction=20ids=20would=20be=20filtered=20= away,=20so=20we=0A=20=09=09=20*=20need=20not=20be=20concerned=20about=20= them.=0A=20=09=09=20*/=0A-=09=09subcount=20=3D=20= KnownAssignedXidsGetAndSetXmin(snapshot->subxip,=20&xmin,=0A-=09=09=09=09= =09=09=09=09=09=09=09=09=20=20xmax);=0A+=09=09xmin=20=3D=20= procArray->oldest_running_primary_xid;=0A=20=0A-=09=09if=20= (TransactionIdPrecedesOrEquals(xmin,=20procArray->lastOverflowedXid))=0A= -=09=09=09suboverflowed=20=3D=20true;=0A+=09=09/*=0A+=09=09=20*=20Take=20= CSN=20under=20ProcArrayLock=20so=20the=20snapshot=20stays=20= synchronized.=0A+=09=09=20*=20(XXX:=20not=20sure=20that's=20strictly=20= required.)=20This=20is=20what=20determines=0A+=09=09=20*=20which=20= transactions=20we=20consider=20finished=20and=20which=20are=20still=20in=0A= +=09=09=20*=20progress.=0A+=09=09=20*/=0A+=09=09csn=20=3D=20= TransamVariables->latestCommitLSN;=0A=20=09}=0A=20=0A-=0A=20=09/*=0A=20=09= =20*=20Fetch=20into=20local=20variable=20while=20ProcArrayLock=20is=20= held=20-=20the=0A=20=09=20*=20LWLockRelease=20below=20is=20a=20barrier,=20= ensuring=20this=20happens=20inside=20the=0A@@=20-2507,6=20+2076,8=20@@=20= GetMVCCSnapshotData(void)=0A=20=09=09latestSnapshotShared=20=3D=20= snapshot;=0A=20=09}=0A=20=0A+=09snapshot->snapshotCsn=20=3D=20csn;=0A+=0A= =20=09return=20snapshot;=0A=20}=0A=20=0A@@=20-2662,9=20+2233,6=20@@=20= ProcArrayInstallRestoredXmin(TransactionId=20xmin,=20PGPROC=20*proc)=0A=20= =20*=20The=20returned=20data=20structure=20is=20statically=20allocated;=20= caller=20should=20not=0A=20=20*=20modify=20it,=20and=20must=20not=20= assume=20it=20is=20valid=20past=20the=20next=20call.=0A=20=20*=0A-=20*=20= This=20is=20never=20executed=20during=20recovery=20so=20there=20is=20no=20= need=20to=20look=20at=0A-=20*=20KnownAssignedXids.=0A-=20*=0A=20=20*=20= Dummy=20PGPROCs=20from=20prepared=20transaction=20are=20included,=20= meaning=20that=20this=0A=20=20*=20may=20return=20entries=20with=20= duplicated=20TransactionId=20values=20coming=20from=0A=20=20*=20= transaction=20finishing=20to=20prepare.=20=20Nothing=20is=20done=20about=20= duplicated=0A@@=20-2695,6=20+2263,7=20@@=20= GetRunningTransactionData(void)=0A=20=09int=09=09=09subcount;=0A=20=09= bool=09=09suboverflowed;=0A=20=0A+=09/*=20This=20is=20never=20executed=20= during=20recovery=20*/=0A=20=09Assert(!RecoveryInProgress());=0A=20=0A=20= =09/*=0A@@=20-2861,15=20+2430,16=20@@=20GetRunningTransactionData(void)=0A= =20=20*=20We=20look=20at=20all=20databases,=20though=20there=20is=20no=20= need=20to=20include=20WALSender=0A=20=20*=20since=20this=20has=20no=20= effect=20on=20hot=20standby=20conflicts.=0A=20=20*=0A-=20*=20This=20is=20= never=20executed=20during=20recovery=20so=20there=20is=20no=20need=20to=20= look=20at=0A-=20*=20KnownAssignedXids.=0A+=20*=20If=20allDbs=20is=20= false,=20skip=20processes=20attached=20to=20other=20databases.=0A+=20*=0A= +=20*=20This=20is=20never=20executed=20during=20recovery.=0A=20=20*=0A=20= =20*=20We=20don't=20worry=20about=20updating=20other=20counters,=20we=20= want=20to=20keep=20this=20as=0A=20=20*=20simple=20as=20possible=20and=20= leave=20GetMVCCSnapshotData()=20as=20the=20primary=20code=20for=0A=20=20= *=20that=20bookkeeping.=0A=20=20*/=0A=20TransactionId=0A= -GetOldestActiveTransactionId(void)=0A+GetOldestActiveTransactionId(bool=20= allDbs)=0A=20{=0A=20=09ProcArrayStruct=20*arrayP=20=3D=20procArray;=0A=20= =09TransactionId=20*other_xids=20=3D=20ProcGlobal->xids;=0A@@=20-2890,11=20= +2460,13=20@@=20GetOldestActiveTransactionId(void)=0A=20=09= LWLockRelease(XidGenLock);=0A=20=0A=20=09/*=0A-=09=20*=20Spin=20over=20= procArray=20collecting=20all=20xids=20and=20subxids.=0A+=09=20*=20Spin=20= over=20procArray=20checking=20each=20xid.=0A=20=09=20*/=0A=20=09= LWLockAcquire(ProcArrayLock,=20LW_SHARED);=0A=20=09for=20(index=20=3D=20= 0;=20index=20<=20arrayP->numProcs;=20index++)=0A=20=09{=0A+=09=09int=09=09= =09pgprocno=20=3D=20arrayP->pgprocnos[index];=0A+=09=09PGPROC=09=20=20=20= *proc=20=3D=20&allProcs[pgprocno];=0A=20=09=09TransactionId=20xid;=0A=20=0A= =20=09=09/*=20Fetch=20xid=20just=20once=20-=20see=20GetNewTransactionId=20= */=0A@@=20-2903,6=20+2475,9=20@@=20GetOldestActiveTransactionId(void)=0A=20= =09=09if=20(!TransactionIdIsNormal(xid))=0A=20=09=09=09continue;=0A=20=0A= +=09=09if=20(!allDbs=20&&=20proc->databaseId=20!=3D=20MyDatabaseId)=0A+=09= =09=09continue;=0A+=0A=20=09=09if=20(TransactionIdPrecedes(xid,=20= oldestRunningXid))=0A=20=09=09=09oldestRunningXid=20=3D=20xid;=0A=20=0A= @@=20-2981,8=20+2556,8=20@@=20GetOldestSafeDecodingTransactionId(bool=20= catalogOnly)=0A=20=09=20*=0A=20=09=20*=20In=20recovery=20we=20can't=20= lower=20the=20safe=20value=20besides=20what=20we've=20computed=0A=20=09=20= *=20above,=20so=20we'll=20have=20to=20wait=20a=20bit=20longer=20there.=20= We=20unfortunately=20can=0A-=09=20*=20*not*=20use=20= KnownAssignedXidsGetOldestXmin()=20since=20the=20KnownAssignedXids=0A-=09= =20*=20machinery=20can=20miss=20values=20and=20return=20an=20older=20= value=20than=20is=20safe.=0A+=09=20*=20*not*=20use=20= oldest_running_primary_xid=20since=20the=20XID=20tracking=20machinery=0A= +=09=20*=20can=20miss=20values=20and=20return=20an=20older=20value=20= than=20is=20safe.=0A=20=09=20*/=0A=20=09if=20(!recovery_in_progress)=0A=20= =09{=0A@@=20-3400,6=20+2975,9=20@@=20GetCurrentVirtualXIDs(TransactionId=20= limitXmin,=20bool=20excludeXmin0,=0A=20=20*=20but=20that=20would=20not=20= be=20true=20in=20the=20case=20of=20FATAL=20errors=20lagging=20in=20= array,=0A=20=20*=20but=20we=20already=20know=20those=20are=20bogus=20= anyway,=20so=20we=20skip=20that=20test.=0A=20=20*=0A+=20*=20XXX:=20= KnownAssignedXids=20is=20gone=20so=20the=20above=20comment=20needs=20= updating.=20Is=0A+=20*=20the=20code=20still=20correct?=20I=20think=20so=20= but=20need=20to=20double-check.=0A+=20*=0A=20=20*=20If=20dbOid=20is=20= valid=20we=20skip=20backends=20attached=20to=20other=20databases.=0A=20=20= *=0A=20=20*=20Be=20careful=20to=20*not*=20pfree=20the=20result=20from=20= this=20function.=20We=20reuse=0A@@=20-4071,14=20+3649,14=20@@=20static=20= void=0A=20DisplayXidCache(void)=0A=20{=0A=20=09fprintf(stderr,=0A-=09=09=09= "XidCache:=20xmin:=20%ld,=20known:=20%ld,=20myxact:=20%ld,=20latest:=20= %ld,=20mainxid:=20%ld,=20childxid:=20%ld,=20knownassigned:=20%ld,=20= nooflo:=20%ld,=20slow:=20%ld\n",=0A+=09=09=09"XidCache:=20xmin:=20%ld,=20= known:=20%ld,=20myxact:=20%ld,=20latest:=20%ld,=20mainxid:=20%ld,=20= childxid:=20%ld,=20during_recovery:=20%ld,=20nooflo:=20%ld,=20slow:=20= %ld\n",=0A=20=09=09=09xc_by_recent_xmin,=0A=20=09=09=09xc_by_known_xact,=0A= =20=09=09=09xc_by_my_xact,=0A=20=09=09=09xc_by_latest_xid,=0A=20=09=09=09= xc_by_main_xid,=0A=20=09=09=09xc_by_child_xid,=0A-=09=09=09= xc_by_known_assigned,=0A+=09=09=09xc_during_recovery,=0A=20=09=09=09= xc_no_overflow,=0A=20=09=09=09xc_slow_answer);=0A=20}=0A@@=20-4325,61=20= +3903,6=20@@=20FullXidRelativeTo(FullTransactionId=20rel,=20= TransactionId=20xid)=0A=20}=0A=20=0A=20=0A-/*=20= ----------------------------------------------=0A-=20*=09=09= KnownAssignedTransactionIds=20sub-module=0A-=20*=20= ----------------------------------------------=0A-=20*/=0A-=0A-/*=0A-=20= *=20In=20Hot=20Standby=20mode,=20we=20maintain=20a=20list=20of=20= transactions=20that=20are=20(or=20were)=0A-=20*=20running=20on=20the=20= primary=20at=20the=20current=20point=20in=20WAL.=20=20These=20XIDs=20= must=20be=0A-=20*=20treated=20as=20running=20by=20standby=20= transactions,=20even=20though=20they=20are=20not=20in=0A-=20*=20the=20= standby=20server's=20PGPROC=20array.=0A-=20*=0A-=20*=20We=20record=20all=20= XIDs=20that=20we=20know=20have=20been=20assigned.=20=20That=20includes=20= all=20the=0A-=20*=20XIDs=20seen=20in=20WAL=20records,=20plus=20all=20= unobserved=20XIDs=20that=20we=20can=20deduce=20have=0A-=20*=20been=20= assigned.=20=20We=20can=20deduce=20the=20existence=20of=20unobserved=20= XIDs=20because=20we=0A-=20*=20know=20XIDs=20are=20assigned=20in=20= sequence,=20with=20no=20gaps.=20=20The=20KnownAssignedXids=0A-=20*=20= list=20expands=20as=20new=20XIDs=20are=20observed=20or=20inferred,=20and=20= contracts=20when=0A-=20*=20transaction=20completion=20records=20arrive.=0A= -=20*=0A-=20*=20During=20hot=20standby=20we=20do=20not=20fret=20too=20= much=20about=20the=20distinction=20between=0A-=20*=20top-level=20XIDs=20= and=20subtransaction=20XIDs.=20We=20store=20both=20together=20in=20the=0A= -=20*=20KnownAssignedXids=20list.=20=20In=20backends,=20this=20is=20= copied=20into=20snapshots=20in=0A-=20*=20GetMVCCSnapshotData(),=20taking=20= advantage=20of=20the=20fact=20that=20XidInMVCCSnapshot()=0A-=20*=20= doesn't=20care=20about=20the=20distinction=20either.=20=20Subtransaction=20= XIDs=20are=0A-=20*=20effectively=20treated=20as=20top-level=20XIDs=20and=20= in=20the=20typical=20case=20pg_subtrans=0A-=20*=20links=20are=20*not*=20= maintained=20(which=20does=20not=20affect=20visibility).=0A-=20*=0A-=20*=20= We=20have=20room=20in=20KnownAssignedXids=20and=20in=20snapshots=20to=20= hold=20maxProcs=20*=0A-=20*=20(1=20+=20PGPROC_MAX_CACHED_SUBXIDS)=20= XIDs,=20so=20every=20primary=20transaction=20must=0A-=20*=20report=20its=20= subtransaction=20XIDs=20in=20a=20WAL=20XLOG_XACT_ASSIGNMENT=20record=20= at=0A-=20*=20least=20every=20PGPROC_MAX_CACHED_SUBXIDS.=20=20When=20we=20= receive=20one=20of=20these=0A-=20*=20records,=20we=20mark=20the=20= subXIDs=20as=20children=20of=20the=20top=20XID=20in=20pg_subtrans,=0A-=20= *=20and=20then=20remove=20them=20from=20KnownAssignedXids.=20=20This=20= prevents=20overflow=20of=0A-=20*=20KnownAssignedXids=20and=20snapshots,=20= at=20the=20cost=20that=20status=20checks=20for=20these=0A-=20*=20subXIDs=20= will=20take=20a=20slower=20path=20through=20TransactionIdIsInProgress().=0A= -=20*=20This=20means=20that=20KnownAssignedXids=20is=20not=20necessarily=20= complete=20for=20subXIDs,=0A-=20*=20though=20it=20should=20be=20complete=20= for=20top-level=20XIDs;=20this=20is=20the=20same=20situation=0A-=20*=20= that=20holds=20with=20respect=20to=20the=20PGPROC=20entries=20in=20= normal=20running.=0A-=20*=0A-=20*=20When=20we=20throw=20away=20subXIDs=20= from=20KnownAssignedXids,=20we=20need=20to=20keep=20track=20of=0A-=20*=20= that,=20similarly=20to=20tracking=20overflow=20of=20a=20PGPROC's=20= subxids=20array.=20=20We=20do=0A-=20*=20that=20by=20remembering=20the=20= lastOverflowedXid,=20ie=20the=20last=20thrown-away=20subXID.=0A-=20*=20= As=20long=20as=20that=20is=20within=20the=20range=20of=20interesting=20= XIDs,=20we=20have=20to=20assume=0A-=20*=20that=20subXIDs=20are=20missing=20= from=20snapshots.=20=20(Note=20that=20subXID=20overflow=20occurs=0A-=20*=20= on=20primary=20when=2065th=20subXID=20arrives,=20whereas=20on=20standby=20= it=20occurs=20when=2064th=0A-=20*=20subXID=20arrives=20-=20that=20is=20= not=20an=20error.)=0A-=20*=0A-=20*=20Should=20a=20backend=20on=20primary=20= somehow=20disappear=20before=20it=20can=20write=20an=20abort=0A-=20*=20= record,=20then=20we=20just=20leave=20those=20XIDs=20in=20= KnownAssignedXids.=20They=20actually=0A-=20*=20aborted=20but=20we=20= think=20they=20were=20running;=20the=20distinction=20is=20irrelevant=0A-=20= *=20because=20either=20way=20any=20changes=20done=20by=20the=20= transaction=20are=20not=20visible=20to=0A-=20*=20backends=20in=20the=20= standby.=20=20We=20prune=20KnownAssignedXids=20when=0A-=20*=20= XLOG_RUNNING_XACTS=20arrives,=20to=20forestall=20possible=20overflow=20= of=20the=0A-=20*=20array=20due=20to=20such=20dead=20XIDs.=0A-=20*/=0A-=0A= =20/*=0A=20=20*=20RecordKnownAssignedTransactionIds=0A=20=20*=09=09= Record=20the=20given=20XID=20in=20KnownAssignedXids,=20as=20well=20as=20= any=20preceding=0A@@=20-4394,7=20+3917,7=20@@=20= FullXidRelativeTo(FullTransactionId=20rel,=20TransactionId=20xid)=0A=20= void=0A=20RecordKnownAssignedTransactionIds(TransactionId=20xid)=0A=20{=0A= -=09Assert(standbyState=20>=3D=20STANDBY_INITIALIZED);=0A+=09= Assert(InHotStandby);=0A=20=09Assert(TransactionIdIsValid(xid));=0A=20=09= Assert(TransactionIdIsValid(latestObservedXid));=0A=20=0A@@=20-4412,38=20= +3935,19=20@@=20RecordKnownAssignedTransactionIds(TransactionId=20xid)=0A= =20=0A=20=09=09/*=0A=20=09=09=20*=20Extend=20subtrans=20like=20we=20do=20= in=20GetNewTransactionId()=20during=20normal=0A-=09=09=20*=20operation=20= using=20individual=20extend=20steps.=20Note=20that=20we=20do=20not=20= need=0A-=09=09=20*=20to=20extend=20clog=20since=20its=20extensions=20are=20= WAL=20logged.=0A-=09=09=20*=0A-=09=09=20*=20This=20part=20has=20to=20be=20= done=20regardless=20of=20standbyState=20since=20we=0A-=09=09=20*=20= immediately=20start=20assigning=20subtransactions=20to=20their=20= toplevel=0A-=09=09=20*=20transactions.=0A+=09=09=20*=20operation=20using=20= individual=20extend=20steps.=20And=20CSN=20log,=20too.=20Note=0A+=09=09=20= *=20that=20we=20do=20not=20need=20to=20extend=20clog=20since=20its=20= extensions=20are=20WAL=0A+=09=09=20*=20logged.=0A=20=09=09=20*/=0A=20=09=09= next_expected_xid=20=3D=20latestObservedXid;=0A=20=09=09while=20= (TransactionIdPrecedes(next_expected_xid,=20xid))=0A=20=09=09{=0A=20=09=09= =09TransactionIdAdvance(next_expected_xid);=0A=20=09=09=09= ExtendSUBTRANS(next_expected_xid);=0A+=09=09=09= ExtendCSNLog(next_expected_xid);=0A=20=09=09}=0A=20=09=09= Assert(next_expected_xid=20=3D=3D=20xid);=0A=20=0A-=09=09/*=0A-=09=09=20= *=20If=20the=20KnownAssignedXids=20machinery=20isn't=20up=20yet,=20= there's=20nothing=0A-=09=09=20*=20more=20to=20do=20since=20we=20don't=20= track=20assigned=20xids=20yet.=0A-=09=09=20*/=0A-=09=09if=20= (standbyState=20<=3D=20STANDBY_INITIALIZED)=0A-=09=09{=0A-=09=09=09= latestObservedXid=20=3D=20xid;=0A-=09=09=09return;=0A-=09=09}=0A-=0A-=09=09= /*=0A-=09=09=20*=20Add=20(latestObservedXid,=20xid]=20onto=20the=20= KnownAssignedXids=20array.=0A-=09=09=20*/=0A-=09=09next_expected_xid=20=3D= =20latestObservedXid;=0A-=09=09TransactionIdAdvance(next_expected_xid);=0A= -=09=09KnownAssignedXidsAdd(next_expected_xid,=20xid,=20false);=0A-=0A=20= =09=09/*=0A=20=09=09=20*=20Now=20we=20can=20advance=20latestObservedXid=0A= =20=09=09=20*/=0A@@=20-4455,805=20+3959,61=20@@=20= RecordKnownAssignedTransactionIds(TransactionId=20xid)=0A=20}=0A=20=0A=20= /*=0A-=20*=20ExpireTreeKnownAssignedTransactionIds=0A-=20*=09=09Remove=20= the=20given=20XIDs=20from=20KnownAssignedXids.=0A+=20*=20= ProcArrayRecoveryEndTransaction=0A+=20*=0A+=20*=20Called=20during=20= recovery=20in=20analogy=20with=20and=20in=20place=20of=0A+=20*=20= ProcArrayEndTransaction().=20The=20transaction=20becomes=20visible=20to=20= any=20new=0A+=20*=20snapshots=20taken=20after=20this.=20'max_xid'=20is=20= the=20highest=20(sub)XID=20of=20the=0A+=20*=20committed=20transaction,=20= and=20'lsn'=20is=20LSN=20of=20the=20commit=20record.=0A=20=20*=0A-=20*=20= Called=20during=20recovery=20in=20analogy=20with=20and=20in=20place=20of=20= ProcArrayEndTransaction()=0A+=20*=20The=20transaction=20and=20all=20its=20= subtransactions=20have=20been=20already=20marked=20as=0A+=20*=20= committed=20in=20the=20CLOG=20and=20in=20the=20CSNLOG.=0A=20=20*/=0A=20= void=0A-ExpireTreeKnownAssignedTransactionIds(TransactionId=20xid,=20int=20= nsubxids,=0A-=09=09=09=09=09=09=09=09=09=20=20TransactionId=20*subxids,=20= TransactionId=20max_xid)=0A= +ProcArrayRecoveryEndTransaction(TransactionId=20max_xid,=20XLogRecPtr=20= lsn)=0A=20{=0A-=09Assert(standbyState=20>=3D=20STANDBY_INITIALIZED);=0A+=09= TransactionId=20oldest_running_primary_xid;=0A+=0A+=09= Assert(InHotStandby);=0A+=0A+=09/*=0A+=09=20*=20If=20this=20was=20the=20= oldest=20XID=20that=20was=20still=20running,=20advance=20it.=20This=20is=0A= +=09=20*=20important=20for=20advancing=20the=20global=20xmin,=20which=20= avoids=20unnecessary=0A+=09=20*=20recovery=20conflicts=0A+=09=20*=0A+=09=20= *=20No=20locking=20required=20because=20this=20runs=20in=20the=20startup=20= process.=0A+=09=20*=0A+=09=20*=20XXX:=20the=20caller=20actually=20has=20= a=20list=20of=20XIDs=20that=20just=20committed.=20We=0A+=09=20*=20could=20= save=20some=20clog=20lookups=20by=20taking=20advantage=20of=20that=20= list.=0A+=09=20*/=0A+=09oldest_running_primary_xid=20=3D=20= procArray->oldest_running_primary_xid;=0A+=09while=20= (oldest_running_primary_xid=20<=20max_xid)=0A+=09{=0A+=09=09if=20= (!TransactionIdDidCommit(oldest_running_primary_xid)=20&&=0A+=09=09=09= !TransactionIdDidAbort(oldest_running_primary_xid))=0A+=09=09{=0A+=09=09=09= break;=0A+=09=09}=0A+=09=09= TransactionIdAdvance(oldest_running_primary_xid);=0A+=09}=0A+=09if=20= (max_xid=20=3D=3D=20oldest_running_primary_xid)=0A+=09=09= TransactionIdAdvance(oldest_running_primary_xid);=0A=20=0A=20=09/*=0A=20=09= =20*=20Uses=20same=20locking=20as=20transaction=20commit=0A=20=09=20*/=0A= =20=09LWLockAcquire(ProcArrayLock,=20LW_EXCLUSIVE);=0A=20=0A-=09= KnownAssignedXidsRemoveTree(xid,=20nsubxids,=20subxids);=0A-=0A=20=09/*=20= As=20in=20ProcArrayEndTransaction,=20advance=20latestCompletedXid=20*/=0A= =20=09MaintainLatestCompletedXidRecovery(max_xid);=0A=20=0A=20=09/*=20= ...=20and=20xactCompletionCount=20*/=0A=20=09= TransamVariables->xactCompletionCount++;=0A=20=0A-=09= LWLockRelease(ProcArrayLock);=0A-}=0A-=0A-/*=0A-=20*=20= ExpireAllKnownAssignedTransactionIds=0A-=20*=09=09Remove=20all=20entries=20= in=20KnownAssignedXids=20and=20reset=20lastOverflowedXid.=0A-=20*/=0A= -void=0A-ExpireAllKnownAssignedTransactionIds(void)=0A-{=0A-=09= FullTransactionId=20latestXid;=0A-=0A-=09LWLockAcquire(ProcArrayLock,=20= LW_EXCLUSIVE);=0A-=09= KnownAssignedXidsRemovePreceding(InvalidTransactionId);=0A-=0A-=09/*=20= Reset=20latestCompletedXid=20to=20nextXid=20-=201=20*/=0A-=09= Assert(FullTransactionIdIsValid(TransamVariables->nextXid));=0A-=09= latestXid=20=3D=20TransamVariables->nextXid;=0A-=09= FullTransactionIdRetreat(&latestXid);=0A-=09= TransamVariables->latestCompletedXid=20=3D=20latestXid;=0A-=0A-=09/*=0A-=09= =20*=20Any=20transactions=20that=20were=20in-progress=20were=20= effectively=20aborted,=20so=0A-=09=20*=20advance=20xactCompletionCount.=0A= -=09=20*/=0A-=09TransamVariables->xactCompletionCount++;=0A-=0A-=09/*=0A= -=09=20*=20Reset=20lastOverflowedXid.=20=20Currently,=20= lastOverflowedXid=20has=20no=20use=20after=0A-=09=20*=20the=20call=20of=20= this=20function.=20=20But=20do=20this=20for=20unification=20with=20what=0A= -=09=20*=20ExpireOldKnownAssignedTransactionIds()=20do.=0A-=09=20*/=0A-=09= procArray->lastOverflowedXid=20=3D=20InvalidTransactionId;=0A-=09= LWLockRelease(ProcArrayLock);=0A-}=0A-=0A-/*=0A-=20*=20= ExpireOldKnownAssignedTransactionIds=0A-=20*=09=09Remove=20= KnownAssignedXids=20entries=20preceding=20the=20given=20XID=20and=0A-=20= *=09=09potentially=20reset=20lastOverflowedXid.=0A-=20*/=0A-void=0A= -ExpireOldKnownAssignedTransactionIds(TransactionId=20xid)=0A-{=0A-=09= TransactionId=20latestXid;=0A-=0A-=09LWLockAcquire(ProcArrayLock,=20= LW_EXCLUSIVE);=0A-=0A-=09/*=20As=20in=20ProcArrayEndTransaction,=20= advance=20latestCompletedXid=20*/=0A-=09latestXid=20=3D=20xid;=0A-=09= TransactionIdRetreat(latestXid);=0A-=09= MaintainLatestCompletedXidRecovery(latestXid);=0A-=0A-=09/*=20...=20and=20= xactCompletionCount=20*/=0A-=09TransamVariables->xactCompletionCount++;=0A= -=0A-=09/*=0A-=09=20*=20Reset=20lastOverflowedXid=20if=20we=20know=20all=20= transactions=20that=20have=20been=0A-=09=20*=20possibly=20running=20are=20= being=20gone.=20=20Not=20doing=20so=20could=20cause=20an=20incorrect=0A-=09= =20*=20lastOverflowedXid=20value,=20which=20makes=20extra=20snapshots=20= be=20marked=20as=0A-=09=20*=20suboverflowed.=0A-=09=20*/=0A-=09if=20= (TransactionIdPrecedes(procArray->lastOverflowedXid,=20xid))=0A-=09=09= procArray->lastOverflowedXid=20=3D=20InvalidTransactionId;=0A-=09= KnownAssignedXidsRemovePreceding(xid);=0A-=09= LWLockRelease(ProcArrayLock);=0A-}=0A-=0A-/*=0A-=20*=20= KnownAssignedTransactionIdsIdleMaintenance=0A-=20*=09=09= Opportunistically=20do=20maintenance=20work=20when=20the=20startup=20= process=0A-=20*=09=09is=20about=20to=20go=20idle.=0A-=20*/=0A-void=0A= -KnownAssignedTransactionIdsIdleMaintenance(void)=0A-{=0A-=09= KnownAssignedXidsCompress(KAX_STARTUP_PROCESS_IDLE,=20false);=0A-}=0A-=0A= -=0A-/*=0A-=20*=20Private=20module=20functions=20to=20manipulate=20= KnownAssignedXids=0A-=20*=0A-=20*=20There=20are=205=20main=20uses=20of=20= the=20KnownAssignedXids=20data=20structure:=0A-=20*=0A-=20*=09*=20= backends=20taking=20snapshots=20-=20all=20valid=20XIDs=20need=20to=20be=20= copied=20out=0A-=20*=09*=20backends=20seeking=20to=20determine=20= presence=20of=20a=20specific=20XID=0A-=20*=09*=20startup=20process=20= adding=20new=20known-assigned=20XIDs=0A-=20*=09*=20startup=20process=20= removing=20specific=20XIDs=20as=20transactions=20end=0A-=20*=09*=20= startup=20process=20pruning=20array=20when=20special=20WAL=20records=20= arrive=0A-=20*=0A-=20*=20This=20data=20structure=20is=20known=20to=20be=20= a=20hot=20spot=20during=20Hot=20Standby,=20so=20we=0A-=20*=20go=20to=20= some=20lengths=20to=20make=20these=20operations=20as=20efficient=20and=20= as=20concurrent=0A-=20*=20as=20possible.=0A-=20*=0A-=20*=20The=20XIDs=20= are=20stored=20in=20an=20array=20in=20sorted=20order=20---=20= TransactionIdPrecedes=0A-=20*=20order,=20to=20be=20exact=20---=20to=20= allow=20binary=20search=20for=20specific=20XIDs.=20=20Note:=0A-=20*=20in=20= general=20TransactionIdPrecedes=20would=20not=20provide=20a=20total=20= order,=20but=0A-=20*=20we=20know=20that=20the=20entries=20present=20at=20= any=20instant=20should=20not=20extend=20across=0A-=20*=20a=20large=20= enough=20fraction=20of=20XID=20space=20to=20wrap=20around=20(the=20= primary=20would=0A-=20*=20shut=20down=20for=20fear=20of=20XID=20wrap=20= long=20before=20that=20happens).=20=20So=20it's=20OK=20to=0A-=20*=20use=20= TransactionIdPrecedes=20as=20a=20binary-search=20comparator.=0A-=20*=0A-=20= *=20It's=20cheap=20to=20maintain=20the=20sortedness=20during=20= insertions,=20since=20new=20known=0A-=20*=20XIDs=20are=20always=20= reported=20in=20XID=20order;=20we=20just=20append=20them=20at=20the=20= right.=0A-=20*=0A-=20*=20To=20keep=20individual=20deletions=20cheap,=20= we=20need=20to=20allow=20gaps=20in=20the=20array.=0A-=20*=20This=20is=20= implemented=20by=20marking=20array=20elements=20as=20valid=20or=20= invalid=20using=0A-=20*=20the=20parallel=20boolean=20array=20= KnownAssignedXidsValid[].=20=20A=20deletion=20is=20done=0A-=20*=20by=20= setting=20KnownAssignedXidsValid[i]=20to=20false,=20*without*=20clearing=20= the=0A-=20*=20XID=20entry=20itself.=20=20This=20preserves=20the=20= property=20that=20the=20XID=20entries=20are=0A-=20*=20sorted,=20so=20we=20= can=20do=20binary=20searches=20easily.=20=20Periodically=20we=20compress=0A= -=20*=20out=20the=20unused=20entries;=20that's=20much=20cheaper=20than=20= having=20to=20compress=20the=0A-=20*=20array=20immediately=20on=20every=20= deletion.=0A-=20*=0A-=20*=20The=20actually=20valid=20items=20in=20= KnownAssignedXids[]=20and=20KnownAssignedXidsValid[]=0A-=20*=20are=20= those=20with=20indexes=20tail=20<=3D=20i=20<=20head;=20items=20outside=20= this=20subscript=20range=0A-=20*=20have=20unspecified=20contents.=20=20= When=20head=20reaches=20the=20end=20of=20the=20array,=20we=0A-=20*=20= force=20compression=20of=20unused=20entries=20rather=20than=20wrapping=20= around,=20since=0A-=20*=20allowing=20wraparound=20would=20greatly=20= complicate=20the=20search=20logic.=20=20We=20maintain=0A-=20*=20an=20= explicit=20tail=20pointer=20so=20that=20pruning=20of=20old=20XIDs=20can=20= be=20done=20without=0A-=20*=20immediately=20moving=20the=20array=20= contents.=20=20In=20most=20cases=20only=20a=20small=20fraction=0A-=20*=20= of=20the=20array=20contains=20valid=20entries=20at=20any=20instant.=0A-=20= *=0A-=20*=20Although=20only=20the=20startup=20process=20can=20ever=20= change=20the=20KnownAssignedXids=0A-=20*=20data=20structure,=20we=20= still=20need=20interlocking=20so=20that=20standby=20backends=20will=0A-=20= *=20not=20observe=20invalid=20intermediate=20states.=20=20The=20= convention=20is=20that=20backends=0A-=20*=20must=20hold=20shared=20= ProcArrayLock=20to=20examine=20the=20array.=20=20To=20remove=20XIDs=20= from=0A-=20*=20the=20array,=20the=20startup=20process=20must=20hold=20= ProcArrayLock=20exclusively,=20for=0A-=20*=20the=20usual=20transactional=20= reasons=20(compare=20commit/abort=20of=20a=20transaction=0A-=20*=20= during=20normal=20running).=20=20Compressing=20unused=20entries=20out=20= of=20the=20array=0A-=20*=20likewise=20requires=20exclusive=20lock.=20=20= To=20add=20XIDs=20to=20the=20array,=20we=20just=20insert=0A-=20*=20them=20= into=20slots=20to=20the=20right=20of=20the=20head=20pointer=20and=20then=20= advance=20the=20head=0A-=20*=20pointer.=20=20This=20doesn't=20require=20= any=20lock=20at=20all,=20but=20on=20machines=20with=20weak=0A-=20*=20= memory=20ordering,=20we=20need=20to=20be=20careful=20that=20other=20= processors=20see=20the=20array=0A-=20*=20element=20changes=20before=20= they=20see=20the=20head=20pointer=20change.=20=20We=20handle=20this=20by=0A= -=20*=20using=20memory=20barriers=20when=20reading=20or=20writing=20the=20= head/tail=20pointers=20(unless=0A-=20*=20the=20caller=20holds=20= ProcArrayLock=20exclusively).=0A-=20*=0A-=20*=20Algorithmic=20analysis:=0A= -=20*=0A-=20*=20If=20we=20have=20a=20maximum=20of=20M=20slots,=20with=20= N=20XIDs=20currently=20spread=20across=0A-=20*=20S=20elements=20then=20= we=20have=20N=20<=3D=20S=20<=3D=20M=20always.=0A-=20*=0A-=20*=09*=20= Adding=20a=20new=20XID=20is=20O(1)=20and=20needs=20no=20lock=20(unless=20= compression=20must=0A-=20*=09=09happen)=0A-=20*=09*=20Compressing=20the=20= array=20is=20O(S)=20and=20requires=20exclusive=20lock=0A-=20*=09*=20= Removing=20an=20XID=20is=20O(logS)=20and=20requires=20exclusive=20lock=0A= -=20*=09*=20Taking=20a=20snapshot=20is=20O(S)=20and=20requires=20shared=20= lock=0A-=20*=09*=20Checking=20for=20an=20XID=20is=20O(logS)=20and=20= requires=20shared=20lock=0A-=20*=0A-=20*=20In=20comparison,=20using=20a=20= hash=20table=20for=20KnownAssignedXids=20would=20mean=20that=0A-=20*=20= taking=20snapshots=20would=20be=20O(M).=20If=20we=20can=20maintain=20S=20= <<=20M=20then=20the=0A-=20*=20sorted=20array=20technique=20will=20= deliver=20significantly=20faster=20snapshots.=0A-=20*=20If=20we=20try=20= to=20keep=20S=20too=20small=20then=20we=20will=20spend=20too=20much=20= time=20compressing,=0A-=20*=20so=20there=20is=20an=20optimal=20point=20= for=20any=20workload=20mix.=20We=20use=20a=20heuristic=20to=0A-=20*=20= decide=20when=20to=20compress=20the=20array,=20though=20trimming=20also=20= helps=20reduce=0A-=20*=20frequency=20of=20compressing.=20The=20heuristic=20= requires=20us=20to=20track=20the=20number=20of=0A-=20*=20currently=20= valid=20XIDs=20in=20the=20array=20(N).=20=20Except=20in=20special=20= cases,=20we'll=0A-=20*=20compress=20when=20S=20>=3D=202N.=20=20Bounding=20= S=20at=202N=20in=20turn=20bounds=20the=20time=20for=0A-=20*=20taking=20a=20= snapshot=20to=20be=20O(N),=20which=20it=20would=20have=20to=20be=20= anyway.=0A-=20*/=0A-=0A-=0A-/*=0A-=20*=20Compress=20KnownAssignedXids=20= by=20shifting=20valid=20data=20down=20to=20the=20start=20of=20the=0A-=20= *=20array,=20removing=20any=20gaps.=0A-=20*=0A-=20*=20A=20compression=20= step=20is=20forced=20if=20"reason"=20is=20KAX_NO_SPACE,=20otherwise=0A-=20= *=20we=20do=20it=20only=20if=20a=20heuristic=20indicates=20it's=20a=20= good=20time=20to=20do=20it.=0A-=20*=0A-=20*=20Compression=20requires=20= holding=20ProcArrayLock=20in=20exclusive=20mode.=0A-=20*=20Caller=20must=20= pass=20haveLock=20=3D=20true=20if=20it=20already=20holds=20the=20lock.=0A= -=20*/=0A-static=20void=0A-KnownAssignedXidsCompress(KAXCompressReason=20= reason,=20bool=20haveLock)=0A-{=0A-=09ProcArrayStruct=20*pArray=20=3D=20= procArray;=0A-=09int=09=09=09head,=0A-=09=09=09=09tail,=0A-=09=09=09=09= nelements;=0A-=09int=09=09=09compress_index;=0A-=09int=09=09=09i;=0A-=0A= -=09/*=20Counters=20for=20compression=20heuristics=20*/=0A-=09static=20= unsigned=20int=20transactionEndsCounter;=0A-=09static=20TimestampTz=20= lastCompressTs;=0A-=0A-=09/*=20Tuning=20constants=20*/=0A-#define=20= KAX_COMPRESS_FREQUENCY=20128=09/*=20in=20transactions=20*/=0A-#define=20= KAX_COMPRESS_IDLE_INTERVAL=201000=20/*=20in=20ms=20*/=0A-=0A-=09/*=0A-=09= =20*=20Since=20only=20the=20startup=20process=20modifies=20the=20= head/tail=20pointers,=20we=0A-=09=20*=20don't=20need=20a=20lock=20to=20= read=20them=20here.=0A-=09=20*/=0A-=09head=20=3D=20= pArray->headKnownAssignedXids;=0A-=09tail=20=3D=20= pArray->tailKnownAssignedXids;=0A-=09nelements=20=3D=20head=20-=20tail;=0A= -=0A-=09/*=0A-=09=20*=20If=20we=20can=20choose=20whether=20to=20= compress,=20use=20a=20heuristic=20to=20avoid=0A-=09=20*=20compressing=20= too=20often=20or=20not=20often=20enough.=20=20"Compress"=20here=20simply=0A= -=09=20*=20means=20moving=20the=20values=20to=20the=20beginning=20of=20= the=20array,=20so=20it=20is=20not=20as=0A-=09=20*=20complex=20or=20= costly=20as=20typical=20data=20compression=20algorithms.=0A-=09=20*/=0A-=09= if=20(nelements=20=3D=3D=20pArray->numKnownAssignedXids)=0A-=09{=0A-=09=09= /*=0A-=09=09=20*=20When=20there=20are=20no=20gaps=20between=20head=20and=20= tail,=20don't=20bother=20to=0A-=09=09=20*=20compress,=20except=20in=20= the=20KAX_NO_SPACE=20case=20where=20we=20must=20compress=20to=0A-=09=09=20= *=20create=20some=20space=20after=20the=20head.=0A-=09=09=20*/=0A-=09=09= if=20(reason=20!=3D=20KAX_NO_SPACE)=0A-=09=09=09return;=0A-=09}=0A-=09= else=20if=20(reason=20=3D=3D=20KAX_TRANSACTION_END)=0A-=09{=0A-=09=09/*=0A= -=09=09=20*=20Consider=20compressing=20only=20once=20every=20so=20many=20= commits.=20=20Frequency=0A-=09=09=20*=20determined=20by=20benchmarks.=0A= -=09=09=20*/=0A-=09=09if=20((transactionEndsCounter++)=20%=20= KAX_COMPRESS_FREQUENCY=20!=3D=200)=0A-=09=09=09return;=0A-=0A-=09=09/*=0A= -=09=09=20*=20Furthermore,=20compress=20only=20if=20the=20used=20part=20= of=20the=20array=20is=20less=0A-=09=09=20*=20than=2050%=20full=20(see=20= comments=20above).=0A-=09=09=20*/=0A-=09=09if=20(nelements=20<=202=20*=20= pArray->numKnownAssignedXids)=0A-=09=09=09return;=0A-=09}=0A-=09else=20= if=20(reason=20=3D=3D=20KAX_STARTUP_PROCESS_IDLE)=0A-=09{=0A-=09=09/*=0A= -=09=09=20*=20We're=20about=20to=20go=20idle=20for=20lack=20of=20new=20= WAL,=20so=20we=20might=20as=20well=0A-=09=09=20*=20compress.=20=20But=20= not=20too=20often,=20to=20avoid=20ProcArray=20lock=20contention=0A-=09=09= =20*=20with=20readers.=0A-=09=09=20*/=0A-=09=09if=20(lastCompressTs=20!=3D= =200)=0A-=09=09{=0A-=09=09=09TimestampTz=20compress_after;=0A-=0A-=09=09=09= compress_after=20=3D=20TimestampTzPlusMilliseconds(lastCompressTs,=0A-=09= =09=09=09=09=09=09=09=09=09=09=09=09=09=20KAX_COMPRESS_IDLE_INTERVAL);=0A= -=09=09=09if=20(GetCurrentTimestamp()=20<=20compress_after)=0A-=09=09=09=09= return;=0A-=09=09}=0A-=09}=0A-=0A-=09/*=20Need=20to=20compress,=20so=20= get=20the=20lock=20if=20we=20don't=20have=20it.=20*/=0A-=09if=20= (!haveLock)=0A-=09=09LWLockAcquire(ProcArrayLock,=20LW_EXCLUSIVE);=0A-=0A= -=09/*=0A-=09=20*=20We=20compress=20the=20array=20by=20reading=20the=20= valid=20values=20from=20tail=20to=20head,=0A-=09=20*=20re-aligning=20= data=20to=200th=20element.=0A-=09=20*/=0A-=09compress_index=20=3D=200;=0A= -=09for=20(i=20=3D=20tail;=20i=20<=20head;=20i++)=0A-=09{=0A-=09=09if=20= (KnownAssignedXidsValid[i])=0A-=09=09{=0A-=09=09=09= KnownAssignedXids[compress_index]=20=3D=20KnownAssignedXids[i];=0A-=09=09= =09KnownAssignedXidsValid[compress_index]=20=3D=20true;=0A-=09=09=09= compress_index++;=0A-=09=09}=0A-=09}=0A-=09Assert(compress_index=20=3D=3D=20= pArray->numKnownAssignedXids);=0A-=0A-=09pArray->tailKnownAssignedXids=20= =3D=200;=0A-=09pArray->headKnownAssignedXids=20=3D=20compress_index;=0A-=0A= -=09if=20(!haveLock)=0A-=09=09LWLockRelease(ProcArrayLock);=0A-=0A-=09/*=20= Update=20timestamp=20for=20maintenance.=20=20No=20need=20to=20hold=20= lock=20for=20this.=20*/=0A-=09lastCompressTs=20=3D=20= GetCurrentTimestamp();=0A-}=0A-=0A-/*=0A-=20*=20Add=20xids=20into=20= KnownAssignedXids=20at=20the=20head=20of=20the=20array.=0A-=20*=0A-=20*=20= xids=20from=20from_xid=20to=20to_xid,=20inclusive,=20are=20added=20to=20= the=20array.=0A-=20*=0A-=20*=20If=20exclusive_lock=20is=20true=20then=20= caller=20already=20holds=20ProcArrayLock=20in=0A-=20*=20exclusive=20= mode,=20so=20we=20need=20no=20extra=20locking=20here.=20=20Else=20caller=20= holds=20no=0A-=20*=20lock,=20so=20we=20need=20to=20be=20sure=20we=20= maintain=20sufficient=20interlocks=20against=0A-=20*=20concurrent=20= readers.=20=20(Only=20the=20startup=20process=20ever=20calls=20this,=20= so=20no=20need=0A-=20*=20to=20worry=20about=20concurrent=20writers.)=0A-=20= */=0A-static=20void=0A-KnownAssignedXidsAdd(TransactionId=20from_xid,=20= TransactionId=20to_xid,=0A-=09=09=09=09=09=20bool=20exclusive_lock)=0A-{=0A= -=09ProcArrayStruct=20*pArray=20=3D=20procArray;=0A-=09TransactionId=20= next_xid;=0A-=09int=09=09=09head,=0A-=09=09=09=09tail;=0A-=09int=09=09=09= nxids;=0A-=09int=09=09=09i;=0A-=0A-=09= Assert(TransactionIdPrecedesOrEquals(from_xid,=20to_xid));=0A-=0A-=09/*=0A= -=09=20*=20Calculate=20how=20many=20array=20slots=20we'll=20need.=20=20= Normally=20this=20is=20cheap;=20in=0A-=09=20*=20the=20unusual=20case=20= where=20the=20XIDs=20cross=20the=20wrap=20point,=20we=20do=20it=20the=20= hard=0A-=09=20*=20way.=0A-=09=20*/=0A-=09if=20(to_xid=20>=3D=20from_xid)=0A= -=09=09nxids=20=3D=20to_xid=20-=20from_xid=20+=201;=0A-=09else=0A-=09{=0A= -=09=09nxids=20=3D=201;=0A-=09=09next_xid=20=3D=20from_xid;=0A-=09=09= while=20(TransactionIdPrecedes(next_xid,=20to_xid))=0A-=09=09{=0A-=09=09=09= nxids++;=0A-=09=09=09TransactionIdAdvance(next_xid);=0A-=09=09}=0A-=09}=0A= -=0A-=09/*=0A-=09=20*=20Since=20only=20the=20startup=20process=20= modifies=20the=20head/tail=20pointers,=20we=0A-=09=20*=20don't=20need=20= a=20lock=20to=20read=20them=20here.=0A-=09=20*/=0A-=09head=20=3D=20= pArray->headKnownAssignedXids;=0A-=09tail=20=3D=20= pArray->tailKnownAssignedXids;=0A-=0A-=09Assert(head=20>=3D=200=20&&=20= head=20<=3D=20pArray->maxKnownAssignedXids);=0A-=09Assert(tail=20>=3D=20= 0=20&&=20tail=20<=20pArray->maxKnownAssignedXids);=0A-=0A-=09/*=0A-=09=20= *=20Verify=20that=20insertions=20occur=20in=20TransactionId=20sequence.=20= =20Note=20that=20even=0A-=09=20*=20if=20the=20last=20existing=20element=20= is=20marked=20invalid,=20it=20must=20still=20have=20a=0A-=09=20*=20= correctly=20sequenced=20XID=20value.=0A-=09=20*/=0A-=09if=20(head=20>=20= tail=20&&=0A-=09=09TransactionIdFollowsOrEquals(KnownAssignedXids[head=20= -=201],=20from_xid))=0A-=09{=0A-=09=09KnownAssignedXidsDisplay(LOG);=0A-=09= =09elog(ERROR,=20"out-of-order=20XID=20insertion=20in=20= KnownAssignedXids");=0A-=09}=0A-=0A-=09/*=0A-=09=20*=20If=20our=20xids=20= won't=20fit=20in=20the=20remaining=20space,=20compress=20out=20free=20= space=0A-=09=20*/=0A-=09if=20(head=20+=20nxids=20>=20= pArray->maxKnownAssignedXids)=0A-=09{=0A-=09=09= KnownAssignedXidsCompress(KAX_NO_SPACE,=20exclusive_lock);=0A-=0A-=09=09= head=20=3D=20pArray->headKnownAssignedXids;=0A-=09=09/*=20note:=20we=20= no=20longer=20care=20about=20the=20tail=20pointer=20*/=0A-=0A-=09=09/*=0A= -=09=09=20*=20If=20it=20still=20won't=20fit=20then=20we're=20out=20of=20= memory=0A-=09=09=20*/=0A-=09=09if=20(head=20+=20nxids=20>=20= pArray->maxKnownAssignedXids)=0A-=09=09=09elog(ERROR,=20"too=20many=20= KnownAssignedXids");=0A-=09}=0A-=0A-=09/*=20Now=20we=20can=20insert=20= the=20xids=20into=20the=20space=20starting=20at=20head=20*/=0A-=09= next_xid=20=3D=20from_xid;=0A-=09for=20(i=20=3D=200;=20i=20<=20nxids;=20= i++)=0A-=09{=0A-=09=09KnownAssignedXids[head]=20=3D=20next_xid;=0A-=09=09= KnownAssignedXidsValid[head]=20=3D=20true;=0A-=09=09= TransactionIdAdvance(next_xid);=0A-=09=09head++;=0A-=09}=0A-=0A-=09/*=20= Adjust=20count=20of=20number=20of=20valid=20entries=20*/=0A-=09= pArray->numKnownAssignedXids=20+=3D=20nxids;=0A-=0A-=09/*=0A-=09=20*=20= Now=20update=20the=20head=20pointer.=20=20We=20use=20a=20write=20barrier=20= to=20ensure=20that=0A-=09=20*=20other=20processors=20see=20the=20above=20= array=20updates=20before=20they=20see=20the=20head=0A-=09=20*=20pointer=20= change.=20=20The=20barrier=20isn't=20required=20if=20we're=20holding=0A-=09= =20*=20ProcArrayLock=20exclusively.=0A-=09=20*/=0A-=09if=20= (!exclusive_lock)=0A-=09=09pg_write_barrier();=0A-=0A-=09= pArray->headKnownAssignedXids=20=3D=20head;=0A-}=0A-=0A-/*=0A-=20*=20= KnownAssignedXidsSearch=0A-=20*=0A-=20*=20Searches=20KnownAssignedXids=20= for=20a=20specific=20xid=20and=20optionally=20removes=20it.=0A-=20*=20= Returns=20true=20if=20it=20was=20found,=20false=20if=20not.=0A-=20*=0A-=20= *=20Caller=20must=20hold=20ProcArrayLock=20in=20shared=20or=20exclusive=20= mode.=0A-=20*=20Exclusive=20lock=20must=20be=20held=20for=20remove=20=3D=20= true.=0A-=20*/=0A-static=20bool=0A-KnownAssignedXidsSearch(TransactionId=20= xid,=20bool=20remove)=0A-{=0A-=09ProcArrayStruct=20*pArray=20=3D=20= procArray;=0A-=09int=09=09=09first,=0A-=09=09=09=09last;=0A-=09int=09=09=09= head;=0A-=09int=09=09=09tail;=0A-=09int=09=09=09result_index=20=3D=20-1;=0A= -=0A-=09tail=20=3D=20pArray->tailKnownAssignedXids;=0A-=09head=20=3D=20= pArray->headKnownAssignedXids;=0A-=0A-=09/*=0A-=09=20*=20Only=20the=20= startup=20process=20removes=20entries,=20so=20we=20don't=20need=20the=20= read=0A-=09=20*=20barrier=20in=20that=20case.=0A-=09=20*/=0A-=09if=20= (!remove)=0A-=09=09pg_read_barrier();=09=09/*=20pairs=20with=20= KnownAssignedXidsAdd=20*/=0A-=0A-=09/*=0A-=09=20*=20Standard=20binary=20= search.=20=20Note=20we=20can=20ignore=20the=20KnownAssignedXidsValid=0A-=09= =20*=20array=20here,=20since=20even=20invalid=20entries=20will=20contain=20= sorted=20XIDs.=0A-=09=20*/=0A-=09first=20=3D=20tail;=0A-=09last=20=3D=20= head=20-=201;=0A-=09while=20(first=20<=3D=20last)=0A-=09{=0A-=09=09int=09= =09=09mid_index;=0A-=09=09TransactionId=20mid_xid;=0A-=0A-=09=09= mid_index=20=3D=20(first=20+=20last)=20/=202;=0A-=09=09mid_xid=20=3D=20= KnownAssignedXids[mid_index];=0A-=0A-=09=09if=20(xid=20=3D=3D=20mid_xid)=0A= -=09=09{=0A-=09=09=09result_index=20=3D=20mid_index;=0A-=09=09=09break;=0A= -=09=09}=0A-=09=09else=20if=20(TransactionIdPrecedes(xid,=20mid_xid))=0A= -=09=09=09last=20=3D=20mid_index=20-=201;=0A-=09=09else=0A-=09=09=09= first=20=3D=20mid_index=20+=201;=0A-=09}=0A-=0A-=09if=20(result_index=20= <=200)=0A-=09=09return=20false;=09=09=09/*=20not=20in=20array=20*/=0A-=0A= -=09if=20(!KnownAssignedXidsValid[result_index])=0A-=09=09return=20= false;=09=09=09/*=20in=20array,=20but=20invalid=20*/=0A-=0A-=09if=20= (remove)=0A-=09{=0A-=09=09KnownAssignedXidsValid[result_index]=20=3D=20= false;=0A-=0A-=09=09pArray->numKnownAssignedXids--;=0A-=09=09= Assert(pArray->numKnownAssignedXids=20>=3D=200);=0A-=0A-=09=09/*=0A-=09=09= =20*=20If=20we're=20removing=20the=20tail=20element=20then=20advance=20= tail=20pointer=20over=0A-=09=09=20*=20any=20invalid=20elements.=20=20= This=20will=20speed=20future=20searches.=0A-=09=09=20*/=0A-=09=09if=20= (result_index=20=3D=3D=20tail)=0A-=09=09{=0A-=09=09=09tail++;=0A-=09=09=09= while=20(tail=20<=20head=20&&=20!KnownAssignedXidsValid[tail])=0A-=09=09=09= =09tail++;=0A-=09=09=09if=20(tail=20>=3D=20head)=0A-=09=09=09{=0A-=09=09=09= =09/*=20Array=20is=20empty,=20so=20we=20can=20reset=20both=20pointers=20= */=0A-=09=09=09=09pArray->headKnownAssignedXids=20=3D=200;=0A-=09=09=09=09= pArray->tailKnownAssignedXids=20=3D=200;=0A-=09=09=09}=0A-=09=09=09else=0A= -=09=09=09{=0A-=09=09=09=09pArray->tailKnownAssignedXids=20=3D=20tail;=0A= -=09=09=09}=0A-=09=09}=0A-=09}=0A-=0A-=09return=20true;=0A-}=0A-=0A-/*=0A= -=20*=20Is=20the=20specified=20XID=20present=20in=20KnownAssignedXids[]?=0A= -=20*=0A-=20*=20Caller=20must=20hold=20ProcArrayLock=20in=20shared=20or=20= exclusive=20mode.=0A-=20*/=0A-static=20bool=0A= -KnownAssignedXidExists(TransactionId=20xid)=0A-{=0A-=09= Assert(TransactionIdIsValid(xid));=0A-=0A-=09return=20= KnownAssignedXidsSearch(xid,=20false);=0A-}=0A-=0A-/*=0A-=20*=20Remove=20= the=20specified=20XID=20from=20KnownAssignedXids[].=0A-=20*=0A-=20*=20= Caller=20must=20hold=20ProcArrayLock=20in=20exclusive=20mode.=0A-=20*/=0A= -static=20void=0A-KnownAssignedXidsRemove(TransactionId=20xid)=0A-{=0A-=09= Assert(TransactionIdIsValid(xid));=0A-=0A-=09elog(DEBUG4,=20"remove=20= KnownAssignedXid=20%u",=20xid);=0A-=0A-=09/*=0A-=09=20*=20Note:=20we=20= cannot=20consider=20it=20an=20error=20to=20remove=20an=20XID=20that's=20= not=0A-=09=20*=20present.=20=20We=20intentionally=20remove=20subxact=20= IDs=20while=20processing=0A-=09=20*=20XLOG_XACT_ASSIGNMENT,=20to=20avoid=20= array=20overflow.=20=20Then=20those=20XIDs=20will=20be=0A-=09=20*=20= removed=20again=20when=20the=20top-level=20xact=20commits=20or=20aborts.=0A= -=09=20*=0A-=09=20*=20It=20might=20be=20possible=20to=20track=20such=20= XIDs=20to=20distinguish=20this=20case=20from=0A-=09=20*=20actual=20= errors,=20but=20it=20would=20be=20complicated=20and=20probably=20not=20= worth=20it.=0A-=09=20*=20So,=20just=20ignore=20the=20search=20result.=0A= -=09=20*/=0A-=09(void)=20KnownAssignedXidsSearch(xid,=20true);=0A-}=0A-=0A= -/*=0A-=20*=20KnownAssignedXidsRemoveTree=0A-=20*=09=09Remove=20xid=20= (if=20it's=20not=20InvalidTransactionId)=20and=20all=20the=20subxids.=0A= -=20*=0A-=20*=20Caller=20must=20hold=20ProcArrayLock=20in=20exclusive=20= mode.=0A-=20*/=0A-static=20void=0A= -KnownAssignedXidsRemoveTree(TransactionId=20xid,=20int=20nsubxids,=0A-=09= =09=09=09=09=09=09TransactionId=20*subxids)=0A-{=0A-=09int=09=09=09i;=0A= -=0A-=09if=20(TransactionIdIsValid(xid))=0A-=09=09= KnownAssignedXidsRemove(xid);=0A-=0A-=09for=20(i=20=3D=200;=20i=20<=20= nsubxids;=20i++)=0A-=09=09KnownAssignedXidsRemove(subxids[i]);=0A-=0A-=09= /*=20Opportunistically=20compress=20the=20array=20*/=0A-=09= KnownAssignedXidsCompress(KAX_TRANSACTION_END,=20true);=0A-}=0A-=0A-/*=0A= -=20*=20Prune=20KnownAssignedXids=20up=20to,=20but=20*not*=20including=20= xid.=20If=20xid=20is=20invalid=0A-=20*=20then=20clear=20the=20whole=20= table.=0A-=20*=0A-=20*=20Caller=20must=20hold=20ProcArrayLock=20in=20= exclusive=20mode.=0A-=20*/=0A-static=20void=0A= -KnownAssignedXidsRemovePreceding(TransactionId=20removeXid)=0A-{=0A-=09= ProcArrayStruct=20*pArray=20=3D=20procArray;=0A-=09int=09=09=09count=20=3D= =200;=0A-=09int=09=09=09head,=0A-=09=09=09=09tail,=0A-=09=09=09=09i;=0A-=0A= -=09if=20(!TransactionIdIsValid(removeXid))=0A-=09{=0A-=09=09= elog(DEBUG4,=20"removing=20all=20KnownAssignedXids");=0A-=09=09= pArray->numKnownAssignedXids=20=3D=200;=0A-=09=09= pArray->headKnownAssignedXids=20=3D=20pArray->tailKnownAssignedXids=20=3D=20= 0;=0A-=09=09return;=0A-=09}=0A-=0A-=09elog(DEBUG4,=20"prune=20= KnownAssignedXids=20to=20%u",=20removeXid);=0A-=0A-=09/*=0A-=09=20*=20= Mark=20entries=20invalid=20starting=20at=20the=20tail.=20=20Since=20= array=20is=20sorted,=20we=0A-=09=20*=20can=20stop=20as=20soon=20as=20we=20= reach=20an=20entry=20>=3D=20removeXid.=0A-=09=20*/=0A-=09tail=20=3D=20= pArray->tailKnownAssignedXids;=0A-=09head=20=3D=20= pArray->headKnownAssignedXids;=0A-=0A-=09for=20(i=20=3D=20tail;=20i=20<=20= head;=20i++)=0A-=09{=0A-=09=09if=20(KnownAssignedXidsValid[i])=0A-=09=09= {=0A-=09=09=09TransactionId=20knownXid=20=3D=20KnownAssignedXids[i];=0A-=0A= -=09=09=09if=20(TransactionIdFollowsOrEquals(knownXid,=20removeXid))=0A-=09= =09=09=09break;=0A-=0A-=09=09=09if=20= (!StandbyTransactionIdIsPrepared(knownXid))=0A-=09=09=09{=0A-=09=09=09=09= KnownAssignedXidsValid[i]=20=3D=20false;=0A-=09=09=09=09count++;=0A-=09=09= =09}=0A-=09=09}=0A-=09}=0A-=0A-=09pArray->numKnownAssignedXids=20-=3D=20= count;=0A-=09Assert(pArray->numKnownAssignedXids=20>=3D=200);=0A-=0A-=09= /*=0A-=09=20*=20Advance=20the=20tail=20pointer=20if=20we've=20marked=20= the=20tail=20item=20invalid.=0A-=09=20*/=0A-=09for=20(i=20=3D=20tail;=20= i=20<=20head;=20i++)=0A-=09{=0A-=09=09if=20(KnownAssignedXidsValid[i])=0A= -=09=09=09break;=0A-=09}=0A-=09if=20(i=20>=3D=20head)=0A-=09{=0A-=09=09= /*=20Array=20is=20empty,=20so=20we=20can=20reset=20both=20pointers=20*/=0A= -=09=09pArray->headKnownAssignedXids=20=3D=200;=0A-=09=09= pArray->tailKnownAssignedXids=20=3D=200;=0A-=09}=0A-=09else=0A-=09{=0A-=09= =09pArray->tailKnownAssignedXids=20=3D=20i;=0A-=09}=0A-=0A-=09/*=20= Opportunistically=20compress=20the=20array=20*/=0A-=09= KnownAssignedXidsCompress(KAX_PRUNE,=20true);=0A-}=0A-=0A-/*=0A-=20*=20= KnownAssignedXidsGet=20-=20Get=20an=20array=20of=20xids=20by=20scanning=20= KnownAssignedXids.=0A-=20*=20We=20filter=20out=20anything=20>=3D=20xmax.=0A= -=20*=0A-=20*=20Returns=20the=20number=20of=20XIDs=20stored=20into=20= xarray[].=20=20Caller=20is=20responsible=0A-=20*=20that=20array=20is=20= large=20enough.=0A-=20*=0A-=20*=20Caller=20must=20hold=20ProcArrayLock=20= in=20(at=20least)=20shared=20mode.=0A-=20*/=0A-static=20int=0A= -KnownAssignedXidsGet(TransactionId=20*xarray,=20TransactionId=20xmax)=0A= -{=0A-=09TransactionId=20xtmp=20=3D=20InvalidTransactionId;=0A-=0A-=09= return=20KnownAssignedXidsGetAndSetXmin(xarray,=20&xtmp,=20xmax);=0A-}=0A= -=0A-/*=0A-=20*=20KnownAssignedXidsGetAndSetXmin=20-=20as=20= KnownAssignedXidsGet,=20plus=0A-=20*=20we=20reduce=20*xmin=20to=20the=20= lowest=20xid=20value=20seen=20if=20not=20already=20lower.=0A-=20*=0A-=20= *=20Caller=20must=20hold=20ProcArrayLock=20in=20(at=20least)=20shared=20= mode.=0A-=20*/=0A-static=20int=0A= -KnownAssignedXidsGetAndSetXmin(TransactionId=20*xarray,=20TransactionId=20= *xmin,=0A-=09=09=09=09=09=09=09=20=20=20TransactionId=20xmax)=0A-{=0A-=09= int=09=09=09count=20=3D=200;=0A-=09int=09=09=09head,=0A-=09=09=09=09= tail;=0A-=09int=09=09=09i;=0A-=0A-=09/*=0A-=09=20*=20Fetch=20head=20just=20= once,=20since=20it=20may=20change=20while=20we=20loop.=20We=20can=20stop=0A= -=09=20*=20once=20we=20reach=20the=20initially=20seen=20head,=20since=20= we=20are=20certain=20that=20an=20xid=0A-=09=20*=20cannot=20enter=20and=20= then=20leave=20the=20array=20while=20we=20hold=20ProcArrayLock.=20=20We=0A= -=09=20*=20might=20miss=20newly-added=20xids,=20but=20they=20should=20be=20= >=3D=20xmax=20so=20irrelevant=0A-=09=20*=20anyway.=0A-=09=20*/=0A-=09= tail=20=3D=20procArray->tailKnownAssignedXids;=0A-=09head=20=3D=20= procArray->headKnownAssignedXids;=0A-=0A-=09pg_read_barrier();=09=09=09= /*=20pairs=20with=20KnownAssignedXidsAdd=20*/=0A-=0A-=09for=20(i=20=3D=20= tail;=20i=20<=20head;=20i++)=0A-=09{=0A-=09=09/*=20Skip=20any=20gaps=20= in=20the=20array=20*/=0A-=09=09if=20(KnownAssignedXidsValid[i])=0A-=09=09= {=0A-=09=09=09TransactionId=20knownXid=20=3D=20KnownAssignedXids[i];=0A-=0A= -=09=09=09/*=0A-=09=09=09=20*=20Update=20xmin=20if=20required.=20=20Only=20= the=20first=20XID=20need=20be=20checked,=0A-=09=09=09=20*=20since=20the=20= array=20is=20sorted.=0A-=09=09=09=20*/=0A-=09=09=09if=20(count=20=3D=3D=20= 0=20&&=0A-=09=09=09=09TransactionIdPrecedes(knownXid,=20*xmin))=0A-=09=09= =09=09*xmin=20=3D=20knownXid;=0A-=0A-=09=09=09/*=0A-=09=09=09=20*=20= Filter=20out=20anything=20>=3D=20xmax,=20again=20relying=20on=20sorted=20= property=0A-=09=09=09=20*=20of=20array.=0A-=09=09=09=20*/=0A-=09=09=09if=20= (TransactionIdIsValid(xmax)=20&&=0A-=09=09=09=09= TransactionIdFollowsOrEquals(knownXid,=20xmax))=0A-=09=09=09=09break;=0A= -=0A-=09=09=09/*=20Add=20knownXid=20into=20output=20array=20*/=0A-=09=09=09= xarray[count++]=20=3D=20knownXid;=0A-=09=09}=0A-=09}=0A-=0A-=09return=20= count;=0A-}=0A-=0A-/*=0A-=20*=20Get=20oldest=20XID=20in=20the=20= KnownAssignedXids=20array,=20or=20InvalidTransactionId=0A-=20*=20if=20= nothing=20there.=0A-=20*/=0A-static=20TransactionId=0A= -KnownAssignedXidsGetOldestXmin(void)=0A-{=0A-=09int=09=09=09head,=0A-=09= =09=09=09tail;=0A-=09int=09=09=09i;=0A-=0A-=09/*=0A-=09=20*=20Fetch=20= head=20just=20once,=20since=20it=20may=20change=20while=20we=20loop.=0A-=09= =20*/=0A-=09tail=20=3D=20procArray->tailKnownAssignedXids;=0A-=09head=20= =3D=20procArray->headKnownAssignedXids;=0A-=0A-=09pg_read_barrier();=09=09= =09/*=20pairs=20with=20KnownAssignedXidsAdd=20*/=0A-=0A-=09for=20(i=20=3D=20= tail;=20i=20<=20head;=20i++)=0A-=09{=0A-=09=09/*=20Skip=20any=20gaps=20= in=20the=20array=20*/=0A-=09=09if=20(KnownAssignedXidsValid[i])=0A-=09=09= =09return=20KnownAssignedXids[i];=0A-=09}=0A-=0A-=09return=20= InvalidTransactionId;=0A-}=0A-=0A-/*=0A-=20*=20Display=20= KnownAssignedXids=20to=20provide=20debug=20trail=0A-=20*=0A-=20*=20= Currently=20this=20is=20only=20called=20within=20startup=20process,=20so=20= we=20need=20no=0A-=20*=20special=20locking.=0A-=20*=0A-=20*=20Note=20= this=20is=20pretty=20expensive,=20and=20much=20of=20the=20expense=20will=20= be=20incurred=0A-=20*=20even=20if=20the=20elog=20message=20will=20get=20= discarded.=20=20It's=20not=20currently=20called=0A-=20*=20in=20any=20= performance-critical=20places,=20however,=20so=20no=20need=20to=20be=20= tenser.=0A-=20*/=0A-static=20void=0A-KnownAssignedXidsDisplay(int=20= trace_level)=0A-{=0A-=09ProcArrayStruct=20*pArray=20=3D=20procArray;=0A-=09= StringInfoData=20buf;=0A-=09int=09=09=09head,=0A-=09=09=09=09tail,=0A-=09= =09=09=09i;=0A-=09int=09=09=09nxids=20=3D=200;=0A-=0A-=09tail=20=3D=20= pArray->tailKnownAssignedXids;=0A-=09head=20=3D=20= pArray->headKnownAssignedXids;=0A-=0A-=09initStringInfo(&buf);=0A-=0A-=09= for=20(i=20=3D=20tail;=20i=20<=20head;=20i++)=0A-=09{=0A-=09=09if=20= (KnownAssignedXidsValid[i])=0A-=09=09{=0A-=09=09=09nxids++;=0A-=09=09=09= appendStringInfo(&buf,=20"[%d]=3D%u=20",=20i,=20KnownAssignedXids[i]);=0A= -=09=09}=0A-=09}=0A-=0A-=09elog(trace_level,=20"%d=20KnownAssignedXids=20= (num=3D%d=20tail=3D%d=20head=3D%d)=20%s",=0A-=09=09=20nxids,=0A-=09=09=20= pArray->numKnownAssignedXids,=0A-=09=09=20pArray->tailKnownAssignedXids,=0A= -=09=09=20pArray->headKnownAssignedXids,=0A-=09=09=20buf.data);=0A-=0A-=09= pfree(buf.data);=0A-}=0A-=0A-/*=0A-=20*=20KnownAssignedXidsReset=0A-=20*=09= =09Resets=20KnownAssignedXids=20to=20be=20empty=0A-=20*/=0A-static=20= void=0A-KnownAssignedXidsReset(void)=0A-{=0A-=09ProcArrayStruct=20= *pArray=20=3D=20procArray;=0A-=0A-=09LWLockAcquire(ProcArrayLock,=20= LW_EXCLUSIVE);=0A+=09Assert(lsn=20>=20= TransamVariables->latestCommitLSN);=0A+=09= TransamVariables->latestCommitLSN=20=3D=20lsn;=0A=20=0A-=09= pArray->numKnownAssignedXids=20=3D=200;=0A-=09= pArray->tailKnownAssignedXids=20=3D=200;=0A-=09= pArray->headKnownAssignedXids=20=3D=200;=0A+=09= procArray->oldest_running_primary_xid=20=3D=20= oldest_running_primary_xid;=0A=20=0A=20=09LWLockRelease(ProcArrayLock);=0A= =20}=0Adiff=20--git=20a/src/backend/storage/ipc/standby.c=20= b/src/backend/storage/ipc/standby.c=0Aindex=205acb4508f85..217b1670f5b=20= 100644=0A---=20a/src/backend/storage/ipc/standby.c=0A+++=20= b/src/backend/storage/ipc/standby.c=0A@@=20-139,8=20+139,6=20@@=20= InitRecoveryTransactionEnvironment(void)=0A=20=09vxid.procNumber=20=3D=20= MyProcNumber;=0A=20=09vxid.localTransactionId=20=3D=20= GetNextLocalTransactionId();=0A=20=09VirtualXactLockTableInsert(vxid);=0A= -=0A-=09standbyState=20=3D=20STANDBY_INITIALIZED;=0A=20}=0A=20=0A=20/*=0A= @@=20-168,9=20+166,6=20@@=20ShutdownRecoveryTransactionEnvironment(void)=0A= =20=09if=20(RecoveryLockHash=20=3D=3D=20NULL)=0A=20=09=09return;=0A=20=0A= -=09/*=20Mark=20all=20tracked=20in-progress=20transactions=20as=20= finished.=20*/=0A-=09ExpireAllKnownAssignedTransactionIds();=0A-=0A=20=09= /*=20Release=20all=20locks=20the=20tracked=20transactions=20were=20= holding=20*/=0A=20=09StandbyReleaseAllLocks();=0A=20=0A@@=20-1167,7=20= +1162,7=20@@=20standby_redo(XLogReaderState=20*record)=0A=20=09= Assert(!XLogRecHasAnyBlockRefs(record));=0A=20=0A=20=09/*=20Do=20nothing=20= if=20we're=20not=20in=20hot=20standby=20mode=20*/=0A-=09if=20= (standbyState=20=3D=3D=20STANDBY_DISABLED)=0A+=09if=20(!InHotStandby)=0A=20= =09=09return;=0A=20=0A=20=09if=20(info=20=3D=3D=20XLOG_STANDBY_LOCK)=0A= @@=20-1182,18=20+1177,21=20@@=20standby_redo(XLogReaderState=20*record)=0A= =20=09}=0A=20=09else=20if=20(info=20=3D=3D=20XLOG_RUNNING_XACTS)=0A=20=09= {=0A+=09=09/*=0A+=09=09=20*=20XXX:=20running=20xacts=20records=20were=20= previously=20used=20to=20update=0A+=09=09=20*=20known-assigned=20xids,=20= but=20now=20we=20only=20need=20it=20for=20the=20logical=0A+=09=09=20*=20= replication=20snapbuilder=20stuff.=20And=20for=20the=0A+=09=09=20*=20= pg_stat_report_stat(true)=20call=20below.=0A+=09=09=20*/=0A=20=09=09= xl_running_xacts=20*xlrec=20=3D=20(xl_running_xacts=20*)=20= XLogRecGetData(record);=0A-=09=09RunningTransactionsData=20running;=0A=20= =0A-=09=09running.xcnt=20=3D=20xlrec->xcnt;=0A-=09=09running.subxcnt=20=3D= =20xlrec->subxcnt;=0A-=09=09running.subxid_status=20=3D=20= xlrec->subxid_overflow=20?=20SUBXIDS_MISSING=20:=20SUBXIDS_IN_ARRAY;=0A-=09= =09running.nextXid=20=3D=20xlrec->nextXid;=0A-=09=09= running.latestCompletedXid=20=3D=20xlrec->latestCompletedXid;=0A-=09=09= running.oldestRunningXid=20=3D=20xlrec->oldestRunningXid;=0A-=09=09= running.xids=20=3D=20xlrec->xids;=0A-=0A-=09=09= ProcArrayApplyRecoveryInfo(&running);=0A+=09=09/*=0A+=09=09=20*=20= Remember=20the=20oldest=20XID=20that=20was=20running=20at=20the=20time.=20= Normally,=20all=0A+=09=09=20*=20transaction=20aborts=20and=20commits=20= are=20WAL-logged,=20so=20our=0A+=09=09=20*=20oldestRunningXid=20value=20= should=20be=20up-to-date,=20but=20if=20not,=20this=0A+=09=09=20*=20= allows=20us=20to=20resynchronize.=0A+=09=09=20*/=0A+=09=09= ProcArrayUpdateOldestRunningXid(xlrec->oldestRunningXid);=0A=20=0A=20=09=09= /*=0A=20=09=09=20*=20The=20startup=20process=20currently=20has=20no=20= convenient=20way=20to=20schedule=0A@@=20-1224,50=20+1222,46=20@@=20= standby_redo(XLogReaderState=20*record)=0A=20=20*=0A=20=20*=20This=20is=20= used=20for=20Hot=20Standby=20as=20follows:=0A=20=20*=0A-=20*=20We=20can=20= move=20directly=20to=20STANDBY_SNAPSHOT_READY=20at=20startup=20if=20we=0A= -=20*=20start=20from=20a=20shutdown=20checkpoint=20because=20we=20know=20= nothing=20was=20running=0A-=20*=20at=20that=20time=20and=20our=20= recovery=20snapshot=20is=20known=20empty.=20In=20the=20more=0A-=20*=20= typical=20case=20of=20an=20online=20checkpoint=20we=20need=20to=20jump=20= through=20a=20few=0A-=20*=20hoops=20to=20get=20a=20correct=20recovery=20= snapshot=20and=20this=20requires=20a=20two=20or=0A-=20*=20sometimes=20a=20= three=20stage=20process.=0A+=20*=20We=20can=20enter=20hot=20standby=20= mode=20and=20start=20accepting=20read-only=20queries=0A+=20*=20= immediately=20at=20startup=20if=20we=20start=20from=20a=20shutdown=20= checkpoint,=20because=20we=0A+=20*=20know=20nothing=20was=20running=20at=20= that=20time=20and=20our=20recovery=20snapshot=20is=20known=0A+=20*=20= empty.=20In=20the=20more=20typical=20case=20of=20an=20online=20= checkpoint,=20the=20checkpoint=0A+=20*=20record=20doesn't=20contain=20= all=20the=20necessary=20information=20about=20running=0A+=20*=20= transaction=20state,=20and=20we=20need=20to=20jump=20through=20a=20few=20= hoops=20to=20get=20a=20correct=0A+=20*=20recovery=20snapshot.=0A=20=20*=0A= -=20*=20The=20initial=20snapshot=20must=20contain=20all=20running=20xids=20= and=20all=20current=0A-=20*=20AccessExclusiveLocks=20at=20a=20point=20in=20= time=20on=20the=20standby.=20Assembling=0A-=20*=20that=20information=20= while=20the=20server=20is=20running=20requires=20many=20and=0A-=20*=20= various=20LWLocks,=20so=20we=20choose=20to=20derive=20that=20information=20= piece=20by=0A-=20*=20piece=20and=20then=20re-assemble=20that=20info=20on=20= the=20standby.=20When=20that=0A-=20*=20information=20is=20fully=20= assembled=20we=20move=20to=20STANDBY_SNAPSHOT_READY.=0A+=20*=20The=20= initial=20snapshot=20must=20contain=20all=20current=20= AccessExclusiveLocks=20at=20a=0A+=20*=20point=20in=20time=20on=20the=20= standby.=20Assembling=20that=20information=20while=20the=20server=0A+=20= *=20is=20running=20requires=20many=20and=20various=20LWLocks,=20so=20we=20= choose=20to=20derive=20that=0A+=20*=20information=20piece=20by=20piece=20= and=20then=20re-assemble=20that=20info=20on=20the=20standby.=0A=20=20*=0A= -=20*=20Since=20locking=20on=20the=20primary=20when=20we=20derive=20the=20= information=20is=20not=0A-=20*=20strict,=20we=20note=20that=20there=20is=20= a=20time=20window=20between=20the=20derivation=20and=0A-=20*=20writing=20= to=20WAL=20of=20the=20derived=20information.=20That=20allows=20race=20= conditions=0A-=20*=20that=20we=20must=20resolve,=20since=20xids=20and=20= locks=20may=20enter=20or=20leave=20the=0A-=20*=20snapshot=20during=20= that=20window.=20This=20creates=20the=20issue=20that=20an=20xid=20or=0A-=20= *=20lock=20may=20start=20*after*=20the=20snapshot=20has=20been=20derived=20= yet=20*before*=20the=0A-=20*=20snapshot=20is=20logged=20in=20the=20= running=20xacts=20WAL=20record.=20We=20resolve=20this=20by=0A-=20*=20= starting=20to=20accumulate=20changes=20at=20a=20point=20just=20prior=20= to=20when=20we=20derive=0A-=20*=20the=20snapshot=20on=20the=20primary,=20= then=20ignore=20duplicates=20when=20we=20later=20apply=0A-=20*=20the=20= snapshot=20from=20the=20running=20xacts=20record.=20This=20is=20= implemented=20during=0A-=20*=20CreateCheckPoint()=20where=20we=20use=20= the=20logical=20checkpoint=20location=20as=0A-=20*=20our=20starting=20= point=20and=20then=20write=20the=20running=20xacts=20record=20= immediately=0A-=20*=20before=20writing=20the=20main=20checkpoint=20WAL=20= record.=20Since=20we=20always=20start=0A-=20*=20up=20from=20a=20= checkpoint=20and=20are=20immediately=20at=20our=20starting=20point,=20we=0A= -=20*=20unconditionally=20move=20to=20STANDBY_INITIALIZED.=20After=20= this=20point=20we=0A-=20*=20must=20do=204=20things:=0A+=20*=20Since=20= locking=20on=20the=20primary=20when=20we=20derive=20the=20information=20= is=20not=20strict,=0A+=20*=20there=20is=20a=20time=20window=20between=20= the=20derivation=20and=20writing=20to=20WAL=20of=20the=0A+=20*=20derived=20= information.=20That=20allows=20race=20conditions=20that=20we=20must=20= resolve,=0A+=20*=20since=20xids=20and=20locks=20may=20enter=20or=20leave=20= the=20snapshot=20during=20that=0A+=20*=20window.=20This=20creates=20the=20= issue=20that=20an=20xid=20or=20lock=20may=20start=20*after*=20the=0A+=20= *=20snapshot=20has=20been=20derived=20yet=20*before*=20the=20snapshot=20= is=20logged=20in=20the=0A+=20*=20running=20xacts=20WAL=20record.=20We=20= resolve=20this=20by=20starting=20to=20accumulate=20changes=0A+=20*=20at=20= a=20point=20just=20prior=20to=20when=20we=20collect=20the=20lock=20= information=20on=20the=0A+=20*=20primary,=20then=20ignore=20duplicates=20= when=20we=20later=20apply=20the=20snapshot=20from=20the=0A+=20*=20= running=20xacts=20record.=20This=20is=20implemented=20during=20= CreateCheckPoint()=20where=0A+=20*=20we=20use=20the=20logical=20= checkpoint=20location=20as=20our=20starting=20point=20and=20then=20write=0A= +=20*=20the=20running=20xacts=20record=20immediately=20before=20writing=20= the=20main=20checkpoint=20WAL=0A+=20*=20record.=20Since=20we=20always=20= start=20up=20from=20a=20checkpoint's=20redo=20pointer,=20we=20will=0A+=20= *=20always=20see=20a=20running-xacts=20record=20between=20before=20= reaching=20the=20checkpoint=0A+=20*=20record,=20and=20can=20immediately=20= enter=20hot=20standby=20mode.=20After=20this=20point=20we=0A+=20*=20must=20= do=203=20things:=0A=20=20*=09*=20move=20shared=20nextXid=20forwards=20as=20= we=20see=20new=20xids=0A=20=20*=09*=20extend=20the=20clog=20and=20= subtrans=20with=20each=20new=20xid=0A-=20*=09*=20keep=20track=20of=20= uncommitted=20known=20assigned=20xids=0A=20=20*=09*=20keep=20track=20of=20= uncommitted=20AccessExclusiveLocks=0A=20=20*=0A-=20*=20When=20we=20see=20= a=20commit/abort=20we=20must=20remove=20known=20assigned=20xids=20and=20= locks=0A-=20*=20from=20the=20completing=20transaction.=20Attempted=20= removals=20that=20cannot=20locate=0A-=20*=20an=20entry=20are=20expected=20= and=20must=20not=20cause=20an=20error=20when=20we=20are=20in=20state=0A-=20= *=20STANDBY_INITIALIZED.=20This=20is=20implemented=20in=20= StandbyReleaseLocks()=20and=0A-=20*=20KnownAssignedXidsRemove().=0A-=20*=0A= -=20*=20Later,=20when=20we=20apply=20the=20running=20xact=20data=20we=20= must=20be=20careful=20to=20ignore=0A-=20*=20transactions=20already=20= committed,=20since=20those=20commits=20raced=20ahead=20when=0A-=20*=20= making=20WAL=20entries.=0A+=20*=20When=20we=20see=20a=20commit/abort=20= we=20must=20advance=20oldest_running_primary_xid=20and=0A+=20*=20remove=20= locks=20from=20the=20completing=20transaction.=20Attempted=20removals=20= that=0A+=20*=20cannot=20locate=20an=20entry=20are=20expected=20and=20= must=20not=20cause=20an=20error=20until=20we=0A+=20*=20have=20seen=20the=20= running-xacts=20record.=20(We=20don't=20throw=20an=20error=20even=20= after=0A+=20*=20that,=20because=20whatever=20the=20reason=20was,=20after=20= the=20transaction=20has=20completed=0A+=20*=20the=20issue=20has=20= already=20been=20resolved=20anyway.)=20This=20is=20implemented=20in=0A+=20= *=20StandbyReleaseLocks().=0A=20=20*=0A=20=20*=20For=20logical=20= decoding=20only=20the=20running=20xacts=20information=20is=20needed;=0A=20= =20*=20there's=20no=20need=20to=20look=20at=20the=20locking=20= information,=20but=20it's=20logged=20anyway,=0Adiff=20--git=20= a/src/backend/storage/lmgr/lwlock.c=20= b/src/backend/storage/lmgr/lwlock.c=0Aindex=203df29658f18..aadec36dc15=20= 100644=0A---=20a/src/backend/storage/lmgr/lwlock.c=0A+++=20= b/src/backend/storage/lmgr/lwlock.c=0A@@=20-140,6=20+140,7=20@@=20static=20= const=20char=20*const=20BuiltinTrancheNames[]=20=3D=20{=0A=20=09= [LWTRANCHE_XACT_BUFFER]=20=3D=20"XactBuffer",=0A=20=09= [LWTRANCHE_COMMITTS_BUFFER]=20=3D=20"CommitTsBuffer",=0A=20=09= [LWTRANCHE_SUBTRANS_BUFFER]=20=3D=20"SubtransBuffer",=0A+=09= [LWTRANCHE_CSN_LOG_BUFFER]=20=3D=20"CsnLogBuffer",=0A=20=09= [LWTRANCHE_MULTIXACTOFFSET_BUFFER]=20=3D=20"MultiXactOffsetBuffer",=0A=20= =09[LWTRANCHE_MULTIXACTMEMBER_BUFFER]=20=3D=20"MultiXactMemberBuffer",=0A= =20=09[LWTRANCHE_NOTIFY_BUFFER]=20=3D=20"NotifyBuffer",=0A@@=20-178,6=20= +179,7=20@@=20static=20const=20char=20*const=20BuiltinTrancheNames[]=20=3D= =20{=0A=20=09[LWTRANCHE_XACT_SLRU]=20=3D=20"XactSLRU",=0A=20=09= [LWTRANCHE_PARALLEL_VACUUM_DSA]=20=3D=20"ParallelVacuumDSA",=0A=20=09= [LWTRANCHE_AIO_URING_COMPLETION]=20=3D=20"AioUringCompletion",=0A+=09= [LWTRANCHE_CSN_LOG_SLRU]=20=3D=20"CsnLogSLRU",=0A=20};=0A=20=0A=20= StaticAssertDecl(lengthof(BuiltinTrancheNames)=20=3D=3D=0Adiff=20--git=20= a/src/backend/utils/activity/wait_event_names.txt=20= b/src/backend/utils/activity/wait_event_names.txt=0Aindex=20= 4f44648aca8..95e248b2c88=20100644=0A---=20= a/src/backend/utils/activity/wait_event_names.txt=0A+++=20= b/src/backend/utils/activity/wait_event_names.txt=0A@@=20-363,6=20+363,7=20= @@=20AioWorkerSubmissionQueue=09"Waiting=20to=20access=20AIO=20worker=20= submission=20queue."=0A=20XactBuffer=09"Waiting=20for=20I/O=20on=20a=20= transaction=20status=20SLRU=20buffer."=0A=20CommitTsBuffer=09"Waiting=20= for=20I/O=20on=20a=20commit=20timestamp=20SLRU=20buffer."=0A=20= SubtransBuffer=09"Waiting=20for=20I/O=20on=20a=20sub-transaction=20SLRU=20= buffer."=0A+CsnlogBuffer=09"Waiting=20for=20I/O=20on=20a=20= sub-transaction=20SLRU=20buffer."=0A=20MultiXactOffsetBuffer=09"Waiting=20= for=20I/O=20on=20a=20multixact=20offset=20SLRU=20buffer."=0A=20= MultiXactMemberBuffer=09"Waiting=20for=20I/O=20on=20a=20multixact=20= member=20SLRU=20buffer."=0A=20NotifyBuffer=09"Waiting=20for=20I/O=20on=20= a=20NOTIFY=20message=20SLRU=20buffer."=0Adiff=20--git=20= a/src/backend/utils/probes.d=20b/src/backend/utils/probes.d=0Aindex=20= e9e413477ba..d8ff9cfdb36=20100644=0A---=20a/src/backend/utils/probes.d=0A= +++=20b/src/backend/utils/probes.d=0A@@=20-77,6=20+77,8=20@@=20provider=20= postgresql=20{=0A=20=09probe=20clog__checkpoint__done(bool);=0A=20=09= probe=20subtrans__checkpoint__start(bool);=0A=20=09probe=20= subtrans__checkpoint__done(bool);=0A+=09probe=20= csnlog__checkpoint__start(bool);=0A+=09probe=20= csnlog__checkpoint__done(bool);=0A=20=09probe=20= multixact__checkpoint__start(bool);=0A=20=09probe=20= multixact__checkpoint__done(bool);=0A=20=09probe=20= twophase__checkpoint__start();=0Adiff=20--git=20= a/src/backend/utils/time/snapmgr.c=20b/src/backend/utils/time/snapmgr.c=0A= index=205f9f2b9d8b2..049c706f2cf=20100644=0A---=20= a/src/backend/utils/time/snapmgr.c=0A+++=20= b/src/backend/utils/time/snapmgr.c=0A@@=20-97,6=20+97,7=20@@=0A=20= #include=20=0A=20#include=20=0A=20=0A+#include=20= "access/csn_log.h"=0A=20#include=20"access/subtrans.h"=0A=20#include=20= "access/transam.h"=0A=20#include=20"access/xact.h"=0A@@=20-1888,36=20= +1889,11=20@@=20XidInMVCCSnapshot(TransactionId=20xid,=20= MVCCSnapshotShared=20snapshot)=0A=20=09}=0A=20=09else=0A=20=09{=0A-=09=09= /*=0A-=09=09=20*=20In=20recovery=20we=20store=20all=20xids=20in=20the=20= subxip=20array=20because=20it=20is=20by=0A-=09=09=20*=20far=20the=20= bigger=20array,=20and=20we=20mostly=20don't=20know=20which=20xids=20are=0A= -=09=09=20*=20top-level=20and=20which=20are=20subxacts.=20The=20xip=20= array=20is=20empty.=0A-=09=09=20*=0A-=09=09=20*=20We=20start=20by=20= searching=20subtrans,=20if=20we=20overflowed.=0A-=09=09=20*/=0A-=09=09if=20= (snapshot->suboverflowed)=0A-=09=09{=0A-=09=09=09/*=0A-=09=09=09=20*=20= Snapshot=20overflowed,=20so=20convert=20xid=20to=20top-level.=20=20This=20= is=20safe=0A-=09=09=09=20*=20because=20we=20eliminated=20too-old=20XIDs=20= above.=0A-=09=09=09=20*/=0A-=09=09=09xid=20=3D=20= SubTransGetTopmostTransaction(xid);=0A-=0A-=09=09=09/*=0A-=09=09=09=20*=20= If=20xid=20was=20indeed=20a=20subxact,=20we=20might=20now=20have=20an=20= xid=20<=20xmin,=0A-=09=09=09=20*=20so=20recheck=20to=20avoid=20an=20= array=20scan.=20=20No=20point=20in=20rechecking=0A-=09=09=09=20*=20xmax.=0A= -=09=09=09=20*/=0A-=09=09=09if=20(TransactionIdPrecedes(xid,=20= snapshot->xmin))=0A-=09=09=09=09return=20false;=0A-=09=09}=0A+=09=09= XLogRecPtr=09csn=20=3D=20CSNLogGetCSNByXid(xid);=0A=20=0A-=09=09/*=0A-=09= =09=20*=20We=20now=20have=20either=20a=20top-level=20xid=20higher=20than=20= xmin=20or=20an=0A-=09=09=20*=20indeterminate=20xid.=20We=20don't=20know=20= whether=20it's=20top=20level=20or=20subxact=0A-=09=09=20*=20but=20it=20= doesn't=20matter.=20If=20it's=20present,=20the=20xid=20is=20visible.=0A-=09= =09=20*/=0A-=09=09if=20(pg_lfind32(xid,=20snapshot->subxip,=20= snapshot->subxcnt))=0A+=09=09if=20(csn=20!=3D=20InvalidXLogRecPtr=20&&=20= csn=20<=3D=20snapshot->snapshotCsn)=0A+=09=09=09return=20false;=0A+=09=09= else=0A=20=09=09=09return=20true;=0A=20=09}=0A=20=0Adiff=20--git=20= a/src/bin/initdb/initdb.c=20b/src/bin/initdb/initdb.c=0Aindex=20= c17fda2bc81..f52817e218f=20100644=0A---=20a/src/bin/initdb/initdb.c=0A= +++=20b/src/bin/initdb/initdb.c=0A@@=20-251,7=20+251,8=20@@=20static=20= const=20char=20*const=20subdirs[]=20=3D=20{=0A=20=09"pg_xact",=0A=20=09= "pg_logical",=0A=20=09"pg_logical/snapshots",=0A-=09= "pg_logical/mappings"=0A+=09"pg_logical/mappings",=0A+=09"pg_csn"=0A=20= };=0A=20=0A=20=0Adiff=20--git=20a/src/bin/pg_rewind/filemap.c=20= b/src/bin/pg_rewind/filemap.c=0Aindex=20a28d1667d4c..64fdd139173=20= 100644=0A---=20a/src/bin/pg_rewind/filemap.c=0A+++=20= b/src/bin/pg_rewind/filemap.c=0A@@=20-146,6=20+146,9=20@@=20static=20= const=20char=20*const=20excludeDirContents[]=20=3D=0A=20=09/*=20Contents=20= zeroed=20on=20startup,=20see=20StartupSUBTRANS().=20*/=0A=20=09= "pg_subtrans",=0A=20=0A+=09/*=20Contents=20zeroed=20on=20startup,=20see=20= StartupCSNLog().=20*/=0A+=09"pg_csn",=0A+=0A=20=09/*=20end=20of=20list=20= */=0A=20=09NULL=0A=20};=0Adiff=20--git=20a/src/include/access/csn_log.h=20= b/src/include/access/csn_log.h=0Anew=20file=20mode=20100644=0Aindex=20= 00000000000..f8cdf573aef=0A---=20/dev/null=0A+++=20= b/src/include/access/csn_log.h=0A@@=20-0,0=20+1,30=20@@=0A+/*=0A+=20*=20= csn_log.h=0A+=20*=0A+=20*=20Mapping=20from=20XID=20to=20commit=20= record's=20LSN=20(Commit=20Sequence=20Number).=0A+=20*=0A+=20*=20= Portions=20Copyright=20(c)=201996-2014,=20PostgreSQL=20Global=20= Development=20Group=0A+=20*=20Portions=20Copyright=20(c)=201994,=20= Regents=20of=20the=20University=20of=20California=0A+=20*=0A+=20*=20= src/include/access/csn_log.h=0A+=20*/=0A+#ifndef=20CSNLOG_H=0A+#define=20= CSNLOG_H=0A+=0A+#include=20"access/xlog.h"=0A+#include=20= "utils/snapshot.h"=0A+=0A+extern=20void=20CSNLogSetCSN(TransactionId=20= xid,=20int=20nsubxids,=0A+=09=09=09=09=09=09=20TransactionId=20*subxids,=20= XLogRecPtr=20csn);=0A+extern=20XLogRecPtr=20= CSNLogGetCSNByXid(TransactionId=20xid);=0A+=0A+extern=20Size=20= CSNLogShmemSize(void);=0A+extern=20void=20CSNLogShmemInit(void);=0A= +extern=20void=20BootStrapCSNLog(void);=0A+extern=20void=20= StartupCSNLog(TransactionId=20oldestActiveXID,=20XLogRecPtr=20csn);=0A= +extern=20void=20ShutdownCSNLog(void);=0A+extern=20void=20= CheckPointCSNLog(void);=0A+extern=20void=20ExtendCSNLog(TransactionId=20= newestXact);=0A+extern=20void=20TruncateCSNLog(TransactionId=20= oldestXact);=0A+=0A+#endif=09=09=09=09=09=09=09/*=20CSNLOG_H=20*/=0Adiff=20= --git=20a/src/include/access/transam.h=20b/src/include/access/transam.h=0A= index=20e71c660118e..76411cca178=20100644=0A---=20= a/src/include/access/transam.h=0A+++=20b/src/include/access/transam.h=0A= @@=20-238,6=20+238,9=20@@=20typedef=20struct=20TransamVariablesData=0A=20= =09FullTransactionId=20latestCompletedXid;=09/*=20newest=20full=20XID=20= that=20has=0A=20=09=09=09=09=09=09=09=09=09=09=09=20*=20committed=20or=20= aborted=20*/=0A=20=0A+=09/*=20During=20recovery,=20LSN=20of=20latest=20= replayed=20commit=20record=20*/=0A+=09XLogRecPtr=09latestCommitLSN;=0A+=0A= =20=09/*=0A=20=09=20*=20Number=20of=20top-level=20transactions=20with=20= xids=20(i.e.=20which=20may=20have=0A=20=09=20*=20modified=20the=20= database)=20that=20completed=20in=20some=20form=20since=20the=20start=20= of=0Adiff=20--git=20a/src/include/access/twophase.h=20= b/src/include/access/twophase.h=0Aindex=209fa82355033..9527695886f=20= 100644=0A---=20a/src/include/access/twophase.h=0A+++=20= b/src/include/access/twophase.h=0A@@=20-47,8=20+47,7=20@@=20extern=20= void=20StartPrepare(GlobalTransaction=20gxact);=0A=20extern=20void=20= EndPrepare(GlobalTransaction=20gxact);=0A=20extern=20bool=20= StandbyTransactionIdIsPrepared(TransactionId=20xid);=0A=20=0A-extern=20= TransactionId=20PrescanPreparedTransactions(TransactionId=20**xids_p,=0A= -=09=09=09=09=09=09=09=09=09=09=09=09=20int=20*nxids_p);=0A+extern=20= TransactionId=20PrescanPreparedTransactions(void);=0A=20extern=20void=20= StandbyRecoverPreparedTransactions(void);=0A=20extern=20void=20= RecoverPreparedTransactions(void);=0A=20=0Adiff=20--git=20= a/src/include/access/xact.h=20b/src/include/access/xact.h=0Aindex=20= b2bc10ee041..b31944d0e6c=20100644=0A---=20a/src/include/access/xact.h=0A= +++=20b/src/include/access/xact.h=0A@@=20-171,7=20+171,7=20@@=20typedef=20= struct=20SavedTransactionCharacteristics=0A=20#define=20XLOG_XACT_ABORT=09= =09=09=090x20=0A=20#define=20XLOG_XACT_COMMIT_PREPARED=090x30=0A=20= #define=20XLOG_XACT_ABORT_PREPARED=090x40=0A-#define=20= XLOG_XACT_ASSIGNMENT=09=090x50=0A+/*=200x50=20is=20unused,=20was=20= XLOG_XACT_ASSIGNMENT=20*/=0A=20#define=20XLOG_XACT_INVALIDATIONS=09=09= 0x60=0A=20/*=20free=20opcode=200x70=20*/=0A=20=0A@@=20-215,15=20+215,6=20= @@=20typedef=20struct=20SavedTransactionCharacteristics=0A=20#define=20= XactCompletionForceSyncCommit(xinfo)=20\=0A=20=09((xinfo=20&=20= XACT_COMPLETION_FORCE_SYNC_COMMIT)=20!=3D=200)=0A=20=0A-typedef=20struct=20= xl_xact_assignment=0A-{=0A-=09TransactionId=20xtop;=09=09=09/*=20= assigned=20XID's=20top-level=20XID=20*/=0A-=09int=09=09=09nsubxacts;=09=09= /*=20number=20of=20subtransaction=20XIDs=20*/=0A-=09TransactionId=20= xsub[FLEXIBLE_ARRAY_MEMBER];=09/*=20assigned=20subxids=20*/=0A-}=20= xl_xact_assignment;=0A-=0A-#define=20MinSizeOfXactAssignment=20= offsetof(xl_xact_assignment,=20xsub)=0A-=0A=20/*=0A=20=20*=20Commit=20= and=20abort=20records=20can=20contain=20a=20lot=20of=20information.=20= But=20a=20large=0A=20=20*=20portion=20of=20the=20records=20won't=20need=20= all=20possible=20pieces=20of=20information.=20So=20we=0A@@=20-448,7=20= +439,6=20@@=20extern=20FullTransactionId=20= GetTopFullTransactionId(void);=0A=20extern=20FullTransactionId=20= GetTopFullTransactionIdIfAny(void);=0A=20extern=20FullTransactionId=20= GetCurrentFullTransactionId(void);=0A=20extern=20FullTransactionId=20= GetCurrentFullTransactionIdIfAny(void);=0A-extern=20void=20= MarkCurrentTransactionIdLoggedIfAny(void);=0A=20extern=20bool=20= SubTransactionIsActive(SubTransactionId=20subxid);=0A=20extern=20= CommandId=20GetCurrentCommandId(bool=20used);=0A=20extern=20void=20= SetParallelStartTimestamps(TimestampTz=20xact_ts,=20TimestampTz=20= stmt_ts);=0Adiff=20--git=20a/src/include/access/xlogutils.h=20= b/src/include/access/xlogutils.h=0Aindex=20a1870d8e5aa..2ab20fcae2f=20= 100644=0A---=20a/src/include/access/xlogutils.h=0A+++=20= b/src/include/access/xlogutils.h=0A@@=20-27,37=20+27,10=20@@=20extern=20= PGDLLIMPORT=20bool=20ignore_invalid_pages;=0A=20extern=20PGDLLIMPORT=20= bool=20InRecovery;=0A=20=0A=20/*=0A-=20*=20Like=20InRecovery,=20= standbyState=20is=20only=20valid=20in=20the=20startup=20process.=0A-=20*=20= In=20all=20other=20processes=20it=20will=20have=20the=20value=20= STANDBY_DISABLED=20(so=0A-=20*=20InHotStandby=20will=20read=20as=20= false).=0A-=20*=0A-=20*=20In=20DISABLED=20state,=20we're=20performing=20= crash=20recovery=20or=20hot=20standby=20was=0A-=20*=20disabled=20in=20= postgresql.conf.=0A-=20*=0A-=20*=20In=20INITIALIZED=20state,=20we've=20= run=20InitRecoveryTransactionEnvironment,=20but=0A-=20*=20we=20haven't=20= yet=20processed=20a=20RUNNING_XACTS=20or=20shutdown-checkpoint=20WAL=20= record=0A-=20*=20to=20initialize=20our=20primary-transaction=20tracking=20= system.=0A-=20*=0A-=20*=20When=20the=20transaction=20tracking=20is=20= initialized,=20we=20enter=20the=20SNAPSHOT_PENDING=0A-=20*=20state.=20= The=20tracked=20information=20might=20still=20be=20incomplete,=20so=20we=20= can't=20allow=0A-=20*=20connections=20yet,=20but=20redo=20functions=20= must=20update=20the=20in-memory=20state=20when=0A-=20*=20appropriate.=0A= -=20*=0A-=20*=20In=20SNAPSHOT_READY=20mode,=20we=20have=20full=20= knowledge=20of=20transactions=20that=20are=0A-=20*=20(or=20were)=20= running=20on=20the=20primary=20at=20the=20current=20WAL=20location.=20= Snapshots=0A-=20*=20can=20be=20taken,=20and=20read-only=20queries=20can=20= be=20run.=0A+=20*=20Like=20InRecovery,=20InHotStandby=20is=20only=20= valid=20in=20the=20startup=20process.=0A+=20*=20In=20all=20other=20= processes=20it=20will=20be=20false.=0A=20=20*/=0A-typedef=20enum=0A-{=0A= -=09STANDBY_DISABLED,=0A-=09STANDBY_INITIALIZED,=0A-=09= STANDBY_SNAPSHOT_PENDING,=0A-=09STANDBY_SNAPSHOT_READY,=0A-}=20= HotStandbyState;=0A-=0A-extern=20PGDLLIMPORT=20HotStandbyState=20= standbyState;=0A-=0A-#define=20InHotStandby=20(standbyState=20>=3D=20= STANDBY_SNAPSHOT_PENDING)=0A+extern=20PGDLLIMPORT=20bool=20InHotStandby;=0A= =20=0A=20=0A=20extern=20bool=20XLogHaveInvalidPages(void);=0Adiff=20= --git=20a/src/include/storage/lwlock.h=20b/src/include/storage/lwlock.h=0A= index=204df1d25c045..457c5511c5e=20100644=0A---=20= a/src/include/storage/lwlock.h=0A+++=20b/src/include/storage/lwlock.h=0A= @@=20-181,6=20+181,7=20@@=20typedef=20enum=20BuiltinTrancheIds=0A=20=09= LWTRANCHE_XACT_BUFFER=20=3D=20NUM_INDIVIDUAL_LWLOCKS,=0A=20=09= LWTRANCHE_COMMITTS_BUFFER,=0A=20=09LWTRANCHE_SUBTRANS_BUFFER,=0A+=09= LWTRANCHE_CSN_LOG_BUFFER,=0A=20=09LWTRANCHE_MULTIXACTOFFSET_BUFFER,=0A=20= =09LWTRANCHE_MULTIXACTMEMBER_BUFFER,=0A=20=09LWTRANCHE_NOTIFY_BUFFER,=0A= @@=20-219,6=20+220,7=20@@=20typedef=20enum=20BuiltinTrancheIds=0A=20=09= LWTRANCHE_XACT_SLRU,=0A=20=09LWTRANCHE_PARALLEL_VACUUM_DSA,=0A=20=09= LWTRANCHE_AIO_URING_COMPLETION,=0A+=09LWTRANCHE_CSN_LOG_SLRU,=0A=20=09= LWTRANCHE_FIRST_USER_DEFINED,=0A=20}=09=09=09BuiltinTrancheIds;=0A=20=0A= diff=20--git=20a/src/include/storage/procarray.h=20= b/src/include/storage/procarray.h=0Aindex=208eedc2d6b9f..57071d1e0f4=20= 100644=0A---=20a/src/include/storage/procarray.h=0A+++=20= b/src/include/storage/procarray.h=0A@@=20-28,18=20+28,11=20@@=20extern=20= void=20ProcArrayRemove(PGPROC=20*proc,=20TransactionId=20latestXid);=0A=20= extern=20void=20ProcArrayEndTransaction(PGPROC=20*proc,=20TransactionId=20= latestXid);=0A=20extern=20void=20ProcArrayClearTransaction(PGPROC=20= *proc);=0A=20=0A+extern=20void=20= ProcArrayUpdateOldestRunningXid(TransactionId=20oldestRunningXID);=0A=20= extern=20void=20ProcArrayInitRecovery(TransactionId=20= initializedUptoXID);=0A-extern=20void=20= ProcArrayApplyRecoveryInfo(RunningTransactions=20running);=0A-extern=20= void=20ProcArrayApplyXidAssignment(TransactionId=20topxid,=0A-=09=09=09=09= =09=09=09=09=09=09int=20nsubxids,=20TransactionId=20*subxids);=0A=20=0A=20= extern=20void=20RecordKnownAssignedTransactionIds(TransactionId=20xid);=0A= -extern=20void=20ExpireTreeKnownAssignedTransactionIds(TransactionId=20= xid,=0A-=09=09=09=09=09=09=09=09=09=09=09=09=20=20int=20nsubxids,=20= TransactionId=20*subxids,=0A-=09=09=09=09=09=09=09=09=09=09=09=09=20=20= TransactionId=20max_xid);=0A-extern=20void=20= ExpireAllKnownAssignedTransactionIds(void);=0A-extern=20void=20= ExpireOldKnownAssignedTransactionIds(TransactionId=20xid);=0A-extern=20= void=20KnownAssignedTransactionIdsIdleMaintenance(void);=0A+extern=20= void=20ProcArrayRecoveryEndTransaction(TransactionId=20max_xid,=20= XLogRecPtr=20lsn);=0A=20=0A=20extern=20int=09= GetMaxSnapshotXidCount(void);=0A=20extern=20int=09= GetMaxSnapshotSubxidCount(void);=0A@@=20-56,7=20+49,7=20@@=20extern=20= bool=20TransactionIdIsInProgress(TransactionId=20xid);=0A=20extern=20= bool=20TransactionIdIsActive(TransactionId=20xid);=0A=20extern=20= TransactionId=20GetOldestNonRemovableTransactionId(Relation=20rel);=0A=20= extern=20TransactionId=20GetOldestTransactionIdConsideredRunning(void);=0A= -extern=20TransactionId=20GetOldestActiveTransactionId(void);=0A+extern=20= TransactionId=20GetOldestActiveTransactionId(bool=20allDbs);=0A=20extern=20= TransactionId=20GetOldestSafeDecodingTransactionId(bool=20catalogOnly);=0A= =20extern=20void=20GetReplicationHorizons(TransactionId=20*xmin,=20= TransactionId=20*catalog_xmin);=0A=20=0Adiff=20--git=20= a/src/include/utils/snapshot.h=20b/src/include/utils/snapshot.h=0Aindex=20= 193366ce052..14ff80904c8=20100644=0A---=20a/src/include/utils/snapshot.h=0A= +++=20b/src/include/utils/snapshot.h=0A@@=20-13,6=20+13,7=20@@=0A=20= #ifndef=20SNAPSHOT_H=0A=20#define=20SNAPSHOT_H=0A=20=0A+#include=20= "access/xlogdefs.h"=0A=20#include=20"lib/ilist.h"=0A=20=0A=20=0A@@=20= -186,6=20+187,13=20@@=20typedef=20struct=20MVCCSnapshotSharedData=0A=20=09= int32=09=09subxcnt;=09=09/*=20#=20of=20xact=20ids=20in=20subxip[]=20*/=0A= =20=09bool=09=09suboverflowed;=09/*=20has=20the=20subxip=20array=20= overflowed?=20*/=0A=20=0A+=09/*=0A+=09=20*=20MVCC=20snapshots=20taken=20= during=20recovery=20use=20this=20CSN=20instead=20of=20the=20xip=0A+=09=20= *=20and=20subxip=20arrays.=20Any=20transactions=20that=20committed=20at=20= or=20before=20this=0A+=09=20*=20LSN=20are=20considered=20as=20visible.=0A= +=09=20*/=0A+=09XLogRecPtr=09snapshotCsn;=0A+=0A=20=09bool=09=09= takenDuringRecovery;=09/*=20recovery-shaped=20snapshot?=20*/=0A=20=0A=20=09= /*=0A--=20=0A2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0010-Make-SnapBuildWaitSnapshot-work-without-xl_runnin.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0010-Make-SnapBuildWaitSnapshot-work-without-xl_runnin.patch" Content-Transfer-Encoding: quoted-printable =46rom=202565b8554e321e8ca9a87f36a48f9ab7f86ab247=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Tue,=2013=20Aug=202024=2020:01:07=20= +0300=0ASubject:=20[PATCH=20v6=2010/12]=20Make=20SnapBuildWaitSnapshot=20= work=20without=0A=20xl_running_xacts.xids=20array=0A=0A= SnapBuildWaitSnapshot=20looped=20through=20all=20the=20XIDs=20in=20the=0A= xl_running_xacts,=20waiting=20for=20them=20to=20finish.=20Change=20it=20= to=20grab=20the=0Alist=20of=20running=20XIDs=20from=20the=20proc=20array=20= instead.=20This=20removes=20the=0Alast=20usage=20of=20the=20XIDs=20array=20= in=20the=20xl_running_xacts=20record,=20allowing=0Ait=20to=20be=20= removed=20in=20the=20next=20commit.=0A=0AWhen=20SnapBuildWaitSnapshot()=20= is=20called=20with=20running->nextXid=20as=20the=0A'cutoff'=20point,=20= the=20new=20code=20should=20wait=20for=20exactly=20the=20same=20set=20of=0A= transactions=20as=20before.=20But=20when=20called=20with=20= initial_xmin_horizon=20as=0Athe=20'cutoff',=20this=20might=20wait=20for=20= more=20transactions=20than=20before:=20those=0Abetween=20= running->nextXid=20and=20initial_xmin_horizon.=20For=20example,=0A= imagine=20that=20we=20see=20a=20running-xacts=20record=20with=20nextXid=20= 100,=20and=0Ainitial_xmin_horizon=20is=20200.=20Before,=20we=20would=20= wait=20for=20all=20XIDs=20<=20100=0Ato=20complete,=20and=20then=20log=20= the=20standby=20snapshot=20and=20proceed,=20but=20now=20we=0Awill=20wait=20= for=20all=20XIDs=20<=20200.=20I=20believe=20that's=20a=20good=20thing,=20= because=0Awe=20won't=20actually=20be=20able=20to=20move=20to=20the=20= next=20state=20in=20the=20snapshot=0Abuilding=20until=20all=20= transactions=20<=20200=20have=20completed.=20The=0Arunning-xacts=20= snapshot=20that=20we=20logged=20after=20waiting=20up=20to=20XID=20100=0A= would=20not=20be=20useful=20to=20us=20either,=20if=20there=20are=20still=20= XIDs=20between=20100=0Aand=20200=20running.=0A=0ASnapBuildWaitSnapshot()=20= used=20to=20do=20useless=20work=20when=20called=20in=20a=0Astandby,=20= because=20in=20a=20standby,=20there=20are=20no=20XID=20locks=20and=20the=0A= XactLockTableWait()=20calls=20returned=20immediately,=20even=20if=20the=20= XIDs=20were=0Ain=20fact=20still=20running=20in=20the=20primary.=20But=20= as=20the=20comment=20says,=20the=0Awaiting=20isn't=20necessary=20for=20= correctness,=20so=20that=20was=20harmless.=20In=20any=0Acase,=20stop=20= doing=20the=20futile=20work=20on=20a=20standby.=0A---=0A=20= src/backend/replication/logical/snapbuild.c=20|=2050=20= ++++++++++++++-------=0A=201=20file=20changed,=2034=20insertions(+),=20= 16=20deletions(-)=0A=0Adiff=20--git=20= a/src/backend/replication/logical/snapbuild.c=20= b/src/backend/replication/logical/snapbuild.c=0Aindex=20= 97d278052df..252526ecf91=20100644=0A---=20= a/src/backend/replication/logical/snapbuild.c=0A+++=20= b/src/backend/replication/logical/snapbuild.c=0A@@=20-164,7=20+164,7=20= @@=20static=20inline=20bool=20SnapBuildXidHasCatalogChanges(SnapBuild=20= *builder,=20Transaction=0A=20=0A=20/*=20xlog=20reading=20helper=20= functions=20for=20SnapBuildProcessRunningXacts=20*/=0A=20static=20bool=20= SnapBuildFindSnapshot(SnapBuild=20*builder,=20XLogRecPtr=20lsn,=20= xl_running_xacts=20*running);=0A-static=20void=20= SnapBuildWaitSnapshot(xl_running_xacts=20*running,=20TransactionId=20= cutoff);=0A+static=20void=20SnapBuildWaitSnapshot(TransactionId=20= cutoff);=0A=20=0A=20/*=20serialization=20functions=20*/=0A=20static=20= void=20SnapBuildSerialize(SnapBuild=20*builder,=20XLogRecPtr=20lsn);=0A= @@=20-1192,14=20+1192,17=20@@=20SnapBuildFindSnapshot(SnapBuild=20= *builder,=20XLogRecPtr=20lsn,=20xl_running_xacts=20*runn=0A=20=09=09= NormalTransactionIdPrecedes(running->oldestRunningXid,=0A=20=09=09=09=09=09= =09=09=09=09builder->initial_xmin_horizon))=0A=20=09{=0A+=09=09= TransactionId=20cutoff;=0A+=0A=20=09=09ereport(DEBUG1,=0A=20=09=09=09=09= (errmsg_internal("skipping=20snapshot=20at=20%X/%X=20while=20building=20= logical=20decoding=20snapshot,=20xmin=20horizon=20too=20low",=0A=20=09=09= =09=09=09=09=09=09=20LSN_FORMAT_ARGS(lsn)),=0A=20=09=09=09=09=20= errdetail_internal("initial=20xmin=20horizon=20of=20%u=20vs=20the=20= snapshot's=20%u",=0A=20=09=09=09=09=09=09=09=09=09= builder->initial_xmin_horizon,=20running->oldestRunningXid)));=0A=20=0A-=0A= -=09=09SnapBuildWaitSnapshot(running,=20builder->initial_xmin_horizon);=0A= +=09=09cutoff=20=3D=20builder->initial_xmin_horizon;=0A+=09=09= TransactionIdRetreat(cutoff);=0A+=09=09SnapBuildWaitSnapshot(cutoff);=0A=20= =0A=20=09=09return=20true;=0A=20=09}=0A@@=20-1286,7=20+1289,7=20@@=20= SnapBuildFindSnapshot(SnapBuild=20*builder,=20XLogRecPtr=20lsn,=20= xl_running_xacts=20*runn=0A=20=09=09=09=09=20errdetail("Waiting=20for=20= transactions=20(approximately=20%d)=20older=20than=20%u=20to=20end.",=0A=20= =09=09=09=09=09=09=20=20=20running->xcnt,=20running->nextXid)));=0A=20=0A= -=09=09SnapBuildWaitSnapshot(running,=20running->nextXid);=0A+=09=09= SnapBuildWaitSnapshot(running->nextXid);=0A=20=09}=0A=20=0A=20=09/*=0A@@=20= -1310,7=20+1313,7=20@@=20SnapBuildFindSnapshot(SnapBuild=20*builder,=20= XLogRecPtr=20lsn,=20xl_running_xacts=20*runn=0A=20=09=09=09=09=20= errdetail("Waiting=20for=20transactions=20(approximately=20%d)=20older=20= than=20%u=20to=20end.",=0A=20=09=09=09=09=09=09=20=20=20running->xcnt,=20= running->nextXid)));=0A=20=0A-=09=09SnapBuildWaitSnapshot(running,=20= running->nextXid);=0A+=09=09SnapBuildWaitSnapshot(running->nextXid);=0A=20= =09}=0A=20=0A=20=09/*=0A@@=20-1343,8=20+1346,8=20@@=20= SnapBuildFindSnapshot(SnapBuild=20*builder,=20XLogRecPtr=20lsn,=20= xl_running_xacts=20*runn=0A=20}=0A=20=0A=20/*=20---=0A-=20*=20Iterate=20= through=20xids=20in=20record,=20wait=20for=20all=20older=20than=20the=20= cutoff=20to=0A-=20*=20finish.=20=20Then,=20if=20possible,=20log=20a=20= new=20xl_running_xacts=20record.=0A+=20*=20Wait=20for=20all=20= transactions=20older=20than=20or=20equal=20to=20the=20cutoff=20to=20= finish.=0A+=20*=20Then,=20if=20possible,=20log=20a=20new=20= xl_running_xacts=20record.=0A=20=20*=0A=20=20*=20This=20isn't=20required=20= for=20the=20correctness=20of=20decoding,=20but=20to:=0A=20=20*=20a)=20= allow=20isolationtester=20to=20notice=20that=20we're=20currently=20= waiting=20for=0A@@=20-1354,13=20+1357,31=20@@=20= SnapBuildFindSnapshot(SnapBuild=20*builder,=20XLogRecPtr=20lsn,=20= xl_running_xacts=20*runn=0A=20=20*=20---=0A=20=20*/=0A=20static=20void=0A= -SnapBuildWaitSnapshot(xl_running_xacts=20*running,=20TransactionId=20= cutoff)=0A+SnapBuildWaitSnapshot(TransactionId=20cutoff)=0A=20{=0A-=09= int=09=09=09off;=0A+=09RunningTransactions=20running;=0A+=0A+=09if=20= (RecoveryInProgress())=0A+=09{=0A+=09=09/*=0A+=09=09=20*=20During=20= recovery,=20we=20have=20no=20mechanism=20for=20waiting=20for=20an=20XID=20= to=0A+=09=09=20*=20finish,=20and=20we=20cannot=20create=20new=20= running-xacts=20records=20either.=0A+=09=09=20*/=0A+=09=09return;=0A+=09= }=0A+=0A+=09running=20=3D=20GetRunningTransactionData();=0A+=0A+=09/*=0A= +=09=20*=20GetRunningTransactionData=20returns=20with=20XidGenLock=20and=20= ProcArrayLock=0A+=09=20*=20held,=20but=20we=20don't=20need=20them.=0A+=09= =20*/=0A+=09LWLockRelease(XidGenLock);=0A+=09= LWLockRelease(ProcArrayLock);=0A=20=0A-=09for=20(off=20=3D=200;=20off=20= <=20running->xcnt;=20off++)=0A+=09for=20(int=20i=20=3D=200;=20i=20<=20= running->xcnt;=20i++)=0A=20=09{=0A-=09=09TransactionId=20xid=20=3D=20= running->xids[off];=0A+=09=09TransactionId=20xid=20=3D=20= running->xids[i];=0A=20=0A=20=09=09/*=0A=20=09=09=20*=20Upper=20layers=20= should=20prevent=20that=20we=20ever=20need=20to=20wait=20on=20ourselves.=0A= @@=20-1370,7=20+1391,7=20@@=20SnapBuildWaitSnapshot(xl_running_xacts=20= *running,=20TransactionId=20cutoff)=0A=20=09=09if=20= (TransactionIdIsCurrentTransactionId(xid))=0A=20=09=09=09elog(ERROR,=20= "waiting=20for=20ourselves");=0A=20=0A-=09=09if=20= (TransactionIdFollows(xid,=20cutoff))=0A+=09=09if=20= (TransactionIdFollowsOrEquals(xid,=20cutoff))=0A=20=09=09=09continue;=0A=20= =0A=20=09=09XactLockTableWait(xid,=20NULL,=20NULL,=20XLTW_None);=0A@@=20= -1382,10=20+1403,7=20@@=20SnapBuildWaitSnapshot(xl_running_xacts=20= *running,=20TransactionId=20cutoff)=0A=20=09=20*=20wait=20for=20bgwriter=20= or=20checkpointer=20to=20log=20one.=20=20During=20recovery=20we=20can't=0A= =20=09=20*=20enforce=20that,=20so=20we'll=20have=20to=20wait.=0A=20=09=20= */=0A-=09if=20(!RecoveryInProgress())=0A-=09{=0A-=09=09= LogStandbySnapshot();=0A-=09}=0A+=09LogStandbySnapshot();=0A=20}=0A=20=0A= =20#define=20SnapBuildOnDiskConstantSize=20\=0A--=20=0A2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0011-Remove-the-now-unused-xids-array-from-xl_running_.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0011-Remove-the-now-unused-xids-array-from-xl_running_.patch" Content-Transfer-Encoding: quoted-printable =46rom=2051212a4f053edb5e4ceef65e3ce5e722fbc3844b=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Tue,=2013=20Aug=202024=2016:40:57=20= +0300=0ASubject:=20[PATCH=20v6=2011/12]=20Remove=20the=20now-unused=20= xids=20array=20from=0A=20xl_running_xacts=0A=0AWe=20still=20generate=20= running-xacts=20records,=20because=20they=20are=20still=20needed=0Ato=20= initialize=20the=20snapshot=20in=20logical=20decoding.=0A---=0A=20= src/backend/access/rmgrdesc/standbydesc.c=20=20=20|=2018=20------------=0A= =20src/backend/replication/logical/snapbuild.c=20|=20=208=20+++---=0A=20= src/backend/storage/ipc/standby.c=20=20=20=20=20=20=20=20=20=20=20|=2032=20= +++++----------------=0A=20src/include/storage/standby.h=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20|=20=202=20--=0A=20= src/include/storage/standbydefs.h=20=20=20=20=20=20=20=20=20=20=20|=2016=20= +++++++----=0A=205=20files=20changed,=2021=20insertions(+),=2055=20= deletions(-)=0A=0Adiff=20--git=20= a/src/backend/access/rmgrdesc/standbydesc.c=20= b/src/backend/access/rmgrdesc/standbydesc.c=0Aindex=20= 81eff5f31c4..5e6812396de=20100644=0A---=20= a/src/backend/access/rmgrdesc/standbydesc.c=0A+++=20= b/src/backend/access/rmgrdesc/standbydesc.c=0A@@=20-19,28=20+19,10=20@@=0A= =20static=20void=0A=20standby_desc_running_xacts(StringInfo=20buf,=20= xl_running_xacts=20*xlrec)=0A=20{=0A-=09int=09=09=09i;=0A-=0A=20=09= appendStringInfo(buf,=20"nextXid=20%u=20latestCompletedXid=20%u=20= oldestRunningXid=20%u",=0A=20=09=09=09=09=09=20xlrec->nextXid,=0A=20=09=09= =09=09=09=20xlrec->latestCompletedXid,=0A=20=09=09=09=09=09=20= xlrec->oldestRunningXid);=0A-=09if=20(xlrec->xcnt=20>=200)=0A-=09{=0A-=09= =09appendStringInfo(buf,=20";=20%d=20xacts:",=20xlrec->xcnt);=0A-=09=09= for=20(i=20=3D=200;=20i=20<=20xlrec->xcnt;=20i++)=0A-=09=09=09= appendStringInfo(buf,=20"=20%u",=20xlrec->xids[i]);=0A-=09}=0A-=0A-=09if=20= (xlrec->subxid_overflow)=0A-=09=09appendStringInfoString(buf,=20";=20= subxid=20overflowed");=0A-=0A-=09if=20(xlrec->subxcnt=20>=200)=0A-=09{=0A= -=09=09appendStringInfo(buf,=20";=20%d=20subxacts:",=20xlrec->subxcnt);=0A= -=09=09for=20(i=20=3D=200;=20i=20<=20xlrec->subxcnt;=20i++)=0A-=09=09=09= appendStringInfo(buf,=20"=20%u",=20xlrec->xids[xlrec->xcnt=20+=20i]);=0A= -=09}=0A=20}=0A=20=0A=20void=0Adiff=20--git=20= a/src/backend/replication/logical/snapbuild.c=20= b/src/backend/replication/logical/snapbuild.c=0Aindex=20= 252526ecf91..eada641d2a4=20100644=0A---=20= a/src/backend/replication/logical/snapbuild.c=0A+++=20= b/src/backend/replication/logical/snapbuild.c=0A@@=20-1286,8=20+1286,8=20= @@=20SnapBuildFindSnapshot(SnapBuild=20*builder,=20XLogRecPtr=20lsn,=20= xl_running_xacts=20*runn=0A=20=09=09ereport(LOG,=0A=20=09=09=09=09= (errmsg("logical=20decoding=20found=20initial=20starting=20point=20at=20= %X/%X",=0A=20=09=09=09=09=09=09LSN_FORMAT_ARGS(lsn)),=0A-=09=09=09=09=20= errdetail("Waiting=20for=20transactions=20(approximately=20%d)=20older=20= than=20%u=20to=20end.",=0A-=09=09=09=09=09=09=20=20=20running->xcnt,=20= running->nextXid)));=0A+=09=09=09=09=20errdetail("Waiting=20for=20= transactions=20older=20than=20%u=20to=20end.",=0A+=09=09=09=09=09=09=20=20= =20running->nextXid)));=0A=20=0A=20=09=09= SnapBuildWaitSnapshot(running->nextXid);=0A=20=09}=0A@@=20-1310,8=20= +1310,8=20@@=20SnapBuildFindSnapshot(SnapBuild=20*builder,=20XLogRecPtr=20= lsn,=20xl_running_xacts=20*runn=0A=20=09=09ereport(LOG,=0A=20=09=09=09=09= (errmsg("logical=20decoding=20found=20initial=20consistent=20point=20at=20= %X/%X",=0A=20=09=09=09=09=09=09LSN_FORMAT_ARGS(lsn)),=0A-=09=09=09=09=20= errdetail("Waiting=20for=20transactions=20(approximately=20%d)=20older=20= than=20%u=20to=20end.",=0A-=09=09=09=09=09=09=20=20=20running->xcnt,=20= running->nextXid)));=0A+=09=09=09=09=20errdetail("Waiting=20for=20= transactions=20older=20than=20%u=20to=20end.",=0A+=09=09=09=09=09=09=20=20= =20running->nextXid)));=0A=20=0A=20=09=09= SnapBuildWaitSnapshot(running->nextXid);=0A=20=09}=0Adiff=20--git=20= a/src/backend/storage/ipc/standby.c=20= b/src/backend/storage/ipc/standby.c=0Aindex=20217b1670f5b..0f8a9aa0fea=20= 100644=0A---=20a/src/backend/storage/ipc/standby.c=0A+++=20= b/src/backend/storage/ipc/standby.c=0A@@=20-1337,9=20+1337,6=20@@=20= LogCurrentRunningXacts(RunningTransactions=20CurrRunningXacts)=0A=20=09= xl_running_xacts=20xlrec;=0A=20=09XLogRecPtr=09recptr;=0A=20=0A-=09= xlrec.xcnt=20=3D=20CurrRunningXacts->xcnt;=0A-=09xlrec.subxcnt=20=3D=20= CurrRunningXacts->subxcnt;=0A-=09xlrec.subxid_overflow=20=3D=20= (CurrRunningXacts->subxid_status=20!=3D=20SUBXIDS_IN_ARRAY);=0A=20=09= xlrec.nextXid=20=3D=20CurrRunningXacts->nextXid;=0A=20=09= xlrec.oldestRunningXid=20=3D=20CurrRunningXacts->oldestRunningXid;=0A=20=09= xlrec.latestCompletedXid=20=3D=20CurrRunningXacts->latestCompletedXid;=0A= @@=20-1347,31=20+1344,16=20@@=20= LogCurrentRunningXacts(RunningTransactions=20CurrRunningXacts)=0A=20=09= /*=20Header=20*/=0A=20=09XLogBeginInsert();=0A=20=09= XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT);=0A-=09= XLogRegisterData(&xlrec,=20MinSizeOfXactRunningXacts);=0A-=0A-=09/*=20= array=20of=20TransactionIds=20*/=0A-=09if=20(xlrec.xcnt=20>=200)=0A-=09=09= XLogRegisterData(CurrRunningXacts->xids,=0A-=09=09=09=09=09=09=20= (xlrec.xcnt=20+=20xlrec.subxcnt)=20*=20sizeof(TransactionId));=0A+=09= XLogRegisterData(&xlrec,=20SizeOfXactRunningXacts);=0A=20=0A=20=09recptr=20= =3D=20XLogInsert(RM_STANDBY_ID,=20XLOG_RUNNING_XACTS);=0A=20=0A-=09if=20= (xlrec.subxid_overflow)=0A-=09=09elog(DEBUG2,=0A-=09=09=09=20"snapshot=20= of=20%d=20running=20transactions=20overflowed=20(lsn=20%X/%X=20oldest=20= xid=20%u=20latest=20complete=20%u=20next=20xid=20%u)",=0A-=09=09=09=20= CurrRunningXacts->xcnt,=0A-=09=09=09=20LSN_FORMAT_ARGS(recptr),=0A-=09=09= =09=20CurrRunningXacts->oldestRunningXid,=0A-=09=09=09=20= CurrRunningXacts->latestCompletedXid,=0A-=09=09=09=20= CurrRunningXacts->nextXid);=0A-=09else=0A-=09=09elog(DEBUG2,=0A-=09=09=09= =20"snapshot=20of=20%d+%d=20running=20transaction=20ids=20(lsn=20%X/%X=20= oldest=20xid=20%u=20latest=20complete=20%u=20next=20xid=20%u)",=0A-=09=09= =09=20CurrRunningXacts->xcnt,=20CurrRunningXacts->subxcnt,=0A-=09=09=09=20= LSN_FORMAT_ARGS(recptr),=0A-=09=09=09=20= CurrRunningXacts->oldestRunningXid,=0A-=09=09=09=20= CurrRunningXacts->latestCompletedXid,=0A-=09=09=09=20= CurrRunningXacts->nextXid);=0A+=09elog(DEBUG2,=0A+=09=09=20"logging=20= running=20transaction=20bounds=20(lsn=20%X/%X=20oldest=20xid=20%u=20= latest=20complete=20%u=20next=20xid=20%u)",=0A+=09=09=20= LSN_FORMAT_ARGS(recptr),=0A+=09=09=20CurrRunningXacts->oldestRunningXid,=0A= +=09=09=20CurrRunningXacts->latestCompletedXid,=0A+=09=09=20= CurrRunningXacts->nextXid);=0A=20=0A=20=09/*=0A=20=09=20*=20Ensure=20= running_xacts=20information=20is=20synced=20to=20disk=20not=20too=20far=20= in=20the=0Adiff=20--git=20a/src/include/storage/standby.h=20= b/src/include/storage/standby.h=0Aindex=2024e2f5082bc..d73a8f58a73=20= 100644=0A---=20a/src/include/storage/standby.h=0A+++=20= b/src/include/storage/standby.h=0A@@=20-60,8=20+60,6=20@@=20extern=20= void=20StandbyReleaseLockTree(TransactionId=20xid,=0A=20extern=20void=20= StandbyReleaseAllLocks(void);=0A=20extern=20void=20= StandbyReleaseOldLocks(TransactionId=20oldxid);=0A=20=0A-#define=20= MinSizeOfXactRunningXacts=20offsetof(xl_running_xacts,=20xids)=0A-=0A=20=0A= =20/*=0A=20=20*=20Declarations=20for=20GetRunningTransactionData().=20= Similar=20to=20Snapshots,=20but=0Adiff=20--git=20= a/src/include/storage/standbydefs.h=20= b/src/include/storage/standbydefs.h=0Aindex=2071e5ae878b5..3d182b66e74=20= 100644=0A---=20a/src/include/storage/standbydefs.h=0A+++=20= b/src/include/storage/standbydefs.h=0A@@=20-42,20=20+42,24=20@@=20= typedef=20struct=20xl_standby_locks=0A=20}=20xl_standby_locks;=0A=20=0A=20= /*=0A-=20*=20When=20we=20write=20running=20xact=20data=20to=20WAL,=20we=20= use=20this=20structure.=0A+=20*=20Data=20included=20in=20an=20= XLOG_RUNNING_XACTS=20record.=0A+=20*=0A+=20*=20This=20used=20to=20= include=20a=20list=20of=20running=20XIDs,=20hence=20the=20name,=20but=20= nowadays=0A+=20*=20this=20only=20contains=20the=20min=20and=20max=20= bounds=20of=20the=20transactions=20that=20were=0A+=20*=20running=20when=20= the=20record=20was=20written.=20=20They=20are=20needed=20to=20initialize=20= logical=0A+=20*=20decoding.=20=20They=20are=20also=20used=20in=20hot=20= standby=20to=20prune=20information=20about=20old=0A+=20*=20running=20= transactions,=20in=20case=20the=20the=20primary=20didn't=20write=20a=20= COMMIT/ABORT=0A+=20*=20record=20for=20some=20reason.=0A=20=20*/=0A=20= typedef=20struct=20xl_running_xacts=0A=20{=0A-=09int=09=09=09xcnt;=09=09=09= /*=20#=20of=20xact=20ids=20in=20xids[]=20*/=0A-=09int=09=09=09subxcnt;=09= =09/*=20#=20of=20subxact=20ids=20in=20xids[]=20*/=0A-=09bool=09=09= subxid_overflow;=09/*=20snapshot=20overflowed,=20subxids=20missing=20*/=0A= =20=09TransactionId=20nextXid;=09=09/*=20xid=20from=20= TransamVariables->nextXid=20*/=0A=20=09TransactionId=20oldestRunningXid;=20= /*=20*not*=20oldestXmin=20*/=0A=20=09TransactionId=20latestCompletedXid;=09= /*=20so=20we=20can=20set=20xmax=20*/=0A-=0A-=09TransactionId=20= xids[FLEXIBLE_ARRAY_MEMBER];=0A=20}=20xl_running_xacts;=0A=20=0A+#define=20= SizeOfXactRunningXacts=20sizeof(xl_running_xacts)=0A+=0A=20/*=0A=20=20*=20= Invalidations=20for=20standby,=20currently=20only=20when=20transactions=20= without=20an=0A=20=20*=20assigned=20xid=20commit.=0A--=20=0A2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0012-Add-a-cache-to-Snapshot-to-avoid-repeated-CSN-loo.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0012-Add-a-cache-to-Snapshot-to-avoid-repeated-CSN-loo.patch" Content-Transfer-Encoding: quoted-printable =46rom=206b8e856c15750f89f9d559ae9f9fbd7f3f2db125=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Heikki=20Linnakangas=20= =0ADate:=20Tue,=201=20Apr=202025=2000:18:14=20= +0300=0ASubject:=20[PATCH=20v6=2012/12]=20Add=20a=20cache=20to=20= Snapshot=20to=20avoid=20repeated=20CSN=0A=20lookups=0A=0ACache=20the=20= status=20of=20all=20XIDs=20that=20have=20been=20looked=20up=20in=20the=20= CSN=20log=0Ain=20the=20SnapshotData.=20This=20avoids=20having=20to=20go=20= the=20CSN=20log=20in=20the=0Acommon=20case=20that=20the=20same=20XIDs=20= are=20looked=20up=20over=20and=20over=20again.=0A---=0A=20= src/backend/utils/time/snapmgr.c=20|=20111=20= +++++++++++++++++++++++++++++--=0A=20src/include/utils/snapshot.h=20=20=20= =20=20|=20=20=209=20+++=0A=202=20files=20changed,=20116=20insertions(+),=20= 4=20deletions(-)=0A=0Adiff=20--git=20a/src/backend/utils/time/snapmgr.c=20= b/src/backend/utils/time/snapmgr.c=0Aindex=20049c706f2cf..250ba1650e4=20= 100644=0A---=20a/src/backend/utils/time/snapmgr.c=0A+++=20= b/src/backend/utils/time/snapmgr.c=0A@@=20-114,6=20+114,35=20@@=0A=20= #include=20"utils/snapmgr.h"=0A=20#include=20"utils/syscache.h"=0A=20=0A= +/*=0A+=20*=20Define=20a=20radix=20tree=20implementation=20to=20cache=20= CSN=20lookups=20in=20a=20snapshot.=0A+=20*=0A+=20*=20We=20need=20only=20= one=20bit=20of=20information=20for=20each=20XID=20stored=20in=20the=20= cache:=20was=0A+=20*=20the=20XID=20running=20or=20not.=20=20However,=20= the=20radix=20tree=20implementation=20uses=208=0A+=20*=20bytes=20for=20= each=20entry=20(on=2064-bit=20machines)=20even=20if=20the=20value=20type=20= is=20smaller=0A+=20*=20than=20that.=20=20To=20reduce=20memory=20usage,=20= we=20use=20uint64=20as=20the=20value=20type,=20and=0A+=20*=20store=20= multiple=20XIDs=20in=20each=20value.=0A+=20*=0A+=20*=20The=2064-bit=20= value=20word=20holds=20two=20bits=20for=20each=20XID:=20whether=20the=20= XID=20is=0A+=20*=20present=20in=20the=20cache=20or=20not,=20and=20if=20= it's=20present,=20whether=20it's=20considered=0A+=20*=20as=20in-progress=20= by=20the=20snapshot=20or=20not.=20=20So=20each=20entry=20in=20the=20= radix=20tree=0A+=20*=20holds=20the=20status=20for=2032=20XIDs.=0A+=20*/=0A= +#define=20RT_PREFIX=20inprogress_cache=0A+#define=20RT_SCOPE=0A+#define=20= RT_DECLARE=0A+#define=20RT_DEFINE=0A+#define=20RT_VALUE_TYPE=20uint64=0A= +#include=20"lib/radixtree.h"=0A+=0A+#define=20INPROGRESS_CACHE_BITS=202=0A= +#define=20INPROGRESS_CACHE_XIDS_PER_WORD=2032=0A+=0A+#define=20= INPROGRESS_CACHE_XID_IS_CACHED(word,=20slotno)=20\=0A+=09((((word)=20&=20= (UINT64CONST(1)=20<<=20(slotno))))=20!=3D=200)=0A+=0A+#define=20= INPROGRESS_CACHE_XID_IS_IN_PROGRESS(word,=20slotno)=20\=0A+=09((((word)=20= &=20(UINT64CONST(1)=20<<=20((slotno)=20+=201))))=20!=3D=200)=0A=20=0A=20= /*=0A=20=20*=20CurrentSnapshot=20points=20to=20the=20only=20snapshot=20= taken=20in=20transaction-snapshot=0A@@=20-240,6=20+269,7=20@@=20typedef=20= struct=20SerializedSnapshotData=0A=20=09int32=09=09subxcnt;=0A=20=09bool=09= =09suboverflowed;=0A=20=09bool=09=09takenDuringRecovery;=0A+=09= XLogRecPtr=09snapshotCsn;=0A=20=09CommandId=09curcid;=0A=20}=20= SerializedSnapshotData;=0A=20=0A@@=20-1177,6=20+1207,7=20@@=20= ExportSnapshot(MVCCSnapshotShared=20snapshot)=0A=20=09=09=09= appendStringInfo(&buf,=20"sxp:%u\n",=20children[i]);=0A=20=09}=0A=20=09= appendStringInfo(&buf,=20"rec:%u\n",=20snapshot->takenDuringRecovery);=0A= +=09appendStringInfo(&buf,=20"snapshotcsn:%X/%X\n",=20= LSN_FORMAT_ARGS(snapshot->snapshotCsn));=0A=20=0A=20=09/*=0A=20=09=20*=20= Now=20write=20the=20text=20representation=20into=20a=20file.=20=20We=20= first=20write=20to=20a=0A@@=20-1449,6=20+1480,7=20@@=20= ImportSnapshot(const=20char=20*idstr)=0A=20=09}=0A=20=0A=20=09= snapshot->takenDuringRecovery=20=3D=20parseIntFromText("rec:",=20= &filebuf,=20path);=0A+=09snapshot->snapshotCsn=20=3D=20= parseIntFromText("snapshotcsn:",=20&filebuf,=20path);=0A=20=0A=20=09= snapshot->refcount=20=3D=201;=0A=20=09= valid_snapshots_push_out_of_order(snapshot);=0A@@=20-1702,6=20+1734,7=20= @@=20SerializeSnapshot(MVCCSnapshot=20snapshot,=20char=20*start_address)=0A= =20=09serialized_snapshot.subxcnt=20=3D=20snapshot->shared->subxcnt;=0A=20= =09serialized_snapshot.suboverflowed=20=3D=20= snapshot->shared->suboverflowed;=0A=20=09= serialized_snapshot.takenDuringRecovery=20=3D=20= snapshot->shared->takenDuringRecovery;=0A+=09= serialized_snapshot.snapshotCsn=20=3D=20snapshot->shared->snapshotCsn;=0A= =20=09serialized_snapshot.curcid=20=3D=20snapshot->curcid;=0A=20=0A=20=09= /*=0A@@=20-1776,6=20+1809,9=20@@=20RestoreSnapshot(char=20= *start_address)=0A=20=09snapshot->shared->subxcnt=20=3D=20= serialized_snapshot.subxcnt;=0A=20=09snapshot->shared->suboverflowed=20=3D= =20serialized_snapshot.suboverflowed;=0A=20=09= snapshot->shared->takenDuringRecovery=20=3D=20= serialized_snapshot.takenDuringRecovery;=0A+=09= snapshot->shared->snapshotCsn=20=3D=20serialized_snapshot.snapshotCsn;=0A= +=09snapshot->shared->inprogress_cache=20=3D=20NULL;=0A+=09= snapshot->shared->inprogress_cache_cxt=20=3D=20NULL;=0A=20=09= snapshot->shared->snapXactCompletionCount=20=3D=200;=0A=20=0A=20=09= snapshot->shared->refcount=20=3D=201;=0A@@=20-1889,12=20+1925,62=20@@=20= XidInMVCCSnapshot(TransactionId=20xid,=20MVCCSnapshotShared=20snapshot)=0A= =20=09}=0A=20=09else=0A=20=09{=0A-=09=09XLogRecPtr=09csn=20=3D=20= CSNLogGetCSNByXid(xid);=0A+=09=09XLogRecPtr=09csn;=0A+=09=09bool=09=09= inprogress;=0A+=09=09uint64=09=20=20=20*cache_entry;=0A+=09=09uint64=09=09= cache_word=20=3D=200;=0A=20=0A-=09=09if=20(csn=20!=3D=20= InvalidXLogRecPtr=20&&=20csn=20<=3D=20snapshot->snapshotCsn)=0A-=09=09=09= return=20false;=0A+=09=09/*=0A+=09=09=20*=20Calculate=20the=20word=20and=20= bit=20slot=20for=20the=20XID=20in=20the=20cache.=20We=20use=20an=0A+=09=09= =20*=20offset=20from=20xmax=20as=20the=20key=20instead=20of=20the=20XID=20= directly,=20because=0A+=09=09=20*=20the=20radix=20tree=20can=20compact=20= away=20leading=20zeros=20and=20is=20thus=20more=0A+=09=09=20*=20= efficient=20with=20keys=20closer=20to=200.=0A+=09=09=20*/=0A+=09=09= uint32=09=09cache_idx=20=3D=20snapshot->xmax=20-=20xid;=0A+=09=09uint64=09= =09wordno=20=3D=20cache_idx=20/=20INPROGRESS_CACHE_XIDS_PER_WORD;=0A+=09=09= uint64=09=09slotno=20=3D=20(cache_idx=20%=20= INPROGRESS_CACHE_XIDS_PER_WORD)=20*=20INPROGRESS_CACHE_BITS;=0A+=0A+=09=09= if=20(snapshot->inprogress_cache)=0A+=09=09{=0A+=09=09=09cache_entry=20=3D= =20inprogress_cache_find(snapshot->inprogress_cache,=20wordno);=0A+=09=09= =09if=20(cache_entry)=0A+=09=09=09{=0A+=09=09=09=09cache_word=20=3D=20= *cache_entry;=0A+=09=09=09=09if=20= (INPROGRESS_CACHE_XID_IS_CACHED(cache_word,=20slotno))=0A+=09=09=09=09=09= return=20INPROGRESS_CACHE_XID_IS_IN_PROGRESS(cache_word,=20slotno);=0A+=09= =09=09}=0A+=09=09}=0A=20=09=09else=0A-=09=09=09return=20true;=0A+=09=09{=0A= +=09=09=09MemoryContext=20save_cxt;=0A+=0A+=09=09=09save_cxt=20=3D=20= MemoryContextSwitchTo(TopMemoryContext);=0A+=0A+=09=09=09if=20= (snapshot->inprogress_cache_cxt=20=3D=3D=20NULL)=0A+=09=09=09=09= snapshot->inprogress_cache_cxt=20=3D=0A+=09=09=09=09=09= AllocSetContextCreate(TopMemoryContext,=0A+=09=09=09=09=09=09=09=09=09=09= =20=20"snapshot=20inprogress=20cache=20context",=0A+=09=09=09=09=09=09=09= =09=09=09=20=20ALLOCSET_SMALL_SIZES);=0A+=09=09=09= snapshot->inprogress_cache=20=3D=20= inprogress_cache_create(snapshot->inprogress_cache_cxt);=0A+=09=09=09= cache_entry=20=3D=20NULL;=0A+=09=09=09MemoryContextSwitchTo(save_cxt);=0A= +=09=09}=0A+=0A+=09=09/*=20Not=20found=20in=20cache,=20look=20up=20the=20= CSN=20*/=0A+=09=09csn=20=3D=20CSNLogGetCSNByXid(xid);=0A+=09=09= inprogress=20=3D=20(csn=20=3D=3D=20InvalidXLogRecPtr=20||=20csn=20>=20= snapshot->snapshotCsn);=0A+=0A+=09=09/*=20Update=20the=20cache=20word,=20= and=20store=20it=20back=20to=20the=20radix=20tree=20*/=0A+=09=09= cache_word=20|=3D=20UINT64CONST(1)=20<<=20slotno;=20/*=20cached=20*/=0A+=09= =09if=20(inprogress)=0A+=09=09=09cache_word=20|=3D=20UINT64CONST(1)=20<<=20= (slotno=20+=201);=09/*=20in-progress=20*/=0A+=0A+=09=09if=20= (cache_entry)=0A+=09=09=09*cache_entry=20=3D=20cache_word;=0A+=09=09else=0A= +=09=09=09inprogress_cache_set(snapshot->inprogress_cache,=20wordno,=20= &cache_word);=0A+=0A+=09=09return=20inprogress;=0A=20=09}=0A=20=0A=20=09= return=20false;=0A@@=20-1944,6=20+2030,9=20@@=20= AllocMVCCSnapshotShared(void)=0A=20=0A=20=09= shared->snapXactCompletionCount=20=3D=200;=0A=20=09shared->refcount=20=3D=20= 0;=0A+=09shared->snapshotCsn=20=3D=20InvalidXLogRecPtr;=0A+=09= shared->inprogress_cache=20=3D=20NULL;=0A+=09= shared->inprogress_cache_cxt=20=3D=20NULL;=0A=20=0A=20=09= MemoryContextSwitchTo(save_cxt);=0A=20=0A@@=20-1972,8=20+2061,22=20@@=20= void=0A=20FreeMVCCSnapshotShared(MVCCSnapshotShared=20shared)=0A=20{=0A=20= =09Assert(shared->refcount=20=3D=3D=200);=0A+=0A+=09if=20= (shared->inprogress_cache)=0A+=09{=0A+=09=09= inprogress_cache_free(shared->inprogress_cache);=0A+=09=09= shared->inprogress_cache=20=3D=20NULL;=0A+=09}=0A+=09if=20= (shared->inprogress_cache_cxt)=0A+=09{=0A+=09=09= MemoryContextDelete(shared->inprogress_cache_cxt);=0A+=09=09= shared->inprogress_cache_cxt=20=3D=20NULL;=0A+=09}=0A+=0A=20=09if=20= (spareSnapshotShared=20=3D=3D=20NULL)=0A+=09{=0A=20=09=09= spareSnapshotShared=20=3D=20shared;=0A+=09}=0A=20=09else=0A=20=09=09= pfree(shared);=0A=20}=0Adiff=20--git=20a/src/include/utils/snapshot.h=20= b/src/include/utils/snapshot.h=0Aindex=2014ff80904c8..edf5bf1ba0a=20= 100644=0A---=20a/src/include/utils/snapshot.h=0A+++=20= b/src/include/utils/snapshot.h=0A@@=20-129,6=20+129,8=20@@=20typedef=20= enum=20MVCCSnapshotKind=0A=20=09SNAPSHOT_REGISTERED,=0A=20}=20= MVCCSnapshotKind;=0A=20=0A+struct=20inprogress_cache_radix_tree;=20/*=20= private=20to=20snapmgr.c=20*/=0A+=0A=20/*=0A=20=20*=20Struct=20= representing=20a=20normal=20MVCC=20snapshot.=0A=20=20*=0A@@=20-194,6=20= +196,13=20@@=20typedef=20struct=20MVCCSnapshotSharedData=0A=20=09=20*/=0A= =20=09XLogRecPtr=09snapshotCsn;=0A=20=0A+=09/*=0A+=09=20*=20Cache=20of=20= XIDs=20known=20to=20be=20running=20or=20not=20according=20to=20the=20= snapshot.=0A+=09=20*=20Used=20in=20snapshots=20taken=20during=20= recovery.=0A+=09=20*/=0A+=09struct=20inprogress_cache_radix_tree=20= *inprogress_cache;=0A+=09MemoryContext=20inprogress_cache_cxt;=0A+=0A=20=09= bool=09=09takenDuringRecovery;=09/*=20recovery-shaped=20snapshot?=20*/=0A= =20=0A=20=09/*=0A--=20=0A2.39.5=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii
--Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Disposition: attachment; filename=v7-0013-use-clog-in-XidInMVCCSnapshot.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v7-0013-use-clog-in-XidInMVCCSnapshot.patch" Content-Transfer-Encoding: quoted-printable =46rom=205cbb8e5806a444df04ed2f54d1c45f4aa1ea8f7b=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mingwei=20Jia=20=0ADate:=20= Sat,=2012=20Apr=202025=2021:10:44=20+0800=0ASubject:=20[PATCH]=20If=20= the=20checkpoint's=20oldestActiveXid=20at=20standby=20startup=20is=0A=20= less=20than=20nextXid,=20then=20the=20visibility=20of=20transactions=20= within=20that=20range=0A=20should=20be=20determined=20using=20the=20= CLOG.=20This=20is=20because=20there=20may=20be=0A=20transactions=20in=20= that=20range=20that=20have=20already=20committed=20on=20the=20primary,=20= and=0A=20these=20committed=20transactions=20will=20not=20be=20replayed=20= again=20on=20the=20standby.=0A=0A---=0A=20= src/backend/access/transam/xlog.c=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=202=20++=0A=20src/backend/storage/ipc/procarray.c=20=20=20=20=20=20=20= =20=20=20=20|=20=204=20+++=0A=20src/backend/utils/time/snapmgr.c=20=20=20= =20=20=20=20=20=20=20=20=20=20=20|=2012=20++++++++=0A=20= src/include/access/transam.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=202=20++=0A=20src/include/storage/procarray.h=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20|=20=202=20++=0A=20= .../modules/test_misc/t/008_csnstandby.pl=20=20=20=20=20|=2030=20= +++++++++++++++++++=0A=206=20files=20changed,=2052=20insertions(+)=0A=20= create=20mode=20100644=20src/test/modules/test_misc/t/008_csnstandby.pl=0A= =0Adiff=20--git=20a/src/backend/access/transam/xlog.c=20= b/src/backend/access/transam/xlog.c=0Aindex=20deb2cd1883c..2796458491d=20= 100644=0A---=20a/src/backend/access/transam/xlog.c=0A+++=20= b/src/backend/access/transam/xlog.c=0A@@=20-5565,6=20+5565,8=20@@=20= StartupXLOG(void)=0A=20=09TransamVariables->nextXid=20=3D=20= checkPoint.nextXid;=0A=20=09TransamVariables->nextOid=20=3D=20= checkPoint.nextOid;=0A=20=09TransamVariables->oidCount=20=3D=200;=0A+=09= TransamVariables->nextXidStandbyStart=20=3D=0A+=09=09=09=09=09= XidFromFullTransactionId(checkPoint.nextXid);=0A=20=09= MultiXactSetNextMXact(checkPoint.nextMulti,=20= checkPoint.nextMultiOffset);=0A=20=09= AdvanceOldestClogXid(checkPoint.oldestXid);=0A=20=09= SetTransactionIdLimit(checkPoint.oldestXid,=20checkPoint.oldestXidDB);=0A= diff=20--git=20a/src/backend/storage/ipc/procarray.c=20= b/src/backend/storage/ipc/procarray.c=0Aindex=20c82e8d8c438..d4c67512c56=20= 100644=0A---=20a/src/backend/storage/ipc/procarray.c=0A+++=20= b/src/backend/storage/ipc/procarray.c=0A@@=20-962,6=20+962,10=20@@=20= ProcArrayUpdateOldestRunningXid(TransactionId=20oldestRunningXID)=0A=20=09= procArray->oldest_running_primary_xid=20=3D=20oldestRunningXID;=0A=20=09= LWLockRelease(ProcArrayLock);=0A=20}=0A+TransactionId=20= GetOldestRunningXid(void)=0A+{=0A+=09return=20=09= procArray->oldest_running_primary_xid;=0A+}=0A=20=0A=20=0A=20/*=0Adiff=20= --git=20a/src/backend/utils/time/snapmgr.c=20= b/src/backend/utils/time/snapmgr.c=0Aindex=20df9e8ba37f4..0ebcb0af835=20= 100644=0A---=20a/src/backend/utils/time/snapmgr.c=0A+++=20= b/src/backend/utils/time/snapmgr.c=0A@@=20-1969,6=20+1969,18=20@@=20= XidInMVCCSnapshot(TransactionId=20xid,=20Snapshot=20snapshot)=0A=20=09=09= uint32=09=09cache_idx=20=3D=20snapshot->xmax=20-=20xid;=0A=20=09=09= uint64=09=09wordno=20=3D=20cache_idx=20/=20= INPROGRESS_CACHE_XIDS_PER_WORD;=0A=20=09=09uint64=09=09slotno=20=3D=20= (cache_idx=20%=20INPROGRESS_CACHE_XIDS_PER_WORD)=20*=20= INPROGRESS_CACHE_BITS;=0A+=09=09TransactionId=20nextXidStart=20=3D=20= TransamVariables->nextXidStandbyStart;=0A+=09=09TransactionId=20= oldestRunning=20=3D=20GetOldestRunningXid();=0A+=0A+=09=09if=20= (TransactionIdPrecedes(oldestRunning,=20nextXidStart)=0A+=09=09=09&&=20= TransactionIdPrecedes(xid,=20nextXidStart))=0A+=09=09{=0A+=09=09=09if=20= (TransactionIdDidCommit(xid)=20||=20TransactionIdDidAbort(xid))=0A+=09=09= =09{=0A+=09=09=09=09return=20false;=0A+=09=09=09}=0A+=09=09=09return=20= true;=0A+=09=09}=0A=20=0A=20=09=09if=20(snapshot->inprogress_cache)=0A=20= =09=09{=0Adiff=20--git=20a/src/include/access/transam.h=20= b/src/include/access/transam.h=0Aindex=20a7054fe11cd..a75d66f4d40=20= 100644=0A---=20a/src/include/access/transam.h=0A+++=20= b/src/include/access/transam.h=0A@@=20-240,6=20+240,8=20@@=20typedef=20= struct=20TransamVariablesData=0A=20=0A=20=09/*=20During=20recovery,=20= LSN=20of=20latest=20replayed=20commit=20record=20*/=0A=20=09XLogRecPtr=09= latestCommitLSN;=0A+=09/*=20checkpoint`s=20next=20xid=20when=20= hot-standby=20start=20*/=0A+=09TransactionId=20nextXidStandbyStart;=0A=20= =0A=20=09/*=0A=20=09=20*=20Number=20of=20top-level=20transactions=20with=20= xids=20(i.e.=20which=20may=20have=0Adiff=20--git=20= a/src/include/storage/procarray.h=20b/src/include/storage/procarray.h=0A= index=20de74fce24e4..a4129de8101=20100644=0A---=20= a/src/include/storage/procarray.h=0A+++=20= b/src/include/storage/procarray.h=0A@@=20-29,6=20+29,8=20@@=20extern=20= void=20ProcArrayEndTransaction(PGPROC=20*proc,=20TransactionId=20= latestXid);=0A=20extern=20void=20ProcArrayClearTransaction(PGPROC=20= *proc);=0A=20=0A=20extern=20void=20= ProcArrayUpdateOldestRunningXid(TransactionId=20oldestRunningXID);=0A+=0A= +extern=20TransactionId=20GetOldestRunningXid(void);=0A=20extern=20void=20= ProcArrayInitRecovery(TransactionId=20initializedUptoXID);=0A=20=0A=20= extern=20void=20RecordKnownAssignedTransactionIds(TransactionId=20xid);=0A= diff=20--git=20a/src/test/modules/test_misc/t/008_csnstandby.pl=20= b/src/test/modules/test_misc/t/008_csnstandby.pl=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..98708490d91=0A---=20/dev/null=0A+++=20= b/src/test/modules/test_misc/t/008_csnstandby.pl=0A@@=20-0,0=20+1,30=20= @@=0A+=0A+use=20strict;=0A+use=20warnings=20FATAL=20=3D>=20'all';=0A+use=20= PostgreSQL::Test::Cluster;=0A+use=20PostgreSQL::Test::Utils;=0A+use=20= Test::More;=0A+=0A+my=20$primary=20=3D=20= PostgreSQL::Test::Cluster->new('primary');=0A+$primary->init();=0A= +$primary->append_conf('postgresql.conf',=20'max_wal_senders=20=3D=20= 5');=0A+$primary->append_conf('postgresql.conf',=20'wal_level=3Dreplica');= =0A+$primary->start;=0A+my=20$count=20=3D=20'';=0A= +$primary->safe_psql('postgres',=20'create=20table=20t1(i=20int,=20j=20= int)');=0A+=0A+my=20$primary_a=20=3D=20=20= $primary->background_psql('postgres',=20on_error_die=20=3D>=201);=0A= +$primary_a->query_safe("begin");=0A+$primary_a->query_safe("insert=20= into=20t1=20values(1,1)");=0A+$primary->safe_psql('postgres',=20'insert=20= into=20t1=20values(2,1)');=0A+$primary->backup('bkp');=0A+=0A+my=20= $replica=20=3D=20PostgreSQL::Test::Cluster->new('replica');=0A= +$replica->init_from_backup($primary,=20'bkp',=20has_streaming=20=3D>=20= 1);=0A+$replica->start;=0A+=0A+$count=20=3D=20= $replica->safe_psql('postgres',=20"select=20count(*)=20from=20t1");=0A= +is($count,=20'1',=20"get=20right=20visiablity=20before=20primary=20= checkpoint=20in=20hot=20standby");=0A+=0A+done_testing();=0A+=0A--=0A= 2.45.0=0A=0A= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8


2025=E5=B9=B44=E6=9C=881=E6=97=A5 05:31=EF=BC=8CHeikki = Linnakangas <hlinnaka@iki.fi> =E5=86=99=E9=81=93=EF=BC=9A

Here's a new patchset = version. Not much has changed in the actual CSN patches. But I spent a = lot of time refactoring the snapshot management code, so that there is a = simple place to add the "inprogress XID cache" for the CSN snapshots, in = a way that avoids duplicating the cache if a snapshot is copied = around.

Patches 0001-0002 are the patches I posted on a separate = thread earlier. See = https://www.postgresql.org/message-id/ec10d398-c9b3-4542-8095-5fc6408b17d1= %40iki.fi.

Patches 0003-0006 contain more snapshot manager = changes. The end state is that an MVCC snapshot consists of two structs: = a shared "inner" struct that contains xmin, xmax and the XID lists, and = an "outer" struct that contains a pointer to the shared struct and the = current command ID. As a snapshot is copied around, all the copies share = the same shared, reference-counted struct.

The rest of the = patches are the same CSN patches I posted before, rebased over the = snapshot manager changes.


There's one thing that hasn't been = discussed yet: The ProcArrayRecoveryEndTransaction() function, which = replaces ExpireTreeKnownAssignedTransactionIds() and is called on replay = of every commit/abort record, does this:

= /*
= * If this was the oldest XID that was still running, advance it. = This is
= * important for advancing the global xmin, which avoids = unnecessary
= * recovery conflicts
*
* No = locking required because this runs in the startup process.
= *
= * XXX: the caller actually has a list of XIDs that just committed. = We
= * could save some clog lookups by taking advantage of that = list.
= */
= oldest_running_primary_xid =3D = procArray->oldest_running_primary_xid;
while = (oldest_running_primary_xid < max_xid)
= {
= = if (!TransactionIdDidCommit(oldest_running_primary_xid) = &&
= = = !TransactionIdDidAbort(oldest_running_primary_xid))
= {
= = = break;
= = }
= = TransactionIdAdvance(oldest_running_primary_xid);
= }
= if (max_xid =3D=3D oldest_running_primary_xid)
= TransactionIdAdvance(oldest_running_primary_xid);
<= br>The point is to maintain an "oldest xmin" value based on the WAL = records that are being replayed. Whenever the currently oldest running = XID finishes, we scan the CLOG to find the next oldest XID that hasn't = completed yet.

That adds approximately one or two CLOG lookup to = every commit record replay on average. I haven't tried measuring that, = but it seems like it could slow down recovery. There are ways that could = be improved. For example, do it in larger batches.


A bunch of = other small XXX comments remain, but they're just markers for comments = that need to be adjusted, or for further cleanups that are now = possible.


There are also several ways the inprogress cache = could be made more efficient, which I haven't explored:

- For = each XID in the cache radix tree, we store one bit to indicate whether = the lookup has been performed, i.e. if the cache is valid for the XID, = and another bit to indicate if the XID is visible or not. With 64-bit = cache words stored in the radix tree, each cache word can store the = status of 32 transactions. It would probably be better to work in bigger = chunks. For example, when doing a lookup in the cache, check the status = of 64 transactions at once. Assuming they're all stored on the same CSN = page, it would not be much more expensive than a single XID lookup. That = would make the cache 2x more compact, and save on future lookups of XIDS = falling on the same cache word.

- Initializing the radix tree = cache is fairly expensive, with several memory allocations. Many of = those allocations could be done lazily with some effort in = radixtree.h.

- Or start the cache as a small array of XIDs, and = switch to the radix tree only after it fills up.

--
Heikki = Linnakangas
Neon (https://neon.tech)
<v6-0001-Split-Snapshot= Data-into-separate-structs-for-each.patch><v6-0002-Simplify-histo= ric-snapshot-refcounting.patch><v6-0003-Add-an-explici= t-valid-flag-to-MVCCSnapshotData.patch><v6-0004-Replace-static= -snapshot-pointers-with-the-valid-f.patch><v6-0005-Make-RestoreSn= apshot-register-the-snapshot-with-c.patch><v6-0006-Replace-the-Re= gisteredSnapshot-pairing-heap-with-.patch><v6-0007-Split-MVCCSnap= shot-into-inner-and-outer-parts.patch><v6-0008-XXX-add-perf-t= est.patch><v6-0009-Use-CSN-snapsh= ots-during-Hot-Standby.patch><v6-0010-Make-SnapBuild= WaitSnapshot-work-without-xl_runnin.patch><v6-0011-Remove-the-now= -unused-xids-array-from-xl_running_.patch><v6-0012-Add-a-cache-to= -Snapshot-to-avoid-repeated-CSN-loo.patch>

= --Apple-Mail=_07B18977-1F84-40C2-8D70-167C552FE794-- --Apple-Mail=_ED800A29-636A-4AE7-B7C0-FC8948D9BD53--