Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit32d3ed8

Browse files
committed
Add path column to pg_backend_memory_contexts view
"path" provides a reliable method of determining the parent/childrelationships between memory contexts. Previously this could be done ina non-reliable way by writing a recursive query and joining the "parent"and "name" columns. This wasn't reliable as the names were not unique,which could result in joining to the wrong parent.To make this reliable, "path" stores an array of numerical identifiersstarting with the identifier for TopLevelMemoryContext. It contains anelement for each intermediate parent between that and the current context.Incompatibility: Here we also adjust the "level" column to make it1-based rather than 0-based. A 1-based level provides a convenient wayto access elements in the "path" array. e.g. path[level] gives theidentifier for the current context.Identifiers are not stable across multiple evaluations of the view. Inan attempt to make these more stable for ad-hoc queries, the identifiersare assigned breadth-first. Contexts closer to TopLevelMemoryContextare less likely to change between queries and during queries.Author: Melih Mutlu <m.melihmutlu@gmail.com>Discussion:https://postgr.es/m/CAGPVpCThLyOsj3e_gYEvLoHkr5w=tadDiN_=z2OwsK3VJppeBA@mail.gmail.comReviewed-by: Andres Freund, Stephen Frost, Atsushi Torikoshi,Reviewed-by: Michael Paquier, Robert Haas, David Rowley
1 parent64c39bd commit32d3ed8

File tree

8 files changed

+225
-40
lines changed

8 files changed

+225
-40
lines changed

‎doc/src/sgml/system-views.sgml

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,22 @@
504504
<structfield>level</structfield> <type>int4</type>
505505
</para>
506506
<para>
507-
Distance from TopMemoryContext in context tree
507+
The 1-based level of the context in the memory context hierarchy. The
508+
level of a context also shows the position of that context in the
509+
<structfield>path</structfield> column.
510+
</para></entry>
511+
</row>
512+
513+
<row>
514+
<entry role="catalog_table_entry"><para role="column_definition">
515+
<structfield>path</structfield> <type>int4[]</type>
516+
</para>
517+
<para>
518+
Array of transient numerical identifiers to describe the memory
519+
context hierarchy. The first element is for
520+
<literal>TopMemoryContext</literal>, subsequent elements contain
521+
intermediate parents and the final element contains the identifier for
522+
the current context.
508523
</para></entry>
509524
</row>
510525

@@ -561,6 +576,29 @@
561576
read only by superusers or roles with the privileges of the
562577
<literal>pg_read_all_stats</literal> role.
563578
</para>
579+
580+
<para>
581+
Since memory contexts are created and destroyed during the running of a
582+
query, the identifiers stored in the <structfield>path</structfield> column
583+
can be unstable between multiple invocations of the view in the same query.
584+
The example below demonstrates an effective usage of this column and
585+
calculates the total number of bytes used by
586+
<literal>CacheMemoryContext</literal> and all of its children:
587+
588+
<programlisting>
589+
WITH memory_contexts AS (
590+
SELECT * FROM pg_backend_memory_contexts
591+
)
592+
SELECT sum(c1.total_bytes)
593+
FROM memory_contexts c1, memory_contexts c2
594+
WHERE c2.name = 'CacheMemoryContext'
595+
AND c1.path[c2.level] = c2.path[c2.level];
596+
</programlisting>
597+
598+
The <link linkend="queries-with">Common Table Expression</link> is used
599+
to ensure the context IDs in the <structfield>path</structfield> column
600+
match between both evaluations of the view.
601+
</para>
564602
</sect1>
565603

566604
<sect1 id="view-pg-config">

‎src/backend/utils/adt/mcxtfuncs.c

Lines changed: 151 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,55 +19,117 @@
1919
#include"mb/pg_wchar.h"
2020
#include"storage/proc.h"
2121
#include"storage/procarray.h"
22+
#include"utils/array.h"
2223
#include"utils/builtins.h"
24+
#include"utils/hsearch.h"
2325

2426
/* ----------
2527
* The max bytes for showing identifiers of MemoryContext.
2628
* ----------
2729
*/
2830
#defineMEMORY_CONTEXT_IDENT_DISPLAY_SIZE1024
2931

