Skip to content

Commit c0e907c

Browse files
author
Commitfest Bot
committed
[CF 5319] Changing shared_buffers without restart
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5319 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/CAExHW5sVxEwQsuzkgjjJQP9-XVe0H2njEVw1HxeYFdT7u7J+eQ@mail.gmail.com Author(s): Dmitry Dolgov
2 parents c0bc9af + 18d355b commit c0e907c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+3628
-322
lines changed

contrib/pg_buffercache/expected/pg_buffercache.out

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
CREATE EXTENSION pg_buffercache;
2-
select count(*) = (select setting::bigint
3-
from pg_settings
4-
where name = 'shared_buffers')
5-
from pg_buffercache;
2+
select pg_size_bytes(setting)/(select setting::bigint from pg_settings where name = 'block_size') AS nbuffers
3+
from pg_settings
4+
where name = 'shared_buffers'
5+
\gset
6+
select count(*) = :nbuffers from pg_buffercache;
67
?column?
78
----------
89
t
@@ -23,6 +24,20 @@ SELECT count(*) > 0 FROM pg_buffercache_usage_counts() WHERE buffers >= 0;
2324
t
2425
(1 row)
2526

27+
-- Test the buffer lookup table function and count is <= shared_buffers
28+
select count(*) <= :nbuffers from pg_buffercache_lookup_table_entries();
29+
?column?
30+
----------
31+
t
32+
(1 row)
33+
34+
-- Check that pg_buffercache_lookup_table view works and count is <= shared_buffers
35+
select count(*) <= :nbuffers from pg_buffercache_lookup_table;
36+
?column?
37+
----------
38+
t
39+
(1 row)
40+
2641
-- Check that the functions / views can't be accessed by default. To avoid
2742
-- having to create a dedicated user, use the pg_database_owner pseudo-role.
2843
SET ROLE pg_database_owner;
@@ -34,6 +49,10 @@ SELECT * FROM pg_buffercache_summary();
3449
ERROR: permission denied for function pg_buffercache_summary
3550
SELECT * FROM pg_buffercache_usage_counts();
3651
ERROR: permission denied for function pg_buffercache_usage_counts
52+
SELECT * FROM pg_buffercache_lookup_table_entries();
53+
ERROR: permission denied for function pg_buffercache_lookup_table_entries
54+
SELECT * FROM pg_buffercache_lookup_table;
55+
ERROR: permission denied for view pg_buffercache_lookup_table
3756
RESET role;
3857
-- Check that pg_monitor is allowed to query view / function
3958
SET ROLE pg_monitor;
@@ -55,6 +74,21 @@ SELECT count(*) > 0 FROM pg_buffercache_usage_counts();
5574
t
5675
(1 row)
5776

77+
RESET role;
78+
-- Check that pg_read_all_stats is allowed to query buffer lookup table
79+
SET ROLE pg_read_all_stats;
80+
SELECT count(*) >= 0 FROM pg_buffercache_lookup_table_entries();
81+
?column?
82+
----------
83+
t
84+
(1 row)
85+
86+
SELECT count(*) >= 0 FROM pg_buffercache_lookup_table;
87+
?column?
88+
----------
89+
t
90+
(1 row)
91+
5892
RESET role;
5993
------
6094
---- Test pg_buffercache_evict* functions

