Skip to content

Commit 1d7e280

Browse files
author
Commitfest Bot
committed
[CF 5493] v8 - Add pg_buffercache_evict_all() and pg_buffercache_mark_dirty[_all]() functions
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5493 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/itcll7zmkvmuyqkcicztyk3pvjr5fkxsadd6hr4dpcrbtgcdox@3mk7hjiecyvr Author(s): Nazir Bilal Yavuz
2 parents 46b4ba5 + ab11b10 commit 1d7e280

File tree

8 files changed

+479
-39
lines changed

8 files changed

+479
-39
lines changed

contrib/pg_buffercache/expected/pg_buffercache.out

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,67 @@ SELECT count(*) > 0 FROM pg_buffercache_usage_counts();
5555
t
5656
(1 row)
5757

58+
RESET role;
59+
------
60+
---- Test pg_buffercache_evict* functions
61+
------
62+
CREATE ROLE regress_buffercache_normal;
63+
SET ROLE regress_buffercache_normal;
64+
-- These should fail because they need to be called as SUPERUSER
65+
SELECT * FROM pg_buffercache_evict(1);
66+
ERROR: must be superuser to use pg_buffercache_evict()
67+
SELECT * FROM pg_buffercache_evict_relation(1);
68+
ERROR: must be superuser to use pg_buffercache_evict_relation()
69+
SELECT * FROM pg_buffercache_evict_all();
70+
ERROR: must be superuser to use pg_buffercache_evict_all()
71+
RESET ROLE;
72+
-- These should return nothing, because these are STRICT functions
73+
SELECT * FROM pg_buffercache_evict(NULL);
74+
evicted | flushed
75+
---------+---------
76+
|
77+
(1 row)
78+
79+
SELECT * FROM pg_buffercache_evict_relation(NULL);
80+
buffers_evicted | buffers_flushed | buffers_skipped
81+
-----------------+-----------------+-----------------
82+
| |
83+
(1 row)
84+
85+
-- These should fail because they are not called by valid range of buffers
86+
-- Number of the shared buffers are limited by max integer
87+
SELECT 2147483647 max_buffers \gset
88+
SELECT * FROM pg_buffercache_evict(-1);
89+
ERROR: bad buffer ID: -1
90+
SELECT * FROM pg_buffercache_evict(0);
91+
ERROR: bad buffer ID: 0
92+
SELECT * FROM pg_buffercache_evict(:max_buffers);
93+
ERROR: bad buffer ID: 2147483647
94+
-- This should fail because pg_buffercache_evict_relation() doesn't accept
95+
-- local relations
96+
CREATE TEMP TABLE temp_pg_buffercache();
97+
SELECT * FROM pg_buffercache_evict_relation('temp_pg_buffercache');
98+
ERROR: relation uses local buffers, pg_buffercache_evict_relation() is intended to be used for shared buffers only
99+
DROP TABLE temp_pg_buffercache;
100+
-- These shouldn't fail
101+
SELECT evicted IS NOT NULL FROM pg_buffercache_evict(1);
102+
?column?
103+
----------
104+
t
105+
(1 row)
106+
107+
SELECT buffers_evicted IS NOT NULL FROM pg_buffercache_evict_all();
108+
?column?
109+
----------
110+
t
111+
(1 row)
112+
113+
CREATE TABLE shared_pg_buffercache();
114+
SELECT buffers_evicted IS NOT NULL FROM pg_buffercache_evict_relation('shared_pg_buffercache');
115+
?column?
116+
----------
117+
t
118+
(1 row)
119+
120+
DROP TABLE shared_pg_buffercache;
121+
DROP ROLE regress_buffercache_normal;

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,27 @@ REVOKE ALL ON pg_buffercache_numa FROM PUBLIC;
2020

2121
GRANT EXECUTE ON FUNCTION pg_buffercache_numa_pages() TO pg_monitor;
2222
GRANT SELECT ON pg_buffercache_numa TO pg_monitor;
23+
24+
25+
DROP FUNCTION pg_buffercache_evict(integer);
26+
CREATE FUNCTION pg_buffercache_evict(
27+
IN int,
28+
OUT evicted boolean,
29+
OUT flushed boolean)
30+
AS 'MODULE_PATHNAME', 'pg_buffercache_evict'
31+
LANGUAGE C PARALLEL SAFE VOLATILE STRICT;
32+
33+
CREATE FUNCTION pg_buffercache_evict_relation(
34+
IN regclass,
35+
OUT buffers_evicted int4,
36+
OUT buffers_flushed int4,
37+
OUT buffers_skipped int4)
38+
AS 'MODULE_PATHNAME', 'pg_buffercache_evict_relation'
39+
LANGUAGE C PARALLEL SAFE VOLATILE STRICT;
40+
41+
CREATE FUNCTION pg_buffercache_evict_all(
42+
OUT buffers_evicted int4,
43+
OUT buffers_flushed int4,
44+
OUT buffers_skipped int4)
45+
AS 'MODULE_PATHNAME', 'pg_buffercache_evict_all'
46+
LANGUAGE C PARALLEL SAFE VOLATILE;

