🌐 AI搜索 & 代理 主页
Skip to content

Commit 9ccc049

Browse files
committed
pg_buffercache: Add pg_buffercache_mark_dirty{,_relation,_all}()
This commit introduces three new functions for marking shared buffers as dirty by using the functions introduced in 9660906: * pg_buffercache_mark_dirty() for one shared buffer. - pg_buffercache_mark_dirt_relation() for all the shared buffers in a relation. * pg_buffercache_mark_dirty_all() for all the shared buffers in pool. The "_all" and "_relation" flavors are designed to address the inefficiency of repeatedly calling pg_buffercache_mark_dirty() for each individual buffer, which can be time-consuming when dealing with with large shared buffers pool. These functions are intended as developer tools and are available only to superusers. There is no need to bump the version of pg_buffercache, 4b203d4 having done this job in this release cycle. Author: Nazir Bilal Yavuz <byavuz81@gmail.com> Reviewed-by: Andres Freund <andres@anarazel.de> Reviewed-by: Aidar Imamov <a.imamov@postgrespro.ru> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com> Reviewed-by: Joseph Koshakow <koshy44@gmail.com> Reviewed-by: Michael Paquier <michael@paquier.xyz> Reviewed-by: Yuhang Qiu <iamqyh@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Discussion: https://postgr.es/m/CAN55FZ0h_YoSqqutxV6DES1RW8ig6wcA8CR9rJk358YRMxZFmw@mail.gmail.com
1 parent d167c19 commit 9ccc049

File tree

5 files changed

+296
-8
lines changed

5 files changed

+296
-8
lines changed

contrib/pg_buffercache/expected/pg_buffercache.out

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ SELECT count(*) > 0 FROM pg_buffercache_usage_counts();
7575

7676
RESET role;
7777
------
78-
---- Test pg_buffercache_evict* functions
78+
---- Test pg_buffercache_evict* and pg_buffercache_mark_dirty* functions
7979
------
8080
CREATE ROLE regress_buffercache_normal;
8181
SET ROLE regress_buffercache_normal;
@@ -86,6 +86,12 @@ SELECT * FROM pg_buffercache_evict_relation(1);
8686
ERROR: must be superuser to use pg_buffercache_evict_relation()
8787
SELECT * FROM pg_buffercache_evict_all();
8888
ERROR: must be superuser to use pg_buffercache_evict_all()
89+
SELECT * FROM pg_buffercache_mark_dirty(1);
90+
ERROR: must be superuser to use pg_buffercache_mark_dirty()
91+
SELECT * FROM pg_buffercache_mark_dirty_relation(1);
92+
ERROR: must be superuser to use pg_buffercache_mark_dirty_relation()
93+
SELECT * FROM pg_buffercache_mark_dirty_all();
94+
ERROR: must be superuser to use pg_buffercache_mark_dirty_all()
8995
RESET ROLE;
9096
-- These should return nothing, because these are STRICT functions
9197
SELECT * FROM pg_buffercache_evict(NULL);
@@ -100,6 +106,18 @@ SELECT * FROM pg_buffercache_evict_relation(NULL);
100106
| |
101107
(1 row)
102108