32+
/*
33+
* MemoryContextId
34+
*Used for storage of transient identifiers for
35+
*pg_get_backend_memory_contexts.
36+
*/
37+
typedefstructMemoryContextId
38+
{
39+
MemoryContextcontext;
40+
intcontext_id;
41+
}MemoryContextId;
42+
43+
/*
44+
* get_memory_context_name_and_ident
45+
*Populate *name and *ident from the name and ident from 'context'.
46+
*/
47+
staticvoid
48+
get_memory_context_name_and_ident(MemoryContextcontext,constchar**constname,
49+
constchar**constident)
50+
{
51+
*name=context->name;
52+
*ident=context->ident;
53+
54+
/*
55+
* To be consistent with logging output, we label dynahash contexts with
56+
* just the hash table name as with MemoryContextStatsPrint().
57+
*/
58+
if (ident&&strcmp(*name,"dynahash")==0)
59+
{
60+
*name=*ident;
61+
*ident=NULL;
62+
}
63+
}
64+
65+
/*
66+
* int_list_to_array
67+
*Convert an IntList to an array of INT4OIDs.
68+
*/
69+
staticDatum
70+
int_list_to_array(constList*list)
71+
{
72+
Datum*datum_array;
73+
intlength;
74+
ArrayType*result_array;
75+
76+
length=list_length(list);
77+
datum_array= (Datum*)palloc(length*sizeof(Datum));
78+
79+
foreach_int(i,list)
80+
datum_array[foreach_current_index(i)]=Int32GetDatum(i);
81+
82+
result_array=construct_array_builtin(datum_array,length,INT4OID);
83+
84+
returnPointerGetDatum(result_array);
85+
}
86+
3087
/*
3188
* PutMemoryContextsStatsTupleStore
32-
*One recursion levelforpg_get_backend_memory_contexts.
89+
*Add detailsforthe given MemoryContext to 'tupstore'.
3390
*/
3491
staticvoid
3592
PutMemoryContextsStatsTupleStore(Tuplestorestate*tupstore,
3693
TupleDesctupdesc,MemoryContextcontext,
37-
constchar*parent,intlevel)
94+
HTAB*context_id_lookup)
3895
{
39-
#definePG_GET_BACKEND_MEMORY_CONTEXTS_COLS10
96+
#definePG_GET_BACKEND_MEMORY_CONTEXTS_COLS11
4097

4198
Datumvalues[PG_GET_BACKEND_MEMORY_CONTEXTS_COLS];
4299
boolnulls[PG_GET_BACKEND_MEMORY_CONTEXTS_COLS];
43100
MemoryContextCountersstat;
44-
MemoryContextchild;
101+
List*path=NIL;
45102
constchar*name;
46103
constchar*ident;
47104
constchar*type;
48105

49106
Assert(MemoryContextIsValid(context));
50107

51-
name=context->name;
52-
ident=context->ident;
53-
54108
/*
55-
*To be consistent with logging output, we label dynahash contexts with
56-
*just the hash table name as with MemoryContextStatsPrint().
109+
*Figure out the transient context_id of this context and each of its
110+
*ancestors.
57111
*/
58-
if (ident&&strcmp(name,"dynahash")==0)
112+
for (MemoryContextcur=context;cur!=NULL;cur=cur->parent)
59113
{
60-
name=ident;
61-
ident=NULL;
114+
MemoryContextId*entry;
115+
boolfound;
116+
117+
entry=hash_search(context_id_lookup,&cur,HASH_FIND,&found);
118+
119+
if (!found)
120+
elog(ERROR,"hash table corrupted");
121+
path=lcons_int(entry->context_id,path);
62122
}
63123

64124
/* Examine the context itself */
65125
memset(&stat,0,sizeof(stat));
66-
(*context->methods->stats) (context,NULL,(void*)&level,&stat, true);
126+
(*context->methods->stats) (context,NULL,NULL,&stat, true);
67127

68128
memset(values,0,sizeof(values));
69129
memset(nulls,0,sizeof(nulls));
70130

131+
get_memory_context_name_and_ident(context,&name,&ident);
132+
71133
if (name)
72134
values[0]=CStringGetTextDatum(name);
73135
else
@@ -92,8 +154,15 @@ PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore,
92154
else
93155
nulls[1]= true;
94156

95-
if (parent)
96-
values[2]=CStringGetTextDatum(parent);
157+
if (context->parent)
158+
{
159+
constchar*parent_name,
160+
*parent_ident;
161+
162+
get_memory_context_name_and_ident(context->parent,&parent_name,
163+
&parent_ident);
164+
values[2]=CStringGetTextDatum(parent_name);
165+
}
97166
else
98167
nulls[2]= true;
99168

@@ -117,19 +186,16 @@ PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore,
117186
}
118187