contrib/pg_buffercache/pg_buffercache--1.5--1.6.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,27 @@ CREATE FUNCTION pg_buffercache_evict_all(
4444
OUT buffers_skipped int4)
4545
AS 'MODULE_PATHNAME', 'pg_buffercache_evict_all'
4646
LANGUAGE C PARALLEL SAFE VOLATILE;
47+
48+
-- Add the buffer lookup table function
49+
CREATE FUNCTION pg_buffercache_lookup_table_entries(
50+
OUT tablespace oid,
51+
OUT database oid,
52+
OUT relfilenode oid,
53+
OUT forknum int2,
54+
OUT blocknum int8,
55+
OUT bufferid int4)
56+
RETURNS SETOF record
57+
AS 'MODULE_PATHNAME', 'pg_buffercache_lookup_table_entries'
58+
LANGUAGE C PARALLEL SAFE VOLATILE;
59+
60+
-- Create a view for convenient access.
61+
CREATE VIEW pg_buffercache_lookup_table AS
62+
SELECT * FROM pg_buffercache_lookup_table_entries();
63+
64+
-- Don't want these to be available to public.
65+
REVOKE ALL ON FUNCTION pg_buffercache_lookup_table_entries() FROM PUBLIC;
66+
REVOKE ALL ON pg_buffercache_lookup_table FROM PUBLIC;
67+
68+
-- Grant access to monitoring role.
69+
GRANT EXECUTE ON FUNCTION pg_buffercache_lookup_table_entries() TO pg_read_all_stats;
70+
GRANT SELECT ON pg_buffercache_lookup_table TO pg_read_all_stats;

contrib/pg_buffercache/pg_buffercache_pages.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "storage/buf_internals.h"
1717
#include "storage/bufmgr.h"
1818
#include "utils/rel.h"
19+
#include "utils/tuplestore.h"
1920

2021

2122
#define NUM_BUFFERCACHE_PAGES_MIN_ELEM 8
@@ -100,6 +101,7 @@ PG_FUNCTION_INFO_V1(pg_buffercache_usage_counts);
100101
PG_FUNCTION_INFO_V1(pg_buffercache_evict);
101102
PG_FUNCTION_INFO_V1(pg_buffercache_evict_relation);
102103
PG_FUNCTION_INFO_V1(pg_buffercache_evict_all);
104+
PG_FUNCTION_INFO_V1(pg_buffercache_lookup_table_entries);
103105

104106

105107
/* Only need to touch memory once per backend process lifetime */
@@ -116,6 +118,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
116118
TupleDesc tupledesc;
117119
TupleDesc expected_tupledesc;
118120
HeapTuple tuple;
121+
int currentNBuffers = pg_atomic_read_u32(&ShmemCtrl->currentNBuffers);
119122

120123
if (SRF_IS_FIRSTCALL())
121124
{
@@ -172,10 +175,10 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
172175
/* Allocate NBuffers worth of BufferCachePagesRec records. */
173176
fctx->record = (BufferCachePagesRec *)
174177
MemoryContextAllocHuge(CurrentMemoryContext,
175-
sizeof(BufferCachePagesRec) * NBuffers);
178+
sizeof(BufferCachePagesRec) * currentNBuffers);
176179

177180
/* Set max calls and remember the user function context. */
178-
funcctx->max_calls = NBuffers;
181+
funcctx->max_calls = currentNBuffers;
179182
funcctx->user_fctx = fctx;
180183

181184
/* Return to original context when allocating transient memory */
@@ -189,13 +192,24 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
189192
* snapshot across all buffers, but we do grab the buffer header
190193
* locks, so the information of each buffer is self-consistent.
191194
*/
192-
for (i = 0; i < NBuffers; i++)
195+
for (i = 0; i < currentNBuffers; i++)
193196
{
194197
BufferDesc *bufHdr;
195198
uint32 buf_state;
196199

197200
CHECK_FOR_INTERRUPTS();
198201

202+
/*
203+
* TODO: We should just scan the entire buffer descriptor
204+
* array instead of relying on curent buffer pool size. But that can
205+
* happen if only we setup the descriptor array large enough at the
206+
* server startup time.
207+
*/
208+
if (currentNBuffers != pg_atomic_read_u32(&ShmemCtrl->currentNBuffers))
209+
ereport(ERROR,
210+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
211+
errmsg("number of shared buffers changed during scan of buffer cache")));
212+
199213
bufHdr = GetBufferDescriptor(i);
200214
/* Lock each buffer header before inspecting. */
201215
buf_state = LockBufHdr(bufHdr);
@@ -776,3 +790,19 @@ pg_buffercache_evict_all(PG_FUNCTION_ARGS)
776790