109+
SELECT * FROM pg_buffercache_mark_dirty(NULL);
110+
buffer_dirtied | buffer_already_dirty
111+
----------------+----------------------
112+
|
113+
(1 row)
114+
115+
SELECT * FROM pg_buffercache_mark_dirty_relation(NULL);
116+
buffers_dirtied | buffers_already_dirty | buffers_skipped
117+
-----------------+-----------------------+-----------------
118+
| |
119+
(1 row)
120+
103121
-- These should fail because they are not called by valid range of buffers
104122
-- Number of the shared buffers are limited by max integer
105123
SELECT 2147483647 max_buffers \gset
@@ -109,11 +127,18 @@ SELECT * FROM pg_buffercache_evict(0);
109127
ERROR: bad buffer ID: 0
110128
SELECT * FROM pg_buffercache_evict(:max_buffers);
111129
ERROR: bad buffer ID: 2147483647
112-
-- This should fail because pg_buffercache_evict_relation() doesn't accept
113-
-- local relations
130+
SELECT * FROM pg_buffercache_mark_dirty(-1);
131+
ERROR: bad buffer ID: -1
132+
SELECT * FROM pg_buffercache_mark_dirty(0);
133+
ERROR: bad buffer ID: 0
134+
SELECT * FROM pg_buffercache_mark_dirty(:max_buffers);
135+
ERROR: bad buffer ID: 2147483647
136+
-- These should fail because they don't accept local relations
114137
CREATE TEMP TABLE temp_pg_buffercache();
115138
SELECT * FROM pg_buffercache_evict_relation('temp_pg_buffercache');
116139
ERROR: relation uses local buffers, pg_buffercache_evict_relation() is intended to be used for shared buffers only
140+
SELECT * FROM pg_buffercache_mark_dirty_relation('temp_pg_buffercache');
141+
ERROR: relation uses local buffers, pg_buffercache_mark_dirty_relation() is intended to be used for shared buffers only
117142
DROP TABLE temp_pg_buffercache;
118143
-- These shouldn't fail
119144
SELECT buffer_evicted IS NOT NULL FROM pg_buffercache_evict(1);
@@ -135,5 +160,23 @@ SELECT buffers_evicted IS NOT NULL FROM pg_buffercache_evict_relation('shared_pg
135160
t
136161
(1 row)
137162

163+
SELECT buffers_dirtied IS NOT NULL FROM pg_buffercache_mark_dirty_relation('shared_pg_buffercache');
164+
?column?
165+
----------
166+
t
167+
(1 row)
168+
138169
DROP TABLE shared_pg_buffercache;
170+
SELECT pg_buffercache_mark_dirty(1) IS NOT NULL;
171+
?column?
172+
----------
173+
t
174+
(1 row)
175+
176+
SELECT pg_buffercache_mark_dirty_all() IS NOT NULL;
177+
?column?
178+
----------
179+
t
180+
(1 row)
181+
139182
DROP ROLE regress_buffercache_normal;

contrib/pg_buffercache/pg_buffercache--1.6--1.7.sql

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,26 @@ REVOKE ALL ON pg_buffercache_numa FROM PUBLIC;
3131
GRANT EXECUTE ON FUNCTION pg_buffercache_os_pages(boolean) TO pg_monitor;
3232
GRANT SELECT ON pg_buffercache_os_pages TO pg_monitor;
3333
GRANT SELECT ON pg_buffercache_numa TO pg_monitor;
34+
35+
-- Functions to mark buffers as dirty.
36+
CREATE FUNCTION pg_buffercache_mark_dirty(
37+
IN int,
38+
OUT buffer_dirtied boolean,
39+
OUT buffer_already_dirty boolean)
40+
AS 'MODULE_PATHNAME', 'pg_buffercache_mark_dirty'
41+
LANGUAGE C PARALLEL SAFE VOLATILE STRICT;
42+
43+
CREATE FUNCTION pg_buffercache_mark_dirty_relation(
44+
IN regclass,
45+
OUT buffers_dirtied int4,
46+
OUT buffers_already_dirty int4,
47+
OUT buffers_skipped int4)
48+
AS 'MODULE_PATHNAME', 'pg_buffercache_mark_dirty_relation'
49+
LANGUAGE C PARALLEL SAFE VOLATILE STRICT;
50+
51+
CREATE FUNCTION pg_buffercache_mark_dirty_all(
52+
OUT buffers_dirtied int4,
53+
OUT buffers_already_dirty int4,
54+
OUT buffers_skipped int4)
55+
AS 'MODULE_PATHNAME', 'pg_buffercache_mark_dirty_all'
56+
LANGUAGE C PARALLEL SAFE VOLATILE;

contrib/pg_buffercache/pg_buffercache_pages.c

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
#define NUM_BUFFERCACHE_EVICT_ELEM 2
2626
#define NUM_BUFFERCACHE_EVICT_RELATION_ELEM 3
2727
#define NUM_BUFFERCACHE_EVICT_ALL_ELEM 3
28+
#define NUM_BUFFERCACHE_MARK_DIRTY_ELEM 2
29+
#define NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM 3
30+
#define NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM 3
2831

2932
#define NUM_BUFFERCACHE_OS_PAGES_ELEM 3
3033

@@ -101,6 +104,9 @@ PG_FUNCTION_INFO_V1(pg_buffercache_usage_counts);
101104
PG_FUNCTION_INFO_V1(pg_buffercache_evict);
102105
PG_FUNCTION_INFO_V1(pg_buffercache_evict_relation);
103106
PG_FUNCTION_INFO_V1(pg_buffercache_evict_all);
107+
PG_FUNCTION_INFO_V1(pg_buffercache_mark_dirty);
108+
PG_FUNCTION_INFO_V1(pg_buffercache_mark_dirty_relation);
109+
PG_FUNCTION_INFO_V1(pg_buffercache_mark_dirty_all);
104110

105111

106112
/* Only need to touch memory once per backend process lifetime */
@@ -826,3 +832,119 @@ pg_buffercache_evict_all(PG_FUNCTION_ARGS)
826832

827833
PG_RETURN_DATUM(result);
828834
}
835+
836+
/*
837+
* Try to mark a shared buffer as dirty.
838+
*/
839+
Datum
840+
pg_buffercache_mark_dirty(PG_FUNCTION_ARGS)
841+
{
842+
843+
Datum result;
844+
TupleDesc tupledesc;
845+
HeapTuple tuple;
846+
Datum values[NUM_BUFFERCACHE_MARK_DIRTY_ELEM];
847+
bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ELEM] = {0};
848+
849+
Buffer buf = PG_GETARG_INT32(0);
850+
bool buffer_already_dirty;
851+
852+
if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
853+
elog(ERROR, "return type must be a row type");
854+
855+
pg_buffercache_superuser_check("pg_buffercache_mark_dirty");
856+
857+
if (buf < 1 || buf > NBuffers)
858+
elog(ERROR, "bad buffer ID: %d", buf);
859+
860+
values[0] = BoolGetDatum(MarkDirtyUnpinnedBuffer(buf, &buffer_already_dirty));
861+
values[1] = BoolGetDatum(buffer_already_dirty);
862+
863+
tuple = heap_form_tuple(tupledesc, values, nulls);
864+
result = HeapTupleGetDatum(tuple);
865+
866+
PG_RETURN_DATUM(result);
867+
}
868+
869+
/*
870+
* Try to mark all the shared buffers of a relation as dirty.
871+
*/
872+
Datum
873+
pg_buffercache_mark_dirty_relation(PG_FUNCTION_ARGS)
874+
{
875+
Datum result;
876+
TupleDesc tupledesc;
877+
HeapTuple tuple;
878+
Datum values[NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM];
879+
bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM] = {0};
880+
881+
Oid relOid;
882+
Relation rel;
883+
884+
int32 buffers_already_dirty = 0;
885+
int32 buffers_dirtied = 0;
886+
int32 buffers_skipped = 0;
887+
888+
if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
889+
elog(ERROR, "return type must be a row type");
890+
891+
pg_buffercache_superuser_check("pg_buffercache_mark_dirty_relation");
892+
893+
relOid = PG_GETARG_OID(0);
894+
895+
rel = relation_open(relOid, AccessShareLock);
896+
897+
if (RelationUsesLocalBuffers(rel))
898+
ereport(ERROR,
899+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
900+
errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only",
901+
"pg_buffercache_mark_dirty_relation")));
902+
903+
MarkDirtyRelUnpinnedBuffers(rel, &buffers_dirtied, &buffers_already_dirty,
904+
&buffers_skipped);
905+
906+
relation_close(rel, AccessShareLock);
907+
908+
values[0] = Int32GetDatum(buffers_dirtied);
909+
values[1] = Int32GetDatum(buffers_already_dirty);
910+
values[2] = Int32GetDatum(buffers_skipped);
911+
912+
tuple = heap_form_tuple(tupledesc, values, nulls);
913+
result = HeapTupleGetDatum(tuple);
914+
915+
PG_RETURN_DATUM(result);
916+
}
917+
918+
/*
919+
* Try to mark all the shared buffers as dirty.
920+
*/
921+
Datum
922+
pg_buffercache_mark_dirty_all(PG_FUNCTION_ARGS)
923+
{
924+
Datum result;
925+
TupleDesc tupledesc;
926+
HeapTuple tuple;
927+
Datum values[NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM];
928+
bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM] = {0};
929+
930+
int32 buffers_already_dirty = 0;
931+
int32 buffers_dirtied = 0;
932+
int32 buffers_skipped = 0;
933+
934+
if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
935+
elog(ERROR, "return type must be a row type");
936+
937+
pg_buffercache_superuser_check("pg_buffercache_mark_dirty_all");
938+
939+
MarkDirtyAllUnpinnedBuffers(&buffers_dirtied, &buffers_already_dirty,
940+
&buffers_skipped);
941+
942+
values[0] = Int32GetDatum(buffers_dirtied);
943+
values[1] = Int32GetDatum(buffers_already_dirty);
944+
values[2] = Int32GetDatum(buffers_skipped);
945+
946+
tuple = heap_form_tuple(tupledesc, values, nulls);
947+
result = HeapTupleGetDatum(tuple);
948+
949+
PG_RETURN_DATUM(result);
950+
}