contrib/pg_buffercache/pg_buffercache_pages.c

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,22 @@
99
#include "postgres.h"
1010

1111
#include "access/htup_details.h"
12+
#include "access/relation.h"
1213
#include "catalog/pg_type.h"
1314
#include "funcapi.h"
1415
#include "port/pg_numa.h"
1516
#include "storage/buf_internals.h"
1617
#include "storage/bufmgr.h"
18+
#include "utils/rel.h"
1719

1820

1921
#define NUM_BUFFERCACHE_PAGES_MIN_ELEM 8
2022
#define NUM_BUFFERCACHE_PAGES_ELEM 9
2123
#define NUM_BUFFERCACHE_SUMMARY_ELEM 5
2224
#define NUM_BUFFERCACHE_USAGE_COUNTS_ELEM 4
25+
#define NUM_BUFFERCACHE_EVICT_ELEM 2
26+
#define NUM_BUFFERCACHE_EVICT_RELATION_ELEM 3
27+
#define NUM_BUFFERCACHE_EVICT_ALL_ELEM 3
2328

2429
#define NUM_BUFFERCACHE_NUMA_ELEM 3
2530

@@ -93,6 +98,8 @@ PG_FUNCTION_INFO_V1(pg_buffercache_numa_pages);
9398
PG_FUNCTION_INFO_V1(pg_buffercache_summary);
9499
PG_FUNCTION_INFO_V1(pg_buffercache_usage_counts);
95100
PG_FUNCTION_INFO_V1(pg_buffercache_evict);
101+
PG_FUNCTION_INFO_V1(pg_buffercache_evict_relation);
102+
PG_FUNCTION_INFO_V1(pg_buffercache_evict_all);
96103

97104

98105
/* Only need to touch memory once per backend process lifetime */
@@ -637,21 +644,131 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS)
637644
return (Datum) 0;
638645
}
639646

647+
/*
648+
* Helper function to check if the user has superuser privileges.
649+
*/
650+
static void
651+
pg_buffercache_superuser_check(char *func_name)
652+
{
653+
if (!superuser())
654+
ereport(ERROR,
655+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
656+
errmsg("must be superuser to use %s()",
657+
func_name)));
658+
}
659+
640660
/*
641661
* Try to evict a shared buffer.
642662
*/
643663
Datum
644664
pg_buffercache_evict(PG_FUNCTION_ARGS)
645665
{
666+
Datum result;
667+
TupleDesc tupledesc;
668+
HeapTuple tuple;
669+
Datum values[NUM_BUFFERCACHE_EVICT_ELEM];
670+
bool nulls[NUM_BUFFERCACHE_EVICT_ELEM] = {0};
671+
646672
Buffer buf = PG_GETARG_INT32(0);
673+
bool flushed;
647674

648-
if (!superuser())
649-
ereport(ERROR,
650-
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
651-
errmsg("must be superuser to use pg_buffercache_evict function")));
675+
if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
676+
elog(ERROR, "return type must be a row type");
677+
678+
pg_buffercache_superuser_check("pg_buffercache_evict");
652679

653680
if (buf < 1 || buf > NBuffers)
654681
elog(ERROR, "bad buffer ID: %d", buf);
655682