119188
values[3]=CStringGetTextDatum(type);
120-
values[4]=Int32GetDatum(level);
121-
values[5]=Int64GetDatum(stat.totalspace);
122-
values[6]=Int64GetDatum(stat.nblocks);
123-
values[7]=Int64GetDatum(stat.freespace);
124-
values[8]=Int64GetDatum(stat.freechunks);
125-
values[9]=Int64GetDatum(stat.totalspace-stat.freespace);
126-
tuplestore_putvalues(tupstore,tupdesc,values,nulls);
189+
values[4]=Int32GetDatum(list_length(path));/* level */
190+
values[5]=int_list_to_array(path);
191+
values[6]=Int64GetDatum(stat.totalspace);
192+
values[7]=Int64GetDatum(stat.nblocks);
193+
values[8]=Int64GetDatum(stat.freespace);
194+
values[9]=Int64GetDatum(stat.freechunks);
195+
values[10]=Int64GetDatum(stat.totalspace-stat.freespace);
127196

128-
for (child=context->firstchild;child!=NULL;child=child->nextchild)
129-
{
130-
PutMemoryContextsStatsTupleStore(tupstore,tupdesc,
131-
child,name,level+1);
132-
}
197+
tuplestore_putvalues(tupstore,tupdesc,values,nulls);
198+
list_free(path);
133199
}
134200

135201
/*
@@ -140,10 +206,66 @@ Datum
140206
pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)
141207
{
142208
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
209+
intcontext_id;
210+
List*contexts;
211+
HASHCTLctl;
212+
HTAB*context_id_lookup;
213+
214+
ctl.keysize=sizeof(MemoryContext);
215+
ctl.entrysize=sizeof(MemoryContextId);
216+
ctl.hcxt=CurrentMemoryContext;
217+
218+
context_id_lookup=hash_create("pg_get_backend_memory_contexts",
219+
256,
220+
&ctl,
221+
HASH_ELEM |HASH_BLOBS |HASH_CONTEXT);
143222

144223
InitMaterializedSRF(fcinfo,0);
145-
PutMemoryContextsStatsTupleStore(rsinfo->setResult,rsinfo->setDesc,
146-
TopMemoryContext,NULL,0);
224+
225+
/*
226+
* Here we use a non-recursive algorithm to visit all MemoryContexts
227+
* starting with TopMemoryContext. The reason we avoid using a recursive
228+
* algorithm is because we want to assign the context_id breadth-first.
229+
* I.e. all contexts at level 1 are assigned IDs before contexts at level
230+
* 2. Because contexts closer to TopMemoryContext are less likely to
231+
* change, this makes the assigned context_id more stable. Otherwise, if
232+
* the first child of TopMemoryContext obtained an additional grandchild,
233+
* the context_id for the second child of TopMemoryContext would change.
234+
*/
235+
contexts=list_make1(TopMemoryContext);
236+
237+
/* TopMemoryContext will always have a context_id of 1 */
238+
context_id=1;
239+
240+
foreach_ptr(MemoryContextData,cur,contexts)
241+
{
242+
MemoryContextId*entry;
243+
boolfound;
244+
245+
/*
246+
* Record the context_id that we've assigned to each MemoryContext.
247+
* PutMemoryContextsStatsTupleStore needs this to populate the "path"
248+
* column with the parent context_ids.
249+
*/
250+
entry= (MemoryContextId*)hash_search(context_id_lookup,&cur,
251+
HASH_ENTER,&found);
252+
entry->context_id=context_id++;
253+
Assert(!found);
254+
255+
PutMemoryContextsStatsTupleStore(rsinfo->setResult,
256+
rsinfo->setDesc,
257+
cur,
258+
context_id_lookup);
259+
260+
/*
261+
* Append all children onto the contexts list so they're processed by
262+
* subsequent iterations.
263+
*/
264+
for (MemoryContextc=cur->firstchild;c!=NULL;c=c->nextchild)
265+
contexts=lappend(contexts,c);
266+
}
267+
268+
hash_destroy(context_id_lookup);
147269

148270
return (Datum)0;
149271
}