777791
PG_RETURN_DATUM(result);
778792
}
793+
794+
/*
795+
* Return lookup table content as a set of records.
796+
*/
797+
Datum
798+
pg_buffercache_lookup_table_entries(PG_FUNCTION_ARGS)
799+
{
800+
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
801+
802+
InitMaterializedSRF(fcinfo, 0);
803+
804+
/* Fill the tuplestore */
805+
BufTableGetContents(rsinfo->setResult, rsinfo->setDesc);
806+
807+
return (Datum) 0;
808+
}

contrib/pg_buffercache/sql/pg_buffercache.sql

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
CREATE EXTENSION pg_buffercache;
22

3-
select count(*) = (select setting::bigint
4-
from pg_settings
5-
where name = 'shared_buffers')
6-
from pg_buffercache;
3+
select pg_size_bytes(setting)/(select setting::bigint from pg_settings where name = 'block_size') AS nbuffers
4+
from pg_settings
5+
where name = 'shared_buffers'
6+
\gset
7+
select count(*) = :nbuffers from pg_buffercache;
78

89
select buffers_used + buffers_unused > 0,
910
buffers_dirty <= buffers_used,
@@ -12,13 +13,21 @@ from pg_buffercache_summary();
1213

1314
SELECT count(*) > 0 FROM pg_buffercache_usage_counts() WHERE buffers >= 0;
1415

16+
-- Test the buffer lookup table function and count is <= shared_buffers
17+
select count(*) <= :nbuffers from pg_buffercache_lookup_table_entries();
18+
19+
-- Check that pg_buffercache_lookup_table view works and count is <= shared_buffers
20+
select count(*) <= :nbuffers from pg_buffercache_lookup_table;
21+
1522
-- Check that the functions / views can't be accessed by default. To avoid
1623
-- having to create a dedicated user, use the pg_database_owner pseudo-role.
1724
SET ROLE pg_database_owner;
1825
SELECT * FROM pg_buffercache;
1926
SELECT * FROM pg_buffercache_pages() AS p (wrong int);
2027
SELECT * FROM pg_buffercache_summary();
2128
SELECT * FROM pg_buffercache_usage_counts();
29+
SELECT * FROM pg_buffercache_lookup_table_entries();
30+
SELECT * FROM pg_buffercache_lookup_table;
2231
RESET role;
2332

2433
-- Check that pg_monitor is allowed to query view / function
@@ -28,6 +37,12 @@ SELECT buffers_used + buffers_unused > 0 FROM pg_buffercache_summary();
2837
SELECT count(*) > 0 FROM pg_buffercache_usage_counts();
2938
RESET role;
3039

40+
-- Check that pg_read_all_stats is allowed to query buffer lookup table
41+
SET ROLE pg_read_all_stats;
42+
SELECT count(*) >= 0 FROM pg_buffercache_lookup_table_entries();
43+
SELECT count(*) >= 0 FROM pg_buffercache_lookup_table;
44+
RESET role;
45+
3146

3247
------
3348
---- Test pg_buffercache_evict* functions

doc/src/sgml/config.sgml

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1724,7 +1724,6 @@ include_dir 'conf.d'
17241724
that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
17251725
(Non-default values of <symbol>BLCKSZ</symbol> change the minimum
17261726
value.)
1727-
This parameter can only be set at server start.
17281727
</para>
17291728

17301729
<para>
@@ -1747,6 +1746,49 @@ include_dir 'conf.d'
17471746
appropriate, so as to leave adequate space for the operating system.
17481747
</para>
17491748