contrib/pg_buffercache/sql/pg_buffercache.sql

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ RESET role;
3838

3939

4040
------
41-
---- Test pg_buffercache_evict* functions
41+
---- Test pg_buffercache_evict* and pg_buffercache_mark_dirty* functions
4242
------
4343

4444
CREATE ROLE regress_buffercache_normal;
@@ -48,31 +48,42 @@ SET ROLE regress_buffercache_normal;
4848
SELECT * FROM pg_buffercache_evict(1);
4949
SELECT * FROM pg_buffercache_evict_relation(1);
5050
SELECT * FROM pg_buffercache_evict_all();
51+
SELECT * FROM pg_buffercache_mark_dirty(1);
52+
SELECT * FROM pg_buffercache_mark_dirty_relation(1);
53+
SELECT * FROM pg_buffercache_mark_dirty_all();
5154

5255
RESET ROLE;
5356

5457
-- These should return nothing, because these are STRICT functions
5558
SELECT * FROM pg_buffercache_evict(NULL);
5659
SELECT * FROM pg_buffercache_evict_relation(NULL);
60+
SELECT * FROM pg_buffercache_mark_dirty(NULL);
61+
SELECT * FROM pg_buffercache_mark_dirty_relation(NULL);
5762

5863
-- These should fail because they are not called by valid range of buffers
5964
-- Number of the shared buffers are limited by max integer
6065
SELECT 2147483647 max_buffers \gset
6166
SELECT * FROM pg_buffercache_evict(-1);
6267
SELECT * FROM pg_buffercache_evict(0);
6368
SELECT * FROM pg_buffercache_evict(:max_buffers);
69+
SELECT * FROM pg_buffercache_mark_dirty(-1);
70+
SELECT * FROM pg_buffercache_mark_dirty(0);
71+
SELECT * FROM pg_buffercache_mark_dirty(:max_buffers);
6472