‎src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@
5757
*/
5858

5959
/*yyyymmddN */
60-
#defineCATALOG_VERSION_NO202407111
60+
#defineCATALOG_VERSION_NO202407251
6161

6262
#endif

‎src/include/catalog/pg_proc.dat

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8290,9 +8290,9 @@
82908290
proname => 'pg_get_backend_memory_contexts', prorows => '100',
82918291
proretset => 't', provolatile => 'v', proparallel => 'r',
82928292
prorettype => 'record', proargtypes => '',
8293-
proallargtypes => '{text,text,text,text,int4,int8,int8,int8,int8,int8}',
8294-
proargmodes => '{o,o,o,o,o,o,o,o,o,o}',
8295-
proargnames => '{name, ident, parent, type, level, total_bytes, total_nblocks, free_bytes, free_chunks, used_bytes}',
8293+
proallargtypes => '{text,text,text,text,int4,_int4,int8,int8,int8,int8,int8}',
8294+
proargmodes => '{o,o,o,o,o,o,o,o,o,o,o}',
8295+
proargnames => '{name, ident, parent, type, level,path,total_bytes, total_nblocks, free_bytes, free_chunks, used_bytes}',
82968296
prosrc => 'pg_get_backend_memory_contexts' },
82978297

82988298
# logging memory contexts of the specified backend

‎src/include/nodes/memnodes.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ typedef struct MemoryContextData
128128
MemoryContextfirstchild;/* head of linked list of children */
129129
MemoryContextprevchild;/* previous child of same parent */
130130
MemoryContextnextchild;/* next child of same parent */
131-
constchar*name;/* context name(just for debugging)*/
132-
constchar*ident;/* context ID if any(just for debugging)*/
131+
constchar*name;/* context name */
132+
constchar*ident;/* context ID if any */
133133
MemoryContextCallback*reset_cbs;/* list of reset/delete callbacks */
134134
}MemoryContextData;
135135

‎src/test/regress/expected/rules.out

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1308,12 +1308,13 @@ pg_backend_memory_contexts| SELECT name,
13081308
parent,
13091309
type,
13101310
level,
1311+
path,
13111312
total_bytes,
13121313
total_nblocks,
13131314
free_bytes,
13141315
free_chunks,
13151316
used_bytes
1316-
FROM pg_get_backend_memory_contexts() pg_get_backend_memory_contexts(name, ident, parent, type, level, total_bytes, total_nblocks, free_bytes, free_chunks, used_bytes);
1317+
FROM pg_get_backend_memory_contexts() pg_get_backend_memory_contexts(name, ident, parent, type, level,path,total_bytes, total_nblocks, free_bytes, free_chunks, used_bytes);
13171318
pg_config| SELECT name,
13181319
setting
13191320
FROM pg_config() pg_config(name, setting);

‎src/test/regress/expected/sysviews.out

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ select count(*) >= 0 as ok from pg_available_extensions;
2222
-- The entire output of pg_backend_memory_contexts is not stable,
2323
-- we test only the existence and basic condition of TopMemoryContext.
2424
select type, name, ident, parent, level, total_bytes >= free_bytes
25-
from pg_backend_memory_contexts where level =0;
25+
from pg_backend_memory_contexts where level =1;
2626
type | name | ident | parent | level | ?column?
2727
----------+------------------+-------+--------+-------+----------
28-
AllocSet | TopMemoryContext | | |0 | t
28+
AllocSet | TopMemoryContext | | |1 | t
2929
(1 row)
3030

3131
-- We can exercise some MemoryContext type stats functions. Most of the
@@ -51,6 +51,20 @@ from pg_backend_memory_contexts where name = 'Caller tuples';
5151
(1 row)
5252

5353
rollback;
54+
-- Further sanity checks on pg_backend_memory_contexts. We expect
55+
-- CacheMemoryContext to have multiple children. Ensure that's the case.
56+
with contexts as (
57+
select * from pg_backend_memory_contexts
58+
)
59+
select count(*) > 1
60+
from contexts c1, contexts c2
61+
where c2.name = 'CacheMemoryContext'
62+
and c1.path[c2.level] = c2.path[c2.level];
63+
?column?
64+
----------
65+
t
66+
(1 row)
67+
5468
-- At introduction, pg_config had 23 entries; it may grow
5569
select count(*) > 20 as ok from pg_config;
5670
ok

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp