Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vSXme-0009YN-1x for pgsql-hackers@arkaria.postgresql.org; Mon, 08 Dec 2025 09:43:57 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vSXmc-00G3ra-03 for pgsql-hackers@arkaria.postgresql.org; Mon, 08 Dec 2025 09:43:54 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vSXmb-00G3rR-07 for pgsql-hackers@lists.postgresql.org; Mon, 08 Dec 2025 09:43:53 +0000 Received: from smtp.outgoing.loopia.se ([93.188.3.37]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vSXmW-003jVH-0W for pgsql-hackers@postgresql.org; Mon, 08 Dec 2025 09:43:52 +0000 Received: from s807.loopia.se (localhost [127.0.0.1]) by s807.loopia.se (Postfix) with ESMTP id B8249489852 for ; Mon, 08 Dec 2025 10:43:29 +0100 (CET) Received: from s979.loopia.se (unknown [172.22.191.5]) by s807.loopia.se (Postfix) with ESMTP id A93A048C396; Mon, 08 Dec 2025 10:43:29 +0100 (CET) Received: from localhost (unknown [172.22.191.5]) by s979.loopia.se (Postfix) with ESMTP id A536110BC3C6; Mon, 08 Dec 2025 10:43:29 +0100 (CET) X-Virus-Scanned: amavis at amavis.loopia.se X-Spam-Flag: NO X-Spam-Score: -1.2 X-Spam-Level: X-Spam-Status: No, score=-1.2 tagged_above=-999 required=6.2 tests=[ALL_TRUSTED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1] autolearn=disabled Authentication-Results: s470.loopia.se (amavis); dkim=pass (2048-bit key) header.d=yesql.se Received: from s981.loopia.se ([172.22.191.5]) by localhost (s470.loopia.se [172.22.190.34]) (amavis, port 10024) with LMTP id zXTKOFZ69vZV; Mon, 8 Dec 2025 10:43:29 +0100 (CET) X-Loopia-Auth: user X-Loopia-User: daniel@yesql.se X-Loopia-Originating-IP: 89.255.232.236 Received: from smtpclient.apple (customer-89-255-232-236.stosn.net [89.255.232.236]) (Authenticated sender: daniel@yesql.se) by s981.loopia.se (Postfix) with ESMTPSA id D7C1422B178D; Mon, 08 Dec 2025 10:43:28 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yesql.se; s=loopiadkim1707475645; t=1765187008; bh=nR2MaJ/gQLS9b6yykRd3HJByLHaI0tFaUrYu2l8QEo8=; h=From:Subject:Date:In-Reply-To:Cc:To:References; b=JQaPoGDkpPDsYxkK/nk88xMZi6YtzDDRVos2PX86YrfvYpF7slE6Ls41wxOYKWO5T aUdWQqjyum9hh7iFCy3mpxfMfo3MnEU5HZ6D9fZ/JNfqJPP5nAfSg2EVX4kNoipFC2 EZzAPhqOBVsp9pDkbrMuHsq6kGmp2WY30XCkIwzQGgIe9WJpLCMz4lHyLpmdUSurKZ EdYul9QUi03fzT738jqN0MfTXIK0H1gZfSLCfiW2B9u7bFJ/7cSTVWG0Ys9seTMx8Q oa2MZg8PT0hQeJciu4rub6K67bGL1fi0YOPMKp1vX43Q3v8SL2C2HAmFqw5cphiRDr VFvzQrrL9f2MQ== From: Daniel Gustafsson Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_21AB57B4-9CC2-4353-9F79-C3685A4FC23C" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3776.700.51.11.2\)) Subject: Re: Enhancing Memory Context Statistics Reporting Date: Mon, 8 Dec 2025 10:43:18 +0100 In-Reply-To: Cc: PostgreSQL Hackers , torikoshia To: Rahila Syed References: <54FAE93D-E156-4684-9352-1CEDE6BD4A1C@yesql.se> <5bxhxniyvjyfldi7yjxcnxkl3i2ghci2grjyeclrbkfqnyhowk@dfkqzbvtbpml> <3eb40b3e-45c7-426a-b7f8-81f7d05a9b53@oss.nttdata.com> <74105887-E4EF-4CA2-9F0A-3C0CE05BF632@yesql.se> <437100f2-dd86-42e6-830c-5ff413a25e8e@oss.nttdata.com> <2a796830-de2d-4030-b480-d673f6cc5d94@eisentraut.org> <02E42650-0C66-4B49-93CA-1B0A5B73E7FD@yesql.se> X-Mailer: Apple Mail (2.3776.700.51.11.2) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_21AB57B4-9CC2-4353-9F79-C3685A4FC23C Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On 28 Nov 2025, at 10:22, Rahila Syed wrote: >=20 > Hi, >=20 > I'm attaching the updated patches, which primarily include cleanup and = have been rebased > following the CFbot report. =20 Thanks for the patch, below are a few comments and suggestions. As I = was reviewing I tweaked the below and have attached the comments as changes = in 0003. =3D=3D in func-admin.sgml + pg_get_process_memory_contexts ( = pid integer, = summary boolean ) We recently simplified the UI by removing the timeout, and the more I = think about it the more I am convinced that there is more simplification to be = had. The most likely usage pattern, IMO, will be to get all the contexts and = not the summary, so we can make the summary parameter DEFAULT to false. This = allows most uses to just pass the pid, without complicating the code at all. =3D=3D in mcxtfuncs.c +/* Size of dshash key */ +#define CLIENT_KEY_SIZE 32 That's still pretty generous isn't it? We are printing a uint32 into it = so the highest number it can reach is ~4 billion (which while the upper limit, = is quite theoretic in this case). 10 + 1 bytes should suffice to store = right? - * MemoryContextId + * MemoryStatsContextId Sorry, but I still don't agree with this rename and I think we should = skip it, if only to avoid changes to existing parts of the code. + * Entry has been deleted due to client process exit. Make sure that = the + * client always deletes the entry after taking required lock or = this + * function may end up writing to unallocated memory. Can you explain this a bit further, I'm not sure I get it. The code = goes on to release a lock immediately and then destroys the hash. Who is = responsible for destroying the entry? =3D=3D In system-views.sql +REVOKE EXECUTE ON FUNCTION + pg_get_process_memory_contexts(integer, boolean) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION + pg_get_process_memory_contexts(integer, boolean) TO = pg_read_all_stats; This is not a view, and the functions aren't used to drive a view, so = these should not be defined here. The above mentioned change to add DEFAULT = handling to the summary parameter fixes this in the attached. =3D=3D In ProcessGetMemoryContextInterrupt() I'm not a fan of having to exit's from the function doing duplicative = cleanups, in the attached I've wrapped them in a conditional to just have one exit = path. What do you think about that? =3D=3D In PublishMemoryContext() + end_memorycontext_reporting(entry, oldcontext, context_id_lookup); Looking at this more I don't really like that resetting the memory = context is done via a separate function, when that function must be called from the = exact right place to ensure CurrentMemoryContext is what it thinks it is. = It's all a bit too magic. Since this is only called in 3 places I would prefer to = inline the code in PublishMemoryContext(). =3D=3D In PublishMemoryContext() + const char *ident =3D context->ident; + const char *name =3D context->name; ident and name are defined as const, but they are later assigned to = after the initial assignment. I think we need to unconstify these. =3D=3D In PublishMemoryContext() + if (strlen(name) >=3D MEMORY_CONTEXT_NAME_SHMEM_SIZE) We already have namelen which is set to exactly strlen(name), so let's = reuse that for readability. =3D=3D In PublishMemoryContext() + /* Allocate DSA memory for storing path information */ This comment is no longer accurate is it? The DSA has already been = allocated at this point. =3D=3D In memutils.h +#include "utils/dsa.h" This is not needed. I also did some smaller comment rewording and reflowing, some smaller = cleanups and a fresh pgindent/pgperltidy run. The attached 0003 contains the = above. -- Daniel Gustafsson --Apple-Mail=_21AB57B4-9CC2-4353-9F79-C3685A4FC23C Content-Disposition: attachment; filename=v43-0001-Add-function-to-report-memory-context-statistics.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v43-0001-Add-function-to-report-memory-context-statistics.patch" Content-Transfer-Encoding: quoted-printable =46rom=208f50ab607db07dc125fda2831e1d234c2a630ccb=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Rahila=20Syed=20=0A= Date:=20Thu,=2027=20Nov=202025=2014:39:43=20+0530=0ASubject:=20[PATCH=20= v43=201/3]=20Add=20function=20to=20report=20memory=20context=20= statistics=0A=0AThis=20adds=20a=20function=20for=20retrieving=20memory=20= context=20statistics=0Aand=20information=20from=20backends=20as=20well=20= as=20auxiliary=20processes.=0AThe=20intended=20usecase=20is=20cluster=20= debugging=20when=20under=20memory=0Apressure=20or=20unanticipated=20= memory=20usage=20characteristics.=0A=0AWhen=20calling=20the=20function=20= it=20sends=20a=20signal=20to=20the=20specified=0Aprocess=20to=20submit=20= statistics=20regarding=20its=20memory=20contexts=0Ainto=20dynamic=20= shared=20memory.=20=20Each=20memory=20context=20is=20returned=0Ain=20= detail,=20followed=20by=20a=20cumulative=20total=20in=20case=20the=20= number=0Aof=20contexts=20exceed=20the=20max=20allocated=20amount=20of=20= shared=20memory.=0AEach=20process=20is=20limited=20to=20use=20at=20most=20= 1Mb=20memory=20for=20this.=0A=0AA=20summary=20can=20also=20be=20= explicitly=20requested=20by=20the=20user,=20this=0Awill=20return=20the=20= TopMemoryContext=20and=20a=20cumulative=20total=20of=0Aall=20lower=20= contexts.=0A=0AIn=20order=20to=20not=20block=20on=20busy=20processes,=20= we=20have=20hardcoded=0Athe=20number=20of=20seconds=20during=20which=20= to=20retry=20before=20timing=20out.=0AIn=20the=20case=20where=20no=20= statistics=20are=20published=20within=20the=20set=0Atimeout,=20NULL=20is=20= returned=0A---=0A=20doc/src/sgml/func/func-admin.sgml=20=20=20=20=20=20=20= =20=20=20=20=20=20|=20=20157=20+++=0A=20= src/backend/catalog/system_views.sql=20=20=20=20=20=20=20=20=20=20|=20=20= =20=205=20+=0A=20src/backend/postmaster/autovacuum.c=20=20=20=20=20=20=20= =20=20=20=20|=20=20=20=204=20+=0A=20= src/backend/postmaster/checkpointer.c=20=20=20=20=20=20=20=20=20|=20=20=20= =204=20+=0A=20src/backend/postmaster/interrupt.c=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=20=204=20+=0A=20src/backend/postmaster/pgarch.c=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=204=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=204=20+=0A=20src/backend/postmaster/walsummarizer.c=20=20=20=20= =20=20=20=20|=20=20=20=204=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=20= src/backend/storage/ipc/procsignal.c=20=20=20=20=20=20=20=20=20=20|=20=20= =20=203=20+=0A=20src/backend/storage/lmgr/proc.c=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20|=20=20=20=201=20+=0A=20src/backend/tcop/postgres.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=20= .../utils/activity/wait_event_names.txt=20=20=20=20=20=20=20|=20=20=20=20= 2=20+=0A=20src/backend/utils/adt/mcxtfuncs.c=20=20=20=20=20=20=20=20=20=20= =20=20=20|=201011=20++++++++++++++++-=0A=20= src/backend/utils/init/globals.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=20=201=20+=0A=20src/backend/utils/init/postinit.c=20=20=20=20=20=20= =20=20=20=20=20=20=20|=20=20=20=207=20+=0A=20= src/backend/utils/mmgr/mcxt.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20|=20=20=2031=20+=0A=20src/include/catalog/pg_proc.dat=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20|=20=20=2010=20+=0A=20= src/include/miscadmin.h=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=201=20+=0A=20= src/include/storage/lwlocklist.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=20=201=20+=0A=20src/include/storage/procsignal.h=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20=20=20=201=20+=0A=20= src/include/utils/memutils.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=2010=20+-=0A=20src/test/regress/expected/sysviews.out=20= =20=20=20=20=20=20=20|=20=20=2019=20+=0A=20= src/test/regress/sql/sysviews.sql=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=2018=20+=0A=20src/tools/pgindent/typedefs.list=20=20=20=20=20=20=20= =20=20=20=20=20=20=20|=20=20=20=204=20+-=0A=2025=20files=20changed,=20= 1282=20insertions(+),=2030=20deletions(-)=0A=0Adiff=20--git=20= a/doc/src/sgml/func/func-admin.sgml=20= b/doc/src/sgml/func/func-admin.sgml=0Aindex=201b465bc8ba7..a5c66837241=20= 100644=0A---=20a/doc/src/sgml/func/func-admin.sgml=0A+++=20= b/doc/src/sgml/func/func-admin.sgml=0A@@=20-251,6=20+251,130=20@@=0A=20=20= =20=20=20=20=20=20=20false=20is=20returned.=0A=20=20=20= =20=20=20=20=20=0A=20=20=20=20=20=20=20=0A+=0A+=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=20=20= pg_get_process_memory_contexts=0A+=20=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=20=20= pg_get_process_memory_contexts=20(=20= pid=20integer,=20= summary=20boolean=20)=0A+=20=20=20=20= =20=20=20=20setof=20record=0A+=20=20=20=20=20=20= =20=20(=20name=20text,=0A+=20=20=20=20= =20=20=20=20ident=20text,=0A+=20=20=20= =20=20=20=20=20type=20text,=0A+=20=20= =20=20=20=20=20=20level=20integer,=0A= +=20=20=20=20=20=20=20=20path=20= integer[],=0A+=20=20=20=20=20=20=20=20= total_bytes=20bigint,=0A+=20=20=20=20= =20=20=20=20total_nblocks=20bigint,=0A= +=20=20=20=20=20=20=20=20free_bytes=20= bigint,=0A+=20=20=20=20=20=20=20=20= free_chunks=20bigint,=0A+=20=20=20=20= =20=20=20=20used_bytes=20bigint,=0A+=20= =20=20=20=20=20=20=20num_agg_contexts=20= integer=20)=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=20This=20function=20handles=20= requests=20to=20display=20the=20memory=20contexts=20of=20a=0A+=20=20=20=20= =20=20=20=20PostgreSQL=20process=20with=20the=20= specified=0A+=20=20=20=20=20=20=20=20process=20ID.=20=20The=20function=20= can=20be=20used=20to=20send=20requests=20to=20backends=20as=0A+=20=20=20=20= =20=20=20=20well=20as=20auxiliary=20processes.=0A= +=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20The=20returned=20record=20contains=20extended=20= statistics=20per=20each=20memory=0A+=20=20=20=20=20=20=20=20context:=0A+=20= =20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=20=20=20=20=20name=20-=20The=20name=20= of=20the=20memory=20context.=0A+=20=20=20=20=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =20=20=20=20ident=20-=20Memory=20context=20ID=20= (if=20any).=0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20=20= type=20-=20The=20type=20of=20memory=20context,=20= possible=0A+=20=20=20=20=20=20=20=20=20=20=20values=20are:=20AllocSet,=20= Generation,=20Slab=20and=20Bump.=0A+=20=20=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20=20=20=20=20level=20-=20The=20level=20in=20= the=20tree=20of=20the=20current=0A+=20=20=20=20=20=20=20=20=20=20=20= memory=20context.=0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20=20= path=20-=20Memory=20contexts=20are=20organized=20= in=20a=0A+=20=20=20=20=20=20=20=20=20=20=20tree=20model=20with=20= TopMemoryContext=20as=20the=20root,=20and=20all=20other=20memory=0A+=20=20= =20=20=20=20=20=20=20=20=20contexts=20as=20nodes=20in=20the=20tree.=20= The=20path=0A+=20=20=20=20=20=20=20=20=20=20=20= displays=20the=20path=20from=20the=20root=20to=20the=20current=20memory=20= context.=20The=0A+=20=20=20=20=20=20=20=20=20=20=20path=20is=20limited=20= to=20100=20children=20per=20node,=20which=20each=20node=20limited=0A+=20=20= =20=20=20=20=20=20=20=20=20to=20a=20max=20depth=20of=20100,=20to=20= preserve=20memory=20during=20reporting.=20The=0A+=20=20=20=20=20=20=20=20= =20=20=20printed=20path=20will=20also=20be=20limited=20to=20100=20nodes=20= counting=20from=20the=0A+=20=20=20=20=20=20=20=20=20=20=20= TopMemoryContext.=0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20=20= total_bytes=20-=20The=20total=20number=20of=20= bytes=0A+=20=20=20=20=20=20=20=20=20=20=20allocated=20to=20this=20memory=20= context.=0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20=20= total_nblocks=20-=20The=20total=20number=20of=20= blocks=0A+=20=20=20=20=20=20=20=20=20=20=20used=20for=20the=20allocated=20= memory.=0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20=20= free_bytes=20-=20The=20amount=20of=20free=20= memory=20in=0A+=20=20=20=20=20=20=20=20=20=20=20this=20memory=20context.=0A= +=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20=20= free_chunks=20-=20The=20number=20of=20chunks=20= that=0A+=20=20=20=20=20=20=20=20=20=20=20= free_bytes=20corresponds=20to.=0A+=20=20=20=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=20=20=20=20used_bytes=20-=20= The=20total=20number=20of=20bytes=0A+=20=20=20=20=20=20=20=20=20=20=20= currently=20occupied.=0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20=20= num_agg_contexts=20-=20The=20number=20of=20memory=0A= +=20=20=20=20=20=20=20=20=20=20=20contexts=20aggregated=20in=20the=20= displayed=20statistics.=0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20When=20summary=20= is=20true,=20statistics=0A+=20=20=20=20=20=20=20=20= for=20memory=20contexts=20at=20levels=201=20and=202=20are=20displayed,=20= with=20level=201=0A+=20=20=20=20=20=20=20=20representing=20the=20root=20= node=20(i.e.,=20TopMemoryContext).=0A+=20=20=20=20=20=20= =20=20Statistics=20for=20contexts=20on=20level=202=20and=20below=20are=20= aggregates=20of=20all=0A+=20=20=20=20=20=20=20=20child=20contexts'=20= statistics,=20where=20num_agg_contexts=0A+=20=20=20=20= =20=20=20=20indicate=20the=20number=20aggregated=20child=20contexts.=20=20= When=0A+=20=20=20=20=20=20=20=20summary=20is=20= false,=0A+=20=20=20=20=20=20=20=20the=20= num_agg_contexts=20value=20is=201,=0A+=20=20= =20=20=20=20=20=20indicating=20that=20individual=20statistics=20are=20= being=20displayed.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20After=20receiving=20memory=20context=20= statistics=20from=20the=20target=20process,=20it=0A+=20=20=20=20=20=20=20= =20returns=20the=20results=20as=20one=20row=20per=20context.=20=20If=20= all=20the=20contexts=20don't=0A+=20=20=20=20=20=20=20=20fit=20within=20= the=20pre-determined=20size=20limit,=20the=20remaining=20context=0A+=20=20= =20=20=20=20=20=20statistics=20are=20aggregated=20and=20a=20cumulative=20= total=20is=20displayed.=20=20The=0A+=20=20=20=20=20=20=20=20= num_agg_contexts=20column=20indicates=20the=20number=20= of=0A+=20=20=20=20=20=20=20=20contexts=20aggregated=20in=20the=20= displayed=20statistics.=20=20When=0A+=20=20=20=20=20=20=20=20= num_agg_contexts=20is=201=20it=20= means=0A+=20=20=20=20=20=20=20=20that=20the=20context=20statistics=20are=20= displayed=20separately.=0A+=20=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=0A=20=20=20=20=20=20=0A=20=20=20=20=20= =0A=20=20=20=20=0A@@=20-302,6=20+426,39=20@@=20LOG:=20=20= Grand=20total:=201651920=20bytes=20in=20201=20blocks;=20622360=20free=20= (88=20chunks);=201029560=0A=20=20=20=20=20because=20it=20may=20generate=20= a=20large=20number=20of=20log=20messages.=0A=20=20=20=20=0A=20=0A= +=20=20=20=0A+=20=20=20=20= pg_get_process_memory_contexts=20can=20be=20used=20= to=20request=0A+=20=20=20=20memory=20contexts=20statistics=20of=20any=20= PostgreSQL=0A+=20=20=20=20process.=20=20For=20= example:=0A+=0A+postgres=3D#=20SELECT=20*=20FROM=20= pg_get_process_memory_contexts(=0A+=20=20(SELECT=20pid=20FROM=20= pg_stat_activity=0A+=20=20=20=20WHERE=20backend_type=20=3D=20= 'checkpointer'),=0A+=20=20false)=20LIMIT=201;=0A+-[=20RECORD=201=20= ]----+------------------------------=0A+name=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20TopMemoryContext=0A+ident=20=20=20=20=20=20=20=20=20=20=20=20= |=0A+type=20=20=20=20=20=20=20=20=20=20=20=20=20|=20AllocSet=0A+level=20=20= =20=20=20=20=20=20=20=20=20=20|=201=0A+path=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20{1}=0A+total_bytes=20=20=20=20=20=20|=2090304=0A= +total_nblocks=20=20=20=20|=203=0A+free_bytes=20=20=20=20=20=20=20|=20= 2880=0A+free_chunks=20=20=20=20=20=20|=201=0A+used_bytes=20=20=20=20=20=20= =20|=2087424=0A+num_agg_contexts=20|=201=0A+=0A+=20=20=20= =20=0A+=20=20=20=20=20=0A+=20=20=20=20=20=20While=20= pg_get_process_memory_contexts=20can=20be=20used=20= to=0A+=20=20=20=20=20=20query=20memory=20contexts=20of=20the=20local=20= backend,=0A+=20=20=20=20=20=20= pg_backend_memory_contexts=0A+=20=20=20=20=20=20= (see=20=20for=20= more=20details)=0A+=20=20=20=20=20=20will=20be=20less=20resource=20= intensive=20when=20only=20the=20local=20backend=20is=20of=20interest.=0A= +=20=20=20=20=20=0A+=20=20=20=20=0A+=20=20=20=0A+=0A= =20=20=20=0A=20=0A=20=20=20= =0Adiff=20--git=20a/src/backend/catalog/system_views.sql=20= b/src/backend/catalog/system_views.sql=0Aindex=20= 086c4c8fb6f..17ec512622b=20100644=0A---=20= a/src/backend/catalog/system_views.sql=0A+++=20= b/src/backend/catalog/system_views.sql=0A@@=20-692,6=20+692,11=20@@=20= GRANT=20SELECT=20ON=20pg_backend_memory_contexts=20TO=20= pg_read_all_stats;=0A=20REVOKE=20EXECUTE=20ON=20FUNCTION=20= pg_get_backend_memory_contexts()=20FROM=20PUBLIC;=0A=20GRANT=20EXECUTE=20= ON=20FUNCTION=20pg_get_backend_memory_contexts()=20TO=20= pg_read_all_stats;=0A=20=0A+REVOKE=20EXECUTE=20ON=20FUNCTION=0A+=09= pg_get_process_memory_contexts(integer,=20boolean)=20FROM=20PUBLIC;=0A= +GRANT=20EXECUTE=20ON=20FUNCTION=0A+=09= pg_get_process_memory_contexts(integer,=20boolean)=20TO=20= pg_read_all_stats;=0A+=0A=20--=20Statistics=20views=0A=20=0A=20CREATE=20= VIEW=20pg_stat_all_tables=20AS=0Adiff=20--git=20= a/src/backend/postmaster/autovacuum.c=20= b/src/backend/postmaster/autovacuum.c=0Aindex=201c38488f2cb..561d88ebb4d=20= 100644=0A---=20a/src/backend/postmaster/autovacuum.c=0A+++=20= b/src/backend/postmaster/autovacuum.c=0A@@=20-791,6=20+791,10=20@@=20= ProcessAutoVacLauncherInterrupts(void)=0A=20=09if=20= (LogMemoryContextPending)=0A=20=09=09ProcessLogMemoryContextInterrupt();=0A= =20=0A+=09/*=20Publish=20memory=20contexts=20of=20this=20process=20*/=0A= +=09if=20(PublishMemoryContextPending)=0A+=09=09= ProcessGetMemoryContextInterrupt();=0A+=0A=20=09/*=20Process=20sinval=20= catchup=20interrupts=20that=20happened=20while=20sleeping=20*/=0A=20=09= ProcessCatchupInterrupt();=0A=20}=0Adiff=20--git=20= a/src/backend/postmaster/checkpointer.c=20= b/src/backend/postmaster/checkpointer.c=0Aindex=20= e84e8663e96..5b3e08805bf=20100644=0A---=20= a/src/backend/postmaster/checkpointer.c=0A+++=20= b/src/backend/postmaster/checkpointer.c=0A@@=20-679,6=20+679,10=20@@=20= ProcessCheckpointerInterrupts(void)=0A=20=09/*=20Perform=20logging=20of=20= memory=20contexts=20of=20this=20process=20*/=0A=20=09if=20= (LogMemoryContextPending)=0A=20=09=09ProcessLogMemoryContextInterrupt();=0A= +=0A+=09/*=20Publish=20memory=20contexts=20of=20this=20process=20*/=0A+=09= if=20(PublishMemoryContextPending)=0A+=09=09= ProcessGetMemoryContextInterrupt();=0A=20}=0A=20=0A=20/*=0Adiff=20--git=20= a/src/backend/postmaster/interrupt.c=20= b/src/backend/postmaster/interrupt.c=0Aindex=20ba63b84dfc5..29454b8bf8a=20= 100644=0A---=20a/src/backend/postmaster/interrupt.c=0A+++=20= b/src/backend/postmaster/interrupt.c=0A@@=20-48,6=20+48,10=20@@=20= ProcessMainLoopInterrupts(void)=0A=20=09/*=20Perform=20logging=20of=20= memory=20contexts=20of=20this=20process=20*/=0A=20=09if=20= (LogMemoryContextPending)=0A=20=09=09ProcessLogMemoryContextInterrupt();=0A= +=0A+=09/*=20Publish=20memory=20contexts=20of=20this=20process=20*/=0A+=09= if=20(PublishMemoryContextPending)=0A+=09=09= ProcessGetMemoryContextInterrupt();=0A=20}=0A=20=0A=20/*=0Adiff=20--git=20= a/src/backend/postmaster/pgarch.c=20b/src/backend/postmaster/pgarch.c=0A= index=20ce6b5299324..fdd385e492d=20100644=0A---=20= a/src/backend/postmaster/pgarch.c=0A+++=20= b/src/backend/postmaster/pgarch.c=0A@@=20-871,6=20+871,10=20@@=20= ProcessPgArchInterrupts(void)=0A=20=09if=20(LogMemoryContextPending)=0A=20= =09=09ProcessLogMemoryContextInterrupt();=0A=20=0A+=09/*=20Publish=20= memory=20contexts=20of=20this=20process=20*/=0A+=09if=20= (PublishMemoryContextPending)=0A+=09=09= ProcessGetMemoryContextInterrupt();=0A+=0A=20=09if=20= (ConfigReloadPending)=0A=20=09{=0A=20=09=09char=09=20=20=20*archiveLib=20= =3D=20pstrdup(XLogArchiveLibrary);=0Adiff=20--git=20= a/src/backend/postmaster/startup.c=20b/src/backend/postmaster/startup.c=0A= index=2027e86cf393f..7149a67fcbc=20100644=0A---=20= a/src/backend/postmaster/startup.c=0A+++=20= b/src/backend/postmaster/startup.c=0A@@=20-192,6=20+192,10=20@@=20= ProcessStartupProcInterrupts(void)=0A=20=09/*=20Perform=20logging=20of=20= memory=20contexts=20of=20this=20process=20*/=0A=20=09if=20= (LogMemoryContextPending)=0A=20=09=09ProcessLogMemoryContextInterrupt();=0A= +=0A+=09/*=20Publish=20memory=20contexts=20of=20this=20process=20*/=0A+=09= if=20(PublishMemoryContextPending)=0A+=09=09= ProcessGetMemoryContextInterrupt();=0A=20}=0A=20=0A=20=0Adiff=20--git=20= a/src/backend/postmaster/walsummarizer.c=20= b/src/backend/postmaster/walsummarizer.c=0Aindex=20= c4a888a081c..00f03b36ed8=20100644=0A---=20= a/src/backend/postmaster/walsummarizer.c=0A+++=20= b/src/backend/postmaster/walsummarizer.c=0A@@=20-879,6=20+879,10=20@@=20= ProcessWalSummarizerInterrupts(void)=0A=20=09/*=20Perform=20logging=20of=20= memory=20contexts=20of=20this=20process=20*/=0A=20=09if=20= (LogMemoryContextPending)=0A=20=09=09ProcessLogMemoryContextInterrupt();=0A= +=0A+=09/*=20Publish=20memory=20contexts=20of=20this=20process=20*/=0A+=09= if=20(PublishMemoryContextPending)=0A+=09=09= ProcessGetMemoryContextInterrupt();=0A=20}=0A=20=0A=20/*=0Adiff=20--git=20= a/src/backend/storage/ipc/ipci.c=20b/src/backend/storage/ipc/ipci.c=0A= index=20b23d0c19360..a5ed58a18c5=20100644=0A---=20= a/src/backend/storage/ipc/ipci.c=0A+++=20= b/src/backend/storage/ipc/ipci.c=0A@@=20-52,6=20+52,7=20@@=0A=20#include=20= "storage/sinvaladt.h"=0A=20#include=20"utils/guc.h"=0A=20#include=20= "utils/injection_point.h"=0A+#include=20"utils/memutils.h"=0A=20=0A=20/*=20= GUCs=20*/=0A=20int=09=09=09shared_memory_type=20=3D=20= DEFAULT_SHARED_MEMORY_TYPE;=0A@@=20-140,6=20+141,7=20@@=20= CalculateShmemSize(void)=0A=20=09size=20=3D=20add_size(size,=20= SlotSyncShmemSize());=0A=20=09size=20=3D=20add_size(size,=20= AioShmemSize());=0A=20=09size=20=3D=20add_size(size,=20= WaitLSNShmemSize());=0A+=09size=20=3D=20add_size(size,=20= MemoryContextKeysShmemSize()=20+=20sizeof(LWLockPadded));=0A=20=0A=20=09= /*=20include=20additional=20requested=20shmem=20from=20preload=20= libraries=20*/=0A=20=09size=20=3D=20add_size(size,=20= total_addin_request);=0A@@=20-328,6=20+330,7=20@@=20= CreateOrAttachShmemStructs(void)=0A=20=09InjectionPointShmemInit();=0A=20= =09AioShmemInit();=0A=20=09WaitLSNShmemInit();=0A+=09= MemoryContextKeysShmemInit();=0A=20}=0A=20=0A=20/*=0Adiff=20--git=20= a/src/backend/storage/ipc/procsignal.c=20= b/src/backend/storage/ipc/procsignal.c=0Aindex=20= 087821311cc..8963285cc12=20100644=0A---=20= a/src/backend/storage/ipc/procsignal.c=0A+++=20= b/src/backend/storage/ipc/procsignal.c=0A@@=20-691,6=20+691,9=20@@=20= procsignal_sigusr1_handler(SIGNAL_ARGS)=0A=20=09if=20= (CheckProcSignal(PROCSIG_LOG_MEMORY_CONTEXT))=0A=20=09=09= HandleLogMemoryContextInterrupt();=0A=20=0A+=09if=20= (CheckProcSignal(PROCSIG_GET_MEMORY_CONTEXT))=0A+=09=09= HandleGetMemoryContextInterrupt();=0A+=0A=20=09if=20= (CheckProcSignal(PROCSIG_PARALLEL_APPLY_MESSAGE))=0A=20=09=09= HandleParallelApplyMessageInterrupt();=0A=20=0Adiff=20--git=20= a/src/backend/storage/lmgr/proc.c=20b/src/backend/storage/lmgr/proc.c=0A= index=20ebc3f4ca457..27b3b51cf2d=20100644=0A---=20= a/src/backend/storage/lmgr/proc.c=0A+++=20= b/src/backend/storage/lmgr/proc.c=0A@@=20-51,6=20+51,7=20@@=0A=20= #include=20"storage/procsignal.h"=0A=20#include=20"storage/spin.h"=0A=20= #include=20"storage/standby.h"=0A+#include=20"utils/memutils.h"=0A=20= #include=20"utils/timeout.h"=0A=20#include=20"utils/timestamp.h"=0A=20=0A= diff=20--git=20a/src/backend/tcop/postgres.c=20= b/src/backend/tcop/postgres.c=0Aindex=207dd75a490aa..e726f40dfbb=20= 100644=0A---=20a/src/backend/tcop/postgres.c=0A+++=20= b/src/backend/tcop/postgres.c=0A@@=20-3539,6=20+3539,9=20@@=20= ProcessInterrupts(void)=0A=20=09if=20(LogMemoryContextPending)=0A=20=09=09= ProcessLogMemoryContextInterrupt();=0A=20=0A+=09if=20= (PublishMemoryContextPending)=0A+=09=09= ProcessGetMemoryContextInterrupt();=0A+=0A=20=09if=20= (ParallelApplyMessagePending)=0A=20=09=09ProcessParallelApplyMessages();=0A= =20}=0Adiff=20--git=20a/src/backend/utils/activity/wait_event_names.txt=20= b/src/backend/utils/activity/wait_event_names.txt=0Aindex=20= c1ac71ff7f2..644d8d988e1=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-162,6=20+162,7=20= @@=20WAL_RECEIVER_EXIT=09"Waiting=20for=20the=20WAL=20receiver=20to=20= exit."=0A=20WAL_RECEIVER_WAIT_START=09"Waiting=20for=20startup=20process=20= to=20send=20initial=20data=20for=20streaming=20replication."=0A=20= WAL_SUMMARY_READY=09"Waiting=20for=20a=20new=20WAL=20summary=20to=20be=20= generated."=0A=20XACT_GROUP_UPDATE=09"Waiting=20for=20the=20group=20= leader=20to=20update=20transaction=20status=20at=20transaction=20end."=0A= +MEM_CXT_PUBLISH=09"Waiting=20for=20a=20process=20to=20publish=20memory=20= information."=0A=20=0A=20ABI_compatibility:=0A=20=0A@@=20-404,6=20+405,7=20= @@=20SubtransSLRU=09"Waiting=20to=20access=20the=20sub-transaction=20= SLRU=20cache."=0A=20XactSLRU=09"Waiting=20to=20access=20the=20= transaction=20status=20SLRU=20cache."=0A=20ParallelVacuumDSA=09"Waiting=20= for=20parallel=20vacuum=20dynamic=20shared=20memory=20allocation."=0A=20= AioUringCompletion=09"Waiting=20for=20another=20process=20to=20complete=20= IO=20via=20io_uring."=0A+MemoryContextReportingKeys=09"Waiting=20for=20= another=20process=20to=20complete=20reading=20or=20writing=20the=20= memory=20reporting=20keys."=0A=20=0A=20#=20No=20"ABI_compatibility"=20= region=20here=20as=20WaitEventLWLock=20has=20its=20own=20C=20code.=0A=20=0A= diff=20--git=20a/src/backend/utils/adt/mcxtfuncs.c=20= b/src/backend/utils/adt/mcxtfuncs.c=0Aindex=20fe6dce9cba3..c661eef7ae9=20= 100644=0A---=20a/src/backend/utils/adt/mcxtfuncs.c=0A+++=20= b/src/backend/utils/adt/mcxtfuncs.c=0A@@=20-17,28=20+17,138=20@@=0A=20=0A= =20#include=20"funcapi.h"=0A=20#include=20"mb/pg_wchar.h"=0A+#include=20= "miscadmin.h"=0A+#include=20"storage/dsm_registry.h"=0A=20#include=20= "storage/proc.h"=0A=20#include=20"storage/procarray.h"=0A=20#include=20= "utils/array.h"=0A=20#include=20"utils/builtins.h"=0A=20#include=20= "utils/hsearch.h"=0A+#include=20"utils/injection_point.h"=0A+#include=20= "utils/memutils.h"=0A+#include=20"utils/wait_event_types.h"=0A+=0A+/*=0A= +=20*=20Memory=20Context=20reporting=20size=20limits.=0A+=20*/=0A+=0A+/*=20= Max=20length=20of=20context=20name=20and=20ident,=20to=20keep=20it=20= consistent=0A+=20*=20with=20ProcessLogMemoryContext()=0A+=20*/=0A= +#define=20MEMORY_CONTEXT_IDENT_SHMEM_SIZE=20100=0A+#define=20= MEMORY_CONTEXT_NAME_SHMEM_SIZE=20100=0A+=0A+/*=20Maximum=20size=20(in=20= bytes)=20of=20DSA=20area=20per=20process=20*/=0A+#define=20= MEMORY_CONTEXT_REPORT_MAX_PER_BACKEND=20=20((size_t)=20(1=20*=201024=20*=20= 1024))=0A+=0A+/*=0A+=20*=20Maximum=20number=20of=20memory=20context=20= statistics=20is=20calculated=20by=20dividing=0A+=20*=20max=20memory=20= allocated=20per=20backend=20with=20maximum=20size=20per=20context=20= statistics.=0A+=20*=20The=20identifier=20and=20name=20are=20statically=20= allocated=20arrays=20of=20size=20100=20bytes.=0A+=20*=20The=20path=20= depth=20is=20limited=20to=20100=20like=20for=20memory=20context=20= logging.=0A+=20*/=0A+#define=20MAX_MEMORY_CONTEXT_STATS_NUM=20= MEMORY_CONTEXT_REPORT_MAX_PER_BACKEND=20/=20(sizeof(MemoryStatsEntry))=0A= +=0A+/*=20Size=20of=20dshash=20key=20*/=0A+#define=20CLIENT_KEY_SIZE=20= 32=0A+=0A+/*=20Dynamic=20shared=20memory=20state=20for=20reporting=20= statistics=20per=20context=20*/=0A+typedef=20struct=20MemoryStatsEntry=0A= +{=0A+=09char=09=09name[MEMORY_CONTEXT_NAME_SHMEM_SIZE];=0A+=09char=09=09= ident[MEMORY_CONTEXT_IDENT_SHMEM_SIZE];=0A+=09int=09=09=09path[100];=0A+=09= NodeTag=09=09type;=0A+=09int=09=09=09path_length;=0A+=09int=09=09=09= levels;=0A+=09int64=09=09totalspace;=0A+=09int64=09=09nblocks;=0A+=09= int64=09=09freespace;=0A+=09int64=09=09freechunks;=0A+=09int=09=09=09= num_agg_stats;=0A+}=20MemoryStatsEntry;=0A+=0A+/*=0A+=20*=20Per=20= backend=20dynamic=20shared=20hash=20entry=20for=20memory=20context=20= statistics=0A+=20*=20reporting.=0A+=20*/=0A+typedef=20struct=20= MemoryStatsDSHashEntry=0A+{=0A+=09char=09=09key[64];=0A+=09= ConditionVariable=20memcxt_cv;=0A+=09bool=09=09stats_written;=0A+=09int=09= =09=09target_server_id;=0A+=09int=09=09=09total_stats;=0A+=09bool=09=09= summary;=0A+=09dsa_pointer=20memstats_dsa_pointer;=0A+}=20= MemoryStatsDSHashEntry;=0A+=0A+static=20const=20dshash_parameters=20= memctx_dsh_params=20=3D=20{=0A+=09offsetof(MemoryStatsDSHashEntry,=20= memcxt_cv),=0A+=09sizeof(MemoryStatsDSHashEntry),=0A+=09dshash_strcmp,=0A= +=09dshash_strhash,=0A+=09dshash_strcpy=0A+};=0A+=0A+/*=0A+=20*=20These=20= are=20used=20for=20reporting=20memory=20context=0A+=20*=20statistics=20= of=20a=20process.=0A+=20*/=0A+=0A+/*=20Lock=20to=20control=20access=20to=20= client_keys=20array=20*/=0A+static=20LWLock=20*client_keys_lock=20=3D=20= NULL;=0A+=0A+/*=20Array=20to=20store=20the=20keys=20of=20= MemoryStatsDsHash=20*/=0A+static=20int=20*client_keys=20=3D=20NULL;=0A+=0A= +/*=0A+=20*=20Table=20to=20store=20pointers=20to=20dsa=20memory=20= containing=0A+=20*=20memory=20statistics=20and=20other=20meta=20data.=20= There=20is=20one=0A+=20*=20entry=20per=20client=20backend=20request,=20= keyed=20by=20ProcNumber=20of=0A+=20*=20the=20client=20obtained=20from=20= client_keys=20array=20above.=0A+=20*/=0A+static=20dshash_table=20= *MemoryStatsDsHash=20=3D=20NULL;=0A+=0A+/*=0A+=20*=20Dsa=20area=20which=20= stores=20the=20actual=20memory=20context=0A+=20*=20statistics.=0A+=20*/=0A= +static=20dsa_area=20*MemoryStatsDsaArea=20=3D=20NULL;=0A+=0A+static=20= void=20memstats_dsa_cleanup(char=20*key);=0A+static=20void=20= memstats_client_key_reset(int=20ProcNumber);=0A+static=20const=20char=20= *ContextTypeToString(NodeTag=20type);=0A+static=20void=20= PublishMemoryContext(MemoryStatsEntry=20*memcxt_info,=0A+=09=09=09=09=09=09= =09=09=20int=20curr_id,=20MemoryContext=20context,=0A+=09=09=09=09=09=09=09= =09=20List=20*path,=0A+=09=09=09=09=09=09=09=09=20MemoryContextCounters=20= stat,=0A+=09=09=09=09=09=09=09=09=20int=20num_contexts);=0A+static=20= List=20*compute_context_path(MemoryContext=20c,=20HTAB=20= *context_id_lookup);=0A+static=20void=20= end_memorycontext_reporting(MemoryStatsDSHashEntry=20*entry,=20= MemoryContext=20oldcontext,=0A+=09=09=09=09=09=09=09=09=09=09HTAB=20= *context_id_lookup);=0A=20=0A=20/*=20----------=0A=20=20*=20The=20max=20= bytes=20for=20showing=20identifiers=20of=20MemoryContext.=0A+=20*=20This=20= is=20used=20by=20pg_get_backend_memory_context=20-=20view=20used=20for=20= local=20backend.=0A=20=20*=20----------=0A=20=20*/=0A=20#define=20= MEMORY_CONTEXT_IDENT_DISPLAY_SIZE=091024=0A=20=0A+#define=20= MAX_PATH_DISPLAY_LENGTH=09100=0A+/*=20Timeout=20in=20seconds=20*/=0A= +#define=20MEMORY_STATS_MAX_TIMEOUT=205=0A+=0A=20/*=0A-=20*=20= MemoryContextId=0A+=20*=20MemoryStatsContextId=0A=20=20*=09=09Used=20for=20= storage=20of=20transient=20identifiers=20for=0A-=20*=09=09= pg_get_backend_memory_contexts.=0A+=20*=09=09= pg_get_backend_memory_contexts=20and=20the=20likes.=0A=20=20*/=0A= -typedef=20struct=20MemoryContextId=0A+typedef=20struct=20= MemoryStatsContextId=0A=20{=0A=20=09MemoryContext=20context;=0A=20=09int=09= =09=09context_id;=0A-}=20MemoryContextId;=0A+}=20MemoryStatsContextId;=0A= =20=0A=20/*=0A=20=20*=20int_list_to_array=0A@@=20-89,7=20+199,7=20@@=20= PutMemoryContextsStatsTupleStore(Tuplestorestate=20*tupstore,=0A=20=09=20= */=0A=20=09for=20(MemoryContext=20cur=20=3D=20context;=20cur=20!=3D=20= NULL;=20cur=20=3D=20cur->parent)=0A=20=09{=0A-=09=09MemoryContextId=20= *entry;=0A+=09=09MemoryStatsContextId=20*entry;=0A=20=09=09bool=09=09= found;=0A=20=0A=20=09=09entry=20=3D=20hash_search(context_id_lookup,=20= &cur,=20HASH_FIND,=20&found);=0A@@=20-143,24=20+253,7=20@@=20= PutMemoryContextsStatsTupleStore(Tuplestorestate=20*tupstore,=0A=20=09= else=0A=20=09=09nulls[1]=20=3D=20true;=0A=20=0A-=09switch=20= (context->type)=0A-=09{=0A-=09=09case=20T_AllocSetContext:=0A-=09=09=09= type=20=3D=20"AllocSet";=0A-=09=09=09break;=0A-=09=09case=20= T_GenerationContext:=0A-=09=09=09type=20=3D=20"Generation";=0A-=09=09=09= break;=0A-=09=09case=20T_SlabContext:=0A-=09=09=09type=20=3D=20"Slab";=0A= -=09=09=09break;=0A-=09=09case=20T_BumpContext:=0A-=09=09=09type=20=3D=20= "Bump";=0A-=09=09=09break;=0A-=09=09default:=0A-=09=09=09type=20=3D=20= "???";=0A-=09=09=09break;=0A-=09}=0A+=09type=20=3D=20= ContextTypeToString(context->type);=0A=20=0A=20=09values[2]=20=3D=20= CStringGetTextDatum(type);=0A=20=09values[3]=20=3D=20= Int32GetDatum(list_length(path));=09/*=20level=20*/=0A@@=20-175,6=20= +268,38=20@@=20PutMemoryContextsStatsTupleStore(Tuplestorestate=20= *tupstore,=0A=20=09list_free(path);=0A=20}=0A=20=0A+/*=0A+=20*=20= ContextTypeToString=0A+=20*=09=09Returns=20a=20textual=20representation=20= of=20a=20context=20type=0A+=20*=0A+=20*=20This=20should=20cover=20the=20= same=20types=20as=20MemoryContextIsValid.=0A+=20*/=0A+const=20char=20*=0A= +ContextTypeToString(NodeTag=20type)=0A+{=0A+=09const=20char=20= *context_type;=0A+=0A+=09switch=20(type)=0A+=09{=0A+=09=09case=20= T_AllocSetContext:=0A+=09=09=09context_type=20=3D=20"AllocSet";=0A+=09=09= =09break;=0A+=09=09case=20T_GenerationContext:=0A+=09=09=09context_type=20= =3D=20"Generation";=0A+=09=09=09break;=0A+=09=09case=20T_SlabContext:=0A= +=09=09=09context_type=20=3D=20"Slab";=0A+=09=09=09break;=0A+=09=09case=20= T_BumpContext:=0A+=09=09=09context_type=20=3D=20"Bump";=0A+=09=09=09= break;=0A+=09=09default:=0A+=09=09=09context_type=20=3D=20"???";=0A+=09=09= =09break;=0A+=09}=0A+=09return=20context_type;=0A+}=0A+=0A=20/*=0A=20=20= *=20pg_get_backend_memory_contexts=0A=20=20*=09=09SQL=20SRF=20showing=20= backend=20memory=20context.=0A@@=20-189,7=20+314,7=20@@=20= pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)=0A=20=09HTAB=09=20=20=20= *context_id_lookup;=0A=20=0A=20=09ctl.keysize=20=3D=20= sizeof(MemoryContext);=0A-=09ctl.entrysize=20=3D=20= sizeof(MemoryContextId);=0A+=09ctl.entrysize=20=3D=20= sizeof(MemoryStatsContextId);=0A=20=09ctl.hcxt=20=3D=20= CurrentMemoryContext;=0A=20=0A=20=09context_id_lookup=20=3D=20= hash_create("pg_get_backend_memory_contexts",=0A@@=20-216,7=20+341,7=20= @@=20pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)=0A=20=0A=20=09= foreach_ptr(MemoryContextData,=20cur,=20contexts)=0A=20=09{=0A-=09=09= MemoryContextId=20*entry;=0A+=09=09MemoryStatsContextId=20*entry;=0A=20=09= =09bool=09=09found;=0A=20=0A=20=09=09/*=0A@@=20-224,8=20+349,8=20@@=20= pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)=0A=20=09=09=20*=20= PutMemoryContextsStatsTupleStore=20needs=20this=20to=20populate=20the=20= "path"=0A=20=09=09=20*=20column=20with=20the=20parent=20context_ids.=0A=20= =09=09=20*/=0A-=09=09entry=20=3D=20(MemoryContextId=20*)=20= hash_search(context_id_lookup,=20&cur,=0A-=09=09=09=09=09=09=09=09=09=09=09= =09HASH_ENTER,=20&found);=0A+=09=09entry=20=3D=20(MemoryStatsContextId=20= *)=20hash_search(context_id_lookup,=20&cur,=0A+=09=09=09=09=09=09=09=09=09= =09=09=09=09=20HASH_ENTER,=20&found);=0A=20=09=09entry->context_id=20=3D=20= context_id++;=0A=20=09=09Assert(!found);=0A=20=0A@@=20-305,3=20+430,835=20= @@=20pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)=0A=20=0A=20=09= PG_RETURN_BOOL(true);=0A=20}=0A+=0A+/*=0A+=20*=20= pg_get_process_memory_contexts=0A+=20*=09=09Signal=20a=20backend=20or=20= an=20auxiliary=20process=20to=20send=20its=20memory=20contexts,=0A+=20*=09= =09wait=20for=20the=20results=20and=20display=20them.=0A+=20*=0A+=20*=20= By=20default,=20only=20superusers=20or=20users=20with=20= ROLE_PG_READ_ALL_STATS=20are=20allowed=0A+=20*=20to=20signal=20a=20= process=20to=20return=20the=20memory=20contexts.=20This=20is=20because=20= allowing=0A+=20*=20any=20users=20to=20issue=20this=20request=20at=20an=20= unbounded=20rate=20would=20cause=20lots=20of=0A+=20*=20requests=20to=20= be=20sent,=20which=20can=20lead=20to=20denial=20of=20service.=20= Additional=20roles=0A+=20*=20can=20be=20permitted=20with=20GRANT.=0A+=20= *=0A+=20*=20On=20receipt=20of=20this=20signal,=20a=20backend=20or=20an=20= auxiliary=20process=20sets=20the=20flag=0A+=20*=20in=20the=20signal=20= handler,=20which=20causes=20the=20next=20CHECK_FOR_INTERRUPTS()=0A+=20*=20= or=20process-specific=20interrupt=20handler=20to=20copy=20the=20memory=20= context=20details=0A+=20*=20to=20a=20dynamic=20shared=20memory=20space.=0A= +=20*=0A+=20*=20We=20have=20defined=20a=20limit=20on=20DSA=20memory=20= that=20could=20be=20allocated=20per=20process=20-=0A+=20*=20if=20the=20= process=20has=20more=20memory=20contexts=20than=20what=20can=20fit=20in=20= the=20allocated=0A+=20*=20size,=20the=20excess=20contexts=20are=20= summarized=20and=20represented=20as=20cumulative=20total=0A+=20*=20at=20= the=20end=20of=20the=20buffer.=0A+=20*=0A+=20*=20After=20sending=20the=20= signal,=20wait=20on=20a=20condition=20variable.=20The=20publishing=0A+=20= *=20backend,=20after=20copying=20the=20data=20to=20shared=20memory,=20= sends=20signal=20on=20that=0A+=20*=20condition=20variable.=20There=20is=20= one=20condition=20variable=20per=20client=20process.=0A+=20*=20Once=20= the=20condition=20variable=20is=20signalled,=20check=20if=20the=20latest=20= memory=20context=0A+=20*=20information=20is=20available=20and=20display.=0A= +=20*=0A+=20*=20If=20the=20publishing=20backend=20does=20not=20respond=20= before=20the=20condition=20variable=0A+=20*=20times=20out,=20which=20is=20= set=20to=20a=20predefined=20value=20MEMORY_STATS_MAX_TIMEOUT,=20give=20= up=0A+=20*=20and=20return=20NULL.=0A+=20*/=0A+Datum=0A= +pg_get_process_memory_contexts(PG_FUNCTION_ARGS)=0A+{=0A+=09int=09=09=09= pid=20=3D=20PG_GETARG_INT32(0);=0A+=09bool=09=09summary=20=3D=20= PG_GETARG_BOOL(1);=0A+=09PGPROC=09=20=20=20*proc;=0A+=09ProcNumber=09= procNumber;=0A+=09bool=09=09proc_is_aux=20=3D=20false;=0A+=09= ReturnSetInfo=20*rsinfo=20=3D=20(ReturnSetInfo=20*)=20= fcinfo->resultinfo;=0A+=09MemoryStatsEntry=20*memcxt_info;=0A+=09= MemoryStatsDSHashEntry=20*entry;=0A+=09bool=09=09found;=0A+=09char=09=09= key[CLIENT_KEY_SIZE];=0A+=09TimestampTz=20start_timestamp;=0A+=0A+=09/*=0A= +=09=20*=20See=20if=20the=20process=20with=20given=20pid=20is=20a=20= backend=20or=20an=20auxiliary=20process=0A+=09=20*=20and=20remember=20= the=20type=20for=20when=20we=20requery=20the=20process=20later.=0A+=09=20= */=0A+=09proc=20=3D=20BackendPidGetProc(pid);=0A+=09if=20(proc=20=3D=3D=20= NULL)=0A+=09{=0A+=09=09proc=20=3D=20AuxiliaryPidGetProc(pid);=0A+=09=09= proc_is_aux=20=3D=20true;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20= BackendPidGetProc()=20and=20AuxiliaryPidGetProc()=20return=20NULL=20if=20= the=20pid=0A+=09=20*=20isn't=20valid;=20this=20is=20however=20not=20a=20= problem=20and=20leave=20with=20a=20WARNING.=0A+=09=20*=20See=20comment=20= in=20pg_log_backend_memory_contexts=20for=20a=20discussion=20on=20this.=0A= +=09=20*/=0A+=09if=20(proc=20=3D=3D=20NULL)=0A+=09{=0A+=09=09/*=0A+=09=09= =20*=20This=20is=20a=20warning=20because=20we=20don't=20want=20to=20= break=20loops.=0A+=09=09=20*/=0A+=09=09ereport(WARNING,=0A+=09=09=09=09= errmsg("PID=20%d=20is=20not=20a=20PostgreSQL=20server=20process",=0A+=09=09= =09=09=09=20=20=20pid));=0A+=09=09PG_RETURN_NULL();=0A+=09}=0A+=0A+=09= procNumber=20=3D=20GetNumberFromPGProc(proc);=0A+=0A+=09/*=0A+=09=20*=20= Create=20a=20DSA=20to=20allocate=20memory=20for=20copying=20memory=20= contexts=20statistics.=0A+=09=20*=20Allocate=20the=20memory=20in=20the=20= DSA=20and=20send=20dsa=20pointer=20to=20the=20server=0A+=09=20*=20= process=20for=20storing=20the=20context=20statistics.=20If=20number=20of=20= contexts=0A+=09=20*=20exceed=20a=20predefined=20limit=20(1MB),=20a=20= cumulative=20total=20is=20stored=20for=20such=0A+=09=20*=20contexts.=0A+=09= =20*=0A+=09=20*=20The=20DSA=20is=20created=20once=20for=20the=20lifetime=20= of=20the=20server,=20and=20only=0A+=09=20*=20attached=20in=20subsequent=20= calls.=0A+=09=20*/=0A+=09if=20(MemoryStatsDsaArea=20=3D=3D=20NULL)=0A+=09= =09MemoryStatsDsaArea=20=3D=20= GetNamedDSA("memory_context_statistics_dsa",=0A+=09=09=09=09=09=09=09=09=09= =09=20&found);=0A+=0A+=09/*=0A+=09=20*=20The=20dsa=20pointers=20= containing=20statistics=20for=20each=20client=20are=20stored=20in=20a=0A= +=09=20*=20dshash=20table.=20In=20addition=20to=20dsa=20pointer,=20each=20= entry=20in=20this=20table=20also=0A+=09=20*=20contains=20information=20= about=20the=20statistics,=20condition=20variable=20for=0A+=09=20*=20= signalling=20between=20client=20and=20the=20server=20and=20miscellaneous=20= data=0A+=09=20*=20specific=20to=20a=20request.=20There=20is=20one=20= entry=20per=20client=20request=20in=20the=0A+=09=20*=20hash=20table.=0A+=09= =20*/=0A+=09if=20(MemoryStatsDsHash=20=3D=3D=20NULL)=0A+=09=09= MemoryStatsDsHash=20=3D=20= GetNamedDSHash("memory_context_statistics_dshash",=0A+=09=09=09=09=09=09=09= =09=09=09=20=20=20&memctx_dsh_params,=20&found);=0A+=0A+=09snprintf(key,=20= sizeof(key),=20"%d",=20MyProcNumber);=0A+=0A+=09/*=0A+=09=20*=20Check=20= if=20the=20publishing=20process=20slot=20is=20empty=20and=20store=20this=20= clients=0A+=09=20*=20key=20i.e=20its=20procNumber.=20This=20informs=20= the=20publishing=20process=20that=20it=20is=0A+=09=20*=20supposed=20to=20= write=20statistics=20in=20the=20hash=20entry=20corresponding=20to=20this=0A= +=09=20*=20client.=0A+=09=20*/=0A+=09LWLockAcquire(client_keys_lock,=20= LW_EXCLUSIVE);=0A+=0A+=09if=20(client_keys[procNumber]=20=3D=3D=20-1)=0A= +=09=09client_keys[procNumber]=20=3D=20MyProcNumber;=0A+=09else=0A+=09{=0A= +=09=09LWLockRelease(client_keys_lock);=0A+=09=09ereport(WARNING,=0A+=09=09= =09=09errmsg("server=20process=20%d=20is=20processing=20previous=20= request",=0A+=09=09=09=09=09=20=20=20pid));=0A+=09=09PG_RETURN_NULL();=0A= +=09}=0A+=09LWLockRelease(client_keys_lock);=0A+=0A+=09/*=0A+=09=20*=20= Insert=20an=20entry=20for=20this=20client=20in=20DSHASH=20table=20the=20= first=20time=20this=0A+=09=20*=20function=20is=20called.=20This=20entry=20= is=20deleted=20when=20the=20process=20exits=20in=0A+=09=20*=20= before_shmem_exit=20call.=0A+=09=20*=0A+=09=20*=20dshash_find_or_insert=20= locks=20the=20entry=20to=20prevent=20the=20publisher=20from=0A+=09=20*=20= reading=20before=20client=20has=20updated=20the=20entry.=0A+=09=20*/=0A+=09= entry=20=3D=20dshash_find_or_insert(MemoryStatsDsHash,=20key,=20&found);=0A= +=09if=20(!found)=0A+=09{=0A+=09=09entry->stats_written=20=3D=20false;=0A= +=09=09ConditionVariableInit(&entry->memcxt_cv);=0A+=09}=0A+=0A+=09/*=0A= +=09=20*=20Allocate=201MB=20of=20memory=20for=20the=20backend=20to=20= publish=20its=20statistics=20on=0A+=09=20*=20every=20call=20to=20this=20= function.=20The=20memory=20is=20freed=20at=20the=20end=20of=20the=0A+=09=20= *=20function.=0A+=09=20*/=0A+=09entry->memstats_dsa_pointer=20=3D=0A+=09=09= dsa_allocate0(MemoryStatsDsaArea,=20= MEMORY_CONTEXT_REPORT_MAX_PER_BACKEND);=0A+=0A+=09/*=0A+=09=20*=20= Specify=20whether=20a=20summary=20of=20statistics=20is=20requested,=20= before=20signalling=0A+=09=20*=20the=20server.=0A+=09=20*/=0A+=09= entry->summary=20=3D=20summary;=0A+=0A+=09/*=0A+=09=20*=20Indicate=20= which=20server=20process=20statistics=20are=20being=20requested=20from.=20= If=0A+=09=20*=20this=20client=20times=20out=20before=20the=20last=20= requested=20process=20can=20publish=20its=0A+=09=20*=20statistics,=20it=20= may=20send=20a=20new=20request=20to=20another=20server=20process.=20= Since=0A+=09=20*=20the=20previous=20server=20was=20notified,=20it=20= might=20attempt=20to=20read=20the=20same=0A+=09=20*=20client=20entry=20= and=20respond=20incorrectly=20with=20its=20statistics.=20By=20storing=0A= +=09=20*=20the=20server=20ID=20in=20the=20client=20entry,=20we=20prevent=20= any=20previously=20signalled=0A+=09=20*=20server=20process=20from=20= writing=20its=20statistics=20in=20the=20space=20meant=20for=20the=0A+=09=20= *=20newly=20requested=20process.=0A+=09=20*/=0A+=09= entry->target_server_id=20=3D=20pid;=0A+=09= dshash_release_lock(MemoryStatsDsHash,=20entry);=0A+=0A+=09/*=0A+=09=20*=20= Send=20a=20signal=20to=20a=20PostgreSQL=20process,=20informing=20it=20we=20= want=20it=20to=0A+=09=20*=20produce=20information=20about=20its=20memory=20= contexts.=0A+=09=20*/=0A+=09if=20(SendProcSignal(pid,=20= PROCSIG_GET_MEMORY_CONTEXT,=20procNumber)=20<=200)=0A+=09{=0A+=09=09= memstats_dsa_cleanup(key);=0A+=09=09= memstats_client_key_reset(procNumber);=0A+=09=09ereport(WARNING,=0A+=09=09= =09=09errmsg("could=20not=20send=20signal=20to=20process=20%d:=20%m",=0A= +=09=09=09=09=09=20=20=20pid));=0A+=09=09PG_RETURN_NULL();=0A+=09}=0A+=09= start_timestamp=20=3D=20GetCurrentTimestamp();=0A+=0A+=09while=20(1)=0A+=09= {=0A+=09=09long=09=09elapsed_time;=0A+=0A+=09=09entry=20=3D=20= dshash_find_or_insert(MemoryStatsDsHash,=20key,=20&found);=0A+=09=09= Assert(found);=0A+=0A+=09=09INJECTION_POINT("memcontext-client-crash",=20= NULL);=0A+=0A+=09=09memcxt_info=20=3D=20(MemoryStatsEntry=20*)=0A+=09=09=09= dsa_get_address(MemoryStatsDsaArea,=20entry->memstats_dsa_pointer);=0A+=0A= +=09=09/*=0A+=09=09=20*=20We=20expect=20to=20come=20out=20of=20sleep=20= when=20the=20requested=20process=20has=0A+=09=09=20*=20finished=20= publishing=20the=20statistics,=20verified=20using=20a=20boolean=0A+=09=09= =20*=20stats_written.=0A+=09=09=20*=0A+=09=09=20*=20Make=20sure=20that=20= the=20statistics=20are=20actually=20written=20by=20checking=20that=0A+=09= =09=20*=20the=20name=20of=20the=20context=20is=20not=20NULL.=20This=20is=20= done=20to=20ensure=20that=0A+=09=09=20*=20the=20subsequent=20waits=20for=20= statistics=20do=20not=20return=20spuriously=20if=20the=0A+=09=09=20*=20= previous=20call=20to=20the=20function=20ended=20in=20error=20and=20thus=20= could=20not=0A+=09=09=20*=20clear=20the=20stats_written=20flag.=0A+=09=09= =20*/=0A+=09=09if=20(entry->stats_written=20&&=20memcxt_info[0].name[0]=20= !=3D=20'\0')=0A+=09=09=09break;=0A+=0A+=09=09= dshash_release_lock(MemoryStatsDsHash,=20entry);=0A+=0A+=09=09= elapsed_time=20=3D=20TimestampDifferenceMilliseconds(start_timestamp,=0A= +=09=09=09=09=09=09=09=09=09=09=09=09=09=20=20=20GetCurrentTimestamp());=0A= +=09=09/*=20Return=20if=20we=20have=20already=20exceeded=20the=20timeout=20= */=0A+=09=09if=20(elapsed_time=20>=3D=20MEMORY_STATS_MAX_TIMEOUT=20*=20= 1000)=0A+=09=09{=0A+=09=09=09memstats_dsa_cleanup(key);=0A+=09=09=09= memstats_client_key_reset(procNumber);=0A+=09=09=09= ConditionVariableCancelSleep();=0A+=09=09=09PG_RETURN_NULL();=0A+=09=09}=0A= +=0A+=09=09/*=0A+=09=09=20*=20Recheck=20the=20state=20of=20the=20backend=20= before=20sleeping=20on=20the=20condition=0A+=09=09=20*=20variable=20to=20= ensure=20the=20process=20is=20still=20alive.=20=20Only=20check=20the=0A+=09= =09=20*=20relevant=20process=20type=20based=20on=20the=20earlier=20PID=20= check.=0A+=09=09=20*/=0A+=09=09if=20(proc_is_aux)=0A+=09=09=09proc=20=3D=20= AuxiliaryPidGetProc(pid);=0A+=09=09else=0A+=09=09=09proc=20=3D=20= BackendPidGetProc(pid);=0A+=0A+=09=09/*=0A+=09=09=20*=20The=20target=20= server=20process=20ending=20during=20memory=20context=20processing=0A+=09= =09=20*=20is=20not=20an=20error.=0A+=09=09=20*/=0A+=09=09if=20(proc=20=3D=3D= =20NULL)=0A+=09=09{=0A+=09=09=09memstats_dsa_cleanup(key);=0A+=09=09=09= memstats_client_key_reset(procNumber);=0A+=09=09=09= ConditionVariableCancelSleep();=0A+=09=09=09ereport(WARNING,=0A+=09=09=09= =09=09errmsg("PID=20%d=20is=20no=20longer=20a=20PostgreSQL=20server=20= process",=0A+=09=09=09=09=09=09=20=20=20pid));=0A+=09=09=09= PG_RETURN_NULL();=0A+=09=09}=0A+=0A+=09=09/*=0A+=09=09=20*=20Wait=20for=20= MEMORY_STATS_MAX_TIMEOUT.=20If=20no=20statistics=20are=20available=0A+=09= =09=20*=20within=20the=20allowed=20time=20then=20return=20NULL.=20The=20= timer=20is=20defined=20in=0A+=09=09=20*=20milliseconds=20since=20that's=20= what=20the=20condition=20variable=20sleep=20uses.=0A+=09=09=20*/=0A+=09=09= if=20(ConditionVariableTimedSleep(&entry->memcxt_cv,=0A+=09=09=09=09=09=09= =09=09=09=09(MEMORY_STATS_MAX_TIMEOUT=20*=201000),=0A+=09=09=09=09=09=09=09= =09=09=09WAIT_EVENT_MEM_CXT_PUBLISH))=0A+=09=09{=0A+=09=09=09/*=20= Timeout=20has=20expired,=20return=20NULL=20*/=0A+=09=09=09= memstats_dsa_cleanup(key);=0A+=09=09=09= memstats_client_key_reset(procNumber);=0A+=09=09=09= ConditionVariableCancelSleep();=0A+=09=09=09PG_RETURN_NULL();=0A+=09=09}=0A= +=09}=0A+=0A+=09InitMaterializedSRF(fcinfo,=200);=0A+=0A+=09/*=0A+=09=20= *=20Backend=20has=20finished=20publishing=20the=20stats,=20project=20= them.=0A+=09=20*/=0A+#define=20PG_GET_PROCESS_MEMORY_CONTEXTS_COLS=0911=0A= +=09for=20(int=20i=20=3D=200;=20i=20<=20entry->total_stats;=20i++)=0A+=09= {=0A+=09=09ArrayType=20=20*path_array;=0A+=09=09int=09=09=09path_length;=0A= +=09=09Datum=09=09values[PG_GET_PROCESS_MEMORY_CONTEXTS_COLS];=0A+=09=09= bool=09=09nulls[PG_GET_PROCESS_MEMORY_CONTEXTS_COLS];=0A+=09=09Datum=09=20= =20=20*path_datum=20=3D=20NULL;=0A+=0A+=09=09memset(values,=200,=20= sizeof(values));=0A+=09=09memset(nulls,=200,=20sizeof(nulls));=0A+=0A+=09= =09Assert(memcxt_info[i].name[0]=20!=3D=20'\0');=0A+=09=09values[0]=20=3D=20= CStringGetTextDatum(memcxt_info[i].name);=0A+=0A+=09=09if=20= (memcxt_info[i].ident[0]=20!=3D=20'\0')=0A+=09=09=09values[1]=20=3D=20= CStringGetTextDatum(memcxt_info[i].ident);=0A+=09=09else=0A+=09=09=09= nulls[1]=20=3D=20true;=0A+=0A+=09=09values[2]=20=3D=20= CStringGetTextDatum(ContextTypeToString(memcxt_info[i].type));=0A+=09=09= values[3]=20=3D=20Int32GetDatum(memcxt_info[i].levels);=0A+=0A+=09=09= path_length=20=3D=20memcxt_info[i].path_length;=0A+=09=09path_datum=20=3D=20= (Datum=20*)=20palloc(path_length=20*=20sizeof(Datum));=0A+=09=09if=20= (memcxt_info[i].path[0]=20!=3D=200)=0A+=09=09{=0A+=09=09=09for=20(int=20= j=20=3D=200;=20j=20<=20path_length;=20j++)=0A+=09=09=09=09path_datum[j]=20= =3D=20Int32GetDatum(memcxt_info[i].path[j]);=0A+=09=09=09path_array=20=3D=20= construct_array_builtin(path_datum,=0A+=09=09=09=09=09=09=09=09=09=09=09=09= =20path_length,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=20INT4OID);=0A+=09= =09=09values[4]=20=3D=20PointerGetDatum(path_array);=0A+=09=09}=0A+=09=09= else=0A+=09=09=09nulls[4]=20=3D=20true;=0A+=0A+=09=09values[5]=20=3D=20= Int64GetDatum(memcxt_info[i].totalspace);=0A+=09=09values[6]=20=3D=20= Int64GetDatum(memcxt_info[i].nblocks);=0A+=09=09values[7]=20=3D=20= Int64GetDatum(memcxt_info[i].freespace);=0A+=09=09values[8]=20=3D=20= Int64GetDatum(memcxt_info[i].freechunks);=0A+=09=09values[9]=20=3D=20= Int64GetDatum(memcxt_info[i].totalspace=20-=0A+=09=09=09=09=09=09=09=09=20= =20memcxt_info[i].freespace);=0A+=09=09values[10]=20=3D=20= Int32GetDatum(memcxt_info[i].num_agg_stats);=0A+=0A+=09=09= tuplestore_putvalues(rsinfo->setResult,=20rsinfo->setDesc,=0A+=09=09=09=09= =09=09=09=20values,=20nulls);=0A+=09}=0A+=09= dshash_release_lock(MemoryStatsDsHash,=20entry);=0A+=09= memstats_dsa_cleanup(key);=0A+=0A+=09ConditionVariableCancelSleep();=0A+=0A= +=09PG_RETURN_NULL();=0A+}=0A+=0A+static=20void=0A= +memstats_dsa_cleanup(char=20*key)=0A+{=0A+=09MemoryStatsDSHashEntry=20= *entry;=0A+=0A+=09entry=20=3D=20dshash_find(MemoryStatsDsHash,=20key,=20= true);=0A+=0A+=09Assert(MemoryStatsDsaArea=20!=3D=20NULL);=0A+=09= dsa_free(MemoryStatsDsaArea,=20entry->memstats_dsa_pointer);=0A+=09= entry->memstats_dsa_pointer=20=3D=20InvalidDsaPointer;=0A+=09= entry->stats_written=20=3D=20false;=0A+=09entry->target_server_id=20=3D=20= 0;=0A+=0A+=09dshash_release_lock(MemoryStatsDsHash,=20entry);=0A+}=0A+=0A= +/*=0A+=20*=20Remove=20this=20process=20from=20the=20publishing=20= process'=0A+=20*=20client=20key=20slot,=20if=20the=20stats=20publishing=20= process=20has=20failed=20to=20do=20so.=0A+=20*/=0A+static=20void=0A= +memstats_client_key_reset(int=20procNumber)=0A+{=0A+=09= LWLockAcquire(client_keys_lock,=20LW_EXCLUSIVE);=0A+=0A+=09if=20= (client_keys[procNumber]=20=3D=3D=20MyProcNumber)=0A+=09=09= client_keys[procNumber]=20=3D=20-1;=0A+=09= LWLockRelease(client_keys_lock);=0A+}=0A+=0A+void=0A= +MemoryContextKeysShmemInit(void)=0A+{=0A+=09bool=09=09found;=0A+=0A+=09= client_keys=20=3D=20(int=20*)=0A+=09=09= ShmemInitStruct("MemoryContextKeys",=0A+=09=09=09=09=09=09= MemoryContextKeysShmemSize()=20+=20sizeof(LWLockPadded),=20&found);=0A+=09= client_keys_lock=20=3D=20(LWLock=20*)=20((char=20*)=20client_keys=20+=20= MemoryContextKeysShmemSize());=0A+=0A+=09if=20(!found)=0A+=09{=0A+=09=09= MemSet(client_keys,=20-1,=20MemoryContextKeysShmemSize());=0A+=09=09= LWLockInitialize(client_keys_lock,=20LWTRANCHE_MEMORY_CONTEXT_KEYS);=0A+=09= }=0A+}=0A+=0A+Size=0A+MemoryContextKeysShmemSize(void)=0A+{=0A+=09Size=09= =09sz=20=3D=200;=0A+=09Size=09=09TotalProcs=20=3D=200;=0A+=0A+=09= TotalProcs=20=3D=20add_size(TotalProcs,=20NUM_AUXILIARY_PROCS);=0A+=09= TotalProcs=20=3D=20add_size(TotalProcs,=20MaxBackends);=0A+=09sz=20=3D=20= add_size(sz,=20mul_size(TotalProcs,=20sizeof(int)));=0A+=0A+=09return=20= sz;=0A+}=0A+=0A+/*=0A+=20*=20HandleGetMemoryContextInterrupt=0A+=20*=09=09= Handle=20receipt=20of=20an=20interrupt=20indicating=20a=20request=20to=20= publish=20memory=0A+=20*=09=09contexts=20statistics.=0A+=20*=0A+=20*=20= All=20the=20actual=20work=20is=20deferred=20to=20= ProcessGetMemoryContextInterrupt()=20as=0A+=20*=20this=20cannot=20be=20= performed=20in=20a=20signal=20handler.=0A+=20*/=0A+void=0A= +HandleGetMemoryContextInterrupt(void)=0A+{=0A+=09InterruptPending=20=3D=20= true;=0A+=09PublishMemoryContextPending=20=3D=20true;=0A+=09/*=20latch=20= will=20be=20set=20by=20procsignal_sigusr1_handler=20*/=0A+}=0A+=0A+/*=0A= +=20*=20ProcessGetMemoryContextInterrupt=0A+=20*=09=09Generate=20= information=20about=20memory=20contexts=20used=20by=20the=20process.=0A+=20= *=0A+=20*=20Performs=20a=20breadth=20first=20search=20on=20the=20memory=20= context=20tree,=20thus=20parents=0A+=20*=20statistics=20are=20reported=20= before=20their=20children=20in=20the=20monitoring=20function=0A+=20*=20= output.=0A+=20*=0A+=20*=20Statistics=20for=20all=20the=20processes=20are=20= shared=20via=20the=20same=20dynamic=20shared=0A+=20*=20area.=20= Individual=20statistics=20are=20tracked=20independently=20in=0A+=20*=20= per-process=20DSA=20pointers.=20These=20pointers=20are=20stored=20in=20a=20= dshash=20table=20with=0A+=20*=20key=20as=20requesting=20clients=20= ProcNumber.=0A+=20*=0A+=20*=20We=20calculate=20maximum=20number=20of=20= context's=20statistics=20that=20can=20be=20displayed=0A+=20*=20using=20a=20= pre-determined=20limit=20for=20memory=20available=20per=20process=20for=20= this=0A+=20*=20utility=20and=20maximum=20size=20of=20statistics=20for=20= each=20context.=20=20The=20remaining=0A+=20*=20context=20statistics=20if=20= any=20are=20captured=20as=20a=20cumulative=20total=20at=20the=20end=20of=0A= +=20*=20individual=20context's=20statistics.=0A+=20*=0A+=20*=20If=20= summary=20is=20true,=20we=20capture=20the=20level=201=20and=20level=202=20= contexts=0A+=20*=20statistics.=20=20For=20that=20we=20traverse=20the=20= memory=20context=20tree=20recursively=20in=0A+=20*=20depth=20first=20= search=20manner=20to=20cover=20all=20the=20children=20of=20a=20parent=20= context,=20to=0A+=20*=20be=20able=20to=20display=20a=20cumulative=20= total=20of=20memory=20consumption=20by=20a=20parent=20at=0A+=20*=20level=20= 2=20and=20all=20its=20children.=0A+=20*/=0A+void=0A= +ProcessGetMemoryContextInterrupt(void)=0A+{=0A+=09List=09=20=20=20= *contexts;=0A+=09HASHCTL=09=09ctl;=0A+=09HTAB=09=20=20=20= *context_id_lookup;=0A+=09int=09=09=09context_id=20=3D=200;=0A+=09= MemoryStatsEntry=20*meminfo;=0A+=09MemoryContextCounters=20stat;=0A+=09= int=09=09=09num_individual_stats=20=3D=200;=0A+=09bool=09=09found;=0A+=09= MemoryStatsDSHashEntry=20*entry;=0A+=09char=09=09key[CLIENT_KEY_SIZE];=0A= +=09int=09=09=09clientProcNumber;=0A+=09MemoryContext=20memstats_ctx=20=3D= =20NULL;=0A+=09MemoryContext=20oldcontext=20=3D=20NULL;=0A+=0A+=09= PublishMemoryContextPending=20=3D=20false;=0A+=0A+=09/*=0A+=09=20*=20= Retrieve=20the=20client=20key=20for=20publishing=20statistics=20and=20= reset=20it=20to=20-1,=0A+=09=20*=20so=20other=20clients=20can=20request=20= memory=20statistics=20from=20this=20process=0A+=09=20*/=0A+=09= LWLockAcquire(client_keys_lock,=20LW_SHARED);=0A+=09= Assert(client_keys[MyProcNumber]=20!=3D=20-1);=0A+=09clientProcNumber=20= =3D=20client_keys[MyProcNumber];=0A+=09client_keys[MyProcNumber]=20=3D=20= -1;=0A+=09LWLockRelease(client_keys_lock);=0A+=0A+=09/*=0A+=09=20*=20= Create=20a=20new=20memory=20context=20which=20is=20not=20a=20part=20of=20= TopMemoryContext=0A+=09=20*=20tree.=20This=20context=20is=20used=20to=20= allocate=20all=20memory=20in=20this=20function.=0A+=09=20*=20This=20= helps=20in=20keeping=20the=20memory=20allocation=20in=20this=20function=20= to=20report=0A+=09=20*=20memory=20consumption=20statistics=20separate.=20= So=20that=20it=20does=20not=20affect=20the=0A+=09=20*=20output=20of=20= this=20function.=0A+=09=20*/=0A+=09memstats_ctx=20=3D=20= AllocSetContextCreate((MemoryContext)=20NULL,=20= "publish_memory_context_statistics",=0A+=09=09=09=09=09=09=09=09=09=09=20= ALLOCSET_SMALL_SIZES);=0A+=09oldcontext=20=3D=20= MemoryContextSwitchTo(memstats_ctx);=0A+=0A+=09/*=0A+=09=20*=20The=20= hash=20table=20is=20used=20for=20constructing=20"path"=20column=20of=20= the=20view,=0A+=09=20*=20similar=20to=20its=20local=20backend=20= counterpart.=0A+=09=20*/=0A+=09ctl.keysize=20=3D=20= sizeof(MemoryContext);=0A+=09ctl.entrysize=20=3D=20= sizeof(MemoryStatsContextId);=0A+=09ctl.hcxt=20=3D=20= CurrentMemoryContext;=0A+=0A+=09context_id_lookup=20=3D=20= hash_create("pg_get_remote_backend_memory_contexts",=0A+=09=09=09=09=09=09= =09=09=09256,=0A+=09=09=09=09=09=09=09=09=09&ctl,=0A+=09=09=09=09=09=09=09= =09=09HASH_ELEM=20|=20HASH_BLOBS=20|=20HASH_CONTEXT);=0A+=0A+=09/*=20= List=20of=20contexts=20to=20process=20in=20the=20next=20round=20-=20= start=20at=20the=20top.=20*/=0A+=09contexts=20=3D=20= list_make1(TopMemoryContext);=0A+=0A+=09/*=0A+=09=20*=20If=20DSA=20= exists,=20created=20by=20another=20process=20requesting=20statistics,=20= attach=0A+=09=20*=20to=20it.=20We=20expect=20the=20client=20process=20to=20= create=20required=20DSA=20and=20Dshash=0A+=09=20*=20table.=0A+=09=20*/=0A= +=09if=20(MemoryStatsDsaArea=20=3D=3D=20NULL)=0A+=09=09= MemoryStatsDsaArea=20=3D=20GetNamedDSA("memory_context_statistics_dsa",=0A= +=09=09=09=09=09=09=09=09=09=09=20&found);=0A+=0A+=09if=20= (MemoryStatsDsHash=20=3D=3D=20NULL)=0A+=09=09MemoryStatsDsHash=20=3D=20= GetNamedDSHash("memory_context_statistics_dshash",=0A+=09=09=09=09=09=09=09= =09=09=09=20=20=20&memctx_dsh_params,=20&found);=0A+=0A+=0A+=09= snprintf(key,=20CLIENT_KEY_SIZE,=20"%d",=20clientProcNumber);=0A+=0A+=09= /*=0A+=09=20*=20The=20entry=20lock=20is=20held=20by=20= dshash_find_or_insert=20to=20protect=20writes=20to=0A+=09=20*=20process=20= specific=20memory.=20Two=20different=20processes=20publishing=20= statistics=0A+=09=20*=20do=20not=20block=20each=20other.=0A+=09=20*/=0A+=09= INJECTION_POINT("memcontext-server-crash",=20NULL);=0A+=09entry=20=3D=20= dshash_find_or_insert(MemoryStatsDsHash,=20key,=20&found);=0A+=0A+=09/*=0A= +=09=20*=20Entry=20has=20been=20deleted=20due=20to=20client=20process=20= exit.=20Make=20sure=20that=20the=0A+=09=20*=20client=20always=20deletes=20= the=20entry=20after=20taking=20required=20lock=20or=20this=0A+=09=20*=20= function=20may=20end=20up=20writing=20to=20unallocated=20memory.=0A+=09=20= */=0A+=09if=20(!found)=0A+=09{=0A+=09=09entry->stats_written=20=3D=20= false;=0A+=09=09end_memorycontext_reporting(entry,=20oldcontext,=20= context_id_lookup);=0A+=09=09return;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20= The=20client=20has=20timed=20out=20waiting=20for=20us=20to=20write=20= statistics=20and=20is=0A+=09=20*=20requesting=20statistics=20from=20some=20= other=20process=0A+=09=20*/=0A+=09if=20(entry->target_server_id=20!=3D=20= MyProcPid)=0A+=09{=0A+=09=09entry->stats_written=20=3D=20false;=0A+=09=09= end_memorycontext_reporting(entry,=20oldcontext,=20context_id_lookup);=0A= +=09=09return;=0A+=09}=0A+=0A+=09/*=20Should=20be=20allocated=20by=20a=20= client=20backend=20that=20is=20requesting=20statistics=20*/=0A+=09= Assert(entry->memstats_dsa_pointer=20!=3D=20InvalidDsaPointer);=0A+=09= meminfo=20=3D=20(MemoryStatsEntry=20*)=0A+=09=09= dsa_get_address(MemoryStatsDsaArea,=20entry->memstats_dsa_pointer);=0A+=0A= +=09if=20(entry->summary)=0A+=09{=0A+=09=09int=09=09=09cxt_id=20=3D=200;=0A= +=09=09List=09=20=20=20*path=20=3D=20NIL;=0A+=09=09MemoryStatsContextId=20= *contextid_entry;=0A+=0A+=09=09/*=20Copy=20TopMemoryContext=20statistics=20= to=20DSA=20*/=0A+=09=09memset(&stat,=200,=20sizeof(stat));=0A+=09=09= (*TopMemoryContext->methods->stats)=20(TopMemoryContext,=20NULL,=20NULL,=0A= +=09=09=09=09=09=09=09=09=09=09=09=20&stat,=20true);=0A+=09=09path=20=3D=20= lcons_int(1,=20path);=0A+=09=09PublishMemoryContext(meminfo,=20cxt_id,=20= TopMemoryContext,=20path,=20stat,=0A+=09=09=09=09=09=09=09=201);=0A+=0A+=09= =09contextid_entry=20=3D=20(MemoryStatsContextId=20*)=20= hash_search(context_id_lookup,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09= =09=09=20=20=20&TopMemoryContext,=0A+=09=09=09=09=09=09=09=09=09=09=09=09= =09=09=09=20=20=20HASH_ENTER,=20&found);=0A+=09=09Assert(!found);=0A+=0A= +=09=09/*=0A+=09=09=20*=20context=20id=20starts=20with=201=0A+=09=09=20= */=0A+=09=09contextid_entry->context_id=20=3D=20cxt_id=20+=201;=0A+=0A+=09= =09/*=0A+=09=09=20*=20Copy=20statistics=20for=20each=20of=20= TopMemoryContexts=20children.=20=20This=0A+=09=09=20*=20includes=20= statistics=20of=20at=20most=20100=20children=20per=20node,=20with=20each=0A= +=09=09=20*=20child=20node=20limited=20to=20a=20depth=20of=20100=20in=20= its=20subtree.=0A+=09=09=20*/=0A+=09=09for=20(MemoryContext=20c=20=3D=20= TopMemoryContext->firstchild;=20c=20!=3D=20NULL;=0A+=09=09=09=20c=20=3D=20= c->nextchild)=0A+=09=09{=0A+=09=09=09MemoryContextCounters=20= grand_totals;=0A+=09=09=09int=09=09=09num_contexts=20=3D=200;=0A+=0A+=09=09= =09path=20=3D=20NIL;=0A+=09=09=09memset(&grand_totals,=200,=20= sizeof(grand_totals));=0A+=0A+=09=09=09cxt_id++;=0A+=09=09=09= contextid_entry=20=3D=20(MemoryStatsContextId=20*)=20= hash_search(context_id_lookup,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09= =09=09=09=20=20=20&c,=20HASH_ENTER,=20&found);=0A+=09=09=09= Assert(!found);=0A+=09=09=09contextid_entry->context_id=20=3D=20cxt_id=20= +=201;=0A+=0A+=09=09=09MemoryContextStatsCounter(c,=20&grand_totals,=20= &num_contexts);=0A+=0A+=09=09=09path=20=3D=20compute_context_path(c,=20= context_id_lookup);=0A+=0A+=09=09=09PublishMemoryContext(meminfo,=20= cxt_id,=20c,=20path,=0A+=09=09=09=09=09=09=09=09=20grand_totals,=20= num_contexts);=0A+=09=09}=0A+=09=09entry->total_stats=20=3D=20cxt_id=20+=20= 1;=0A+=0A+=09=09entry->stats_written=20=3D=20true;=0A+=09=09= end_memorycontext_reporting(entry,=20oldcontext,=20context_id_lookup);=0A= +=09=09/*=20Notify=20waiting=20client=20backend=20and=20return=20*/=0A+=09= =09ConditionVariableSignal(&entry->memcxt_cv);=0A+=09=09return;=0A+=09}=0A= +=09foreach_ptr(MemoryContextData,=20cur,=20contexts)=0A+=09{=0A+=09=09= List=09=20=20=20*path=20=3D=20NIL;=0A+=09=09MemoryStatsContextId=20= *contextid_entry;=0A+=0A+=09=09contextid_entry=20=3D=20= (MemoryStatsContextId=20*)=20hash_search(context_id_lookup,=0A+=09=09=09=09= =09=09=09=09=09=09=09=09=09=09=09=20=20=20&cur,=0A+=09=09=09=09=09=09=09=09= =09=09=09=09=09=09=09=20=20=20HASH_ENTER,=20&found);=0A+=09=09= Assert(!found);=0A+=0A+=09=09/*=0A+=09=09=20*=20context=20id=20starts=20= with=201=0A+=09=09=20*/=0A+=09=09contextid_entry->context_id=20=3D=20= context_id=20+=201;=0A+=0A+=09=09/*=0A+=09=09=20*=20Figure=20out=20the=20= transient=20context_id=20of=20this=20context=20and=20each=20of=20its=0A+=09= =09=20*=20ancestors,=20to=20compute=20a=20path=20for=20this=20context.=0A= +=09=09=20*/=0A+=09=09path=20=3D=20compute_context_path(cur,=20= context_id_lookup);=0A+=0A+=09=09/*=20Examine=20the=20context=20stats=20= */=0A+=09=09memset(&stat,=200,=20sizeof(stat));=0A+=09=09= (*cur->methods->stats)=20(cur,=20NULL,=20NULL,=20&stat,=20true);=0A+=0A+=09= =09/*=20Account=20for=20saving=20one=20statistics=20slot=20for=20= cumulative=20reporting=20*/=0A+=09=09if=20(context_id=20<=20= (MAX_MEMORY_CONTEXT_STATS_NUM=20-=201))=0A+=09=09{=0A+=09=09=09/*=20Copy=20= statistics=20to=20DSA=20memory=20*/=0A+=09=09=09= PublishMemoryContext(meminfo,=20context_id,=20cur,=20path,=20stat,=201);=0A= +=09=09}=0A+=09=09else=0A+=09=09{=0A+=09=09=09= meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].totalspace=20+=3D=20= stat.totalspace;=0A+=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=20= 1].nblocks=20+=3D=20stat.nblocks;=0A+=09=09=09= meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].freespace=20+=3D=20= stat.freespace;=0A+=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=20= 1].freechunks=20+=3D=20stat.freechunks;=0A+=09=09}=0A+=0A+=09=09/*=0A+=09= =09=20*=20DSA=20max=20limit=20per=20process=20is=20reached,=20write=20= aggregate=20of=20the=0A+=09=09=20*=20remaining=20statistics.=0A+=09=09=20= *=0A+=09=09=20*=20We=20can=20store=20contexts=20from=200=20to=20= max_stats=20-=201.=20When=20context_id=20is=0A+=09=09=20*=20greater=20= than=20max_stats,=20we=20stop=20reporting=20individual=20statistics=0A+=09= =09=20*=20when=20context_id=20equals=20max_stats=20-=202.=20As=20we=20= use=20max_stats=20-=201=20array=0A+=09=09=20*=20slot=20for=20reporting=20= cumulative=20statistics=20or=20"Remaining=20Totals".=0A+=09=09=20*/=0A+=09= =09if=20(context_id=20=3D=3D=20(MAX_MEMORY_CONTEXT_STATS_NUM=20-=202))=0A= +=09=09{=0A+=09=09=09int=09=09=09namelen=20=3D=20strlen("Remaining=20= Totals");=0A+=0A+=09=09=09num_individual_stats=20=3D=20context_id=20+=20= 1;=0A+=09=09=09strlcpy(meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=20= 1].name,=0A+=09=09=09=09=09"Remaining=20Totals",=20namelen=20+=201);=0A+=09= =09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].ident[0]=20=3D=20= '\0';=0A+=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].path[0]=20= =3D=200;=0A+=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].type=20= =3D=200;=0A+=09=09}=0A+=09=09context_id++;=0A+=0A+=09=09for=20= (MemoryContext=20c=20=3D=20cur->firstchild;=20c=20!=3D=20NULL;=20c=20=3D=20= c->nextchild)=0A+=09=09=09contexts=20=3D=20lappend(contexts,=20c);=0A+=09= }=0A+=0A+=09/*=0A+=09=20*=20Statistics=20are=20not=20aggregated,=20i.e=20= individual=20statistics=20reported=20when=0A+=09=20*=20context_id=20<=3D=20= max_stats.=0A+=09=20*/=0A+=09if=20(context_id=20<=3D=20= MAX_MEMORY_CONTEXT_STATS_NUM)=0A+=09{=0A+=09=09entry->total_stats=20=3D=20= context_id;=0A+=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=20= 1].num_agg_stats=20=3D=201;=0A+=09}=0A+=09/*=20Report=20number=20of=20= aggregated=20memory=20contexts=20*/=0A+=09else=0A+=09{=0A+=09=09= meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].num_agg_stats=20=3D=20= context_id=0A+=09=09=09-=20num_individual_stats;=0A+=0A+=09=09/*=0A+=09=09= =20*=20Total=20stats=20equals=20num_individual_stats=20+=201=20record=20= for=20cumulative=0A+=09=09=20*=20statistics.=0A+=09=09=20*/=0A+=09=09= entry->total_stats=20=3D=20num_individual_stats=20+=201;=0A+=09}=0A+=09= entry->stats_written=20=3D=20true;=0A+=09= end_memorycontext_reporting(entry,=20oldcontext,=20context_id_lookup);=0A= +=09/*=20Notify=20waiting=20client=20backend=20and=20return=20*/=0A+=09= ConditionVariableSignal(&entry->memcxt_cv);=0A+}=0A+=0A+/*=0A+=20*=20= Clean=20up=20before=20exit=20from=20ProcessGetMemoryContextInterrupt=0A+=20= */=0A+static=20void=0A= +end_memorycontext_reporting(MemoryStatsDSHashEntry=20*entry,=0A+=09=09=09= =09=09=09=09MemoryContext=20oldcontext,=20HTAB=20*context_id_lookup)=0A= +{=0A+=09MemoryContext=20curr_ctx=20=3D=20CurrentMemoryContext;=0A+=0A+=09= dshash_release_lock(MemoryStatsDsHash,=20entry);=0A+=0A+=09= hash_destroy(context_id_lookup);=0A+=09= MemoryContextSwitchTo(oldcontext);=0A+=09MemoryContextReset(curr_ctx);=0A= +}=0A+=0A+/*=0A+=20*=20compute_context_path=0A+=20*=0A+=20*=20Append=20= the=20transient=20context_id=20of=20this=20context=20and=20each=20of=20= its=20ancestors=0A+=20*=20to=20a=20list,=20in=20order=20to=20compute=20a=20= path.=0A+=20*/=0A+static=20List=20*=0A= +compute_context_path(MemoryContext=20c,=20HTAB=20*context_id_lookup)=0A= +{=0A+=09bool=09=09found;=0A+=09List=09=20=20=20*path=20=3D=20NIL;=0A+=09= MemoryContext=20cur_context;=0A+=0A+=09for=20(cur_context=20=3D=20c;=20= cur_context=20!=3D=20NULL;=20cur_context=20=3D=20cur_context->parent)=0A= +=09{=0A+=09=09MemoryStatsContextId=20*cur_entry;=0A+=0A+=09=09cur_entry=20= =3D=20hash_search(context_id_lookup,=20&cur_context,=20HASH_FIND,=20= &found);=0A+=0A+=09=09if=20(!found)=0A+=09=09=09elog(ERROR,=20"hash=20= table=20corrupted,=20can't=20construct=20path=20value");=0A+=0A+=09=09= path=20=3D=20lcons_int(cur_entry->context_id,=20path);=0A+=09}=0A+=0A+=09= return=20path;=0A+}=0A+=0A+/*=0A+=20*=20PublishMemoryContext=0A+=20*=0A+=20= *=20Copy=20the=20memory=20context=20statistics=20of=20a=20single=20= context=20to=20a=20DSA=20memory=0A+=20*/=0A+static=20void=0A= +PublishMemoryContext(MemoryStatsEntry=20*memcxt_info,=20int=20curr_id,=0A= +=09=09=09=09=09=20MemoryContext=20context,=20List=20*path,=0A+=09=09=09=09= =09=20MemoryContextCounters=20stat,=20int=20num_contexts)=0A+{=0A+=09= const=20char=20*ident=20=3D=20context->ident;=0A+=09const=20char=20*name=20= =3D=20context->name;=0A+=0A+=09/*=0A+=09=20*=20To=20be=20consistent=20= with=20logging=20output,=20we=20label=20dynahash=20contexts=20with=0A+=09= =20*=20just=20the=20hash=20table=20name=20as=20with=20= MemoryContextStatsPrint().=0A+=09=20*/=0A+=09if=20(context->ident=20&&=20= strncmp(context->name,=20"dynahash",=208)=20=3D=3D=200)=0A+=09{=0A+=09=09= name=20=3D=20context->ident;=0A+=09=09ident=20=3D=20NULL;=0A+=09}=0A+=0A= +=09if=20(name=20!=3D=20NULL)=0A+=09{=0A+=09=09int=09=09=09namelen=20=3D=20= strlen(name);=0A+=0A+=09=09if=20(strlen(name)=20>=3D=20= MEMORY_CONTEXT_NAME_SHMEM_SIZE)=0A+=09=09=09namelen=20=3D=20= pg_mbcliplen(name,=20namelen,=0A+=09=09=09=09=09=09=09=09=20=20=20= MEMORY_CONTEXT_NAME_SHMEM_SIZE=20-=201);=0A+=0A+=09=09= strlcpy(memcxt_info[curr_id].name,=20name,=20namelen=20+=201);=0A+=09}=0A= +=09else=0A+=09=09/*=20Clearing=20the=20array=20*/=0A+=09=09= memcxt_info[curr_id].name[0]=20=3D=20'\0';=0A+=0A+=09/*=20Trim=20and=20= copy=20the=20identifier=20if=20it=20is=20not=20set=20to=20NULL=20*/=0A+=09= if=20(ident=20!=3D=20NULL)=0A+=09{=0A+=09=09int=09=09=09idlen=20=3D=20= strlen(context->ident);=0A+=0A+=09=09/*=0A+=09=09=20*=20Some=20= identifiers=20such=20as=20SQL=20query=20string=20can=20be=20very=20long,=0A= +=09=09=20*=20truncate=20oversize=20identifiers.=0A+=09=09=20*/=0A+=09=09= if=20(idlen=20>=3D=20MEMORY_CONTEXT_IDENT_SHMEM_SIZE)=0A+=09=09=09idlen=20= =3D=20pg_mbcliplen(ident,=20idlen,=0A+=09=09=09=09=09=09=09=09=20= MEMORY_CONTEXT_IDENT_SHMEM_SIZE=20-=201);=0A+=0A+=09=09= strlcpy(memcxt_info[curr_id].ident,=20ident,=20idlen=20+=201);=0A+=09}=0A= +=09else=0A+=09=09memcxt_info[curr_id].ident[0]=20=3D=20'\0';=0A+=0A+=09= /*=20Allocate=20DSA=20memory=20for=20storing=20path=20information=20*/=0A= +=09if=20(path=20=3D=3D=20NIL)=0A+=09=09memcxt_info[curr_id].path[0]=20=3D= =200;=0A+=09else=0A+=09{=0A+=09=09int=09=09=09levels=20=3D=20= Min(list_length(path),=20MAX_PATH_DISPLAY_LENGTH);=0A+=0A+=09=09= memcxt_info[curr_id].path_length=20=3D=20levels;=0A+=09=09= memcxt_info[curr_id].levels=20=3D=20list_length(path);=0A+=0A+=09=09= foreach_int(i,=20path)=0A+=09=09{=0A+=09=09=09= memcxt_info[curr_id].path[foreach_current_index(i)]=20=3D=20i;=0A+=09=09=09= if=20(--levels=20=3D=3D=200)=0A+=09=09=09=09break;=0A+=09=09}=0A+=09}=0A= +=09memcxt_info[curr_id].type=20=3D=20context->type;=0A+=09= memcxt_info[curr_id].totalspace=20=3D=20stat.totalspace;=0A+=09= memcxt_info[curr_id].nblocks=20=3D=20stat.nblocks;=0A+=09= memcxt_info[curr_id].freespace=20=3D=20stat.freespace;=0A+=09= memcxt_info[curr_id].freechunks=20=3D=20stat.freechunks;=0A+=09= memcxt_info[curr_id].num_agg_stats=20=3D=20num_contexts;=0A+}=0A+=0A= +void=0A+AtProcExit_memstats_cleanup(int=20code,=20Datum=20arg)=0A+{=0A+=09= int=09=09=09idx=20=3D=20MyProcNumber;=0A+=09MemoryStatsDSHashEntry=20= *entry;=0A+=09char=09=09key[CLIENT_KEY_SIZE];=0A+=09bool=09=09found;=0A+=0A= +=09if=20(MemoryStatsDsHash=20!=3D=20NULL)=0A+=09{=0A+=09=09= snprintf(key,=20CLIENT_KEY_SIZE,=20"%d",=20idx);=0A+=09=09entry=20=3D=20= dshash_find_or_insert(MemoryStatsDsHash,=20key,=20&found);=0A+=0A+=09=09= if=20(found)=0A+=09=09{=0A+=09=09=09if=20(MemoryStatsDsaArea=20!=3D=20= NULL=20&&=0A+=09=09=09=09DsaPointerIsValid(entry->memstats_dsa_pointer))=0A= +=09=09=09=09dsa_free(MemoryStatsDsaArea,=20= entry->memstats_dsa_pointer);=0A+=09=09}=0A+=09=09= dshash_delete_entry(MemoryStatsDsHash,=20entry);=0A+=09}=0A+=09= LWLockAcquire(client_keys_lock,=20LW_EXCLUSIVE);=0A+=09client_keys[idx]=20= =3D=20-1;=0A+=09LWLockRelease(client_keys_lock);=0A+}=0Adiff=20--git=20= a/src/backend/utils/init/globals.c=20b/src/backend/utils/init/globals.c=0A= index=20d31cb45a058..92b0446b80c=20100644=0A---=20= a/src/backend/utils/init/globals.c=0A+++=20= b/src/backend/utils/init/globals.c=0A@@=20-39,6=20+39,7=20@@=20volatile=20= sig_atomic_t=20TransactionTimeoutPending=20=3D=20false;=0A=20volatile=20= sig_atomic_t=20IdleSessionTimeoutPending=20=3D=20false;=0A=20volatile=20= sig_atomic_t=20ProcSignalBarrierPending=20=3D=20false;=0A=20volatile=20= sig_atomic_t=20LogMemoryContextPending=20=3D=20false;=0A+volatile=20= sig_atomic_t=20PublishMemoryContextPending=20=3D=20false;=0A=20volatile=20= sig_atomic_t=20IdleStatsUpdateTimeoutPending=20=3D=20false;=0A=20= volatile=20uint32=20InterruptHoldoffCount=20=3D=200;=0A=20volatile=20= uint32=20QueryCancelHoldoffCount=20=3D=200;=0Adiff=20--git=20= a/src/backend/utils/init/postinit.c=20= b/src/backend/utils/init/postinit.c=0Aindex=2098f9598cd78..202403ebc63=20= 100644=0A---=20a/src/backend/utils/init/postinit.c=0A+++=20= b/src/backend/utils/init/postinit.c=0A@@=20-658,6=20+658,13=20@@=20= BaseInit(void)=0A=20=09=20*=20drop=20ephemeral=20slots,=20which=20in=20= turn=20triggers=20stats=20reporting.=0A=20=09=20*/=0A=20=09= ReplicationSlotInitialize();=0A+=0A+=09/*=0A+=09=20*=20The=20before=20= shmem=20exit=20callback=20frees=20the=20DSA=20memory=20occupied=20by=20= the=0A+=09=20*=20latest=20memory=20context=20statistics=20that=20could=20= be=20published=20by=20this=20proc=0A+=09=20*=20if=20requested.=0A+=09=20= */=0A+=09before_shmem_exit(AtProcExit_memstats_cleanup,=200);=0A=20}=0A=20= =0A=20=0Adiff=20--git=20a/src/backend/utils/mmgr/mcxt.c=20= b/src/backend/utils/mmgr/mcxt.c=0Aindex=2047fd774c7d2..31c4de9f0b4=20= 100644=0A---=20a/src/backend/utils/mmgr/mcxt.c=0A+++=20= b/src/backend/utils/mmgr/mcxt.c=0A@@=20-1008,6=20+1008,37=20@@=20= MemoryContextStatsInternal(MemoryContext=20context,=20int=20level,=0A=20=09= }=0A=20}=0A=20=0A+=0A+/*=0A+=20*=20MemoryContextStatsCounter=0A+=20*=0A+=20= *=20Accumulate=20statistics=20counts=20into=20*totals.=20totals=20should=20= not=20be=20NULL.=0A+=20*=20This=20involves=20a=20non-recursive=20tree=20= traversal.=0A+=20*/=0A+void=0A+MemoryContextStatsCounter(MemoryContext=20= context,=20MemoryContextCounters=20*totals,=0A+=09=09=09=09=09=09=20=20= int=20*num_contexts)=0A+{=0A+=09int=09=09=09ichild=20=3D=201;=0A+=0A+=09= *num_contexts=20=3D=200;=0A+=09context->methods->stats(context,=20NULL,=20= NULL,=20totals,=20false);=0A+=0A+=09for=20(MemoryContext=20curr=20=3D=20= context->firstchild;=0A+=09=09=20curr=20!=3D=20NULL;=0A+=09=09=20curr=20= =3D=20MemoryContextTraverseNext(curr,=20context))=0A+=09{=0A+=09=09= curr->methods->stats(curr,=20NULL,=20NULL,=20totals,=20false);=0A+=09=09= ichild++;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20Add=20the=20count=20of=20all=20= the=20children=20contexts=20which=20are=20traversed=0A+=09=20*=20= including=20the=20parent.=0A+=09=20*/=0A+=09*num_contexts=20=3D=20= *num_contexts=20+=20ichild;=0A+}=0A+=0A=20/*=0A=20=20*=20= MemoryContextStatsPrint=0A=20=20*=09=09Print=20callback=20used=20by=20= MemoryContextStatsInternal=0Adiff=20--git=20= a/src/include/catalog/pg_proc.dat=20b/src/include/catalog/pg_proc.dat=0A= index=2066af2d96d67..5713bbb1550=20100644=0A---=20= a/src/include/catalog/pg_proc.dat=0A+++=20= b/src/include/catalog/pg_proc.dat=0A@@=20-8617,6=20+8617,16=20@@=0A=20=20= =20prorettype=20=3D>=20'bool',=20proargtypes=20=3D>=20'int4',=0A=20=20=20= prosrc=20=3D>=20'pg_log_backend_memory_contexts'=20},=0A=20=0A+#=20= publishing=20memory=20contexts=20of=20the=20specified=20postgres=20= process=0A+{=20oid=20=3D>=20'2173',=20descr=20=3D>=20'publish=20memory=20= contexts=20of=20the=20specified=20backend',=0A+=20=20proname=20=3D>=20= 'pg_get_process_memory_contexts',=20provolatile=20=3D>=20'v',=0A+=20=20= prorows=20=3D>=20'100',=20proretset=20=3D>=20't',=20proparallel=20=3D>=20= 'r',=0A+=20=20prorettype=20=3D>=20'record',=20proargtypes=20=3D>=20'int4=20= bool',=0A+=20=20proallargtypes=20=3D>=20= '{int4,bool,text,text,text,int4,_int4,int8,int8,int8,int8,int8,int4}',=0A= +=20=20proargmodes=20=3D>=20'{i,i,o,o,o,o,o,o,o,o,o,o,o}',=0A+=20=20= proargnames=20=3D>=20'{pid,=20summary,=20name,=20ident,=20type,=20level,=20= path,=20total_bytes,=20total_nblocks,=20free_bytes,=20free_chunks,=20= used_bytes,=20num_agg_contexts}',=0A+=20=20prosrc=20=3D>=20= 'pg_get_process_memory_contexts'=20},=0A+=0A=20#=20non-persistent=20= series=20generator=0A=20{=20oid=20=3D>=20'1066',=20descr=20=3D>=20= 'non-persistent=20series=20generator',=0A=20=20=20proname=20=3D>=20= 'generate_series',=20prorows=20=3D>=20'1000',=0Adiff=20--git=20= a/src/include/miscadmin.h=20b/src/include/miscadmin.h=0Aindex=20= 9a7d733ddef..b76f24baed6=20100644=0A---=20a/src/include/miscadmin.h=0A= +++=20b/src/include/miscadmin.h=0A@@=20-96,6=20+96,7=20@@=20extern=20= PGDLLIMPORT=20volatile=20sig_atomic_t=20IdleSessionTimeoutPending;=0A=20= extern=20PGDLLIMPORT=20volatile=20sig_atomic_t=20= ProcSignalBarrierPending;=0A=20extern=20PGDLLIMPORT=20volatile=20= sig_atomic_t=20LogMemoryContextPending;=0A=20extern=20PGDLLIMPORT=20= volatile=20sig_atomic_t=20IdleStatsUpdateTimeoutPending;=0A+extern=20= PGDLLIMPORT=20volatile=20sig_atomic_t=20PublishMemoryContextPending;=0A=20= =0A=20extern=20PGDLLIMPORT=20volatile=20sig_atomic_t=20= CheckClientConnectionPending;=0A=20extern=20PGDLLIMPORT=20volatile=20= sig_atomic_t=20ClientConnectionLost;=0Adiff=20--git=20= a/src/include/storage/lwlocklist.h=20b/src/include/storage/lwlocklist.h=0A= index=205b0ce383408..613e769c84e=20100644=0A---=20= a/src/include/storage/lwlocklist.h=0A+++=20= b/src/include/storage/lwlocklist.h=0A@@=20-136,3=20+136,4=20@@=20= PG_LWLOCKTRANCHE(SUBTRANS_SLRU,=20SubtransSLRU)=0A=20= PG_LWLOCKTRANCHE(XACT_SLRU,=20XactSLRU)=0A=20= PG_LWLOCKTRANCHE(PARALLEL_VACUUM_DSA,=20ParallelVacuumDSA)=0A=20= PG_LWLOCKTRANCHE(AIO_URING_COMPLETION,=20AioUringCompletion)=0A= +PG_LWLOCKTRANCHE(MEMORY_CONTEXT_KEYS,=20MemoryContextReportingKeys)=0A= diff=20--git=20a/src/include/storage/procsignal.h=20= b/src/include/storage/procsignal.h=0Aindex=20afeeb1ca019..345d5a0ecb1=20= 100644=0A---=20a/src/include/storage/procsignal.h=0A+++=20= b/src/include/storage/procsignal.h=0A@@=20-35,6=20+35,7=20@@=20typedef=20= enum=0A=20=09PROCSIG_WALSND_INIT_STOPPING,=09/*=20ask=20walsenders=20to=20= prepare=20for=20shutdown=20=20*/=0A=20=09PROCSIG_BARRIER,=09=09=09/*=20= global=20barrier=20interrupt=20=20*/=0A=20=09PROCSIG_LOG_MEMORY_CONTEXT,=20= /*=20ask=20backend=20to=20log=20the=20memory=20contexts=20*/=0A+=09= PROCSIG_GET_MEMORY_CONTEXT,=20/*=20ask=20backend=20to=20send=20the=20= memory=20contexts=20*/=0A=20=09PROCSIG_PARALLEL_APPLY_MESSAGE,=20/*=20= Message=20from=20parallel=20apply=20workers=20*/=0A=20=0A=20=09/*=20= Recovery=20conflict=20reasons=20*/=0Adiff=20--git=20= a/src/include/utils/memutils.h=20b/src/include/utils/memutils.h=0Aindex=20= 7bbe5a36959..4296667cbf0=20100644=0A---=20a/src/include/utils/memutils.h=0A= +++=20b/src/include/utils/memutils.h=0A@@=20-18,7=20+18,7=20@@=0A=20= #define=20MEMUTILS_H=0A=20=0A=20#include=20"nodes/memnodes.h"=0A-=0A= +#include=20"utils/dsa.h"=0A=20=0A=20/*=0A=20=20*=20MaxAllocSize,=20= MaxAllocHugeSize=0A@@=20-48,7=20+48,6=20@@=0A=20=0A=20#define=20= AllocHugeSizeIsValid(size)=09((Size)=20(size)=20<=3D=20MaxAllocHugeSize)=0A= =20=0A-=0A=20/*=0A=20=20*=20Standard=20top-level=20memory=20contexts.=0A=20= =20*=0A@@=20-319,4=20+318,11=20@@=20pg_memory_is_all_zeros(const=20void=20= *ptr,=20size_t=20len)=0A=20=09return=20true;=0A=20}=0A=20=0A+extern=20= void=20ProcessGetMemoryContextInterrupt(void);=0A+extern=20void=20= HandleGetMemoryContextInterrupt(void);=0A+extern=20void=20= MemoryContextKeysShmemInit(void);=0A+extern=20Size=20= MemoryContextKeysShmemSize(void);=0A+extern=20void=20= MemoryContextStatsCounter(MemoryContext=20context,=20= MemoryContextCounters=20*totals,=0A+=09=09=09=09=09=09=09=09=09=20=20int=20= *num_contexts);=0A+extern=20void=20AtProcExit_memstats_cleanup(int=20= code,=20Datum=20arg);=0A=20#endif=09=09=09=09=09=09=09/*=20MEMUTILS_H=20= */=0Adiff=20--git=20a/src/test/regress/expected/sysviews.out=20= b/src/test/regress/expected/sysviews.out=0Aindex=20= 3b37fafa65b..21c65ad2d10=20100644=0A---=20= a/src/test/regress/expected/sysviews.out=0A+++=20= b/src/test/regress/expected/sysviews.out=0A@@=20-233,3=20+233,22=20@@=20= select=20*=20from=20pg_timezone_abbrevs=20where=20abbrev=20=3D=20'LMT';=0A= =20=20LMT=20=20=20=20|=20@=207=20hours=2052=20mins=2058=20secs=20ago=20|=20= f=0A=20(1=20row)=0A=20=0A+DO=20$$=0A+DECLARE=0A+=20=20=20=20= bg_writer_pid=20int;=0A+=20=20=20=20r=20RECORD;=0A+BEGIN=0A+=20=20=20=20=20= =20=20=20SELECT=20pid=20from=20pg_stat_activity=20where=20= backend_type=3D'background=20writer'=0A+=09=20INTO=20bg_writer_pid;=0A+=0A= +=20=20=20=20=20=20=20=20select=20type,=20name,=20ident=0A+=20=20=20=20=20= =20=20=20from=20pg_get_process_memory_contexts(bg_writer_pid,=20false)=0A= +=09=20where=20path=20=3D=20'{1}'=20into=20r;=0A+=09RAISE=20NOTICE=20= '%',=20r;=0A+=20=20=20=20=20=20=20=20select=20type,=20name,=20ident=0A+=20= =20=20=20=20=20=20=20from=20= pg_get_process_memory_contexts(pg_backend_pid(),=20false)=0A+=09=20where=20= path=20=3D=20'{1}'=20into=20r;=0A+=09RAISE=20NOTICE=20'%',=20r;=0A+END=20= $$;=0A+NOTICE:=20=20(AllocSet,TopMemoryContext,)=0A+NOTICE:=20=20= (AllocSet,TopMemoryContext,)=0Adiff=20--git=20= a/src/test/regress/sql/sysviews.sql=20= b/src/test/regress/sql/sysviews.sql=0Aindex=2066179f026b3..c9da4fc8c90=20= 100644=0A---=20a/src/test/regress/sql/sysviews.sql=0A+++=20= b/src/test/regress/sql/sysviews.sql=0A@@=20-101,3=20+101,21=20@@=20= select=20count(distinct=20utc_offset)=20>=3D=2024=20as=20ok=20from=20= pg_timezone_abbrevs;=0A=20--=20One=20specific=20case=20we=20can=20check=20= without=20much=20fear=20of=20breakage=0A=20--=20is=20the=20historical=20= local-mean-time=20value=20used=20for=20America/Los_Angeles.=0A=20select=20= *=20from=20pg_timezone_abbrevs=20where=20abbrev=20=3D=20'LMT';=0A+=0A+DO=20= $$=0A+DECLARE=0A+=20=20=20=20bg_writer_pid=20int;=0A+=20=20=20=20r=20= RECORD;=0A+BEGIN=0A+=20=20=20=20=20=20=20=20SELECT=20pid=20from=20= pg_stat_activity=20where=20backend_type=3D'background=20writer'=0A+=09=20= INTO=20bg_writer_pid;=0A+=0A+=20=20=20=20=20=20=20=20select=20type,=20= name,=20ident=0A+=20=20=20=20=20=20=20=20from=20= pg_get_process_memory_contexts(bg_writer_pid,=20false)=0A+=09=20where=20= path=20=3D=20'{1}'=20into=20r;=0A+=09RAISE=20NOTICE=20'%',=20r;=0A+=20=20= =20=20=20=20=20=20select=20type,=20name,=20ident=0A+=20=20=20=20=20=20=20= =20from=20pg_get_process_memory_contexts(pg_backend_pid(),=20false)=0A+=09= =20where=20path=20=3D=20'{1}'=20into=20r;=0A+=09RAISE=20NOTICE=20'%',=20= r;=0A+END=20$$;=0Adiff=20--git=20a/src/tools/pgindent/typedefs.list=20= b/src/tools/pgindent/typedefs.list=0Aindex=20cf3f6a7dafd..aa898f025c0=20= 100644=0A---=20a/src/tools/pgindent/typedefs.list=0A+++=20= b/src/tools/pgindent/typedefs.list=0A@@=20-1686,9=20+1686,11=20@@=20= MemoryContextCallback=0A=20MemoryContextCallbackFunction=0A=20= MemoryContextCounters=0A=20MemoryContextData=0A-MemoryContextId=0A=20= MemoryContextMethodID=0A=20MemoryContextMethods=0A+MemoryStatsContextId=0A= +MemoryStatsEntry=0A+MemoryStatsDSHashEntry=0A=20MemoryStatsPrintFunc=0A=20= MergeAction=0A=20MergeActionState=0A--=20=0A2.39.3=20(Apple=20Git-146)=0A= =0A= --Apple-Mail=_21AB57B4-9CC2-4353-9F79-C3685A4FC23C Content-Disposition: attachment; filename=v43-0002-Test-module-to-test-memory-context-reporting-wit.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v43-0002-Test-module-to-test-memory-context-reporting-wit.patch" Content-Transfer-Encoding: quoted-printable =46rom=2000c38517db21893543f0af5b0c2f4eccc0a23658=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Rahila=20Syed=20=0A= Date:=20Fri,=2028=20Nov=202025=2014:46:38=20+0530=0ASubject:=20[PATCH=20= v43=202/3]=20Test=20module=20to=20test=20memory=20context=20reporting=20= with=0A=20injection=20points=0A=0A---=0A=20src/test/modules/Makefile=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=201=20+=0A= =20.../test_memcontext_reporting/Makefile=20=20=20=20=20=20=20=20|=20=20= 32=20++++++=0A=20.../t/001_memcontext_inj.pl=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20|=20=2058=20++++++++++=0A=20= .../test_memcontext_reporting--1.0.sql=20=20=20=20=20=20=20=20|=20=20=20= 7=20++=0A=20.../test_memcontext_reporting.c=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20|=20102=20++++++++++++++++++=0A=20= .../test_memcontext_reporting.control=20=20=20=20=20=20=20=20=20|=20=20=20= 4=20+=0A=206=20files=20changed,=20204=20insertions(+)=0A=20create=20mode=20= 100644=20src/test/modules/test_memcontext_reporting/Makefile=0A=20create=20= mode=20100644=20= src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl=0A=20= create=20mode=20100644=20= src/test/modules/test_memcontext_reporting/test_memcontext_reporting--1.0.= sql=0A=20create=20mode=20100644=20= src/test/modules/test_memcontext_reporting/test_memcontext_reporting.c=0A= =20create=20mode=20100644=20= src/test/modules/test_memcontext_reporting/test_memcontext_reporting.contr= ol=0A=0Adiff=20--git=20a/src/test/modules/Makefile=20= b/src/test/modules/Makefile=0Aindex=20d079b91b1a2..1ed0cdc66b3=20100644=0A= ---=20a/src/test/modules/Makefile=0A+++=20b/src/test/modules/Makefile=0A= @@=20-32,6=20+32,7=20@@=20SUBDIRS=20=3D=20\=0A=20=09=09=20=20= test_json_parser=20\=0A=20=09=09=20=20test_lfind=20\=0A=20=09=09=20=20= test_lwlock_tranches=20\=0A+=09=09=20=20test_memcontext_reporting=20\=0A=20= =09=09=20=20test_misc=20\=0A=20=09=09=20=20test_oat_hooks=20\=0A=20=09=09= =20=20test_parser=20\=0Adiff=20--git=20= a/src/test/modules/test_memcontext_reporting/Makefile=20= b/src/test/modules/test_memcontext_reporting/Makefile=0Anew=20file=20= mode=20100644=0Aindex=2000000000000..01a7baa0263=0A---=20/dev/null=0A+++=20= b/src/test/modules/test_memcontext_reporting/Makefile=0A@@=20-0,0=20= +1,32=20@@=0A+#=20src/test/modules/test_memcontext_reporting/Makefile=0A= +=0A+EXTRA_INSTALL=20=3D=20src/test/modules/injection_points=0A+=0A= +export=20enable_injection_points=0A+MODULE_big=20=3D=20= test_memcontext_reporting=0A+OBJS=20=3D=20\=0A+=09$(WIN32RES)=20\=0A+=09= test_memcontext_reporting.o=0A+PGFILEDESC=20=3D=20= "test_memcontext_reporting=20-=20test=20code=20for=20memory=20context=20= reporting"=0A+=0A+EXTENSION=20=3D=20test_memcontext_reporting=0A+DATA=20= =3D=20test_memcontext_reporting--1.0.sql=0A+=0A+REGRESS=20=3D=20= test_memcontext_reporting=0A+=0A+ifdef=20USE_PGXS=0A+PG_CONFIG=20=3D=20= pg_config=0A+PGXS=20:=3D=20$(shell=20$(PG_CONFIG)=20--pgxs)=0A+include=20= $(PGXS)=0A+else=0A+subdir=20=3D=20= src/test/modules/test_memcontext_reporting=0A+top_builddir=20=3D=20= ../../../..=0A+include=20$(top_builddir)/src/Makefile.global=0A+include=20= $(top_srcdir)/contrib/contrib-global.mk=0A+endif=0A+=0A+check:=0A+=09= $(prove_check)=0A+=0A+installcheck:=0A+=09$(prove_installcheck)=0Adiff=20= --git=20= a/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl=20= b/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl=0A= new=20file=20mode=20100644=0Aindex=2000000000000..69d8489eb37=0A---=20= /dev/null=0A+++=20= b/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl=0A= @@=20-0,0=20+1,58=20@@=0A+#=20Copyright=20(c)=202025,=20PostgreSQL=20= Global=20Development=20Group=0A+=0A+#=20Test=20suite=20for=20testing=20= memory=20context=20statistics=20reporting=0A+=0A+use=20strict;=0A+use=20= warnings=20FATAL=20=3D>=20'all';=0A+=0A+use=20PostgreSQL::Test::Cluster;=0A= +use=20PostgreSQL::Test::Utils;=0A+use=20Test::More;=0A+=0A+if=20= ($ENV{enable_injection_points}=20ne=20'yes')=0A+{=0A+=20=20=20=20=20=20=20= plan=20skip_all=20=3D>=20'Injection=20points=20not=20supported=20by=20= this=20build';=0A+}=0A+my=20$psql_err;=0A+#=20Create=20and=20start=20a=20= cluster=20with=20one=20node=0A+my=20$node=20=3D=20= PostgreSQL::Test::Cluster->new('main');=0A+$node->init(allows_streaming=20= =3D>=201);=0A+#=20max_connections=20need=20to=20be=20bumped=20in=20order=20= to=20accommodate=20for=20pgbench=20clients=0A+#=20and=20log_statement=20= is=20dialled=20down=20since=20it=20otherwise=20will=20generate=20= enormous=0A+#=20amounts=20of=20logging.=20Page=20verification=20failures=20= are=20still=20logged.=0A+$node->append_conf(=0A+=20=20=20=20=20=20=20= 'postgresql.conf',=0A+=20=20=20=20=20=20=20qq[=0A+max_connections=20=3D=20= 100=0A+log_statement=20=3D=20none=0A+]);=0A+$node->start;=0A= +$node->safe_psql('postgres',=20'CREATE=20EXTENSION=20= test_memcontext_reporting;');=0A+$node->safe_psql('postgres',=20'CREATE=20= EXTENSION=20injection_points;');=0A+#=20Attaching=20to=20a=20client=20= process=20injection=20point=20that=20throws=20an=20error=0A= +$node->safe_psql('postgres',=20"select=20= injection_points_attach('memcontext-client-crash',=20'error');");=0A+=0A= +my=20$pid=20=3D=20$node->safe_psql('postgres',=20"SELECT=20pid=20from=20= pg_stat_activity=20where=20backend_type=3D'checkpointer'");=0A+print=20= "PID";=0A+print=20$pid;=0A+=0A+#Client=20should=20have=20thrown=20error=0A= +$node->psql('postgres',=20qq(select=20= pg_get_process_memory_contexts($pid,=20true);),=20stderr=20=3D>=20= \$psql_err);=0A+like=20(=20$psql_err,=20qr/error=20triggered=20for=20= injection=20point=20memcontext-client-crash/);=0A+=0A+#Query=20the=20= same=20process=20after=20detaching=20the=20injection=20point,=20using=20= some=20other=20client=20and=20it=20should=20succeed.=0A= +$node->safe_psql('postgres',=20"select=20= injection_points_detach('memcontext-client-crash');");=0A+my=20= $topcontext_name=20=3D=20$node->safe_psql('postgres',=20"select=20name=20= from=20pg_get_process_memory_contexts($pid,=20true)=20where=20path=20=3D=20= '{1}';");=0A+ok($topcontext_name=20=3D=20'TopMemoryContext');=0A+=0A+#=20= Attaching=20to=20a=20target=20process=20injection=20point=20that=20= throws=20an=20error=0A+$node->safe_psql('postgres',=20"select=20= injection_points_attach('memcontext-server-crash',=20'error');");=0A+=0A= +#Server=20should=20have=20thrown=20error=0A+$node->psql('postgres',=20= qq(select=20pg_get_process_memory_contexts($pid,=20true);),=20stderr=20= =3D>=20\$psql_err);=0A+=0A+#Query=20the=20same=20process=20after=20= detaching=20the=20injection=20point,=20using=20some=20other=20client=20= and=20it=20should=20succeed.=0A+$node->safe_psql('postgres',=20"select=20= injection_points_detach('memcontext-server-crash');");=0A= +$topcontext_name=20=3D=20$node->safe_psql('postgres',=20"select=20name=20= from=20pg_get_process_memory_contexts($pid,=20true)=20where=20path=20=3D=20= '{1}';");=0A+ok($topcontext_name=20=3D=20'TopMemoryContext');=0A= +done_testing();=0Adiff=20--git=20= a/src/test/modules/test_memcontext_reporting/test_memcontext_reporting--1.= 0.sql=20= b/src/test/modules/test_memcontext_reporting/test_memcontext_reporting--1.= 0.sql=0Anew=20file=20mode=20100644=0Aindex=2000000000000..4f787cf789e=0A= ---=20/dev/null=0A+++=20= b/src/test/modules/test_memcontext_reporting/test_memcontext_reporting--1.= 0.sql=0A@@=20-0,0=20+1,7=20@@=0A+CREATE=20FUNCTION=20= memcontext_crash_server()=0A+RETURNS=20pg_catalog.void=0A+AS=20= 'MODULE_PATHNAME'=20LANGUAGE=20C;=0A+=0A+CREATE=20FUNCTION=20= memcontext_crash_client()=0A+RETURNS=20pg_catalog.void=0A+AS=20= 'MODULE_PATHNAME'=20LANGUAGE=20C;=0Adiff=20--git=20= a/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.c=20= b/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.c=0A= new=20file=20mode=20100644=0Aindex=2000000000000..774ae7df49d=0A---=20= /dev/null=0A+++=20= b/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.c=0A= @@=20-0,0=20+1,102=20@@=0A+/*=0A+=20*=20= -------------------------------------------------------------------------=0A= +=20*=0A+=20*=20Copyright=20(c)=202025,=20PostgreSQL=20Global=20= Development=20Group=0A+=20*=0A+=20*=20IDENTIFICATION=0A+=20*=20=20=20=20=20= =20=20=20=20=20=20=20=20= src/test/modules/test_memcontext_reporting/test_memcontext_reporting.c=0A= +=20*=0A+=20*=20= -------------------------------------------------------------------------=0A= +=20*/=0A+=0A+#include=20"postgres.h"=0A+#include=20= "utils/injection_point.h"=0A+#include=20"funcapi.h"=0A+#include=20= "utils/injection_point.h"=0A+#include=20"storage/dsm_registry.h"=0A+=0A= +PG_MODULE_MAGIC;=0A+=0A+extern=20PGDLLEXPORT=20void=20crash(const=20= char=20*name,=20const=20void=20*private_data,=20void=20*arg);=0A+=0A= +void=0A+crash(const=20char=20*name,=20const=20void=20*private_data,=20= void=20*arg)=0A+{=0A+=09abort();=0A+}=0A+=0A+/*=0A+=20*=20= memcontext_crash_client=0A+=20*=0A+=20*=20Ensure=20that=20the=20client=20= process=20aborts=20in=20between=20memory=20context=0A+=20*=20reporting.=0A= +=20*/=0A+PG_FUNCTION_INFO_V1(memcontext_crash_client);=0A+Datum=0A= +memcontext_crash_client(PG_FUNCTION_ARGS)=0A+{=0A+#ifdef=20= USE_INJECTION_POINTS=0A+=09= InjectionPointAttach("memcontext-client-crash",=0A+=09=09=09=09=09=09=20= "test_memcontext_reporting",=20"crash",=20NULL,=200);=0A+=0A+#else=0A+=09= elog(ERROR,=0A+=09=09=20"test=20is=20not=20working=20as=20intended=20= when=20injection=20points=20are=20disabled");=0A+#endif=0A+=09= PG_RETURN_VOID();=0A+}=0A+=0A= +PG_FUNCTION_INFO_V1(memcontext_detach_client);=0A+Datum=0A= +memcontext_detach_client(PG_FUNCTION_ARGS)=0A+{=0A+#ifdef=20= USE_INJECTION_POINTS=0A+=09= InjectionPointDetach("memcontext-client-crash");=0A+=0A+#else=0A+=09= elog(ERROR,=0A+=09=09=20"test=20is=20not=20working=20as=20intended=20= when=20injection=20points=20are=20disabled");=0A+#endif=0A+=09= PG_RETURN_VOID();=0A+}=0A+=0A+/*=0A+=20*=20memcontext_crash_server=0A+=20= *=0A+=20*=20Ensure=20that=20the=20server=20process=20crashes=20in=20= between=20memory=20context=0A+=20*=20reporting.=0A+=20*/=0A= +PG_FUNCTION_INFO_V1(memcontext_crash_server);=0A+Datum=0A= +memcontext_crash_server(PG_FUNCTION_ARGS)=0A+{=0A+#ifdef=20= USE_INJECTION_POINTS=0A+=09= InjectionPointAttach("memcontext-server-crash",=0A+=09=09=09=09=09=09=20= "test_memcontext_reporting",=20"crash",=20NULL,=200);=0A+=0A+#else=0A+=09= elog(ERROR,=0A+=09=09=20"test=20is=20not=20working=20as=20intended=20= when=20injection=20points=20are=20disabled");=0A+#endif=0A+=09= PG_RETURN_VOID();=0A+}=0A+=0A+/*=0A+=20*=20memcontext_detach_server=0A+=20= *=0A+=20*=20Detach=20the=20injection=20point=20which=20crashes=20the=20= server=0A+=20*=20reporting.=0A+=20*/=0A= +PG_FUNCTION_INFO_V1(memcontext_detach_server);=0A+Datum=0A= +memcontext_detach_server(PG_FUNCTION_ARGS)=0A+{=0A+#ifdef=20= USE_INJECTION_POINTS=0A+=09= InjectionPointDetach("memcontext-server-crash");=0A+=0A+#else=0A+=09= elog(ERROR,=0A+=09=09=20"test=20is=20not=20working=20as=20intended=20= when=20injection=20points=20are=20disabled");=0A+#endif=0A+=09= PG_RETURN_VOID();=0A+}=0Adiff=20--git=20= a/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.con= trol=20= b/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.con= trol=0Anew=20file=20mode=20100644=0Aindex=2000000000000..48b501682d5=0A= ---=20/dev/null=0A+++=20= b/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.con= trol=0A@@=20-0,0=20+1,4=20@@=0A+comment=20=3D=20'Test=20code=20for=20= memcontext=20reporting'=0A+default_version=20=3D=20'1.0'=0A= +module_pathname=20=3D=20'$libdir/test_memcontext_reporting'=0A= +relocatable=20=3D=20true=0A--=20=0A2.39.3=20(Apple=20Git-146)=0A=0A= --Apple-Mail=_21AB57B4-9CC2-4353-9F79-C3685A4FC23C Content-Disposition: attachment; filename=v43-0003-Review-comments.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v43-0003-Review-comments.patch" Content-Transfer-Encoding: quoted-printable =46rom=20257b7d87aaa55c415e205afad9ba6ae90e8d6195=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Daniel=20Gustafsson=20=0A= Date:=20Mon,=208=20Dec=202025=2010:38:43=20+0100=0ASubject:=20[PATCH=20= v43=203/3]=20Review=20comments=0A=0A---=0A=20= doc/src/sgml/func/func-admin.sgml=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=204=20+-=0A=20src/backend/catalog/system_functions.sql=20=20=20=20= =20=20|=20=2014=20+=0A=20src/backend/catalog/system_views.sql=20=20=20=20= =20=20=20=20=20=20|=20=20=205=20-=0A=20src/backend/utils/adt/mcxtfuncs.c=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20314=20+++++++++---------=0A=20= src/include/utils/memutils.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.../t/001_memcontext_inj.pl=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=2042=20++-=0A=20= src/tools/pgindent/typedefs.list=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=202=20+-=0A=207=20files=20changed,=20195=20insertions(+),=20188=20= deletions(-)=0A=0Adiff=20--git=20a/doc/src/sgml/func/func-admin.sgml=20= b/doc/src/sgml/func/func-admin.sgml=0Aindex=20a5c66837241..3e71ced60a2=20= 100644=0A---=20a/doc/src/sgml/func/func-admin.sgml=0A+++=20= b/doc/src/sgml/func/func-admin.sgml=0A@@=20-257,7=20+257,7=20@@=0A=20=20=20= =20=20=20=20=20=20=0A=20=20=20=20=20=20=20=20=20=20= pg_get_process_memory_contexts=0A=20=20=20=20=20=20=20= =20=20=0A-=20=20=20=20=20=20=20=20= pg_get_process_memory_contexts=20(=20= pid=20integer,=20= summary=20boolean=20)=0A+=20=20=20=20= =20=20=20=20pg_get_process_memory_contexts=20(=20= pid=20integer=20= ,summary=20boolean=20= DEFAULT=20false=20)=0A=20= =20=20=20=20=20=20=20=20setof=20record=0A=20=20= =20=20=20=20=20=20=20(=20name=20= text,=0A=20=20=20=20=20=20=20=20=20= ident=20text,=0A@@=20-360,7=20+360,7=20= @@=0A=20=20=20=20=20=20=20=20=20Statistics=20for=20contexts=20on=20level=20= 2=20and=20below=20are=20aggregates=20of=20all=0A=20=20=20=20=20=20=20=20=20= child=20contexts'=20statistics,=20where=20= num_agg_contexts=0A=20=20=20=20=20=20=20=20=20= indicate=20the=20number=20aggregated=20child=20contexts.=20=20When=0A-=20= =20=20=20=20=20=20=20summary=20is=20= false,=0A+=20=20=20=20=20=20=20=20= summary=20is=20false=20(the=20= default),=0A=20=20=20=20=20=20=20=20=20the=20= num_agg_contexts=20value=20is=201,=0A=20=20=20= =20=20=20=20=20=20indicating=20that=20individual=20statistics=20are=20= being=20displayed.=0A=20=20=20=20=20=20=20=20=0Adiff=20--git=20= a/src/backend/catalog/system_functions.sql=20= b/src/backend/catalog/system_functions.sql=0Aindex=20= 2d946d6d9e9..7b40bac5f57=20100644=0A---=20= a/src/backend/catalog/system_functions.sql=0A+++=20= b/src/backend/catalog/system_functions.sql=0A@@=20-657,6=20+657,17=20@@=20= LANGUAGE=20INTERNAL=0A=20STRICT=20VOLATILE=20PARALLEL=20UNSAFE=0A=20AS=20= 'pg_replication_origin_session_setup';=0A=20=0A+CREATE=20OR=20REPLACE=20= FUNCTION=0A+=20=20pg_get_process_memory_contexts(IN=20pid=20integer,=20= IN=20summary=20boolean=20DEFAULT=20false,=0A+=20=20OUT=20name=20text,=20= OUT=20ident=20text,=20OUT=20type=20text,=20OUT=20level=20integer,=0A+=20=20= OUT=20path=20integer[],=20OUT=20total_bytes=20bigint,=20OUT=20= total_nblocks=20bigint,=0A+=20=20OUT=20free_bytes=20bigint,=20OUT=20= free_chunks=20bigint,=20OUT=20used_bytes=20bigint,=0A+=20=20OUT=20= num_agg_contexts=20integer)=0A+RETURNS=20SETOF=20RECORD=0A+LANGUAGE=20= INTERNAL=0A+STRICT=20VOLATILE=20PARALLEL=20UNSAFE=0A+AS=20= 'pg_get_process_memory_contexts';=0A+=0A=20--=0A=20--=20The=20default=20= permissions=20for=20functions=20mean=20that=20anyone=20can=20execute=20= them.=0A=20--=20A=20number=20of=20functions=20shouldn't=20be=20= executable=20by=20just=20anyone,=20but=20rather=0A@@=20-782,6=20+793,7=20= @@=20REVOKE=20EXECUTE=20ON=20FUNCTION=20pg_ls_logicalmapdir()=20FROM=20= PUBLIC;=0A=20=0A=20REVOKE=20EXECUTE=20ON=20FUNCTION=20= pg_ls_replslotdir(text)=20FROM=20PUBLIC;=0A=20=0A+REVOKE=20EXECUTE=20ON=20= FUNCTION=20pg_get_process_memory_contexts(integer,=20boolean)=20FROM=20= PUBLIC;=0A=20--=0A=20--=20We=20also=20set=20up=20some=20things=20as=20= accessible=20to=20standard=20roles.=0A=20--=0A@@=20-808,6=20+820,8=20@@=20= GRANT=20EXECUTE=20ON=20FUNCTION=20pg_current_logfile()=20TO=20= pg_monitor;=0A=20=0A=20GRANT=20EXECUTE=20ON=20FUNCTION=20= pg_current_logfile(text)=20TO=20pg_monitor;=0A=20=0A+GRANT=20EXECUTE=20= ON=20FUNCTION=20pg_get_process_memory_contexts(integer,=20boolean)=20TO=20= pg_read_all_stats;=0A+=0A=20GRANT=20pg_read_all_settings=20TO=20= pg_monitor;=0A=20=0A=20GRANT=20pg_read_all_stats=20TO=20pg_monitor;=0A= diff=20--git=20a/src/backend/catalog/system_views.sql=20= b/src/backend/catalog/system_views.sql=0Aindex=20= 17ec512622b..086c4c8fb6f=20100644=0A---=20= a/src/backend/catalog/system_views.sql=0A+++=20= b/src/backend/catalog/system_views.sql=0A@@=20-692,11=20+692,6=20@@=20= GRANT=20SELECT=20ON=20pg_backend_memory_contexts=20TO=20= pg_read_all_stats;=0A=20REVOKE=20EXECUTE=20ON=20FUNCTION=20= pg_get_backend_memory_contexts()=20FROM=20PUBLIC;=0A=20GRANT=20EXECUTE=20= ON=20FUNCTION=20pg_get_backend_memory_contexts()=20TO=20= pg_read_all_stats;=0A=20=0A-REVOKE=20EXECUTE=20ON=20FUNCTION=0A-=09= pg_get_process_memory_contexts(integer,=20boolean)=20FROM=20PUBLIC;=0A= -GRANT=20EXECUTE=20ON=20FUNCTION=0A-=09= pg_get_process_memory_contexts(integer,=20boolean)=20TO=20= pg_read_all_stats;=0A-=0A=20--=20Statistics=20views=0A=20=0A=20CREATE=20= VIEW=20pg_stat_all_tables=20AS=0Adiff=20--git=20= a/src/backend/utils/adt/mcxtfuncs.c=20= b/src/backend/utils/adt/mcxtfuncs.c=0Aindex=20c661eef7ae9..f1b5c3a0887=20= 100644=0A---=20a/src/backend/utils/adt/mcxtfuncs.c=0A+++=20= b/src/backend/utils/adt/mcxtfuncs.c=0A@@=20-49,8=20+49,11=20@@=0A=20=20= */=0A=20#define=20MAX_MEMORY_CONTEXT_STATS_NUM=20= MEMORY_CONTEXT_REPORT_MAX_PER_BACKEND=20/=20(sizeof(MemoryStatsEntry))=0A= =20=0A-/*=20Size=20of=20dshash=20key=20*/=0A-#define=20CLIENT_KEY_SIZE=20= 32=0A+/*=0A+=20*=20Size=20of=20dshash=20key.=20The=20key=20is=20a=20= uint32=20rendered=20as=20a=20string,=2010=20chars=0A+=20*=20plus=20space=20= for=20a=20NULL=20terminator=20can=20hold=20all=20the=20values.=0A+=20*/=0A= +#define=20CLIENT_KEY_SIZE=20(10=20+=201)=0A=20=0A=20/*=20Dynamic=20= shared=20memory=20state=20for=20reporting=20statistics=20per=20context=20= */=0A=20typedef=20struct=20MemoryStatsEntry=0A@@=20-92,8=20+95,7=20@@=20= static=20const=20dshash_parameters=20memctx_dsh_params=20=3D=20{=0A=20};=0A= =20=0A=20/*=0A-=20*=20These=20are=20used=20for=20reporting=20memory=20= context=0A-=20*=20statistics=20of=20a=20process.=0A+=20*=20These=20are=20= used=20for=20reporting=20memory=20context=20statistics=20of=20a=20= process.=0A=20=20*/=0A=20=0A=20/*=20Lock=20to=20control=20access=20to=20= client_keys=20array=20*/=0A@@=20-103,10=20+105,9=20@@=20static=20LWLock=20= *client_keys_lock=20=3D=20NULL;=0A=20static=20int=20*client_keys=20=3D=20= NULL;=0A=20=0A=20/*=0A-=20*=20Table=20to=20store=20pointers=20to=20dsa=20= memory=20containing=0A-=20*=20memory=20statistics=20and=20other=20meta=20= data.=20There=20is=20one=0A-=20*=20entry=20per=20client=20backend=20= request,=20keyed=20by=20ProcNumber=20of=0A-=20*=20the=20client=20= obtained=20from=20client_keys=20array=20above.=0A+=20*=20Table=20to=20= store=20pointers=20to=20DSA=20memory=20containing=20memory=20statistics=20= and=20other=0A+=20*=20metadata.=20There=20is=20one=20entry=20per=20= client=20backend=20request,=20keyed=20by=20ProcNumber=0A+=20*=20of=20the=20= client=20obtained=20from=20client_keys=20array=20above.=0A=20=20*/=0A=20= static=20dshash_table=20*MemoryStatsDsHash=20=3D=20NULL;=0A=20=0A@@=20= -125,8=20+126,6=20@@=20static=20void=20= PublishMemoryContext(MemoryStatsEntry=20*memcxt_info,=0A=20=09=09=09=09=09= =09=09=09=20MemoryContextCounters=20stat,=0A=20=09=09=09=09=09=09=09=09=20= int=20num_contexts);=0A=20static=20List=20= *compute_context_path(MemoryContext=20c,=20HTAB=20*context_id_lookup);=0A= -static=20void=20end_memorycontext_reporting(MemoryStatsDSHashEntry=20= *entry,=20MemoryContext=20oldcontext,=0A-=09=09=09=09=09=09=09=09=09=09= HTAB=20*context_id_lookup);=0A=20=0A=20/*=20----------=0A=20=20*=20The=20= max=20bytes=20for=20showing=20identifiers=20of=20MemoryContext.=0A@@=20= -140,15=20+139,14=20@@=20static=20void=20= end_memorycontext_reporting(MemoryStatsDSHashEntry=20*entry,=20MemoryCon=0A= =20#define=20MEMORY_STATS_MAX_TIMEOUT=205=0A=20=0A=20/*=0A-=20*=20= MemoryStatsContextId=0A-=20*=09=09Used=20for=20storage=20of=20transient=20= identifiers=20for=0A-=20*=09=09pg_get_backend_memory_contexts=20and=20= the=20likes.=0A+=20*=20MemoryContextId=0A+=20*=09=09Used=20for=20storage=20= of=20transient=20identifiers=20for=20memory=20context=20reporting=0A=20=20= */=0A-typedef=20struct=20MemoryStatsContextId=0A+typedef=20struct=20= MemoryContextId=0A=20{=0A=20=09MemoryContext=20context;=0A=20=09int=09=09= =09context_id;=0A-}=20MemoryStatsContextId;=0A+}=20MemoryContextId;=0A=20= =0A=20/*=0A=20=20*=20int_list_to_array=0A@@=20-199,7=20+197,7=20@@=20= PutMemoryContextsStatsTupleStore(Tuplestorestate=20*tupstore,=0A=20=09=20= */=0A=20=09for=20(MemoryContext=20cur=20=3D=20context;=20cur=20!=3D=20= NULL;=20cur=20=3D=20cur->parent)=0A=20=09{=0A-=09=09MemoryStatsContextId=20= *entry;=0A+=09=09MemoryContextId=20*entry;=0A=20=09=09bool=09=09found;=0A= =20=0A=20=09=09entry=20=3D=20hash_search(context_id_lookup,=20&cur,=20= HASH_FIND,=20&found);=0A@@=20-314,7=20+312,7=20@@=20= pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)=0A=20=09HTAB=09=20=20=20= *context_id_lookup;=0A=20=0A=20=09ctl.keysize=20=3D=20= sizeof(MemoryContext);=0A-=09ctl.entrysize=20=3D=20= sizeof(MemoryStatsContextId);=0A+=09ctl.entrysize=20=3D=20= sizeof(MemoryContextId);=0A=20=09ctl.hcxt=20=3D=20CurrentMemoryContext;=0A= =20=0A=20=09context_id_lookup=20=3D=20= hash_create("pg_get_backend_memory_contexts",=0A@@=20-341,7=20+339,7=20= @@=20pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)=0A=20=0A=20=09= foreach_ptr(MemoryContextData,=20cur,=20contexts)=0A=20=09{=0A-=09=09= MemoryStatsContextId=20*entry;=0A+=09=09MemoryContextId=20*entry;=0A=20=09= =09bool=09=09found;=0A=20=0A=20=09=09/*=0A@@=20-349,8=20+347,8=20@@=20= pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)=0A=20=09=09=20*=20= PutMemoryContextsStatsTupleStore=20needs=20this=20to=20populate=20the=20= "path"=0A=20=09=09=20*=20column=20with=20the=20parent=20context_ids.=0A=20= =09=09=20*/=0A-=09=09entry=20=3D=20(MemoryStatsContextId=20*)=20= hash_search(context_id_lookup,=20&cur,=0A-=09=09=09=09=09=09=09=09=09=09=09= =09=09=20HASH_ENTER,=20&found);=0A+=09=09entry=20=3D=20(MemoryContextId=20= *)=20hash_search(context_id_lookup,=20&cur,=0A+=09=09=09=09=09=09=09=09=09= =09=09=09HASH_ENTER,=20&found);=0A=20=09=09entry->context_id=20=3D=20= context_id++;=0A=20=09=09Assert(!found);=0A=20=0A@@=20-437,10=20+435,8=20= @@=20pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)=0A=20=20*=09=09= wait=20for=20the=20results=20and=20display=20them.=0A=20=20*=0A=20=20*=20= By=20default,=20only=20superusers=20or=20users=20with=20= ROLE_PG_READ_ALL_STATS=20are=20allowed=0A-=20*=20to=20signal=20a=20= process=20to=20return=20the=20memory=20contexts.=20This=20is=20because=20= allowing=0A-=20*=20any=20users=20to=20issue=20this=20request=20at=20an=20= unbounded=20rate=20would=20cause=20lots=20of=0A-=20*=20requests=20to=20= be=20sent,=20which=20can=20lead=20to=20denial=20of=20service.=20= Additional=20roles=0A-=20*=20can=20be=20permitted=20with=20GRANT.=0A+=20= *=20to=20signal=20a=20process=20to=20return=20the=20memory=20contexts.=20= =20Additional=20roles=20can=20be=0A+=20*=20permitted=20with=20GRANT.=0A=20= =20*=0A=20=20*=20On=20receipt=20of=20this=20signal,=20a=20backend=20or=20= an=20auxiliary=20process=20sets=20the=20flag=0A=20=20*=20in=20the=20= signal=20handler,=20which=20causes=20the=20next=20CHECK_FOR_INTERRUPTS()=0A= @@=20-453,14=20+449,14=20@@=20= pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)=0A=20=20*=20at=20the=20= end=20of=20the=20buffer.=0A=20=20*=0A=20=20*=20After=20sending=20the=20= signal,=20wait=20on=20a=20condition=20variable.=20The=20publishing=0A-=20= *=20backend,=20after=20copying=20the=20data=20to=20shared=20memory,=20= sends=20signal=20on=20that=0A+=20*=20backend,=20after=20copying=20the=20= data=20to=20shared=20memory,=20sends=20a=20signal=20on=20that=0A=20=20*=20= condition=20variable.=20There=20is=20one=20condition=20variable=20per=20= client=20process.=0A=20=20*=20Once=20the=20condition=20variable=20is=20= signalled,=20check=20if=20the=20latest=20memory=20context=0A=20=20*=20= information=20is=20available=20and=20display.=0A=20=20*=0A=20=20*=20If=20= the=20publishing=20backend=20does=20not=20respond=20before=20the=20= condition=20variable=0A-=20*=20times=20out,=20which=20is=20set=20to=20a=20= predefined=20value=20MEMORY_STATS_MAX_TIMEOUT,=20give=20up=0A-=20*=20and=20= return=20NULL.=0A+=20*=20times=20out,=20which=20is=20set=20to=20a=20= predefined=20value=20MEMORY_STATS_MAX_TIMEOUT,=20give=0A+=20*=20up=20and=20= return=20NULL.=0A=20=20*/=0A=20Datum=0A=20= pg_get_process_memory_contexts(PG_FUNCTION_ARGS)=0A@@=20-495,12=20+491,8=20= @@=20pg_get_process_memory_contexts(PG_FUNCTION_ARGS)=0A=20=09=20*/=0A=20= =09if=20(proc=20=3D=3D=20NULL)=0A=20=09{=0A-=09=09/*=0A-=09=09=20*=20= This=20is=20a=20warning=20because=20we=20don't=20want=20to=20break=20= loops.=0A-=09=09=20*/=0A=20=09=09ereport(WARNING,=0A-=09=09=09=09= errmsg("PID=20%d=20is=20not=20a=20PostgreSQL=20server=20process",=0A-=09=09= =09=09=09=20=20=20pid));=0A+=09=09=09=09errmsg("PID=20%d=20is=20not=20a=20= PostgreSQL=20server=20process",=20pid));=0A=20=09=09PG_RETURN_NULL();=0A=20= =09}=0A=20=0A@@=20-508,7=20+500,7=20@@=20= pg_get_process_memory_contexts(PG_FUNCTION_ARGS)=0A=20=0A=20=09/*=0A=20=09= =20*=20Create=20a=20DSA=20to=20allocate=20memory=20for=20copying=20= memory=20contexts=20statistics.=0A-=09=20*=20Allocate=20the=20memory=20= in=20the=20DSA=20and=20send=20dsa=20pointer=20to=20the=20server=0A+=09=20= *=20Allocate=20the=20memory=20in=20the=20DSA=20and=20send=20DSA=20= pointer=20to=20the=20server=0A=20=09=20*=20process=20for=20storing=20the=20= context=20statistics.=20If=20number=20of=20contexts=0A=20=09=20*=20= exceed=20a=20predefined=20limit=20(1MB),=20a=20cumulative=20total=20is=20= stored=20for=20such=0A=20=09=20*=20contexts.=0A@@=20-521,8=20+513,8=20@@=20= pg_get_process_memory_contexts(PG_FUNCTION_ARGS)=0A=20=09=09=09=09=09=09=09= =09=09=09=20&found);=0A=20=0A=20=09/*=0A-=09=20*=20The=20dsa=20pointers=20= containing=20statistics=20for=20each=20client=20are=20stored=20in=20a=0A= -=09=20*=20dshash=20table.=20In=20addition=20to=20dsa=20pointer,=20each=20= entry=20in=20this=20table=20also=0A+=09=20*=20The=20DSA=20pointers=20= containing=20statistics=20for=20each=20client=20are=20stored=20in=20a=0A= +=09=20*=20dshash=20table.=20In=20addition=20to=20DSA=20pointer,=20each=20= entry=20in=20this=20table=20also=0A=20=09=20*=20contains=20information=20= about=20the=20statistics,=20condition=20variable=20for=0A=20=09=20*=20= signalling=20between=20client=20and=20the=20server=20and=20miscellaneous=20= data=0A=20=09=20*=20specific=20to=20a=20request.=20There=20is=20one=20= entry=20per=20client=20request=20in=20the=0A@@=20-838,9=20+830,9=20@@=20= HandleGetMemoryContextInterrupt(void)=0A=20=20*=20output.=0A=20=20*=0A=20= =20*=20Statistics=20for=20all=20the=20processes=20are=20shared=20via=20= the=20same=20dynamic=20shared=0A-=20*=20area.=20Individual=20statistics=20= are=20tracked=20independently=20in=0A-=20*=20per-process=20DSA=20= pointers.=20These=20pointers=20are=20stored=20in=20a=20dshash=20table=20= with=0A-=20*=20key=20as=20requesting=20clients=20ProcNumber.=0A+=20*=20= area.=20Individual=20statistics=20are=20tracked=20independently=20in=20= per-process=20DSA=0A+=20*=20pointers.=20These=20pointers=20are=20stored=20= in=20a=20dshash=20table=20with=20key=20as=20requesting=0A+=20*=20clients=20= ProcNumber.=0A=20=20*=0A=20=20*=20We=20calculate=20maximum=20number=20of=20= context's=20statistics=20that=20can=20be=20displayed=0A=20=20*=20using=20= a=20pre-determined=20limit=20for=20memory=20available=20per=20process=20= for=20this=0A@@=20-848,11=20+840,11=20@@=20= HandleGetMemoryContextInterrupt(void)=0A=20=20*=20context=20statistics=20= if=20any=20are=20captured=20as=20a=20cumulative=20total=20at=20the=20end=20= of=0A=20=20*=20individual=20context's=20statistics.=0A=20=20*=0A-=20*=20= If=20summary=20is=20true,=20we=20capture=20the=20level=201=20and=20level=20= 2=20contexts=0A-=20*=20statistics.=20=20For=20that=20we=20traverse=20the=20= memory=20context=20tree=20recursively=20in=0A-=20*=20depth=20first=20= search=20manner=20to=20cover=20all=20the=20children=20of=20a=20parent=20= context,=20to=0A-=20*=20be=20able=20to=20display=20a=20cumulative=20= total=20of=20memory=20consumption=20by=20a=20parent=20at=0A-=20*=20level=20= 2=20and=20all=20its=20children.=0A+=20*=20If=20summary=20is=20true,=20we=20= capture=20the=20level=201=20and=20level=202=20contexts=20statistics.=0A+=20= *=20For=20that=20we=20traverse=20the=20memory=20context=20tree=20= recursively=20in=20depth=20first=0A+=20*=20search=20manner=20to=20cover=20= all=20the=20children=20of=20a=20parent=20context,=20to=20be=20able=20to=0A= +=20*=20display=20a=20cumulative=20total=20of=20memory=20consumption=20= by=20a=20parent=20at=20level=202=20and=0A+=20*=20all=20its=20children.=0A= =20=20*/=0A=20void=0A=20ProcessGetMemoryContextInterrupt(void)=0A@@=20= -899,7=20+891,7=20@@=20ProcessGetMemoryContextInterrupt(void)=0A=20=09=20= *=20similar=20to=20its=20local=20backend=20counterpart.=0A=20=09=20*/=0A=20= =09ctl.keysize=20=3D=20sizeof(MemoryContext);=0A-=09ctl.entrysize=20=3D=20= sizeof(MemoryStatsContextId);=0A+=09ctl.entrysize=20=3D=20= sizeof(MemoryContextId);=0A=20=09ctl.hcxt=20=3D=20CurrentMemoryContext;=0A= =20=0A=20=09context_id_lookup=20=3D=20= hash_create("pg_get_remote_backend_memory_contexts",=0A@@=20-912,7=20= +904,7=20@@=20ProcessGetMemoryContextInterrupt(void)=0A=20=0A=20=09/*=0A=20= =09=20*=20If=20DSA=20exists,=20created=20by=20another=20process=20= requesting=20statistics,=20attach=0A-=09=20*=20to=20it.=20We=20expect=20= the=20client=20process=20to=20create=20required=20DSA=20and=20Dshash=0A+=09= =20*=20to=20it.=20We=20expect=20the=20client=20process=20to=20create=20= required=20DSA=20and=20DSHash=0A=20=09=20*=20table.=0A=20=09=20*/=0A=20=09= if=20(MemoryStatsDsaArea=20=3D=3D=20NULL)=0A@@=20-923,7=20+915,6=20@@=20= ProcessGetMemoryContextInterrupt(void)=0A=20=09=09MemoryStatsDsHash=20=3D=20= GetNamedDSHash("memory_context_statistics_dshash",=0A=20=09=09=09=09=09=09= =09=09=09=09=20=20=20&memctx_dsh_params,=20&found);=0A=20=0A-=0A=20=09= snprintf(key,=20CLIENT_KEY_SIZE,=20"%d",=20clientProcNumber);=0A=20=0A=20= =09/*=0A@@=20-935,25=20+926,24=20@@=20= ProcessGetMemoryContextInterrupt(void)=0A=20=09entry=20=3D=20= dshash_find_or_insert(MemoryStatsDsHash,=20key,=20&found);=0A=20=0A=20=09= /*=0A-=09=20*=20Entry=20has=20been=20deleted=20due=20to=20client=20= process=20exit.=20Make=20sure=20that=20the=0A-=09=20*=20client=20always=20= deletes=20the=20entry=20after=20taking=20required=20lock=20or=20this=0A-=09= =20*=20function=20may=20end=20up=20writing=20to=20unallocated=20memory.=0A= +=09=20*=20Check=20if=20the=20entry=20has=20been=20deleted=20due=20to=20= calling=20process=20exiting,=20or=0A+=09=20*=20if=20the=20caller=20has=20= timed=20out=20waiting=20for=20us=20and=20have=20issued=20a=20request=20= to=0A+=09=20*=20another=20backend.=0A+=09=20*=0A+=09=20*=20XXX=20?:=20= Make=20sure=20that=20the=20client=20always=20deletes=20the=20entry=20= after=20taking=0A+=09=20*=20required=20lock=20or=20this=20function=20may=20= end=20up=20writing=20to=20unallocated=0A+=09=20*=20memory.=0A=20=09=20*/=0A= -=09if=20(!found)=0A+=09if=20(!found=20||=20entry->target_server_id=20!=3D= =20MyProcPid)=0A=20=09{=0A=20=09=09entry->stats_written=20=3D=20false;=0A= -=09=09end_memorycontext_reporting(entry,=20oldcontext,=20= context_id_lookup);=0A-=09=09return;=0A-=09}=0A=20=0A-=09/*=0A-=09=20*=20= The=20client=20has=20timed=20out=20waiting=20for=20us=20to=20write=20= statistics=20and=20is=0A-=09=20*=20requesting=20statistics=20from=20some=20= other=20process=0A-=09=20*/=0A-=09if=20(entry->target_server_id=20!=3D=20= MyProcPid)=0A-=09{=0A-=09=09entry->stats_written=20=3D=20false;=0A-=09=09= end_memorycontext_reporting(entry,=20oldcontext,=20context_id_lookup);=0A= +=09=09dshash_release_lock(MemoryStatsDsHash,=20entry);=0A+=0A+=09=09= hash_destroy(context_id_lookup);=0A+=09=09= MemoryContextSwitchTo(oldcontext);=0A+=09=09= MemoryContextReset(memstats_ctx);=0A+=0A=20=09=09return;=0A=20=09}=0A=20=0A= @@=20-966,7=20+956,7=20@@=20ProcessGetMemoryContextInterrupt(void)=0A=20=09= {=0A=20=09=09int=09=09=09cxt_id=20=3D=200;=0A=20=09=09List=09=20=20=20= *path=20=3D=20NIL;=0A-=09=09MemoryStatsContextId=20*contextid_entry;=0A+=09= =09MemoryContextId=20*contextid_entry;=0A=20=0A=20=09=09/*=20Copy=20= TopMemoryContext=20statistics=20to=20DSA=20*/=0A=20=09=09memset(&stat,=20= 0,=20sizeof(stat));=0A@@=20-976,9=20+966,9=20@@=20= ProcessGetMemoryContextInterrupt(void)=0A=20=09=09= PublishMemoryContext(meminfo,=20cxt_id,=20TopMemoryContext,=20path,=20= stat,=0A=20=09=09=09=09=09=09=09=201);=0A=20=0A-=09=09contextid_entry=20= =3D=20(MemoryStatsContextId=20*)=20hash_search(context_id_lookup,=0A-=09=09= =09=09=09=09=09=09=09=09=09=09=09=09=09=20=20=20&TopMemoryContext,=0A-=09= =09=09=09=09=09=09=09=09=09=09=09=09=09=09=20=20=20HASH_ENTER,=20= &found);=0A+=09=09contextid_entry=20=3D=20(MemoryContextId=20*)=20= hash_search(context_id_lookup,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09= =09=20=20&TopMemoryContext,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09=09= =20=20HASH_ENTER,=20&found);=0A=20=09=09Assert(!found);=0A=20=0A=20=09=09= /*=0A@@=20-1001,8=20+991,8=20@@=20ProcessGetMemoryContextInterrupt(void)=0A= =20=09=09=09memset(&grand_totals,=200,=20sizeof(grand_totals));=0A=20=0A=20= =09=09=09cxt_id++;=0A-=09=09=09contextid_entry=20=3D=20= (MemoryStatsContextId=20*)=20hash_search(context_id_lookup,=0A-=09=09=09=09= =09=09=09=09=09=09=09=09=09=09=09=09=20=20=20&c,=20HASH_ENTER,=20= &found);=0A+=09=09=09contextid_entry=20=3D=20(MemoryContextId=20*)=20= hash_search(context_id_lookup,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09= =09=09=20=20&c,=20HASH_ENTER,=20&found);=0A=20=09=09=09Assert(!found);=0A= =20=09=09=09contextid_entry->context_id=20=3D=20cxt_id=20+=201;=0A=20=0A= @@=20-1014,119=20+1004,111=20@@=20ProcessGetMemoryContextInterrupt(void)=0A= =20=09=09=09=09=09=09=09=09=20grand_totals,=20num_contexts);=0A=20=09=09= }=0A=20=09=09entry->total_stats=20=3D=20cxt_id=20+=201;=0A-=0A-=09=09= entry->stats_written=20=3D=20true;=0A-=09=09= end_memorycontext_reporting(entry,=20oldcontext,=20context_id_lookup);=0A= -=09=09/*=20Notify=20waiting=20client=20backend=20and=20return=20*/=0A-=09= =09ConditionVariableSignal(&entry->memcxt_cv);=0A-=09=09return;=0A=20=09= }=0A-=09foreach_ptr(MemoryContextData,=20cur,=20contexts)=0A+=09else=0A=20= =09{=0A-=09=09List=09=20=20=20*path=20=3D=20NIL;=0A-=09=09= MemoryStatsContextId=20*contextid_entry;=0A+=09=09= foreach_ptr(MemoryContextData,=20cur,=20contexts)=0A+=09=09{=0A+=09=09=09= List=09=20=20=20*path=20=3D=20NIL;=0A+=09=09=09MemoryContextId=20= *contextid_entry;=0A=20=0A-=09=09contextid_entry=20=3D=20= (MemoryStatsContextId=20*)=20hash_search(context_id_lookup,=0A-=09=09=09=09= =09=09=09=09=09=09=09=09=09=09=09=20=20=20&cur,=0A-=09=09=09=09=09=09=09=09= =09=09=09=09=09=09=09=20=20=20HASH_ENTER,=20&found);=0A-=09=09= Assert(!found);=0A+=09=09=09contextid_entry=20=3D=20(MemoryContextId=20= *)=20hash_search(context_id_lookup,=0A+=09=09=09=09=09=09=09=09=09=09=09=09= =09=09=09=20=20&cur,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=20=20= HASH_ENTER,=20&found);=0A+=09=09=09Assert(!found);=0A=20=0A-=09=09/*=0A-=09= =09=20*=20context=20id=20starts=20with=201=0A-=09=09=20*/=0A-=09=09= contextid_entry->context_id=20=3D=20context_id=20+=201;=0A+=09=09=09/*=0A= +=09=09=09=20*=20context=20id=20starts=20with=201=0A+=09=09=09=20*/=0A+=09= =09=09contextid_entry->context_id=20=3D=20context_id=20+=201;=0A+=0A+=09=09= =09/*=0A+=09=09=09=20*=20Figure=20out=20the=20transient=20context_id=20= of=20this=20context=20and=20each=20of=0A+=09=09=09=20*=20its=20= ancestors,=20to=20compute=20a=20path=20for=20this=20context.=0A+=09=09=09= =20*/=0A+=09=09=09path=20=3D=20compute_context_path(cur,=20= context_id_lookup);=0A+=0A+=09=09=09/*=20Examine=20the=20context=20stats=20= */=0A+=09=09=09memset(&stat,=200,=20sizeof(stat));=0A+=09=09=09= (*cur->methods->stats)=20(cur,=20NULL,=20NULL,=20&stat,=20true);=0A+=0A+=09= =09=09/*=20Account=20for=20saving=20one=20statistics=20slot=20for=20= cumulative=20reporting=20*/=0A+=09=09=09if=20(context_id=20<=20= (MAX_MEMORY_CONTEXT_STATS_NUM=20-=201))=0A+=09=09=09{=0A+=09=09=09=09/*=20= Copy=20statistics=20to=20DSA=20memory=20*/=0A+=09=09=09=09= PublishMemoryContext(meminfo,=20context_id,=20cur,=20path,=20stat,=201);=0A= +=09=09=09}=0A+=09=09=09else=0A+=09=09=09{=0A+=09=09=09=09= meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].totalspace=20+=3D=20= stat.totalspace;=0A+=09=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=20= 1].nblocks=20+=3D=20stat.nblocks;=0A+=09=09=09=09= meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].freespace=20+=3D=20= stat.freespace;=0A+=09=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=20= 1].freechunks=20+=3D=20stat.freechunks;=0A+=09=09=09}=0A+=0A+=09=09=09/*=0A= +=09=09=09=20*=20DSA=20max=20limit=20per=20process=20is=20reached,=20= write=20aggregate=20of=20the=0A+=09=09=09=20*=20remaining=20statistics.=0A= +=09=09=09=20*=0A+=09=09=09=20*=20We=20can=20store=20contexts=20from=200=20= to=20max_stats=20-=201.=20When=20context_id=0A+=09=09=09=20*=20is=20= greater=20than=20max_stats,=20we=20stop=20reporting=20individual=0A+=09=09= =09=20*=20statistics=20when=20context_id=20equals=20max_stats=20-=202.=20= As=20we=20use=0A+=09=09=09=20*=20max_stats=20-=201=20array=20slot=20for=20= reporting=20cumulative=20statistics=20or=0A+=09=09=09=20*=20"Remaining=20= Totals".=0A+=09=09=09=20*/=0A+=09=09=09if=20(context_id=20=3D=3D=20= (MAX_MEMORY_CONTEXT_STATS_NUM=20-=202))=0A+=09=09=09{=0A+=09=09=09=09int=09= =09=09namelen=20=3D=20strlen("Remaining=20Totals");=0A+=0A+=09=09=09=09= num_individual_stats=20=3D=20context_id=20+=201;=0A+=09=09=09=09= strlcpy(meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].name,=0A+=09=09=09=09= =09=09"Remaining=20Totals",=20namelen=20+=201);=0A+=09=09=09=09= meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].ident[0]=20=3D=20'\0';=0A+=09= =09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].path[0]=20=3D=20= 0;=0A+=09=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].type=20=3D= =200;=0A+=09=09=09}=0A+=09=09=09context_id++;=0A+=0A+=09=09=09for=20= (MemoryContext=20c=20=3D=20cur->firstchild;=20c=20!=3D=20NULL;=20c=20=3D=20= c->nextchild)=0A+=09=09=09=09contexts=20=3D=20lappend(contexts,=20c);=0A= +=09=09}=0A=20=0A=20=09=09/*=0A-=09=09=20*=20Figure=20out=20the=20= transient=20context_id=20of=20this=20context=20and=20each=20of=20its=0A-=09= =09=20*=20ancestors,=20to=20compute=20a=20path=20for=20this=20context.=0A= +=09=09=20*=20Check=20if=20there=20are=20aggregated=20statistics=20or=20= not=20in=20the=20result=20set.=0A+=09=09=20*=20Statistics=20are=20= individually=20reported=20when=20context_id=20<=3D=20max_stats,=0A+=09=09= =20*=20only=20if=20context_id=20>=20max_stats=20will=20there=20be=20= aggregates.=0A=20=09=09=20*/=0A-=09=09path=20=3D=20= compute_context_path(cur,=20context_id_lookup);=0A-=0A-=09=09/*=20= Examine=20the=20context=20stats=20*/=0A-=09=09memset(&stat,=200,=20= sizeof(stat));=0A-=09=09(*cur->methods->stats)=20(cur,=20NULL,=20NULL,=20= &stat,=20true);=0A-=0A-=09=09/*=20Account=20for=20saving=20one=20= statistics=20slot=20for=20cumulative=20reporting=20*/=0A-=09=09if=20= (context_id=20<=20(MAX_MEMORY_CONTEXT_STATS_NUM=20-=201))=0A+=09=09if=20= (context_id=20<=3D=20MAX_MEMORY_CONTEXT_STATS_NUM)=0A=20=09=09{=0A-=09=09= =09/*=20Copy=20statistics=20to=20DSA=20memory=20*/=0A-=09=09=09= PublishMemoryContext(meminfo,=20context_id,=20cur,=20path,=20stat,=201);=0A= -=09=09}=0A-=09=09else=0A-=09=09{=0A-=09=09=09= meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].totalspace=20+=3D=20= stat.totalspace;=0A-=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=20= 1].nblocks=20+=3D=20stat.nblocks;=0A-=09=09=09= meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].freespace=20+=3D=20= stat.freespace;=0A-=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=20= 1].freechunks=20+=3D=20stat.freechunks;=0A+=09=09=09entry->total_stats=20= =3D=20context_id;=0A+=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=20= 1].num_agg_stats=20=3D=201;=0A=20=09=09}=0A=20=0A=20=09=09/*=0A-=09=09=20= *=20DSA=20max=20limit=20per=20process=20is=20reached,=20write=20= aggregate=20of=20the=0A-=09=09=20*=20remaining=20statistics.=0A-=09=09=20= *=0A-=09=09=20*=20We=20can=20store=20contexts=20from=200=20to=20= max_stats=20-=201.=20When=20context_id=20is=0A-=09=09=20*=20greater=20= than=20max_stats,=20we=20stop=20reporting=20individual=20statistics=0A-=09= =09=20*=20when=20context_id=20equals=20max_stats=20-=202.=20As=20we=20= use=20max_stats=20-=201=20array=0A-=09=09=20*=20slot=20for=20reporting=20= cumulative=20statistics=20or=20"Remaining=20Totals".=0A+=09=09=20*=20The=20= number=20of=20contexts=20exceeded=20the=20space=20available,=20so=20= report=20the=0A+=09=09=20*=20number=20of=20aggregated=20memory=20= contexts=0A=20=09=09=20*/=0A-=09=09if=20(context_id=20=3D=3D=20= (MAX_MEMORY_CONTEXT_STATS_NUM=20-=202))=0A+=09=09else=0A=20=09=09{=0A-=09= =09=09int=09=09=09namelen=20=3D=20strlen("Remaining=20Totals");=0A-=0A-=09= =09=09num_individual_stats=20=3D=20context_id=20+=201;=0A-=09=09=09= strlcpy(meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].name,=0A-=09=09=09=09= =09"Remaining=20Totals",=20namelen=20+=201);=0A-=09=09=09= meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].ident[0]=20=3D=20'\0';=0A-=09= =09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].path[0]=20=3D=200;=0A= -=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].type=20=3D=200;=0A= +=09=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].num_agg_stats=20= =3D=0A+=09=09=09=09context_id=20-=20num_individual_stats;=0A+=0A+=09=09=09= /*=0A+=09=09=09=20*=20Total=20stats=20equals=20num_individual_stats=20+=20= 1=20record=20for=0A+=09=09=09=20*=20cumulative=20statistics.=0A+=09=09=09= =20*/=0A+=09=09=09entry->total_stats=20=3D=20num_individual_stats=20+=20= 1;=0A=20=09=09}=0A-=09=09context_id++;=0A-=0A-=09=09for=20(MemoryContext=20= c=20=3D=20cur->firstchild;=20c=20!=3D=20NULL;=20c=20=3D=20c->nextchild)=0A= -=09=09=09contexts=20=3D=20lappend(contexts,=20c);=0A=20=09}=0A=20=0A-=09= /*=0A-=09=20*=20Statistics=20are=20not=20aggregated,=20i.e=20individual=20= statistics=20reported=20when=0A-=09=20*=20context_id=20<=3D=20max_stats.=0A= -=09=20*/=0A-=09if=20(context_id=20<=3D=20MAX_MEMORY_CONTEXT_STATS_NUM)=0A= -=09{=0A-=09=09entry->total_stats=20=3D=20context_id;=0A-=09=09= meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=201].num_agg_stats=20=3D=201;=0A= -=09}=0A-=09/*=20Report=20number=20of=20aggregated=20memory=20contexts=20= */=0A-=09else=0A-=09{=0A-=09=09meminfo[MAX_MEMORY_CONTEXT_STATS_NUM=20-=20= 1].num_agg_stats=20=3D=20context_id=0A-=09=09=09-=20= num_individual_stats;=0A-=0A-=09=09/*=0A-=09=09=20*=20Total=20stats=20= equals=20num_individual_stats=20+=201=20record=20for=20cumulative=0A-=09=09= =20*=20statistics.=0A-=09=09=20*/=0A-=09=09entry->total_stats=20=3D=20= num_individual_stats=20+=201;=0A-=09}=0A=20=09entry->stats_written=20=3D=20= true;=0A-=09end_memorycontext_reporting(entry,=20oldcontext,=20= context_id_lookup);=0A-=09/*=20Notify=20waiting=20client=20backend=20and=20= return=20*/=0A-=09ConditionVariableSignal(&entry->memcxt_cv);=0A-}=0A-=0A= -/*=0A-=20*=20Clean=20up=20before=20exit=20from=20= ProcessGetMemoryContextInterrupt=0A-=20*/=0A-static=20void=0A= -end_memorycontext_reporting(MemoryStatsDSHashEntry=20*entry,=0A-=09=09=09= =09=09=09=09MemoryContext=20oldcontext,=20HTAB=20*context_id_lookup)=0A= -{=0A-=09MemoryContext=20curr_ctx=20=3D=20CurrentMemoryContext;=0A-=0A=20= =09dshash_release_lock(MemoryStatsDsHash,=20entry);=0A-=0A=20=09= hash_destroy(context_id_lookup);=0A+=0A=20=09= MemoryContextSwitchTo(oldcontext);=0A-=09MemoryContextReset(curr_ctx);=0A= +=09MemoryContextReset(memstats_ctx);=0A+=09/*=20Notify=20waiting=20= client=20backend=20and=20return=20*/=0A+=09= ConditionVariableSignal(&entry->memcxt_cv);=0A=20}=0A=20=0A=20/*=0A@@=20= -1144,7=20+1126,7=20@@=20compute_context_path(MemoryContext=20c,=20HTAB=20= *context_id_lookup)=0A=20=0A=20=09for=20(cur_context=20=3D=20c;=20= cur_context=20!=3D=20NULL;=20cur_context=20=3D=20cur_context->parent)=0A=20= =09{=0A-=09=09MemoryStatsContextId=20*cur_entry;=0A+=09=09= MemoryContextId=20*cur_entry;=0A=20=0A=20=09=09cur_entry=20=3D=20= hash_search(context_id_lookup,=20&cur_context,=20HASH_FIND,=20&found);=0A= =20=0A@@=20-1167,8=20+1149,8=20@@=20= PublishMemoryContext(MemoryStatsEntry=20*memcxt_info,=20int=20curr_id,=0A= =20=09=09=09=09=09=20MemoryContext=20context,=20List=20*path,=0A=20=09=09= =09=09=09=20MemoryContextCounters=20stat,=20int=20num_contexts)=0A=20{=0A= -=09const=20char=20*ident=20=3D=20context->ident;=0A-=09const=20char=20= *name=20=3D=20context->name;=0A+=09char=09=20=20=20*ident=20=3D=20= unconstify(char=20*,=20context->ident);=0A+=09char=09=20=20=20*name=20=3D=20= unconstify(char=20*,=20context->name);=0A=20=0A=20=09/*=0A=20=09=20*=20= To=20be=20consistent=20with=20logging=20output,=20we=20label=20dynahash=20= contexts=20with=0A@@=20-1176,7=20+1158,7=20@@=20= PublishMemoryContext(MemoryStatsEntry=20*memcxt_info,=20int=20curr_id,=0A= =20=09=20*/=0A=20=09if=20(context->ident=20&&=20strncmp(context->name,=20= "dynahash",=208)=20=3D=3D=200)=0A=20=09{=0A-=09=09name=20=3D=20= context->ident;=0A+=09=09name=20=3D=20unconstify(char=20*,=20= context->ident);=0A=20=09=09ident=20=3D=20NULL;=0A=20=09}=0A=20=0A@@=20= -1184,7=20+1166,7=20@@=20PublishMemoryContext(MemoryStatsEntry=20= *memcxt_info,=20int=20curr_id,=0A=20=09{=0A=20=09=09int=09=09=09namelen=20= =3D=20strlen(name);=0A=20=0A-=09=09if=20(strlen(name)=20>=3D=20= MEMORY_CONTEXT_NAME_SHMEM_SIZE)=0A+=09=09if=20(namelen=20>=3D=20= MEMORY_CONTEXT_NAME_SHMEM_SIZE)=0A=20=09=09=09namelen=20=3D=20= pg_mbcliplen(name,=20namelen,=0A=20=09=09=09=09=09=09=09=09=20=20=20= MEMORY_CONTEXT_NAME_SHMEM_SIZE=20-=201);=0A=20=0A@@=20-1212,7=20+1194,7=20= @@=20PublishMemoryContext(MemoryStatsEntry=20*memcxt_info,=20int=20= curr_id,=0A=20=09else=0A=20=09=09memcxt_info[curr_id].ident[0]=20=3D=20= '\0';=0A=20=0A-=09/*=20Allocate=20DSA=20memory=20for=20storing=20path=20= information=20*/=0A+=09/*=20Store=20the=20path=20*/=0A=20=09if=20(path=20= =3D=3D=20NIL)=0A=20=09=09memcxt_info[curr_id].path[0]=20=3D=200;=0A=20=09= else=0Adiff=20--git=20a/src/include/utils/memutils.h=20= b/src/include/utils/memutils.h=0Aindex=204296667cbf0..617de0ebf91=20= 100644=0A---=20a/src/include/utils/memutils.h=0A+++=20= b/src/include/utils/memutils.h=0A@@=20-18,7=20+18,6=20@@=0A=20#define=20= MEMUTILS_H=0A=20=0A=20#include=20"nodes/memnodes.h"=0A-#include=20= "utils/dsa.h"=0A=20=0A=20/*=0A=20=20*=20MaxAllocSize,=20MaxAllocHugeSize=0A= @@=20-48,6=20+47,7=20@@=0A=20=0A=20#define=20AllocHugeSizeIsValid(size)=09= ((Size)=20(size)=20<=3D=20MaxAllocHugeSize)=0A=20=0A+=0A=20/*=0A=20=20*=20= Standard=20top-level=20memory=20contexts.=0A=20=20*=0Adiff=20--git=20= a/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl=20= b/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl=0A= index=2069d8489eb37..8fa12d1f693=20100644=0A---=20= a/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl=0A= +++=20= b/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl=0A= @@=20-11,7=20+11,7=20@@=20use=20Test::More;=0A=20=0A=20if=20= ($ENV{enable_injection_points}=20ne=20'yes')=0A=20{=0A-=20=20=20=20=20=20= =20plan=20skip_all=20=3D>=20'Injection=20points=20not=20supported=20by=20= this=20build';=0A+=09plan=20skip_all=20=3D>=20'Injection=20points=20not=20= supported=20by=20this=20build';=0A=20}=0A=20my=20$psql_err;=0A=20#=20= Create=20and=20start=20a=20cluster=20with=20one=20node=0A@@=20-21,8=20= +21,8=20@@=20$node->init(allows_streaming=20=3D>=201);=0A=20#=20and=20= log_statement=20is=20dialled=20down=20since=20it=20otherwise=20will=20= generate=20enormous=0A=20#=20amounts=20of=20logging.=20Page=20= verification=20failures=20are=20still=20logged.=0A=20$node->append_conf(=0A= -=20=20=20=20=20=20=20'postgresql.conf',=0A-=20=20=20=20=20=20=20qq[=0A+=09= 'postgresql.conf',=0A+=09qq[=0A=20max_connections=20=3D=20100=0A=20= log_statement=20=3D=20none=0A=20]);=0A@@=20-30,29=20+30,45=20@@=20= $node->start;=0A=20$node->safe_psql('postgres',=20'CREATE=20EXTENSION=20= test_memcontext_reporting;');=0A=20$node->safe_psql('postgres',=20= 'CREATE=20EXTENSION=20injection_points;');=0A=20#=20Attaching=20to=20a=20= client=20process=20injection=20point=20that=20throws=20an=20error=0A= -$node->safe_psql('postgres',=20"select=20= injection_points_attach('memcontext-client-crash',=20'error');");=0A= +$node->safe_psql('postgres',=0A+=09"select=20= injection_points_attach('memcontext-client-crash',=20'error');");=0A=20=0A= -my=20$pid=20=3D=20$node->safe_psql('postgres',=20"SELECT=20pid=20from=20= pg_stat_activity=20where=20backend_type=3D'checkpointer'");=0A+my=20$pid=20= =3D=20$node->safe_psql('postgres',=0A+=09"SELECT=20pid=20from=20= pg_stat_activity=20where=20backend_type=3D'checkpointer'");=0A=20print=20= "PID";=0A=20print=20$pid;=0A=20=0A=20#Client=20should=20have=20thrown=20= error=0A-$node->psql('postgres',=20qq(select=20= pg_get_process_memory_contexts($pid,=20true);),=20stderr=20=3D>=20= \$psql_err);=0A-like=20(=20$psql_err,=20qr/error=20triggered=20for=20= injection=20point=20memcontext-client-crash/);=0A+$node->psql(=0A+=09= 'postgres',=0A+=09qq(select=20pg_get_process_memory_contexts($pid,=20= true);),=0A+=09stderr=20=3D>=20\$psql_err);=0A+like($psql_err,=0A+=09= qr/error=20triggered=20for=20injection=20point=20= memcontext-client-crash/);=0A=20=0A=20#Query=20the=20same=20process=20= after=20detaching=20the=20injection=20point,=20using=20some=20other=20= client=20and=20it=20should=20succeed.=0A-$node->safe_psql('postgres',=20= "select=20injection_points_detach('memcontext-client-crash');");=0A-my=20= $topcontext_name=20=3D=20$node->safe_psql('postgres',=20"select=20name=20= from=20pg_get_process_memory_contexts($pid,=20true)=20where=20path=20=3D=20= '{1}';");=0A+$node->safe_psql('postgres',=0A+=09"select=20= injection_points_detach('memcontext-client-crash');");=0A+my=20= $topcontext_name=20=3D=20$node->safe_psql('postgres',=0A+=09"select=20= name=20from=20pg_get_process_memory_contexts($pid,=20true)=20where=20= path=20=3D=20'{1}';"=0A+);=0A=20ok($topcontext_name=20=3D=20= 'TopMemoryContext');=0A=20=0A=20#=20Attaching=20to=20a=20target=20= process=20injection=20point=20that=20throws=20an=20error=0A= -$node->safe_psql('postgres',=20"select=20= injection_points_attach('memcontext-server-crash',=20'error');");=0A= +$node->safe_psql('postgres',=0A+=09"select=20= injection_points_attach('memcontext-server-crash',=20'error');");=0A=20=0A= =20#Server=20should=20have=20thrown=20error=0A-$node->psql('postgres',=20= qq(select=20pg_get_process_memory_contexts($pid,=20true);),=20stderr=20= =3D>=20\$psql_err);=0A+$node->psql(=0A+=09'postgres',=0A+=09qq(select=20= pg_get_process_memory_contexts($pid,=20true);),=0A+=09stderr=20=3D>=20= \$psql_err);=0A=20=0A=20#Query=20the=20same=20process=20after=20= detaching=20the=20injection=20point,=20using=20some=20other=20client=20= and=20it=20should=20succeed.=0A-$node->safe_psql('postgres',=20"select=20= injection_points_detach('memcontext-server-crash');");=0A= -$topcontext_name=20=3D=20$node->safe_psql('postgres',=20"select=20name=20= from=20pg_get_process_memory_contexts($pid,=20true)=20where=20path=20=3D=20= '{1}';");=0A+$node->safe_psql('postgres',=0A+=09"select=20= injection_points_detach('memcontext-server-crash');");=0A= +$topcontext_name=20=3D=20$node->safe_psql('postgres',=0A+=09"select=20= name=20from=20pg_get_process_memory_contexts($pid,=20true)=20where=20= path=20=3D=20'{1}';"=0A+);=0A=20ok($topcontext_name=20=3D=20= 'TopMemoryContext');=0A=20done_testing();=0Adiff=20--git=20= a/src/tools/pgindent/typedefs.list=20b/src/tools/pgindent/typedefs.list=0A= index=20aa898f025c0..5e3122a468b=20100644=0A---=20= a/src/tools/pgindent/typedefs.list=0A+++=20= b/src/tools/pgindent/typedefs.list=0A@@=20-1686,9=20+1686,9=20@@=20= MemoryContextCallback=0A=20MemoryContextCallbackFunction=0A=20= MemoryContextCounters=0A=20MemoryContextData=0A+MemoryContextId=0A=20= MemoryContextMethodID=0A=20MemoryContextMethods=0A-MemoryStatsContextId=0A= =20MemoryStatsEntry=0A=20MemoryStatsDSHashEntry=0A=20= MemoryStatsPrintFunc=0A--=20=0A2.39.3=20(Apple=20Git-146)=0A=0A= --Apple-Mail=_21AB57B4-9CC2-4353-9F79-C3685A4FC23C--