656-
PG_RETURN_BOOL(EvictUnpinnedBuffer(buf));
683+
values[0] = BoolGetDatum(EvictUnpinnedBuffer(buf, &flushed));
684+
values[1] = BoolGetDatum(flushed);
685+
686+
tuple = heap_form_tuple(tupledesc, values, nulls);
687+
result = HeapTupleGetDatum(tuple);
688+
689+
PG_RETURN_DATUM(result);
690+
}
691+
692+
/*
693+
* Try to evict specified relation.
694+
*/
695+
Datum
696+
pg_buffercache_evict_relation(PG_FUNCTION_ARGS)
697+
{
698+
Datum result;
699+
TupleDesc tupledesc;
700+
HeapTuple tuple;
701+
Datum values[NUM_BUFFERCACHE_EVICT_RELATION_ELEM];
702+
bool nulls[NUM_BUFFERCACHE_EVICT_RELATION_ELEM] = {0};
703+
704+
Oid relOid;
705+
Relation rel;
706+
707+
int32 buffers_evicted = 0;
708+
int32 buffers_flushed = 0;
709+
int32 buffers_skipped = 0;
710+
711+
if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
712+
elog(ERROR, "return type must be a row type");
713+
714+
pg_buffercache_superuser_check("pg_buffercache_evict_relation");
715+
716+
relOid = PG_GETARG_OID(0);
717+
718+
rel = relation_open(relOid, AccessShareLock);
719+
720+
if (RelationUsesLocalBuffers(rel))
721+
ereport(ERROR,
722+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
723+
errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only",
724+
"pg_buffercache_evict_relation")));
725+
726+
EvictRelUnpinnedBuffers(rel, &buffers_evicted, &buffers_flushed,
727+
&buffers_skipped);
728+
729+
relation_close(rel, AccessShareLock);
730+
731+
values[0] = Int32GetDatum(buffers_evicted);
732+
values[1] = Int32GetDatum(buffers_flushed);
733+
values[2] = Int32GetDatum(buffers_skipped);
734+
735+
tuple = heap_form_tuple(tupledesc, values, nulls);
736+
result = HeapTupleGetDatum(tuple);
737+
738+
PG_RETURN_DATUM(result);
739+
}
740+
741+
742+
/*
743+
* Try to evict all shared buffers.
744+
*/
745+
Datum
746+
pg_buffercache_evict_all(PG_FUNCTION_ARGS)
747+
{
748+
Datum result;
749+
TupleDesc tupledesc;
750+
HeapTuple tuple;
751+
Datum values[NUM_BUFFERCACHE_EVICT_ALL_ELEM];
752+
bool nulls[NUM_BUFFERCACHE_EVICT_ALL_ELEM] = {0};
753+
754+
int32 buffers_evicted = 0;
755+
int32 buffers_flushed = 0;
756+
int32 buffers_skipped = 0;
757+
758+
if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
759+
elog(ERROR, "return type must be a row type");
760+
761+
pg_buffercache_superuser_check("pg_buffercache_evict_all");
762+
763+
EvictAllUnpinnedBuffers(&buffers_evicted, &buffers_flushed,
764+
&buffers_skipped);
765+
766+
values[0] = Int32GetDatum(buffers_evicted);
767+
values[1] = Int32GetDatum(buffers_flushed);
768+
values[2] = Int32GetDatum(buffers_skipped);
769+
770+
tuple = heap_form_tuple(tupledesc, values, nulls);
771+
result = HeapTupleGetDatum(tuple);
772+
773+
PG_RETURN_DATUM(result);
657774
}

contrib/pg_buffercache/sql/pg_buffercache.sql

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,45 @@ SET ROLE pg_monitor;
2626
SELECT count(*) > 0 FROM pg_buffercache;
2727
SELECT buffers_used + buffers_unused > 0 FROM pg_buffercache_summary();
2828
SELECT count(*) > 0 FROM pg_buffercache_usage_counts();
29+
RESET role;
30+
31+
32+
------
33+
---- Test pg_buffercache_evict* functions
34+
------
35+
36+
CREATE ROLE regress_buffercache_normal;
37+
SET ROLE regress_buffercache_normal;
38+
39+
-- These should fail because they need to be called as SUPERUSER
40+
SELECT * FROM pg_buffercache_evict(1);
41+
SELECT * FROM pg_buffercache_evict_relation(1);
42+
SELECT * FROM pg_buffercache_evict_all();
43+
44+
RESET ROLE;
45+
46+
-- These should return nothing, because these are STRICT functions
47+
SELECT * FROM pg_buffercache_evict(NULL);
48+
SELECT * FROM pg_buffercache_evict_relation(NULL);
49+
50+
-- These should fail because they are not called by valid range of buffers
51+
-- Number of the shared buffers are limited by max integer
52+
SELECT 2147483647 max_buffers \gset
53+
SELECT * FROM pg_buffercache_evict(-1);
54+
SELECT * FROM pg_buffercache_evict(0);
55+
SELECT * FROM pg_buffercache_evict(:max_buffers);
56+
57+
-- This should fail because pg_buffercache_evict_relation() doesn't accept
58+
-- local relations
59+
CREATE TEMP TABLE temp_pg_buffercache();
60+
SELECT * FROM pg_buffercache_evict_relation('temp_pg_buffercache');
61+
DROP TABLE temp_pg_buffercache;
62+
63+
-- These shouldn't fail
64+
SELECT evicted IS NOT NULL FROM pg_buffercache_evict(1);
65+
SELECT buffers_evicted IS NOT NULL FROM pg_buffercache_evict_all();
66+
CREATE TABLE shared_pg_buffercache();
67+
SELECT buffers_evicted IS NOT NULL FROM pg_buffercache_evict_relation('shared_pg_buffercache');
68+
DROP TABLE shared_pg_buffercache;
69+
70+
DROP ROLE regress_buffercache_normal;

0 commit comments

Comments
 (0)