Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1u05t7-00BYbm-EZ for pgsql-hackers@arkaria.postgresql.org; Wed, 02 Apr 2025 21:44:46 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1u05t3-000N1J-QC for pgsql-hackers@arkaria.postgresql.org; Wed, 02 Apr 2025 21:44:41 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1u05t3-000N1A-6r for pgsql-hackers@lists.postgresql.org; Wed, 02 Apr 2025 21:44:41 +0000 Received: from smtp.outgoing.loopia.se ([93.188.3.37]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1u05t0-0032e5-2r for pgsql-hackers@postgresql.org; Wed, 02 Apr 2025 21:44:40 +0000 Received: from s807.loopia.se (localhost [127.0.0.1]) by s807.loopia.se (Postfix) with ESMTP id C5F3232F38F for ; Wed, 02 Apr 2025 23:44:37 +0200 (CEST) Received: from s980.loopia.se (unknown [172.22.191.6]) by s807.loopia.se (Postfix) with ESMTP id AF2C832E962; Wed, 02 Apr 2025 23:44:37 +0200 (CEST) Received: from s472.loopia.se (unknown [172.22.191.5]) by s980.loopia.se (Postfix) with ESMTP id ACFF02201650; Wed, 02 Apr 2025 23:44:37 +0200 (CEST) X-Virus-Scanned: amavisd-new 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: s472.loopia.se (amavisd-new); dkim=pass (2048-bit key) header.d=yesql.se Received: from s980.loopia.se ([172.22.191.5]) by s472.loopia.se (s472.loopia.se [172.22.190.12]) (amavisd-new, port 10024) with LMTP id 72otktjrI_25; Wed, 2 Apr 2025 23:44:37 +0200 (CEST) X-Loopia-Auth: user X-Loopia-User: daniel@yesql.se X-Loopia-Originating-IP: 89.255.232.193 Received: from smtpclient.apple (customer-89-255-232-193.stosn.net [89.255.232.193]) (Authenticated sender: daniel@yesql.se) by s980.loopia.se (Postfix) with ESMTPSA id 977D122015F6; Wed, 02 Apr 2025 23:44:36 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yesql.se; s=loopiadkim1707475645; t=1743630276; bh=czXyRw3P2KXZ8ZwQiT1eld6I8sEfcEOOxOIXr/CCcwc=; h=From:Subject:Date:In-Reply-To:Cc:To:References; b=LtFeHi/HAr9NKYAIaO7UgzYKPUun6j7RfB1pR0kNl4Z1oYadPvkyFoBpQO0wpfUbM 2zX6YuaaJb+L+RQYl+Yr0YxhSrq98CUsz6A6fvPOGqYT9gChzcl8p2idx8CtVp5Q/E ApE3IhaFBu11/R13NpoyMvlO2OxInJkEn46b+u70a75MLy0xvToDnvEIvSe/qk1cuS gFJwYfNb0wFZMFrUFJ5PGfOabCYcYMkmxuijwjqUGJBYqL/krli2R/Apk4O9F9bHEw Am+l4YCZAS7Fe3+eFJwRB/6Apurx0a3nH1SqPImAVd72CeM6x5t3kcRQKB1QEhdmej OmQKYPCpEr8SA== From: Daniel Gustafsson Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_4EFDEB30-F8D3-4E32-86A9-BE439A72E4B8" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3776.700.51.11.1\)) Subject: Re: Enhancing Memory Context Statistics Reporting Date: Wed, 2 Apr 2025 23:44:25 +0200 In-Reply-To: Cc: PostgreSQL Hackers To: Rahila Syed References: <7d4db5cf-8d72-4ee1-8f2e-f88ef9615f27@vondra.me> <637b3ae3-b9eb-4d83-a942-5f7483911ea4@vondra.me> <29ced66e28ec696d1ac29747bd901df2@oss.nttdata.com> <5a899047-65fc-47c5-9c35-1035f44956c6@vondra.me> <70146bd0-da0f-48ee-bece-1e35536189e0@oss.nttdata.com> <2eb8fd76-89f0-42e8-bc79-152d50c63016@vondra.me> <81607c8c04a21b5cac87b21e46566074@oss.nttdata.com> <4c2b5401-41ad-43b9-9215-c7b2d901f8ed@vondra.me> <84996B31-C278-4373-8F56-C5A38A4530BA@yesql.se> X-Mailer: Apple Mail (2.3776.700.51.11.1) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_4EFDEB30-F8D3-4E32-86A9-BE439A72E4B8 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On 26 Mar 2025, at 11:34, Rahila Syed wrote: > + ereport(LOG, > + errmsg("hash table corrupted, can't construct path = value")); > I know you switched from elog(LOG.. to ereport(LOG.. but I still = think a LOG > entry stating corruption isn't helpful, it's not actionable for the = user. > Given that it's a case that shouldn't happen I wonder if we should = downgrade it > to an Assert(false) and potentially a DEBUG1? >=20 > How about changing it to ERROR, in accordance with current occurrences = of the > same message? I did it in the attached version, however I am open to = changing > it to an Assert(false) and DEBUG1. In the attached I moved it to an elog() as it's an internal error, and = spending translation effort on it seems fruitless. > 1. Eliminated the unnecessary creation of an extra memory context = before calling hash_create.=20 > The hash_create function already generates a memory context containing = the hash table,=20 > enabling easy memory deallocation by simply deleting the context via = hash_destroy.=20 > Therefore, the patch relies on hash_destroy for memory management = instead of manual freeing. Nice > 2. Optimized memory usage by storing the path as an array of integers = rather than as an array of=20 > Datums.=20 > This approach conserves DSA memory allocated for storing this = information. Ah yes, much better. The attached v21 has a few improvements: * The function documentation didn't specify the return type, only the = fact that it's setof record. I've added all output columns. * Some general cleaups of the docs with better markup, improved xref = linking and various rewording. * Comment cleanups and language alignment * Added a missing_ok parameter to ContextTypeToString(). While all = callers are fine with unknown context types, if we introduce an API for this it = seems prudent to not place that burden on callers but to take it on in the = function. * Renamed get_summary to just summary, and num_of_tries to retries which = feels more in line with the naming convention in other functions * Deferred calling InitMaterializedSRF() until after the PID has been = checked for validity. * Pulled back the timeout to 500msec from 1 second. In running = congested pgbench simulations I saw better performance and improved results in = getting stats. * Replaced strncpy with strlcpy and consistently used idlen to keep all = length calculations equal. * Fixed misspelled param name in pg_proc.dat * Pulled back maximum memory usage from 8Mb to 1Mb. 8Mb for the = duration of a process (once allocated) is a lot for a niche feature and I while I'm = still not sure 1Mb is the right value I think from experimentation that it's = closer. I think this version is close to a committable state, will spend a = little more time testing, polishing and rewriting the commit message. I will also = play around with placement within the memory context code files to keep it = from making backpatch issues. -- Daniel Gustafsson --Apple-Mail=_4EFDEB30-F8D3-4E32-86A9-BE439A72E4B8 Content-Disposition: attachment; filename=v21-0002-Function-to-report-memory-context-statistics.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v21-0002-Function-to-report-memory-context-statistics.patch" Content-Transfer-Encoding: quoted-printable =46rom=20ddaf0ff1fdc7f0b68743bb8676d04ca7c2c63432=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Rahila=20Syed=20=0A= Date:=20Wed,=2026=20Mar=202025=2015:08:16=20+0530=0ASubject:=20[PATCH=20= v21=202/2]=20Function=20to=20report=20memory=20context=20statistics=0A=0A= This=20function=20sends=20a=20signal=20to=20a=20backend=20to=20publish=0A= statistics=20of=20all=20its=20memory=20contexts.=20Signal=20handler=0A= running=20in=20the=20backend=20process,=20sets=20a=20flag,=20which=20= causes=0Ait=20to=20copy=20its=20MemoryContextStats=20to=20a=20DSA,=20= during=20the=0Anext=20call=20to=20CHECK_FOR_INTERRUPTS().=0AIf=20there=20= are=20more=20statistics=20than=20that=20fit=20in=2016MB,=20the=0A= remaining=20statistics=20are=20copied=20as=20a=20cumulative=0Atotal=20of=20= the=20remaining=20contexts.=0AOnce=20its=20done,=20it=20signals=20the=20= client=20backend=20using=0Aa=20condition=20variable.=20The=20client=20= backend=20wakes=20up,=20reads=0Athe=20shared=20memory=20and=20returns=20= these=20values=20in=20the=20form=0Aof=20set=20of=20records,=20one=20for=20= each=20memory=20context,=20to=20the=0Auser,=20followed=20by=20a=20= cumulative=20total=20of=20the=20remaining=0Acontexts,=20if=20any.=0AIf=20= get_summary=20is=20true=20return=20statistics=20of=20all=20children=0Aof=20= TopMemoryContext=20with=20aggregated=20statistics=20of=20their=0A= children.=0AUser=20can=20pass=20num_of_tries=20which=20determines=20the=20= total=0Anumber=20of=20wait=20cycles=20in=20a=20client=20backend=20for=20= latest=0Astatistics.=0AEach=20cycle=20wait=20timeout=20is=20set=20to=201=20= seconds.=20Post=20this=0Athe=20client=20displays=20previously=20= published=20statistics=20or=0Areturns=20without=20results.=0AEach=20= backend=20and=20auxiliary=20process=20has=20its=20own=20slot=20for=0A= reporting=20the=20stats.=20There=20is=20an=20array=20of=20such=20memory=20= slots=0Aof=20size=20MaxBackends+NumofAuxiliary=0Aprocesses=20in=20fixed=20= shared=20memory.=20Each=20of=20these=20slots=20point=0Ato=20a=20smaller=20= dsa=20allocations=20within=20a=20single=20DSA,=0Awhich=20contains=20the=20= stats=20to=20be=20shared=20by=20the=20corresponding=0Aprocess.=0AEach=20= slot=20has=20its=20own=20LW=20lock=20and=20condition=20variable=20for=0A= synchronization=20and=20communication=20between=20the=20publishing=0A= process=20and=20the=20client=20backend.=0A---=0A=20= doc/src/sgml/func.sgml=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=2094=20++++=0A=20= src/backend/postmaster/autovacuum.c=20=20=20=20=20=20=20=20=20=20=20|=20=20= =204=20+=0A=20src/backend/postmaster/checkpointer.c=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=204=20+=0A=20= src/backend/postmaster/pgarch.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=20=204=20+=0A=20src/backend/postmaster/startup.c=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20=20=204=20+=0A=20= src/backend/postmaster/walsummarizer.c=20=20=20=20=20=20=20=20|=20=20=20= 4=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=203=20+=0A=20src/backend/storage/ipc/procsignal.c=20= =20=20=20=20=20=20=20=20=20|=20=20=203=20+=0A=20= src/backend/storage/lmgr/proc.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=2015=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=203=20+=0A=20= .../utils/activity/wait_event_names.txt=20=20=20=20=20=20=20|=20=20=201=20= +=0A=20src/backend/utils/adt/mcxtfuncs.c=20=20=20=20=20=20=20=20=20=20=20= =20=20|=20432=20+++++++++++++-=0A=20src/backend/utils/init/globals.c=20=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20=20=201=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|=20531=20+++++++++++++++++-=0A=20src/include/catalog/pg_proc.dat=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=201=20+=0A=20src/include/storage/procsignal.h=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=2069=20+++=0A=20src/test/regress/expected/sysviews.out=20=20= =20=20=20=20=20=20|=20=2014=20+=0A=20src/test/regress/sql/sysviews.sql=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20=2014=20+=0A=20= src/tools/pgindent/typedefs.list=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=204=20+=0A=2022=20files=20changed,=201190=20insertions(+),=2030=20= deletions(-)=0A=0Adiff=20--git=20a/doc/src/sgml/func.sgml=20= b/doc/src/sgml/func.sgml=0Aindex=202488e9ba998..b163da128c9=20100644=0A= ---=20a/doc/src/sgml/func.sgml=0A+++=20b/doc/src/sgml/func.sgml=0A@@=20= -28645,6=20+28645,67=20@@=20acl=20=20=20=20=20=20|=20= {postgres=3DarwdDxtm/postgres,foo=3Dr/postgres}=0A=20=20=20=20=20=20=20=20= =0A=20=20=20=20=20=20=20=0A=20=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=20pg_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= retries=20integer=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=20path=20integer[],=0A= +=20=20=20=20=20=20=20=20level=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,=0A+=20=20=20=20=20=20=20=20= stats_timestamp=20timestamptz=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=20requests=20to=20display=20the=20= memory=20contexts=20of=20a=0A+=20=20=20=20=20=20=20=20= PostgreSQL=20process=20with=20the=20specified=0A= +=20=20=20=20=20=20=20=20process=20ID.=20=20The=20function=20can=20be=20= used=20to=20send=20requests=20to=20backends=20as=0A+=20=20=20=20=20=20=20= =20well=20as=20auxiliary=20= processes.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=20Memory=20contexts=20are=20= arranged=20in=20a=20tree-like=20hierarchy.=20=20When=0A+=20=20=20=20=20=20= =20=20summary=20is=20true,=20= statistics=0A+=20=20=20=20=20=20=20=20for=20memory=20contexts=20at=20= levels=201=20and=202=20are=20displayed,=20with=20level=201=0A+=20=20=20=20= =20=20=20=20representing=20the=20root=20node=20(i.e.,=20= TopMemoryContext).=0A+=20=20=20=20=20=20=20=20= Statistics=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=20Busy=20processes=20can=20delay=20= reporting=20memory=20context=20statistics,=0A+=20=20=20=20=20=20=20=20= retries=20sets=20the=20number=20of=20times=20the=20= client=20will=0A+=20=20=20=20=20=20=20=20retry=20to=20get=20updated=20= statistics.=20=20The=20sleep=20per=20try=20is=0A+=20=20=20=20=20=20=20=20= 0.5=20seconds.=20=20This=20parameter=20can=20be=20= increased=20if=20the=0A+=20=20=20=20=20=20=20=20user=20anticipates=20a=20= delay=20in=20the=20response=20from=20the=20reporting=20process.=0A+=20=20= =20=20=20=20=20=20Conversely,=20if=20users=20are=20frequently=20and=20= periodically=20querying=20the=0A+=20=20=20=20=20=20=20=20process=20for=20= statistics,=20or=20if=20there=20are=20concurrent=20requests=20for=0A+=20=20= =20=20=20=20=20=20statistics=20of=20the=20same=20process,=20lowering=20= the=20parameter=20might=20help=0A+=20=20=20=20=20=20=20=20achieve=20a=20= faster=20response.=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=20is=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+=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=0A@@=20-28784,6=20+28845,39=20@@=20= LOG:=20=20Grand=20total:=201651920=20bytes=20in=20201=20blocks;=20622360=20= free=20(88=20chunks);=201029560=0A=20=20=20=20=20because=20it=20may=20= generate=20a=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=0A= +=20=20=20=20to=20request=20the=20memory=20contexts=20statistics=20of=20= any=20postgres=20process.=20For=20example:=0A+=0A= +postgres=3D#=20SELECT=20*=20FROM=20pg_get_process_memory_contexts(=0A+=20= =20(SELECT=20pid=20FROM=20pg_stat_activity=0A+=20=20=20=20WHERE=20= backend_type=20=3D=20'checkpointer')=0A+=20=20,=20false,=205)=20LIMIT=20= 1;=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+path=20=20=20=20=20=20=20=20=20=20=20=20=20|=20{1}=0A= +level=20=20=20=20=20=20=20=20=20=20=20=20|=201=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|=202880=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+stats_timestamp=20= =20|=202025-03-24=2013:55:47.796698+01=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/postmaster/autovacuum.c=20= b/src/backend/postmaster/autovacuum.c=0Aindex=202513a8ef8a6..16756152b71=20= 100644=0A---=20a/src/backend/postmaster/autovacuum.c=0A+++=20= b/src/backend/postmaster/autovacuum.c=0A@@=20-781,6=20+781,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= fda91ffd1ce..d3cb3f1891c=20100644=0A---=20= a/src/backend/postmaster/checkpointer.c=0A+++=20= b/src/backend/postmaster/checkpointer.c=0A@@=20-663,6=20+663,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=200ae9bf906ec..f24f574e748=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=207e622ae4bd2..cb7408acf4c=20100644=0A---=20= a/src/backend/postmaster/pgarch.c=0A+++=20= b/src/backend/postmaster/pgarch.c=0A@@=20-867,6=20+867,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= 0fec4f1f871..c7a76711cc5=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=202fa045e6b0f..362a6dc9528=20100644=0A---=20= a/src/backend/storage/ipc/ipci.c=0A+++=20= b/src/backend/storage/ipc/ipci.c=0A@@=20-51,6=20+51,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-343,6=20+344,8=20@@=20= CreateOrAttachShmemStructs(void)=0A=20=09WaitEventCustomShmemInit();=0A=20= =09InjectionPointShmemInit();=0A=20=09AioShmemInit();=0A+=09= MemCtxShmemInit();=0A+=09MemCtxBackendShmemInit();=0A=20}=0A=20=0A=20/*=0A= diff=20--git=20a/src/backend/storage/ipc/procsignal.c=20= b/src/backend/storage/ipc/procsignal.c=0Aindex=20= 7d201965503..b59034fdc38=20100644=0A---=20= a/src/backend/storage/ipc/procsignal.c=0A+++=20= b/src/backend/storage/ipc/procsignal.c=0A@@=20-690,6=20+690,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=20066319afe2b..026c4bc992f=20100644=0A---=20= a/src/backend/storage/lmgr/proc.c=0A+++=20= b/src/backend/storage/lmgr/proc.c=0A@@=20-50,6=20+50,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= @@=20-497,6=20+498,13=20@@=20InitProcess(void)=0A=20=09=20*/=0A=20=09= PGSemaphoreReset(MyProc->sem);=0A=20=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=0A+=09=20*=20backend=20if=20requested.=0A+=09=20= */=0A+=09before_shmem_exit(AtProcExit_memstats_dsa_free,=200);=0A+=0A=20=09= /*=0A=20=09=20*=20Arrange=20to=20clean=20up=20at=20backend=20exit.=0A=20=09= =20*/=0A@@=20-671,6=20+679,13=20@@=20InitAuxiliaryProcess(void)=0A=20=09=20= */=0A=20=09PGSemaphoreReset(MyProc->sem);=0A=20=0A+=09/*=0A+=09=20*=20= The=20before=20shmem=20exit=20callback=20frees=20the=20DSA=20memory=20= occupied=20by=20the=0A+=09=20*=20latest=20memory=20context=20statistics=20= that=20could=20be=20published=20by=20this=0A+=09=20*=20process=20if=20= requested.=0A+=09=20*/=0A+=09= before_shmem_exit(AtProcExit_memstats_dsa_free,=200);=0A+=0A=20=09/*=0A=20= =09=20*=20Arrange=20to=20clean=20up=20at=20process=20exit.=0A=20=09=20*/=0A= diff=20--git=20a/src/backend/tcop/postgres.c=20= b/src/backend/tcop/postgres.c=0Aindex=20aec65007bb6..ad020adee93=20= 100644=0A---=20a/src/backend/tcop/postgres.c=0A+++=20= b/src/backend/tcop/postgres.c=0A@@=20-3531,6=20+3531,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= 8bce14c38fd..ee0e42535b6=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-161,6=20+161,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_CTX_PUBLISH=09"Waiting=20for=20a=20process=20to=20publish=20memory=20= information."=0A=20=0A=20ABI_compatibility:=0A=20=0Adiff=20--git=20= a/src/backend/utils/adt/mcxtfuncs.c=20= b/src/backend/utils/adt/mcxtfuncs.c=0Aindex=20396c2f223b4..375509f2551=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,26=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"access/twophase.h"=0A+#include=20= "catalog/pg_authid_d.h"=0A+#include=20"nodes/pg_list.h"=0A=20#include=20= "storage/proc.h"=0A=20#include=20"storage/procarray.h"=0A+#include=20= "utils/acl.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/memutils.h"=0A+#include=20"utils/wait_event_types.h"=0A=20=0A=20= /*=20----------=0A=20=20*=20The=20max=20bytes=20for=20showing=20= identifiers=20of=20MemoryContext.=0A=20=20*=20----------=0A=20=20*/=0A=20= #define=20MEMORY_CONTEXT_IDENT_DISPLAY_SIZE=091024=0A-=0A-/*=0A-=20*=20= MemoryContextId=0A-=20*=09=09Used=20for=20storage=20of=20transient=20= identifiers=20for=0A-=20*=09=09pg_get_backend_memory_contexts.=0A-=20*/=0A= -typedef=20struct=20MemoryContextId=0A-{=0A-=09MemoryContext=20context;=0A= -=09int=09=09=09context_id;=0A-}=09=09=09MemoryContextId;=0A+struct=20= MemoryContextBackendState=20*memCtxState=20=3D=20NULL;=0A+struct=20= MemoryContextState=20*memCtxArea=20=3D=20NULL;=0A=20=0A=20/*=0A=20=20*=20= int_list_to_array=0A@@=20-143,24=20+141,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,=20true);=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= +156,44=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.=20If=20missing_ok=20is=0A+=20*=20= false=20then=20execution=20will=20error=20out=20on=20invalid=20context=20= types.=0A+=20*/=0A+const=20char=20*=0A+ContextTypeToString(NodeTag=20= type,=20bool=20missing_ok)=0A+{=0A+=09const=20char=20*context_type;=0A+=0A= +=09switch=20(type)=0A+=09{=0A+=09=09case=20T_AllocSetContext:=0A+=09=09=09= context_type=20=3D=20"AllocSet";=0A+=09=09=09break;=0A+=09=09case=20= T_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=20T_BumpContext:=0A+=09=09=09= context_type=20=3D=20"Bump";=0A+=09=09=09break;=0A+=09=09default:=0A+=09=09= =09if=20(missing_ok)=0A+=09=09=09=09context_type=20=3D=20"???";=0A+=09=09= =09else=0A+=09=09=09=09ereport(ERROR,=0A+=09=09=09=09=09=09= errcode(ERRCODE_UNDEFINED_OBJECT),=0A+=09=09=09=09=09=09errmsg("invalid=20= memory=20context=20type=20specified"));=0A+=09=09=09break;=0A+=09}=0A+=09= return=20(context_type);=0A+}=0A+=0A=20/*=0A=20=20*=20= pg_get_backend_memory_contexts=0A=20=20*=09=09SQL=20SRF=20showing=20= backend=20memory=20context.=0A@@=20-305,3=20+324,358=20@@=20= pg_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= PG_READ_ALL_STATS=20are=20allowed=20to=0A+=20*=20signal=20a=20process=20= to=20return=20the=20memory=20contexts.=20This=20is=20because=20allowing=0A= +=20*=20any=20users=20to=20issue=20this=20request=20at=20an=20unbounded=20= rate=20would=20cause=20lots=20of=0A+=20*=20requests=20to=20be=20sent,=20= which=20can=20lead=20to=20denial=20of=20service.=20Additional=20roles=0A= +=20*=20can=20be=20permitted=20with=20GRANT.=0A+=20*=0A+=20*=20On=20= receipt=20of=20this=20signal,=20a=20backend=20or=20an=20auxiliary=20= process=20sets=20the=20flag=0A+=20*=20in=20the=20signal=20handler,=20= which=20causes=20the=20next=20CHECK_FOR_INTERRUPTS()=0A+=20*=20or=20= process-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=20publishing=20backend.=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=20MEMSTATS_WAIT_TIMEOUT,=20retry=20for=20max_retries=0A+=20*=20= number=20of=20times,=20which=20is=20defined=20by=20user,=20before=20= giving=20up=20and=0A+=20*=20returning=20previously=20published=20= statistics,=20if=20any.=20If=20no=20previous=20statistics=0A+=20*=20= exist,=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=09get_summary=20=3D=20= PG_GETARG_BOOL(1);=0A+=09PGPROC=09=20=20=20*proc;=0A+=09ProcNumber=09= procNumber=20=3D=20INVALID_PROC_NUMBER;=0A+=09bool=09=09proc_is_aux=20=3D=20= false;=0A+=09ReturnSetInfo=20*rsinfo=20=3D=20(ReturnSetInfo=20*)=20= fcinfo->resultinfo;=0A+=09dsa_area=20=20=20*area;=0A+=09= MemoryContextEntry=20*memctx_info;=0A+=09int=09=09=09num_retries=20=3D=20= 0;=0A+=09TimestampTz=20curr_timestamp;=0A+=09int=09=09=09max_retries=20=3D= =20PG_GETARG_INT32(2);=0A+=0A+=09/*=0A+=09=20*=20Only=20superusers=20or=20= users=20with=20pg_read_all_stats=20privileges=20can=20view=20the=0A+=09=20= *=20memory=20context=20statistics=20of=20another=20process.=0A+=09=20*/=0A= +=09if=20(!has_privs_of_role(GetUserId(),=20ROLE_PG_READ_ALL_STATS))=0A+=09= =09ereport(ERROR,=0A+=09=09=09=09= errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),=0A+=09=09=09=09= errmsg("permission=20denied=20to=20extract=20memory=20context=20= statistics"));=0A+=0A+=09/*=0A+=09=20*=20See=20if=20the=20process=20with=20= given=20pid=20is=20a=20backend=20or=20an=20auxiliary=20process=0A+=09=20= *=20and=20remember=20the=20type=20for=20when=20we=20requery=20the=20= process=20later.=0A+=09=20*/=0A+=09proc=20=3D=20BackendPidGetProc(pid);=0A= +=09if=20(proc=20=3D=3D=20NULL)=0A+=09{=0A+=09=09proc=20=3D=20= AuxiliaryPidGetProc(pid);=0A+=09=09proc_is_aux=20=3D=20true;=0A+=09}=0A+=0A= +=09/*=0A+=09=20*=20BackendPidGetProc()=20and=20AuxiliaryPidGetProc()=20= return=20NULL=20if=20the=20pid=0A+=09=20*=20isn't=20valid;=20this=20is=20= however=20not=20a=20problem=20and=20leave=20with=20a=20WARNING.=0A+=09=20= *=20See=20comment=20in=20pg_log_backend_memory_contexts=20for=20a=20= discussion=20on=20this.=0A+=09=20*/=0A+=09if=20(proc=20=3D=3D=20NULL)=0A= +=09{=0A+=09=09/*=0A+=09=09=20*=20This=20is=20just=20a=20warning=20so=20= a=20loop-through-resultset=20will=20not=20abort=0A+=09=09=20*=20if=20one=20= backend=20terminated=20on=20its=20own=20during=20the=20run.=0A+=09=09=20= */=0A+=09=09ereport(WARNING,=0A+=09=09=09=09(errmsg("PID=20%d=20is=20not=20= a=20PostgreSQL=20server=20process",=20pid)));=0A+=09=09PG_RETURN_NULL();=0A= +=09}=0A+=0A+=09InitMaterializedSRF(fcinfo,=200);=0A+=0A+=09procNumber=20= =3D=20GetNumberFromPGProc(proc);=0A+=0A+=09= LWLockAcquire(&memCtxState[procNumber].lw_lock,=20LW_EXCLUSIVE);=0A+=09= memCtxState[procNumber].get_summary=20=3D=20get_summary;=0A+=09= LWLockRelease(&memCtxState[procNumber].lw_lock);=0A+=0A+=09= curr_timestamp=20=3D=20GetCurrentTimestamp();=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= ereport(WARNING,=0A+=09=09=09=09errmsg("could=20not=20send=20signal=20to=20= process=20%d:=20%m",=20pid));=0A+=09=09PG_RETURN_NULL();=0A+=09}=0A+=0A+=09= /*=0A+=09=20*=20A=20valid=20DSA=20pointer=20isn't=20proof=20that=20= statistics=20are=20available,=20it=20can=0A+=09=20*=20be=20valid=20due=20= to=20previously=20published=20stats.=20Check=20if=20the=20stats=20are=0A= +=09=20*=20updated=20by=20comparing=20the=20timestamp,=20if=20the=20= stats=20are=20newer=20than=20our=0A+=09=20*=20previously=20recorded=20= timestamp=20from=20before=20sending=20the=20procsignal,=20they=0A+=09=20= *=20must=20by=20definition=20be=20updated.=20Wait=20for=20max_retries=20= *=0A+=09=20*=20MEMSTATS_WAIT_TIMEOUT,=20following=20which=20display=20= old=20statistics=20if=0A+=09=20*=20available=20or=20return=20NULL.=0A+=09= =20*/=0A+=09while=20(1)=0A+=09{=0A+=09=09long=09=09msecs;=0A+=0A+=09=09= /*=0A+=09=09=20*=20We=20expect=20to=20come=20out=20of=20sleep=20when=20= the=20requested=20process=20has=0A+=09=09=20*=20finished=20publishing=20= the=20statistics,=20verified=20using=20the=20valid=20DSA=0A+=09=09=20*=20= pointer.=0A+=09=09=20*=0A+=09=09=20*=20Make=20sure=20that=20the=20= information=20belongs=20to=20pid=20we=20requested=0A+=09=09=20*=20= information=20for,=20Otherwise=20loop=20back=20and=20wait=20for=20the=20= server=0A+=09=09=20*=20process=20to=20finish=20publishing=20statistics.=0A= +=09=09=20*/=0A+=09=09LWLockAcquire(&memCtxState[procNumber].lw_lock,=20= LW_EXCLUSIVE);=0A+=0A+=09=09/*=0A+=09=09=20*=20Note=20in=20procnumber.h=20= file=20says=20that=20a=20procNumber=20can=20be=20re-used=20for=0A+=09=09=20= *=20a=20different=20backend=20immediately=20after=20a=20backend=20exits.=20= In=20case=20an=0A+=09=09=20*=20old=20process'=20data=20was=20there=20and=20= not=20updated=20by=20the=20current=20process=0A+=09=09=20*=20in=20the=20= slot=20identified=20by=20the=20procNumber,=20the=20pid=20of=20the=20= requested=0A+=09=09=20*=20process=20and=20the=20proc_id=20might=20not=20= match.=0A+=09=09=20*/=0A+=09=09if=20(memCtxState[procNumber].proc_id=20= =3D=3D=20pid)=0A+=09=09{=0A+=09=09=09/*=0A+=09=09=09=20*=20Break=20if=20= the=20latest=20stats=20have=20been=20read,=20indicated=20by=0A+=09=09=09=20= *=20statistics=20timestamp=20being=20newer=20than=20the=20current=20= request=0A+=09=09=09=20*=20timestamp.=0A+=09=09=09=20*/=0A+=09=09=09= msecs=20=3D=20TimestampDifferenceMilliseconds(curr_timestamp,=0A+=09=09=09= =09=09=09=09=09=09=09=09=09=09memCtxState[procNumber].stats_timestamp);=0A= +=0A+=09=09=09if=20= (DsaPointerIsValid(memCtxState[procNumber].memstats_dsa_pointer)=0A+=09=09= =09=09&&=20msecs=20>=200)=0A+=09=09=09=09break;=0A+=09=09}=0A+=09=09= LWLockRelease(&memCtxState[procNumber].lw_lock);=0A+=0A+=09=09/*=0A+=09=09= =20*=20Recheck=20the=20state=20of=20the=20backend=20before=20sleeping=20= on=20the=20condition=0A+=09=09=20*=20variable=20to=20ensure=20the=20= process=20is=20still=20alive.=20=20Only=20check=20the=0A+=09=09=20*=20= relevant=20process=20type=20based=20on=20the=20earlier=20PID=20check.=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=20process=20= ending=20during=20memory=20context=20processing=20is=20not=20an=0A+=09=09= =20*=20error.=0A+=09=09=20*/=0A+=09=09if=20(proc=20=3D=3D=20NULL)=0A+=09=09= {=0A+=09=09=09ereport(WARNING,=0A+=09=09=09=09=09errmsg("PID=20%d=20is=20= no=20longer=20a=20PostgreSQL=20server=20process",=0A+=09=09=09=09=09=09=20= =20=20pid));=0A+=09=09=09PG_RETURN_NULL();=0A+=09=09}=0A+=0A+#define=20= MEMSTATS_WAIT_TIMEOUT=20500=0A+=0A+=09=09if=20= (ConditionVariableTimedSleep(&memCtxState[procNumber].memctx_cv,=0A+=09=09= =09=09=09=09=09=09=09=09MEMSTATS_WAIT_TIMEOUT,=0A+=09=09=09=09=09=09=09=09= =09=09WAIT_EVENT_MEM_CTX_PUBLISH))=0A+=09=09{=0A+=09=09=09/*=0A+=09=09=09= =20*=20Wait=20for=20max_retries,=20as=20defined=20by=20the=20user.=20If=20= no=20updated=0A+=09=09=09=20*=20statistics=20are=20available=20within=20= the=20wait=20time=20defined=20by=0A+=09=09=09=20*=20max_retries=20then=20= display=20previously=20published=20statistics=20if=0A+=09=09=09=20*=20= there=20are=20any.=20If=20no=20previous=20statistics=20are=20available=20= then=0A+=09=09=09=20*=20return=20NULL.=0A+=09=09=09=20*/=0A+=09=09=09if=20= (num_retries=20>=20max_retries)=0A+=09=09=09{=0A+=09=09=09=09= LWLockAcquire(&memCtxState[procNumber].lw_lock,=20LW_EXCLUSIVE);=0A+=09=09= =09=09/*=20Displaying=20previously=20published=20statistics=20if=20= available=20*/=0A+=09=09=09=09if=20= (DsaPointerIsValid(memCtxState[procNumber].memstats_dsa_pointer))=0A+=09=09= =09=09=09break;=0A+=09=09=09=09else=0A+=09=09=09=09{=0A+=09=09=09=09=09= LWLockRelease(&memCtxState[procNumber].lw_lock);=0A+=09=09=09=09=09= PG_RETURN_NULL();=0A+=09=09=09=09}=0A+=09=09=09}=0A+=09=09=09= ereport(DEBUG1,=0A+=09=09=09=09=09errmsg("timed=20out=20waiting=20for=20= process=20with=20PID=20%d=20to=20publish=20stats,=20retrying",=0A+=09=09=09= =09=09=09=20=20=20pid));=0A+=09=09=09num_retries=20=3D=20num_retries=20+=20= 1;=0A+=09=09}=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20We=20should=20only=20= reach=20here=20with=20a=20valid=20DSA=20handle,=20either=20containing=0A= +=09=20*=20updated=20statistics=20or=20previously=20published=20= statistics=20(identified=20by=0A+=09=20*=20the=20timestamp.=0A+=09=20*/=0A= +=09Assert(memCtxArea->memstats_dsa_handle=20!=3D=20DSA_HANDLE_INVALID);=0A= +=09area=20=3D=20dsa_attach(memCtxArea->memstats_dsa_handle);=0A+=0A+=09= /*=0A+=09=20*=20Backend=20has=20finished=20publishing=20the=20stats,=20= project=20them.=0A+=09=20*/=0A+=09memctx_info=20=3D=20= (MemoryContextEntry=20*)=0A+=09=09dsa_get_address(area,=20= memCtxState[procNumber].memstats_dsa_pointer);=0A+=0A+#define=20= PG_GET_PROCESS_MEMORY_CONTEXTS_COLS=0912=0A+=09for=20(int=20i=20=3D=200;=20= i=20<=20memCtxState[procNumber].total_stats;=20i++)=0A+=09{=0A+=09=09= ArrayType=20=20*path_array;=0A+=09=09int=09=09=09path_length;=0A+=09=09= Datum=09=09values[PG_GET_PROCESS_MEMORY_CONTEXTS_COLS];=0A+=09=09bool=09=09= nulls[PG_GET_PROCESS_MEMORY_CONTEXTS_COLS];=0A+=09=09char=09=20=20=20= *name;=0A+=09=09char=09=20=20=20*ident;=0A+=09=09Datum=09=20=20=20= *path_datum=20=3D=20NULL;=0A+=09=09int=09=09=20=20=20*path_int=20=3D=20= NULL;=0A+=0A+=09=09memset(values,=200,=20sizeof(values));=0A+=09=09= memset(nulls,=200,=20sizeof(nulls));=0A+=0A+=09=09if=20= (DsaPointerIsValid(memctx_info[i].name))=0A+=09=09{=0A+=09=09=09name=20=3D= =20(char=20*)=20dsa_get_address(area,=20memctx_info[i].name);=0A+=09=09=09= values[0]=20=3D=20CStringGetTextDatum(name);=0A+=09=09}=0A+=09=09else=0A= +=09=09=09nulls[0]=20=3D=20true;=0A+=0A+=09=09if=20= (DsaPointerIsValid(memctx_info[i].ident))=0A+=09=09{=0A+=09=09=09ident=20= =3D=20(char=20*)=20dsa_get_address(area,=20memctx_info[i].ident);=0A+=09=09= =09values[1]=20=3D=20CStringGetTextDatum(ident);=0A+=09=09}=0A+=09=09= else=0A+=09=09=09nulls[1]=20=3D=20true;=0A+=0A+=09=09if=20= (memctx_info[i].type=20!=3D=20NULL)=0A+=09=09=09values[2]=20=3D=20= CStringGetTextDatum(memctx_info[i].type);=0A+=09=09else=0A+=09=09=09= nulls[2]=20=3D=20true;=0A+=0A+=09=09path_length=20=3D=20= memctx_info[i].path_length;=0A+=09=09path_datum=20=3D=20(Datum=20*)=20= palloc(path_length=20*=20sizeof(Datum));=0A+=09=09if=20= (DsaPointerIsValid(memctx_info[i].path))=0A+=09=09{=0A+=09=09=09path_int=20= =3D=20(int=20*)=20dsa_get_address(area,=20memctx_info[i].path);=0A+=09=09= =09for=20(int=20j=20=3D=200;=20j=20<=20path_length;=20j++)=0A+=09=09=09=09= path_datum[j]=20=3D=20Int32GetDatum(path_int[j]);=0A+=09=09=09path_array=20= =3D=20construct_array_builtin(path_datum,=20path_length,=20INT4OID);=0A+=09= =09=09values[3]=20=3D=20PointerGetDatum(path_array);=0A+=09=09}=0A+=09=09= else=0A+=09=09=09nulls[3]=20=3D=20true;=0A+=0A+=09=09values[4]=20=3D=20= Int32GetDatum(path_length);=20/*=20level=20*/=0A+=09=09values[5]=20=3D=20= Int64GetDatum(memctx_info[i].totalspace);=0A+=09=09values[6]=20=3D=20= Int64GetDatum(memctx_info[i].nblocks);=0A+=09=09values[7]=20=3D=20= Int64GetDatum(memctx_info[i].freespace);=0A+=09=09values[8]=20=3D=20= Int64GetDatum(memctx_info[i].freechunks);=0A+=09=09values[9]=20=3D=20= Int64GetDatum(memctx_info[i].totalspace=20-=0A+=09=09=09=09=09=09=09=09=20= =20memctx_info[i].freespace);=0A+=09=09values[10]=20=3D=20= Int32GetDatum(memctx_info[i].num_agg_stats);=0A+=09=09values[11]=20=3D=20= TimestampTzGetDatum(memCtxState[procNumber].stats_timestamp);=0A+=0A+=09=09= tuplestore_putvalues(rsinfo->setResult,=20rsinfo->setDesc,=0A+=09=09=09=09= =09=09=09=20values,=20nulls);=0A+=09}=0A+=09= LWLockRelease(&memCtxState[procNumber].lw_lock);=0A+=0A+=09= ConditionVariableCancelSleep();=0A+=09dsa_detach(area);=0A+=0A+=09= PG_RETURN_NULL();=0A+}=0A+=0A+/*=0A+=20*=20Init=20shared=20memory=20for=20= reporting=20memory=20context=20information.=0A+=20*/=0A+void=0A= +MemCtxBackendShmemInit(void)=0A+{=0A+=09bool=09=09found;=0A+=09Size=09=09= TotalProcs;=0A+=0A+=09TotalProcs=20=3D=20add_size(MaxBackends,=20= NUM_AUXILIARY_PROCS);=0A+=09TotalProcs=20=3D=20add_size(TotalProcs,=20= max_prepared_xacts);=0A+=0A+=09memCtxState=20=3D=20= (MemoryContextBackendState=20*)=0A+=09=09= ShmemInitStruct("MemoryContextBackendState",=0A+=09=09=09=09=09=09= mul_size(TotalProcs,=20sizeof(MemoryContextBackendState)),=0A+=09=09=09=09= =09=09&found);=0A+=0A+=09if=20(!IsUnderPostmaster)=0A+=09{=0A+=09=09= Assert(!found);=0A+=0A+=09=09for=20(int=20i=20=3D=200;=20i=20<=20= TotalProcs;=20i++)=0A+=09=09{=0A+=09=09=09= ConditionVariableInit(&memCtxState[i].memctx_cv);=0A+=0A+=09=09=09= LWLockInitialize(&memCtxState[i].lw_lock,=20LWLockNewTrancheId());=0A+=09= =09=09LWLockRegisterTranche(memCtxState[i].lw_lock.tranche,=0A+=09=09=09=09= =09=09=09=09=20=20"mem_context_backend_stats_reporting");=0A+=0A+=09=09=09= memCtxState[i].memstats_dsa_pointer=20=3D=20InvalidDsaPointer;=0A+=09=09= }=0A+=09}=0A+=09else=0A+=09{=0A+=09=09Assert(found);=0A+=09}=0A+}=0A+=0A= +/*=0A+=20*=20Initialize=20shared=20memory=20for=20displaying=20memory=20= context=20statistics=0A+=20*/=0A+void=0A+MemCtxShmemInit(void)=0A+{=0A+=09= bool=09=09found;=0A+=0A+=09memCtxArea=20=3D=20(MemoryContextState=20*)=0A= +=09=09ShmemInitStruct("MemoryContextState",=20= sizeof(MemoryContextState),=20&found);=0A+=0A+=09if=20= (!IsUnderPostmaster)=0A+=09{=0A+=09=09Assert(!found);=0A+=0A+=09=09= LWLockInitialize(&memCtxArea->lw_lock,=0A+=09=09=09=09=09=09=20= LWLockNewTrancheId());=0A+=09=09= LWLockRegisterTranche(memCtxArea->lw_lock.tranche,=0A+=09=09=09=09=09=09=09= =20=20"mem_context_stats_reporting");=0A+=09=09= memCtxArea->memstats_dsa_handle=20=3D=20DSA_HANDLE_INVALID;=0A+=09}=0A+=09= else=0A+=09{=0A+=09=09Assert(found);=0A+=09}=0A+}=0Adiff=20--git=20= a/src/backend/utils/init/globals.c=20b/src/backend/utils/init/globals.c=0A= index=20b844f9fdaef..13938ccb0f5=20100644=0A---=20= a/src/backend/utils/init/globals.c=0A+++=20= b/src/backend/utils/init/globals.c=0A@@=20-38,6=20+38,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/mmgr/mcxt.c=20b/src/backend/utils/mmgr/mcxt.c=0A= index=202cbde8f39c3..bfcd65a69a5=20100644=0A---=20= a/src/backend/utils/mmgr/mcxt.c=0A+++=20b/src/backend/utils/mmgr/mcxt.c=0A= @@=20-23,6=20+23,13=20@@=0A=20=0A=20#include=20"mb/pg_wchar.h"=0A=20= #include=20"miscadmin.h"=0A+#include=20"nodes/pg_list.h"=0A+#include=20= "storage/fd.h"=0A+#include=20"storage/lwlock.h"=0A+#include=20= "storage/dsm.h"=0A+#include=20"storage/ipc.h"=0A+#include=20= "utils/dsa.h"=0A+#include=20"utils/hsearch.h"=0A=20#include=20= "utils/memdebug.h"=0A=20#include=20"utils/memutils.h"=0A=20#include=20= "utils/memutils_internal.h"=0A@@=20-177,6=20+184,16=20@@=20static=20void=20= MemoryContextStatsInternal(MemoryContext=20context,=20int=20level,=0A=20= static=20void=20MemoryContextStatsPrint(MemoryContext=20context,=20void=20= *passthru,=0A=20=09=09=09=09=09=09=09=09=09const=20char=20*stats_string,=0A= =20=09=09=09=09=09=09=09=09=09bool=20print_to_stderr);=0A+static=20void=20= PublishMemoryContext(MemoryContextEntry=20*memctx_infos,=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=20= MemoryContextCounters=20stat,=0A+=09=09=09=09=09=09=09=09=20int=20= num_contexts,=20dsa_area=20*area);=0A+static=20void=20= compute_contexts_count_and_ids(List=20*contexts,=20HTAB=20= *context_id_lookup,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20int=20= *stats_count,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20bool=20= get_summary);=0A+static=20List=20*compute_context_path(MemoryContext=20= c,=20HTAB=20*context_id_lookup);=0A+static=20void=20= dsa_free_previous_stats(dsa_area=20*area,=20int=20total_stats,=20= dsa_pointer=20prev_dsa_pointer);=0A=20=0A=20/*=0A=20=20*=20You=20should=20= not=20do=20memory=20allocations=20within=20a=20critical=20section,=20= because=0A@@=20-927,7=20+944,7=20@@=20= MemoryContextStatsInternal(MemoryContext=20context,=20int=20level,=0A=20=09= =09=09=20*=20PRINT_STATS_NONE,=20only=20compute=20totals.=20This=20is=20= used=20in=0A=20=09=09=09=20*=20reporting=20of=20memory=20context=20= statistics=20via=20a=20sql=20function.=20Last=0A=20=09=09=09=20*=20= parameter=20is=20not=20relevant.=0A-+=09=09=09=20*/=0A+=09=09=09=20*/=0A=20= =09=09=09context->methods->stats(context,=0A=20=09=09=09=09=09=09=09=09=09= NULL,=0A=20=09=09=09=09=09=09=09=09=09NULL,=0A@@=20-1331,6=20+1348,22=20= @@=20HandleLogMemoryContextInterrupt(void)=0A=20=09/*=20latch=20will=20= be=20set=20by=20procsignal_sigusr1_handler=20*/=0A=20}=0A=20=0A+/*=0A+=20= *=20HandleGetMemoryContextInterrupt=0A+=20*=09=09Handle=20receipt=20of=20= an=20interrupt=20indicating=20a=20request=20to=20publish=20memory=0A+=20= *=09=09contexts=20statistics.=0A+=20*=0A+=20*=20All=20the=20actual=20= work=20is=20deferred=20to=20ProcessGetMemoryContextInterrupt()=20as=0A+=20= *=20this=20cannot=20be=20performed=20in=20a=20signal=20handler.=0A+=20*/=0A= +void=0A+HandleGetMemoryContextInterrupt(void)=0A+{=0A+=09= InterruptPending=20=3D=20true;=0A+=09PublishMemoryContextPending=20=3D=20= true;=0A+=09/*=20latch=20will=20be=20set=20by=20= procsignal_sigusr1_handler=20*/=0A+}=0A+=0A=20/*=0A=20=20*=20= ProcessLogMemoryContextInterrupt=0A=20=20*=20=09=09Perform=20logging=20= of=20memory=20contexts=20of=20this=20backend=20process.=0A@@=20-1368,6=20= +1401,502=20@@=20ProcessLogMemoryContextInterrupt(void)=0A=20=09= MemoryContextStatsDetail(TopMemoryContext,=20100,=20100,=20false);=0A=20= }=0A=20=0A+/*=0A+=20*=20ProcessGetMemoryContextInterrupt=0A+=20*=09=09= Generate=20information=20about=20memory=20contexts=20used=20by=20the=20= process.=0A+=20*=0A+=20*=20Performs=20a=20breadth=20first=20search=20on=20= the=20memory=20context=20tree,=20thus=20parents=0A+=20*=20statistics=20= are=20reported=20before=20their=20children=20in=20the=20monitoring=20= function=0A+=20*=20output.=0A+=20*=0A+=20*=20Statistics=20for=20all=20= the=20processes=20are=20shared=20via=20the=20same=20dynamic=20shared=0A+=20= *=20area.=20=20Statistics=20written=20by=20each=20process=20are=20= tracked=20independently=20in=0A+=20*=20per-process=20DSA=20pointers.=20= These=20pointers=20are=20stored=20in=20static=20shared=20memory.=0A+=20*=0A= +=20*=20We=20calculate=20maximum=20number=20of=20context's=20statistics=20= that=20can=20be=20displayed=0A+=20*=20using=20a=20pre-determined=20limit=20= for=20memory=20available=20per=20process=20for=20this=0A+=20*=20utility=20= maximum=20size=20of=20statistics=20for=20each=20context.=20=20The=20= remaining=20context=0A+=20*=20statistics=20if=20any=20are=20captured=20= as=20a=20cumulative=20total=20at=20the=20end=20of=0A+=20*=20individual=20= context's=20statistics.=0A+=20*=0A+=20*=20If=20get_summary=20is=20true,=20= we=20capture=20the=20level=201=20and=20level=202=20contexts=0A+=20*=20= statistics.=20=20For=20that=20we=20traverse=20the=20memory=20context=20= tree=20recursively=20in=0A+=20*=20depth=20first=20search=20manner=20to=20= cover=20all=20the=20children=20of=20a=20parent=20context,=20to=0A+=20*=20= be=20able=20to=20display=20a=20cumulative=20total=20of=20memory=20= consumption=20by=20a=20parent=20at=0A+=20*=20level=202=20and=20all=20its=20= children.=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= MemoryContextEntry=20*meminfo;=0A+=09bool=09=09get_summary=20=3D=20= false;=0A+=09dsa_area=20=20=20*area=20=3D=20NULL;=0A+=09int=09=09=09= max_stats;=0A+=09int=09=09=09idx=20=3D=20MyProcNumber;=0A+=09int=09=09=09= stats_count=20=3D=200;=0A+=09MemoryContextCounters=20stat;=0A+=09int=09=09= =09num_individual_stats=20=3D=200;=0A+=0A+=09PublishMemoryContextPending=20= =3D=20false;=0A+=0A+=09/*=0A+=09=20*=20The=20hash=20table=20is=20used=20= for=20constructing=20"path"=20column=20of=20the=20view,=0A+=09=20*=20= similar=20to=20its=20local=20backend=20counterpart.=0A+=09=20*/=0A+=09= ctl.keysize=20=3D=20sizeof(MemoryContext);=0A+=09ctl.entrysize=20=3D=20= sizeof(MemoryContextId);=0A+=09ctl.hcxt=20=3D=20CurrentMemoryContext;=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/*=20Compute=20the=20number=20of=20= stats=20that=20can=20fit=20in=20the=20defined=20limit=20*/=0A+=09= max_stats=20=3D=20(MAX_SEGMENTS_PER_BACKEND=20*=20= DSA_DEFAULT_INIT_SEGMENT_SIZE)=0A+=09=09/=20= (MAX_MEMORY_CONTEXT_STATS_SIZE);=0A+=09= LWLockAcquire(&memCtxState[idx].lw_lock,=20LW_EXCLUSIVE);=0A+=09= get_summary=20=3D=20memCtxState[idx].get_summary;=0A+=09= LWLockRelease(&memCtxState[idx].lw_lock);=0A+=0A+=09/*=0A+=09=20*=20= Traverse=20the=20memory=20context=20tree=20to=20find=20total=20number=20= of=20contexts.=20If=0A+=09=20*=20summary=20is=20requested=20report=20the=20= total=20number=20of=20contexts=20at=20level=201=20and=0A+=09=20*=202=20= from=20the=20top.=20Also,=20populate=20the=20hash=20table=20of=20context=20= ids.=0A+=09=20*/=0A+=09compute_contexts_count_and_ids(contexts,=20= context_id_lookup,=20&stats_count,=0A+=09=09=09=09=09=09=09=09=20=20=20= get_summary);=0A+=0A+=09/*=0A+=09=20*=20Allocate=20memory=20in=20this=20= process's=20DSA=20for=20storing=20statistics=20of=20the=20the=0A+=09=20*=20= memory=20contexts=20upto=20max_stats,=20for=20contexts=20that=20don't=20= fit=20within=20a=0A+=09=20*=20limit,=20a=20cumulative=20total=20is=20= written=20as=20the=20last=20record=20in=20the=20DSA=0A+=09=20*=20= segment.=0A+=09=20*/=0A+=09stats_count=20=3D=20(stats_count=20>=20= max_stats)=20?=20max_stats=20:=20stats_count;=0A+=0A+=09= LWLockAcquire(&memCtxArea->lw_lock,=20LW_EXCLUSIVE);=0A+=0A+=09/*=0A+=09=20= *=20Create=20a=20DSA=20and=20send=20handle=20to=20the=20the=20client=20= process=20after=20storing=0A+=09=20*=20the=20context=20statistics.=20If=20= number=20of=20contexts=20exceed=20a=20predefined=0A+=09=20*=20= limit(8MB),=20a=20cumulative=20total=20is=20stored=20for=20such=20= contexts.=0A+=09=20*/=0A+=09if=20(memCtxArea->memstats_dsa_handle=20=3D=3D= =20DSA_HANDLE_INVALID)=0A+=09{=0A+=09=09MemoryContext=20oldcontext=20=3D=20= CurrentMemoryContext;=0A+=09=09dsa_handle=09handle;=0A+=0A+=09=09= MemoryContextSwitchTo(TopMemoryContext);=0A+=0A+=09=09area=20=3D=20= dsa_create(memCtxArea->lw_lock.tranche);=0A+=0A+=09=09handle=20=3D=20= dsa_get_handle(area);=0A+=09=09MemoryContextSwitchTo(oldcontext);=0A+=0A= +=09=09dsa_pin_mapping(area);=0A+=0A+=09=09/*=0A+=09=09=20*=20Pin=20the=20= DSA=20area,=20this=20is=20to=20make=20sure=20the=20area=20remains=20= attachable=0A+=09=09=20*=20even=20if=20current=20backend=20exits.=20This=20= is=20done=20so=20that=20the=20statistics=0A+=09=09=20*=20are=20published=20= even=20if=20the=20process=20exits=20while=20a=20client=20is=20waiting.=0A= +=09=09=20*/=0A+=09=09dsa_pin(area);=0A+=0A+=09=09/*=20Set=20the=20= handle=20in=20shared=20memory=20*/=0A+=09=09= memCtxArea->memstats_dsa_handle=20=3D=20handle;=0A+=09}=0A+=0A+=09/*=0A+=09= =20*=20If=20DSA=20exists,=20created=20by=20another=20process=20= publishing=20statistics,=20or=20by=0A+=09=20*=20the=20previous=20= execution=20of=20this=20function=20by=20this=20process,=20attach=20to=20= it.=0A+=09=20*/=0A+=09else=20if=20(area=20=3D=3D=20NULL)=0A+=09{=0A+=09=09= MemoryContext=20oldcontext=20=3D=20CurrentMemoryContext;=0A+=0A+=09=09= MemoryContextSwitchTo(TopMemoryContext);=0A+=09=09area=20=3D=20= dsa_attach(memCtxArea->memstats_dsa_handle);=0A+=09=09= MemoryContextSwitchTo(oldcontext);=0A+=09=09dsa_pin_mapping(area);=0A+=09= }=0A+=09LWLockRelease(&memCtxArea->lw_lock);=0A+=0A+=09/*=0A+=09=20*=20= Hold=20the=20process=20lock=20to=20protect=20writes=20to=20process=20= specific=20memory.=20Two=0A+=09=20*=20processes=20publishing=20= statistics=20do=20not=20block=20each=20other.=0A+=09=20*/=0A+=09= LWLockAcquire(&memCtxState[idx].lw_lock,=20LW_EXCLUSIVE);=0A+=09= memCtxState[idx].proc_id=20=3D=20MyProcPid;=0A+=0A+=09if=20= (DsaPointerIsValid(memCtxState[idx].memstats_dsa_pointer))=0A+=09{=0A+=09= =09/*=0A+=09=09=20*=20Free=20any=20previous=20allocations,=20free=20the=20= name,=20ident=20and=20path=0A+=09=09=20*=20pointers=20before=20freeing=20= the=20pointer=20that=20contains=20them.=0A+=09=09=20*/=0A+=09=09= dsa_free_previous_stats(area,=20memCtxState[idx].total_stats,=0A+=09=09=09= =09=09=09=09=09memCtxState[idx].memstats_dsa_pointer);=0A+=0A+=09=09= dsa_free(area,=20memCtxState[idx].memstats_dsa_pointer);=0A+=09=09= memCtxState[idx].memstats_dsa_pointer=20=3D=20InvalidDsaPointer;=0A+=09}=0A= +=09memCtxState[idx].memstats_dsa_pointer=20=3D=0A+=09=09= dsa_allocate0(area,=20stats_count=20*=20sizeof(MemoryContextEntry));=0A+=0A= +=09meminfo=20=3D=20(MemoryContextEntry=20*)=0A+=09=09= dsa_get_address(area,=20memCtxState[idx].memstats_dsa_pointer);=0A+=0A+=09= if=20(get_summary)=0A+=09{=0A+=09=09int=09=09=09ctx_id=20=3D=200;=0A+=09=09= List=09=20=20=20*path=20=3D=20NIL;=0A+=0A+=09=09/*=20Copy=20= TopMemoryContext=20statistics=20to=20DSA=20*/=0A+=09=09memset(&stat,=20= 0,=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=20lcons_int(1,=20path);=0A+=09=09= PublishMemoryContext(meminfo,=20ctx_id,=20TopMemoryContext,=20path,=20= stat,=0A+=09=09=09=09=09=09=09=201,=20area);=0A+=09=09ctx_id=20=3D=20= ctx_id=20+=201;=0A+=0A+=09=09/*=0A+=09=09=20*=20Copy=20statistics=20for=20= each=20of=20TopMemoryContexts=20children.=09This=0A+=09=09=20*=20= includes=20statistics=20of=20all=20of=20their=20children=20upto=20level=20= 100.=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=09MemoryContextStatsInternal(c,=20= 0,=20100,=20100,=20&grand_totals,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= PRINT_STATS_NONE,=20&num_contexts);=0A+=0A+=09=09=09path=20=3D=20= compute_context_path(c,=20context_id_lookup);=0A+=0A+=09=09=09= PublishMemoryContext(meminfo,=20ctx_id,=20c,=20path,=0A+=09=09=09=09=09=09= =09=09=20grand_totals,=20num_contexts,=20area);=0A+=09=09=09ctx_id=20=3D=20= ctx_id=20+=201;=0A+=09=09}=0A+=09=09memCtxState[idx].total_stats=20=3D=20= ctx_id;=0A+=09=09goto=20cleanup;=0A+=09}=0A+=0A+=09= foreach_ptr(MemoryContextData,=20cur,=20contexts)=0A+=09{=0A+=09=09List=09= =20=20=20*path=20=3D=20NIL;=0A+=09=09char=09=20=20=20*name;=0A+=0A+=09=09= /*=0A+=09=09=20*=20Figure=20out=20the=20transient=20context_id=20of=20= this=20context=20and=20each=20of=20its=0A+=09=09=20*=20ancestors,=20to=20= compute=20a=20path=20for=20this=20context.=0A+=09=09=20*/=0A+=09=09path=20= =3D=20compute_context_path(cur,=20context_id_lookup);=0A+=0A+=09=09if=20= (context_id=20<=3D=20(max_stats=20-=202))=0A+=09=09{=0A+=09=09=09/*=20= Examine=20the=20context=20stats=20*/=0A+=09=09=09memset(&stat,=200,=20= sizeof(stat));=0A+=09=09=09(*cur->methods->stats)=20(cur,=20NULL,=20= NULL,=20&stat,=20true);=0A+=09=09=09/*=20Copy=20statistics=20to=20DSA=20= memory=20*/=0A+=09=09=09PublishMemoryContext(meminfo,=20context_id,=20= cur,=20path,=20stat,=201,=20area);=0A+=09=09}=0A+=09=09else=0A+=09=09{=0A= +=09=09=09/*=20Examine=20the=20context=20stats=20*/=0A+=09=09=09= memset(&stat,=200,=20sizeof(stat));=0A+=09=09=09(*cur->methods->stats)=20= (cur,=20NULL,=20NULL,=20&stat,=20true);=0A+=0A+=09=09=09= meminfo[max_stats=20-=201].totalspace=20+=3D=20stat.totalspace;=0A+=09=09= =09meminfo[max_stats=20-=201].nblocks=20+=3D=20stat.nblocks;=0A+=09=09=09= meminfo[max_stats=20-=201].freespace=20+=3D=20stat.freespace;=0A+=09=09=09= meminfo[max_stats=20-=201].freechunks=20+=3D=20stat.freechunks;=0A+=09=09= }=0A+=0A+=09=09/*=0A+=09=09=20*=20DSA=20max=20limit=20per=20process=20is=20= reached,=20write=20aggregate=20of=20the=0A+=09=09=20*=20remaining=20= statistics.=0A+=09=09=20*/=0A+=09=09if=20(context_id=20=3D=3D=20= (max_stats=20-=202)=20&&=20context_id=20<=20(stats_count=20-=201))=0A+=09= =09{=0A+=09=09=09num_individual_stats=20=3D=20context_id=20+=201;=0A+=09=09= =09meminfo[max_stats=20-=201].name=20=3D=20dsa_allocate0(area,=2017);=0A= +=09=09=09name=20=3D=20dsa_get_address(area,=20meminfo[max_stats=20-=20= 1].name);=0A+=09=09=09strncpy(name,=20"Remaining=20Totals",=2016);=0A+=09= =09=09meminfo[max_stats=20-=201].ident=20=3D=20InvalidDsaPointer;=0A+=09=09= =09meminfo[max_stats=20-=201].path=20=3D=20InvalidDsaPointer;=0A+=09=09=09= meminfo[max_stats=20-=201].type=20=3D=20NULL;=0A+=09=09}=0A+=09=09= context_id++;=0A+=09}=0A+=09/*=20Statistics=20are=20not=20aggregated,=20= i.e=20individual=20statistics=20reported=20*/=0A+=09if=20(context_id=20<=20= (max_stats=20-=202))=0A+=09{=0A+=09=09memCtxState[idx].total_stats=20=3D=20= context_id;=0A+=09}=0A+=09/*=20Report=20number=20of=20aggregated=20= memory=20contexts=20*/=0A+=09else=0A+=09{=0A+=09=09meminfo[max_stats=20-=20= 1].num_agg_stats=20=3D=20context_id=20-=0A+=09=09=09= 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=09memCtxState[idx].total_stats=20= =3D=20num_individual_stats=20+=201;=0A+=09}=0A+=0A+cleanup:=0A+=0A+=09/*=0A= +=09=20*=20Signal=20all=20the=20waiting=20client=20backends=20after=20= copying=20all=20the=20statistics=0A+=09=20*/=0A+=09= memCtxState[idx].stats_timestamp=20=3D=20GetCurrentTimestamp();=0A+=09= LWLockRelease(&memCtxState[idx].lw_lock);=0A+=09= ConditionVariableBroadcast(&memCtxState[idx].memctx_cv);=0A+=09= hash_destroy(context_id_lookup);=0A+=09dsa_detach(area);=0A+}=0A+=0A+/*=0A= +=20*=20compute_context_path=0A+=20*=0A+=20*=20Append=20the=20transient=20= context_id=20of=20this=20context=20and=20each=20of=20its=20ancestors=0A+=20= *=20to=20a=20list,=20in=20order=20to=20compute=20a=20path.=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+=0A+=09for=20(MemoryContext=20cur_context=20=3D=20= c;=20cur_context=20!=3D=20NULL;=20cur_context=20=3D=20= cur_context->parent)=0A+=09{=0A+=09=09MemoryContextId=20*cur_entry;=0A+=0A= +=09=09cur_entry=20=3D=20hash_search(context_id_lookup,=20&cur_context,=20= HASH_FIND,=20&found);=0A+=0A+=09=09if=20(!found)=0A+=09=09=09elog(ERROR,=20= "hash=20table=20corrupted,=20can't=20construct=20path=20value");=0A+=0A+=09= =09path=20=3D=20lcons_int(cur_entry->context_id,=20path);=0A+=09}=0A+=09= return=20path;=0A+}=0A+=0A+/*=0A+=20*=20Return=20the=20number=20of=20= contexts=20allocated=20currently=20by=20the=20backend=0A+=20*=20Assign=20= context=20ids=20to=20each=20of=20the=20contexts.=0A+=20*/=0A+static=20= void=0A+compute_contexts_count_and_ids(List=20*contexts,=20HTAB=20= *context_id_lookup,=0A+=09=09=09=09=09=09=09=20=20=20int=20*stats_count,=20= bool=20get_summary)=0A+{=0A+=09foreach_ptr(MemoryContextData,=20cur,=20= contexts)=0A+=09{=0A+=09=09MemoryContextId=20*entry;=0A+=09=09bool=09=09= found;=0A+=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=09Assert(!found);=0A+=0A+=09=09/*=20= context=20id=20starts=20with=201=20*/=0A+=09=09entry->context_id=20=3D=20= (++(*stats_count));=0A+=0A+=09=09/*=20Append=20the=20children=20of=20the=20= current=20context=20to=20the=20main=20list.=20*/=0A+=09=09for=20= (MemoryContext=20c=20=3D=20cur->firstchild;=20c=20!=3D=20NULL;=20c=20=3D=20= c->nextchild)=0A+=09=09{=0A+=09=09=09if=20(get_summary)=0A+=09=09=09{=0A= +=09=09=09=09entry=20=3D=20(MemoryContextId=20*)=20= hash_search(context_id_lookup,=20&c,=0A+=09=09=09=09=09=09=09=09=09=09=09= =09=09=09HASH_ENTER,=20&found);=0A+=09=09=09=09Assert(!found);=0A+=0A+=09= =09=09=09entry->context_id=20=3D=20(++(*stats_count));=0A+=09=09=09}=0A+=0A= +=09=09=09contexts=20=3D=20lappend(contexts,=20c);=0A+=09=09}=0A+=0A+=09=09= /*=0A+=09=09=20*=20In=20summary=20only=20the=20first=20two=20level=20= (from=20top)=20contexts=20are=0A+=09=09=20*=20displayed=0A+=09=09=20*/=0A= +=09=09if=20(get_summary)=0A+=09=09=09break;=0A+=09}=0A+}=0A+=0A+/*=0A+=20= *=20PublishMemoryContext=0A+=20*=0A+=20*=20Copy=20the=20memory=20context=20= statistics=20of=20a=20single=20context=20to=20a=20DSA=20memory=0A+=20*/=0A= +static=20void=0A+PublishMemoryContext(MemoryContextEntry=20= *memctx_info,=20int=20curr_id,=0A+=09=09=09=09=09=20MemoryContext=20= context,=20List=20*path,=0A+=09=09=09=09=09=20MemoryContextCounters=20= stat,=20int=20num_contexts,=0A+=09=09=09=09=09=20dsa_area=20*area)=0A+{=0A= +=09char=09=09clipped_ident[MEMORY_CONTEXT_IDENT_SHMEM_SIZE];=0A+=09char=09= =20=20=20*name;=0A+=09char=09=20=20=20*ident;=0A+=09int=09=09=20=20=20= *path_list;=0A+=0A+=09Assert(MemoryContextIsValid(context));=0A+=0A+=09= if=20(context->name=20!=3D=20NULL)=0A+=09{=0A+=09=09= Assert(strlen(context->name)=20<=20MEMORY_CONTEXT_IDENT_SHMEM_SIZE);=0A+=09= =09memctx_info[curr_id].name=20=3D=20dsa_allocate0(area,=20= strlen(context->name)=20+=201);=0A+=09=09name=20=3D=20(char=20*)=20= dsa_get_address(area,=20memctx_info[curr_id].name);=0A+=09=09= strlcpy(name,=20context->name,=20strlen(context->name)=20+=201);=0A+=09}=0A= +=09else=0A+=09=09memctx_info[curr_id].name=20=3D=20InvalidDsaPointer;=0A= +=0A+=09/*=20Trim=20and=20copy=20the=20identifier=20if=20it=20is=20not=20= set=20to=20NULL=20*/=0A+=09if=20(context->ident=20!=3D=20NULL)=0A+=09{=0A= +=09=09int=09=09=09idlen=20=3D=20strlen(context->ident);=0A+=0A+=09=09/*=0A= +=09=09=20*=20Some=20identifiers=20such=20as=20SQL=20query=20string=20= can=20be=20very=20long,=0A+=09=09=20*=20truncate=20oversize=20= identifiers.=0A+=09=09=20*/=0A+=09=09if=20(idlen=20>=3D=20= MEMORY_CONTEXT_IDENT_SHMEM_SIZE)=0A+=09=09=09idlen=20=3D=20= pg_mbcliplen(context->ident,=20idlen,=0A+=09=09=09=09=09=09=09=09=20= MEMORY_CONTEXT_IDENT_SHMEM_SIZE=20-=201);=0A+=0A+=09=09= memcpy(clipped_ident,=20context->ident,=20idlen);=0A+=09=09= clipped_ident[idlen]=20=3D=20'\0';=0A+=0A+=09=09/*=0A+=09=09=20*=20To=20= be=20consistent=20with=20logging=20output,=20we=20label=20dynahash=20= contexts=0A+=09=09=20*=20with=20just=20the=20hash=20table=20name=20as=20= with=20MemoryContextStatsPrint().=0A+=09=09=20*/=0A+=09=09if=20= (strncmp(context->name,=20"dynahash",=208)=20=3D=3D=200)=0A+=09=09{=0A+=09= =09=09dsa_free(area,=20memctx_info[curr_id].name);=0A+=09=09=09= memctx_info[curr_id].name=20=3D=20dsa_allocate0(area,=20idlen=20+=201);=0A= +=09=09=09name=20=3D=20(char=20*)=20dsa_get_address(area,=20= memctx_info[curr_id].name);=0A+=09=09=09strlcpy(name,=20clipped_ident,=20= idlen=20+=201);=0A+=09=09=09memctx_info[curr_id].ident=20=3D=20= InvalidDsaPointer;=0A+=09=09}=0A+=09=09else=0A+=09=09{=0A+=09=09=09= memctx_info[curr_id].ident=20=3D=20dsa_allocate0(area,=20idlen=20+=201);=0A= +=09=09=09ident=20=3D=20(char=20*)=20dsa_get_address(area,=20= memctx_info[curr_id].ident);=0A+=09=09=09strlcpy(ident,=20clipped_ident,=20= idlen=20+=201);=0A+=09=09}=0A+=09}=0A+=09else=0A+=09=09= memctx_info[curr_id].ident=20=3D=20InvalidDsaPointer;=0A+=0A+=09/*=20= Allocate=20DSA=20memory=20for=20storing=20path=20information=20*/=0A+=09= if=20(path=20=3D=3D=20NIL)=0A+=09=09memctx_info[curr_id].path=20=3D=20= InvalidDsaPointer;=0A+=09else=0A+=09{=0A+=09=09= memctx_info[curr_id].path_length=20=3D=20list_length(path);=0A+=09=09= memctx_info[curr_id].path=20=3D=20dsa_allocate0(area,=0A+=09=09=09=09=09=09= =09=09=09=09=09=09=20=20memctx_info[curr_id].path_length=20*=20= sizeof(int));=0A+=09=09path_list=20=3D=20(int=20*)=20= dsa_get_address(area,=20memctx_info[curr_id].path);=0A+=09=09= foreach_int(i,=20path)=0A+=09=09=09path_list[foreach_current_index(i)]=20= =3D=20i;=0A+=09}=0A+=09memctx_info[curr_id].type=20=3D=20= ContextTypeToString(context->type,=20true);=0A+=09= memctx_info[curr_id].totalspace=20=3D=20stat.totalspace;=0A+=09= memctx_info[curr_id].nblocks=20=3D=20stat.nblocks;=0A+=09= memctx_info[curr_id].freespace=20=3D=20stat.freespace;=0A+=09= memctx_info[curr_id].freechunks=20=3D=20stat.freechunks;=0A+=09= memctx_info[curr_id].num_agg_stats=20=3D=20num_contexts;=0A+}=0A+=0A+/*=0A= +=20*=20dsa_free_previous_stats=0A+=20*=0A+=20*=20Worker=20for=20freeing=20= resources=20from=20a=20MemoryContextEntry.=20=20Callers=20are=0A+=20*=20= responsible=20for=20ensuring=20that=20the=20DSA=20pointer=20is=20valid.=0A= +=20*/=0A+static=20void=0A+dsa_free_previous_stats(dsa_area=20*area,=20= int=20total_stats,=0A+=09=09=09=09=09=09dsa_pointer=20prev_dsa_pointer)=0A= +{=0A+=09MemoryContextEntry=20*meminfo;=0A+=0A+=09meminfo=20=3D=20= (MemoryContextEntry=20*)=20dsa_get_address(area,=20prev_dsa_pointer);=0A= +=09Assert(meminfo=20!=3D=20NULL);=0A+=09for=20(int=20i=20=3D=200;=20i=20= <=20total_stats;=20i++)=0A+=09{=0A+=09=09if=20= (DsaPointerIsValid(meminfo[i].name))=0A+=09=09=09dsa_free(area,=20= meminfo[i].name);=0A+=0A+=09=09if=20= (DsaPointerIsValid(meminfo[i].ident))=0A+=09=09=09dsa_free(area,=20= meminfo[i].ident);=0A+=0A+=09=09if=20= (DsaPointerIsValid(meminfo[i].path))=0A+=09=09=09dsa_free(area,=20= meminfo[i].path);=0A+=09}=0A+}=0A+=0A+/*=0A+=20*=20Free=20the=20memory=20= context=20statistics=20stored=20by=20this=20process=0A+=20*=20in=20DSA=20= area.=0A+=20*/=0A+void=0A+AtProcExit_memstats_dsa_free(int=20code,=20= Datum=20arg)=0A+{=0A+=09int=09=09=09idx=20=3D=20MyProcNumber;=0A+=09= dsm_segment=20*dsm_seg=20=3D=20NULL;=0A+=09dsa_area=20=20=20*area=20=3D=20= NULL;=0A+=0A+=09if=20(memCtxArea->memstats_dsa_handle=20=3D=3D=20= DSA_HANDLE_INVALID)=0A+=09=09return;=0A+=0A+=09dsm_seg=20=3D=20= dsm_find_mapping(memCtxArea->memstats_dsa_handle);=0A+=0A+=09= LWLockAcquire(&memCtxState[idx].lw_lock,=20LW_EXCLUSIVE);=0A+=0A+=09if=20= (!DsaPointerIsValid(memCtxState[idx].memstats_dsa_pointer))=0A+=09{=0A+=09= =09LWLockRelease(&memCtxState[idx].lw_lock);=0A+=09=09return;=0A+=09}=0A= +=0A+=09/*=20If=20the=20dsm=20mapping=20could=20not=20be=20found,=20= attach=20to=20the=20area=20*/=0A+=09if=20(dsm_seg=20!=3D=20NULL)=0A+=09=09= return;=0A+=09area=20=3D=20dsa_attach(memCtxArea->memstats_dsa_handle);=0A= +=0A+=09/*=0A+=09=20*=20Free=20the=20memory=20context=20statistics,=20= free=20the=20name,=20ident=20and=20path=0A+=09=20*=20pointers=20before=20= freeing=20the=20pointer=20that=20contains=20these=20pointers=20and=0A+=09= =20*=20integer=20statistics.=0A+=09=20*/=0A+=09= dsa_free_previous_stats(area,=20memCtxState[idx].total_stats,=0A+=09=09=09= =09=09=09=09memCtxState[idx].memstats_dsa_pointer);=0A+=09dsa_free(area,=20= memCtxState[idx].memstats_dsa_pointer);=0A+=09= memCtxState[idx].memstats_dsa_pointer=20=3D=20InvalidDsaPointer;=0A+=0A+=09= dsa_detach(area);=0A+=09LWLockRelease(&memCtxState[idx].lw_lock);=0A+}=0A= +=0A=20void=20*=0A=20palloc(Size=20size)=0A=20{=0Adiff=20--git=20= a/src/include/catalog/pg_proc.dat=20b/src/include/catalog/pg_proc.dat=0A= index=206b57b7e18d9..ff25f729d94=20100644=0A---=20= a/src/include/catalog/pg_proc.dat=0A+++=20= b/src/include/catalog/pg_proc.dat=0A@@=20-8535,6=20+8535,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=20int4',=0A+=20=20proallargtypes=20=3D>=20= '{int4,bool,int4,text,text,text,_int4,int4,int8,int8,int8,int8,int8,int4,t= imestamptz}',=0A+=20=20proargmodes=20=3D>=20= '{i,i,i,o,o,o,o,o,o,o,o,o,o,o,o}',=0A+=20=20proargnames=20=3D>=20'{pid,=20= summary,=20retries,=20name,=20ident,=20type,=20path,=20level,=20= total_bytes,=20total_nblocks,=20free_bytes,=20free_chunks,=20used_bytes,=20= num_agg_contexts,=20stats_timestamp}',=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= 603d0424354..d3c44df6e13=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/procsignal.h=20b/src/include/storage/procsignal.h=0A= index=20022fd8ed933..5d4b2fbfc9c=20100644=0A---=20= a/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= 8abc26abce2..da6b633cbda=20100644=0A---=20a/src/include/utils/memutils.h=0A= +++=20b/src/include/utils/memutils.h=0A@@=20-18,6=20+18,9=20@@=0A=20= #define=20MEMUTILS_H=0A=20=0A=20#include=20"nodes/memnodes.h"=0A= +#include=20"storage/condition_variable.h"=0A+#include=20= "storage/lmgr.h"=0A+#include=20"utils/dsa.h"=0A=20=0A=20=0A=20/*=0A@@=20= -48,7=20+51,12=20@@=0A=20=0A=20#define=20AllocHugeSizeIsValid(size)=09= ((Size)=20(size)=20<=3D=20MaxAllocHugeSize)=0A=20=0A+#define=20= MEMORY_CONTEXT_IDENT_SHMEM_SIZE=20128=0A=20=0A+#define=20= MEM_CONTEXT_MAX_LEVEL=2064=0A+#define=20MAX_SEGMENTS_PER_BACKEND=201=0A= +#define=20MEM_CONTEXT_PATH_SIZE=20=20MEM_CONTEXT_MAX_LEVEL=20*=20= sizeof(int)=0A+#define=20MAX_MEMORY_CONTEXT_STATS_SIZE=20= sizeof(MemoryContextEntry)=20+=20MEM_CONTEXT_PATH_SIZE=20+=202=20*=20= MEMORY_CONTEXT_IDENT_SHMEM_SIZE=0A=20/*=0A=20=20*=20Standard=20top-level=20= memory=20contexts.=0A=20=20*=0A@@=20-319,4=20+327,65=20@@=20= pg_memory_is_all_zeros(const=20void=20*ptr,=20size_t=20len)=0A=20=09= return=20true;=0A=20}=0A=20=0A+/*=20Dynamic=20shared=20memory=20state=20= for=20statistics=20per=20context=20*/=0A+typedef=20struct=20= MemoryContextEntry=0A+{=0A+=09dsa_pointer=20name;=0A+=09dsa_pointer=20= ident;=0A+=09dsa_pointer=20path;=0A+=09const=20char=20*type;=0A+=09int=09= =09=09path_length;=0A+=09int64=09=09totalspace;=0A+=09int64=09=09= nblocks;=0A+=09int64=09=09freespace;=0A+=09int64=09=09freechunks;=0A+=09= int=09=09=09num_agg_stats;=0A+}=20MemoryContextEntry;=0A+=0A+/*=0A+=20*=20= Static=20shared=20memory=20state=20representing=20the=20DSA=20area=20= created=20for=20memory=0A+=20*=20context=20statistics=20reporting.=20=20= A=20single=20DSA=20area=20is=20created=20and=20used=20by=20all=0A+=20*=20= the=20processes,=20each=20having=20its=20specific=20DSA=20allocations=20= for=20sharing=20memory=0A+=20*=20statistics,=20tracked=20by=20per=20= backend=20static=20shared=20memory=20state.=0A+=20*/=0A+typedef=20struct=20= MemoryContextState=0A+{=0A+=09dsa_handle=09memstats_dsa_handle;=0A+=09= LWLock=09=09lw_lock;=0A+}=20MemoryContextState;=0A+=0A+/*=0A+=20*=20Per=20= backend=20static=20shared=20memory=20state=20for=20memory=20context=20= statistics=0A+=20*=20reporting.=0A+=20*/=0A+typedef=20struct=20= MemoryContextBackendState=0A+{=0A+=09ConditionVariable=20memctx_cv;=0A+=09= LWLock=09=09lw_lock;=0A+=09int=09=09=09proc_id;=0A+=09int=09=09=09= total_stats;=0A+=09bool=09=09get_summary;=0A+=09dsa_pointer=20= memstats_dsa_pointer;=0A+=09TimestampTz=20stats_timestamp;=0A+}=20= MemoryContextBackendState;=0A+=0A+=0A+/*=0A+=20*=20Used=20for=20storage=20= of=20transient=20identifiers=20for=20pg_get_backend_memory_contexts=0A+=20= */=0A+typedef=20struct=20MemoryContextId=0A+{=0A+=09MemoryContext=20= context;=0A+=09int=09=09=09context_id;=0A+}=20MemoryContextId;=0A+=0A= +extern=20PGDLLIMPORT=20MemoryContextBackendState=20*memCtxState;=0A= +extern=20PGDLLIMPORT=20MemoryContextState=20*memCtxArea;=0A+extern=20= void=20ProcessGetMemoryContextInterrupt(void);=0A+extern=20const=20char=20= *ContextTypeToString(NodeTag=20type,=20bool=20missing_ok);=0A+extern=20= void=20HandleGetMemoryContextInterrupt(void);=0A+extern=20void=20= MemCtxShmemInit(void);=0A+extern=20void=20MemCtxBackendShmemInit(void);=0A= +extern=20void=20AtProcExit_memstats_dsa_free(int=20code,=20Datum=20= arg);=0A+=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= 83228cfca29..dca20ae1a26=20100644=0A---=20= a/src/test/regress/expected/sysviews.out=0A+++=20= b/src/test/regress/expected/sysviews.out=0A@@=20-232,3=20+232,17=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=20launcher_pid=20= int;=0A+=20=20=20=20r=20RECORD;=0A+BEGIN=0A+=20=20=20=20=20=20=20=20= SELECT=20pid=20from=20pg_stat_activity=20where=20= backend_type=3D'autovacuum=20launcher'=0A+=09=20INTO=20launcher_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(launcher_pid,=20false,=20= 20)=0A+=09=20where=20path=20=3D=20'{1}'=20into=20r;=0A+=09RAISE=20NOTICE=20= '%',=20r;=0A+END=20$$;=0A+NOTICE:=20=20(AllocSet,TopMemoryContext,)=0A= diff=20--git=20a/src/test/regress/sql/sysviews.sql=20= b/src/test/regress/sql/sysviews.sql=0Aindex=2066179f026b3..4767351d4e2=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,17=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=20launcher_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'autovacuum=20launcher'=0A+=09=20= INTO=20launcher_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(launcher_pid,=20false,=2020)=0A+=09=20= where=20path=20=3D=20'{1}'=20into=20r;=0A+=09RAISE=20NOTICE=20'%',=20r;=0A= +END=20$$;=0Adiff=20--git=20a/src/tools/pgindent/typedefs.list=20= b/src/tools/pgindent/typedefs.list=0Aindex=20449bafc123c..f083690c5ce=20= 100644=0A---=20a/src/tools/pgindent/typedefs.list=0A+++=20= b/src/tools/pgindent/typedefs.list=0A@@=20-1654,12=20+1654,16=20@@=20= MemoizeState=0A=20MemoizeTuple=0A=20MemoryChunk=0A=20MemoryContext=0A= +MemoryContextBackendState=0A=20MemoryContextCallback=0A=20= MemoryContextCallbackFunction=0A=20MemoryContextCounters=0A=20= MemoryContextData=0A+MemoryContextEntry=0A+MemoryContextId=0A=20= MemoryContextMethodID=0A=20MemoryContextMethods=0A+MemoryContextState=0A=20= MemoryStatsPrintFunc=0A=20MergeAction=0A=20MergeActionState=0A--=20=0A= 2.39.3=20(Apple=20Git-146)=0A=0A= --Apple-Mail=_4EFDEB30-F8D3-4E32-86A9-BE439A72E4B8 Content-Disposition: attachment; filename=v21-0001-Preparatory-changes-for-reporting-memory-context.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v21-0001-Preparatory-changes-for-reporting-memory-context.patch" Content-Transfer-Encoding: quoted-printable =46rom=203f3597952fac250eeb55aa1b09a6409c4417beab=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Rahila=20Syed=20=0A= Date:=20Wed,=2026=20Mar=202025=2014:38:39=20+0530=0ASubject:=20[PATCH=20= v21=201/2]=20Preparatory=20changes=20for=20reporting=20memory=20context=0A= =20statistics=0A=0AEnsure=20that=20MemoryContextStatsInternal=20can=20= return=20number=20of=0Acontexts.=20Also,=20provide=20an=20option=20in=20= MemoryContextStatsInternal=0Ato=20return=20without=20printing=20stats=20= to=20either=20stderr=20or=20logs.=0A---=0A=20= src/backend/utils/mmgr/mcxt.c=20|=2077=20= ++++++++++++++++++++++++++++++-----=0A=201=20file=20changed,=2066=20= insertions(+),=2011=20deletions(-)=0A=0Adiff=20--git=20= a/src/backend/utils/mmgr/mcxt.c=20b/src/backend/utils/mmgr/mcxt.c=0A= index=20d98ae9db6be..2cbde8f39c3=20100644=0A---=20= a/src/backend/utils/mmgr/mcxt.c=0A+++=20b/src/backend/utils/mmgr/mcxt.c=0A= @@=20-135,6=20+135,17=20@@=20static=20const=20MemoryContextMethods=20= mcxt_methods[]=20=3D=20{=0A=20};=0A=20=0A=20#undef=20BOGUS_MCTX=0A+/*=0A= +=20*=20This=20is=20passed=20to=20MemoryContextStatsInternal=20to=20= determine=20whether=0A+=20*=20to=20print=20context=20statistics=20or=20= not=20and=20where=20to=20print=20them=20logs=20or=0A+=20*=20stderr.=0A+=20= */=0A+typedef=20enum=20PrintDestination=0A+{=0A+=09PRINT_STATS_TO_STDERR=20= =3D=200,=0A+=09PRINT_STATS_TO_LOGS,=0A+=09PRINT_STATS_NONE=0A+}=09=09=09= PrintDestination;=0A=20=0A=20/*=0A=20=20*=20CurrentMemoryContext=0A@@=20= -162,7=20+173,7=20@@=20static=20void=20= MemoryContextCallResetCallbacks(MemoryContext=20context);=0A=20static=20= void=20MemoryContextStatsInternal(MemoryContext=20context,=20int=20= level,=0A=20=09=09=09=09=09=09=09=09=09=20=20=20int=20max_level,=20int=20= max_children,=0A=20=09=09=09=09=09=09=09=09=09=20=20=20= MemoryContextCounters=20*totals,=0A-=09=09=09=09=09=09=09=09=09=20=20=20= bool=20print_to_stderr);=0A+=09=09=09=09=09=09=09=09=09=20=20=20= PrintDestination=20print_location,=20int=20*num_contexts);=0A=20static=20= void=20MemoryContextStatsPrint(MemoryContext=20context,=20void=20= *passthru,=0A=20=09=09=09=09=09=09=09=09=09const=20char=20*stats_string,=0A= =20=09=09=09=09=09=09=09=09=09bool=20print_to_stderr);=0A@@=20-831,11=20= +842,19=20@@=20MemoryContextStatsDetail(MemoryContext=20context,=0A=20=09= =09=09=09=09=09=20bool=20print_to_stderr)=0A=20{=0A=20=09= MemoryContextCounters=20grand_totals;=0A+=09int=09=09=09num_contexts;=0A= +=09PrintDestination=20print_location;=0A=20=0A=20=09= memset(&grand_totals,=200,=20sizeof(grand_totals));=0A=20=0A+=09if=20= (print_to_stderr)=0A+=09=09print_location=20=3D=20PRINT_STATS_TO_STDERR;=0A= +=09else=0A+=09=09print_location=20=3D=20PRINT_STATS_TO_LOGS;=0A+=0A+=09= /*=20num_contexts=20report=20number=20of=20contexts=20aggregated=20in=20= the=20output=20*/=0A=20=09MemoryContextStatsInternal(context,=200,=20= max_level,=20max_children,=0A-=09=09=09=09=09=09=09=20=20=20= &grand_totals,=20print_to_stderr);=0A+=09=09=09=09=09=09=09=20=20=20= &grand_totals,=20print_location,=20&num_contexts);=0A=20=0A=20=09if=20= (print_to_stderr)=0A=20=09=09fprintf(stderr,=0A@@=20-870,13=20+889,14=20= @@=20MemoryContextStatsDetail(MemoryContext=20context,=0A=20=20*=09=09= One=20recursion=20level=20for=20MemoryContextStats=0A=20=20*=0A=20=20*=20= Print=20stats=20for=20this=20context=20if=20possible,=20but=20in=20any=20= case=20accumulate=20counts=0A-=20*=20into=20*totals=20(if=20not=20NULL).=0A= +=20*=20into=20*totals=20(if=20not=20NULL).=20The=20callers=20should=20= make=20sure=20that=20print_location=0A+=20*=20is=20set=20to=20= PRINT_STATS_STDERR=20or=20PRINT_STATS_TO_LOGS=20or=20PRINT_STATS_NONE.=0A= =20=20*/=0A=20static=20void=0A=20= MemoryContextStatsInternal(MemoryContext=20context,=20int=20level,=0A=20=09= =09=09=09=09=09=20=20=20int=20max_level,=20int=20max_children,=0A=20=09=09= =09=09=09=09=20=20=20MemoryContextCounters=20*totals,=0A-=09=09=09=09=09=09= =20=20=20bool=20print_to_stderr)=0A+=09=09=09=09=09=09=20=20=20= PrintDestination=20print_location,=20int=20*num_contexts)=0A=20{=0A=20=09= MemoryContext=20child;=0A=20=09int=09=09=09ichild;=0A@@=20-884,10=20= +904,39=20@@=20MemoryContextStatsInternal(MemoryContext=20context,=20int=20= level,=0A=20=09Assert(MemoryContextIsValid(context));=0A=20=0A=20=09/*=20= Examine=20the=20context=20itself=20*/=0A-=09= context->methods->stats(context,=0A-=09=09=09=09=09=09=09= MemoryContextStatsPrint,=0A-=09=09=09=09=09=09=09&level,=0A-=09=09=09=09=09= =09=09totals,=20print_to_stderr);=0A+=09switch=20(print_location)=0A+=09= {=0A+=09=09case=20PRINT_STATS_TO_STDERR:=0A+=09=09=09= context->methods->stats(context,=0A+=09=09=09=09=09=09=09=09=09= MemoryContextStatsPrint,=0A+=09=09=09=09=09=09=09=09=09&level,=0A+=09=09=09= =09=09=09=09=09=09totals,=20true);=0A+=09=09=09break;=0A+=0A+=09=09case=20= PRINT_STATS_TO_LOGS:=0A+=09=09=09context->methods->stats(context,=0A+=09=09= =09=09=09=09=09=09=09MemoryContextStatsPrint,=0A+=09=09=09=09=09=09=09=09= =09&level,=0A+=09=09=09=09=09=09=09=09=09totals,=20false);=0A+=09=09=09= break;=0A+=0A+=09=09case=20PRINT_STATS_NONE:=0A+=0A+=09=09=09/*=0A+=09=09= =09=20*=20Do=20not=20print=20the=20statistics=20if=20print_location=20is=0A= +=09=09=09=20*=20PRINT_STATS_NONE,=20only=20compute=20totals.=20This=20= is=20used=20in=0A+=09=09=09=20*=20reporting=20of=20memory=20context=20= statistics=20via=20a=20sql=20function.=20Last=0A+=09=09=09=20*=20= parameter=20is=20not=20relevant.=0A++=09=09=09=20*/=0A+=09=09=09= context->methods->stats(context,=0A+=09=09=09=09=09=09=09=09=09NULL,=0A+=09= =09=09=09=09=09=09=09=09NULL,=0A+=09=09=09=09=09=09=09=09=09totals,=20= false);=0A+=09=09=09break;=0A+=09}=0A+=0A+=09/*=20Increment=20the=20= context=20count=20for=20each=20of=20the=20recursive=20call=20*/=0A+=09= *num_contexts=20=3D=20*num_contexts=20+=201;=0A=20=0A=20=09/*=0A=20=09=20= *=20Examine=20children.=0A@@=20-907,7=20+956,7=20@@=20= MemoryContextStatsInternal(MemoryContext=20context,=20int=20level,=0A=20=09= =09=09MemoryContextStatsInternal(child,=20level=20+=201,=0A=20=09=09=09=09= =09=09=09=09=09=20=20=20max_level,=20max_children,=0A=20=09=09=09=09=09=09= =09=09=09=20=20=20totals,=0A-=09=09=09=09=09=09=09=09=09=20=20=20= print_to_stderr);=0A+=09=09=09=09=09=09=09=09=09=20=20=20print_location,=20= num_contexts);=0A=20=09=09}=0A=20=09}=0A=20=0A@@=20-926,7=20+975,13=20@@=20= MemoryContextStatsInternal(MemoryContext=20context,=20int=20level,=0A=20=09= =09=09child=20=3D=20MemoryContextTraverseNext(child,=20context);=0A=20=09= =09}=0A=20=0A-=09=09if=20(print_to_stderr)=0A+=09=09/*=0A+=09=09=20*=20= Add=20the=20count=20of=20children=20contexts=20which=20are=20traversed=20= in=20the=0A+=09=09=20*=20non-recursive=20manner.=0A+=09=09=20*/=0A+=09=09= *num_contexts=20=3D=20*num_contexts=20+=20ichild;=0A+=0A+=09=09if=20= (print_location=20=3D=3D=20PRINT_STATS_TO_STDERR)=0A=20=09=09{=0A=20=09=09= =09for=20(int=20i=20=3D=200;=20i=20<=3D=20level;=20i++)=0A=20=09=09=09=09= fprintf(stderr,=20"=20=20");=0A@@=20-939,7=20+994,7=20@@=20= MemoryContextStatsInternal(MemoryContext=20context,=20int=20level,=0A=20=09= =09=09=09=09local_totals.freechunks,=0A=20=09=09=09=09=09= local_totals.totalspace=20-=20local_totals.freespace);=0A=20=09=09}=0A-=09= =09else=0A+=09=09else=20if=20(print_location=20=3D=3D=20= PRINT_STATS_TO_LOGS)=0A=20=09=09=09ereport(LOG_SERVER_ONLY,=0A=20=09=09=09= =09=09(errhidestmt(true),=0A=20=09=09=09=09=09=20errhidecontext(true),=0A= --=20=0A2.39.3=20(Apple=20Git-146)=0A=0A= --Apple-Mail=_4EFDEB30-F8D3-4E32-86A9-BE439A72E4B8--