1749+
<para>
1750+
The shared memory consumed by the buffer pool is allocated and
1751+
initialized according to the value of the GUC at the time of starting
1752+
the server. A desired new value of GUC can be loaded while the server is
1753+
running using <systemitem>SIGHUP</systemitem>. But the buffer pool will
1754+
not be resized immediately. Use
1755+
<function>pg_resize_shared_buffers()</function> to dynamically resize
1756+
the shared buffer pool (see <xref linkend="functions-admin"/> for details).
1757+
<command>SHOW shared_buffers</command> shows the current number of
1758+
shared buffers and pending number, if any. Please note that when the GUC
1759+
is changed, the other GUCS which use this GUCs value to set their
1760+
defaults will not be changed. They may still require a server restart to
1761+
consider new value.
1762+
</para>
1763+
</listitem>
1764+
</varlistentry>
1765+
1766+
<varlistentry id="guc-max-shared-buffers" xreflabel="max_shared_buffers">
1767+
<term><varname>max_shared_buffers</varname> (<type>integer</type>)
1768+
<indexterm>
1769+
<primary><varname>max_shared_buffers</varname> configuration parameter</primary>
1770+
</indexterm>
1771+
</term>
1772+
<listitem>
1773+
<para>
1774+
Sets the upper limit for the <varname>shared_buffers</varname> value.
1775+
The default value is <literal>0</literal>,
1776+
which means no explicit limit is set and <varname>max_shared_buffers</varname>
1777+
will be automatically set to the value of <varname>shared_buffers</varname>
1778+
at server startup.
1779+
If this value is specified without units, it is taken as blocks,
1780+
that is <symbol>BLCKSZ</symbol> bytes, typically 8kB.
1781+
This parameter can only be set at server start.
1782+
</para>
1783+
1784+
<para>
1785+
This parameter determines the amount of memory address space to reserve
1786+
in each backend for expanding the buffer pool in future. While the
1787+
memory for buffer pool is allocated on demand as it is resized, the
1788+
memory required to hold the buffer manager metadata is allocated
1789+
statically at the server start accounting for the largest buffer pool
1790+
size allowed by this parameter.
1791+
</para>
17501792
</listitem>
17511793
</varlistentry>
17521794

doc/src/sgml/func/func-admin.sgml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,63 @@
9999
<returnvalue>off</returnvalue>
100100
</para></entry>
101101
</row>
102+
103+
<row>
104+
<entry role="func_table_entry"><para role="func_signature">
105+
<indexterm>
106+
<primary>pg_resize_shared_buffers</primary>
107+
</indexterm>
108+
<function>pg_resize_shared_buffers</function> ()
109+
<returnvalue>boolean</returnvalue>
110+
</para>
111+
<para>
112+
Dynamically resizes the shared buffer pool to match the current
113+
value of the <varname>shared_buffers</varname> parameter. This
114+
function implements a coordinated resize process that ensures all
115+
backend processes acknowledge the change before completing the
116+
operation. The resize happens in multiple phases to maintain
117+
data consistency and system stability. Returns <literal>true</literal>
118+
if the resize was successful, or raises an error if the operation
119+
fails. This function can only be called by superusers.
120+
</para>
121+
<para>
122+
To resize shared buffers, first update the <varname>shared_buffers</varname>
123+
setting and reload the configuration, then verify the new value is loaded
124+
before calling this function. For example:
125+
<programlisting>
126+
postgres=# ALTER SYSTEM SET shared_buffers = '256MB';
127+
ALTER SYSTEM
128+
postgres=# SELECT pg_reload_conf();
129+
pg_reload_conf
130+
----------------
131+
t
132+
(1 row)
133+
134+
postgres=# SHOW shared_buffers;
135+
shared_buffers
136+
-------------------------
137+
128MB (pending: 256MB)
138+
(1 row)
139+
140+
postgres=# SELECT pg_resize_shared_buffers();
141+
pg_resize_shared_buffers
142+
--------------------------
143+
t
144+
(1 row)
145+
146+
postgres=# SHOW shared_buffers;
147+
shared_buffers
148+
----------------
149+
256MB
150+
(1 row)
151+
</programlisting>
152+
The <command>SHOW shared_buffers</command> step is important to verify
153+
that the configuration reload was successful and the new value is
154+
available to the current session before attempting the resize. The
155+
output shows both the current and pending values when a change is waiting
156+
to be applied.
157+
</para></entry>
158+
</row>
102159
</tbody>
103160
</tgroup>
104161
</table>

0 commit comments

Comments
 (0)