65-
-- This should fail because pg_buffercache_evict_relation() doesn't accept
66-
-- local relations
73+
-- These should fail because they don't accept local relations
6774
CREATE TEMP TABLE temp_pg_buffercache();
6875
SELECT * FROM pg_buffercache_evict_relation('temp_pg_buffercache');
76+
SELECT * FROM pg_buffercache_mark_dirty_relation('temp_pg_buffercache');
6977
DROP TABLE temp_pg_buffercache;
7078

7179
-- These shouldn't fail
7280
SELECT buffer_evicted IS NOT NULL FROM pg_buffercache_evict(1);
7381
SELECT buffers_evicted IS NOT NULL FROM pg_buffercache_evict_all();
7482
CREATE TABLE shared_pg_buffercache();
7583
SELECT buffers_evicted IS NOT NULL FROM pg_buffercache_evict_relation('shared_pg_buffercache');
84+
SELECT buffers_dirtied IS NOT NULL FROM pg_buffercache_mark_dirty_relation('shared_pg_buffercache');
7685
DROP TABLE shared_pg_buffercache;
86+
SELECT pg_buffercache_mark_dirty(1) IS NOT NULL;
87+
SELECT pg_buffercache_mark_dirty_all() IS NOT NULL;
7788

7889
DROP ROLE regress_buffercache_normal;

0 commit comments

Comments
 (0)