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

Commitd70b176

Browse files
committed
amcheck: Move common routines into a separate module
Before performing checks on an index, we need to take some safetymeasures that apply to all index AMs. This includes:* verifying that the index can be checked - Only selected AMs aresupported by amcheck (right now only B-Tree). The index has to bevalid and not a temporary index from another session.* changing (and then restoring) user's security context* obtaining proper locks on the index (and table, if needed)* discarding GUC changes from the index functionsUntil now this was implemented in the B-Tree amcheck module, but it'ssomething every AM will have to do. So relocate the code into a newmodule verify_common for reuse.The shared steps are implemented by amcheck_lock_relation_and_check(),receiving the AM-specific verification as a callback. Custom parametersmay be supplied using a pointer.Author: Andrey Borodin <amborodin@acm.org>Reviewed-By: José Villanova <jose.arthur@gmail.com>Reviewed-By: Aleksander Alekseev <aleksander@timescale.com>Reviewed-By: Nikolay Samokhvalov <samokhvalov@gmail.com>Reviewed-By: Andres Freund <andres@anarazel.de>Reviewed-By: Tomas Vondra <tomas@vondra.me>Reviewed-By: Mark Dilger <mark.dilger@enterprisedb.com>Reviewed-By: Peter Geoghegan <pg@bowt.ie>Reviewed-By: Kirill Reshke <reshkekirill@gmail.com>Discussion:https://postgr.es/m/45AC9B0A-2B45-40EE-B08F-BDCF5739D1E1%40yandex-team.ru
1 parentfb9dff7 commitd70b176

File tree

7 files changed

+297
-199
lines changed

7 files changed

+297
-199
lines changed

‎contrib/amcheck/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
MODULE_big= amcheck
44
OBJS =\
55
$(WIN32RES)\
6+
verify_common.o\
67
verify_heapam.o\
78
verify_nbtree.o
89

‎contrib/amcheck/expected/check_btree.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ ERROR: could not open relation with OID 17
5757
BEGIN;
5858
CREATE INDEX bttest_a_brin_idx ON bttest_a USING brin(id);
5959
SELECT bt_index_parent_check('bttest_a_brin_idx');
60-
ERROR:only B-Tree indexes are supported as targets for verification
61-
DETAIL: Relation "bttest_a_brin_idx" isnot a B-Tree index.
60+
ERROR:expected "btree" index as targets for verification
61+
DETAIL: Relation "bttest_a_brin_idx" isa brin index.
6262
ROLLBACK;
6363
-- normal check outside of xact
6464
SELECT bt_index_check('bttest_a_idx');

‎contrib/amcheck/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (c) 2022-2025, PostgreSQL Global Development Group
22

33
amcheck_sources=files(
4+
'verify_common.c',
45
'verify_heapam.c',
56
'verify_nbtree.c',
67
)

‎contrib/amcheck/verify_common.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* verify_common.c
4+
*Utility functions common to all access methods.
5+
*
6+
* Copyright (c) 2016-2025, PostgreSQL Global Development Group
7+
*
8+
* IDENTIFICATION
9+
* contrib/amcheck/verify_common.c
10+
*
11+
*-------------------------------------------------------------------------
12+
*/
13+
#include"postgres.h"
14+
15+
#include"access/genam.h"
16+
#include"access/table.h"
17+
#include"access/tableam.h"
18+
#include"verify_common.h"
19+
#include"catalog/index.h"
20+
#include"catalog/pg_am.h"
21+
#include"commands/tablecmds.h"
22+
#include"utils/guc.h"
23+
#include"utils/syscache.h"
24+
25+
staticboolamcheck_index_mainfork_expected(Relationrel);
26+
27+
28+
/*
29+
* Check if index relation should have a file for its main relation fork.
30+
* Verification uses this to skip unlogged indexes when in hot standby mode,
31+
* where there is simply nothing to verify.
32+
*
33+
* NB: Caller should call index_checkable() before calling here.
34+
*/
35+
staticbool
36+
amcheck_index_mainfork_expected(Relationrel)
37+
{
38+
if (rel->rd_rel->relpersistence!=RELPERSISTENCE_UNLOGGED||
39+
!RecoveryInProgress())
40+
return true;
41+
42+
ereport(NOTICE,
43+
(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
44+
errmsg("cannot verify unlogged index \"%s\" during recovery, skipping",
45+
RelationGetRelationName(rel))));
46+
47+
return false;
48+
}
49+
50+
/*
51+
* Amcheck main workhorse.
52+
* Given index relation OID, lock relation.
53+
* Next, take a number of standard actions:
54+
* 1) Make sure the index can be checked
55+
* 2) change the context of the user,
56+
* 3) keep track of GUCs modified via index functions
57+
* 4) execute callback function to verify integrity.
58+
*/
59+
void
60+
amcheck_lock_relation_and_check(Oidindrelid,
61+
Oidam_id,
62+
IndexDoCheckCallbackcheck,
63+
LOCKMODElockmode,
64+
void*state)
65+
{
66+
Oidheapid;
67+
Relationindrel;
68+
Relationheaprel;
69+
Oidsave_userid;
70+
intsave_sec_context;
71+
intsave_nestlevel;
72+
73+
/*
74+
* We must lock table before index to avoid deadlocks. However, if the
75+
* passed indrelid isn't an index then IndexGetRelation() will fail.
76+
* Rather than emitting a not-very-helpful error message, postpone
77+
* complaining, expecting that the is-it-an-index test below will fail.
78+
*
79+
* In hot standby mode this will raise an error when parentcheck is true.
80+
*/
81+
heapid=IndexGetRelation(indrelid, true);
82+
if (OidIsValid(heapid))
83+
{
84+
heaprel=table_open(heapid,lockmode);
85+
86+
/*
87+
* Switch to the table owner's userid, so that any index functions are
88+
* run as that user. Also lock down security-restricted operations
89+
* and arrange to make GUC variable changes local to this command.
90+
*/
91+
GetUserIdAndSecContext(&save_userid,&save_sec_context);
92+
SetUserIdAndSecContext(heaprel->rd_rel->relowner,
93+
save_sec_context |SECURITY_RESTRICTED_OPERATION);
94+
save_nestlevel=NewGUCNestLevel();
95+
}
96+
else
97+
{
98+
heaprel=NULL;
99+
/* Set these just to suppress "uninitialized variable" warnings */
100+
save_userid=InvalidOid;
101+
save_sec_context=-1;
102+
save_nestlevel=-1;
103+
}
104+
105+
/*
106+
* Open the target index relations separately (like relation_openrv(), but
107+
* with heap relation locked first to prevent deadlocking). In hot
108+
* standby mode this will raise an error when parentcheck is true.
109+
*
110+
* There is no need for the usual indcheckxmin usability horizon test
111+
* here, even in the heapallindexed case, because index undergoing
112+
* verification only needs to have entries for a new transaction snapshot.
113+
* (If this is a parentcheck verification, there is no question about
114+
* committed or recently dead heap tuples lacking index entries due to
115+
* concurrent activity.)
116+
*/
117+
indrel=index_open(indrelid,lockmode);
118+
119+
/*
120+
* Since we did the IndexGetRelation call above without any lock, it's
121+
* barely possible that a race against an index drop/recreation could have
122+
* netted us the wrong table.
123+
*/
124+
if (heaprel==NULL||heapid!=IndexGetRelation(indrelid, false))
125+
ereport(ERROR,
126+
(errcode(ERRCODE_UNDEFINED_TABLE),
127+
errmsg("could not open parent table of index \"%s\"",
128+
RelationGetRelationName(indrel))));
129+
130+
/* Check that relation suitable for checking */
131+
if (index_checkable(indrel,am_id))
132+
check(indrel,heaprel,state,lockmode==ShareLock);
133+
134+
/* Roll back any GUC changes executed by index functions */
135+
AtEOXact_GUC(false,save_nestlevel);
136+
137+
/* Restore userid and security context */
138+
SetUserIdAndSecContext(save_userid,save_sec_context);
139+
140+
/*
141+
* Release locks early. That's ok here because nothing in the called
142+
* routines will trigger shared cache invalidations to be sent, so we can
143+
* relax the usual pattern of only releasing locks after commit.
144+
*/
145+
index_close(indrel,lockmode);
146+
if (heaprel)
147+
table_close(heaprel,lockmode);
148+
}
149+
150+
/*
151+
* Basic checks about the suitability of a relation for checking as an index.
152+
*
153+
*
154+
* NB: Intentionally not checking permissions, the function is normally not
155+
* callable by non-superusers. If granted, it's useful to be able to check a
156+
* whole cluster.
157+
*/
158+
bool
159+
index_checkable(Relationrel,Oidam_id)
160+
{
161+
if (rel->rd_rel->relkind!=RELKIND_INDEX||
162+
rel->rd_rel->relam!=am_id)
163+
{
164+
HeapTupleamtup;
165+
HeapTupleamtuprel;
166+
167+
amtup=SearchSysCache1(AMOID,ObjectIdGetDatum(am_id));
168+
amtuprel=SearchSysCache1(AMOID,ObjectIdGetDatum(rel->rd_rel->relam));
169+
ereport(ERROR,
170+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
171+
errmsg("expected \"%s\" index as targets for verification",NameStr(((Form_pg_am)GETSTRUCT(amtup))->amname)),
172+
errdetail("Relation \"%s\" is a %s index.",
173+
RelationGetRelationName(rel),NameStr(((Form_pg_am)GETSTRUCT(amtuprel))->amname))));
174+
}
175+
176+
if (RELATION_IS_OTHER_TEMP(rel))
177+
ereport(ERROR,
178+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
179+
errmsg("cannot access temporary tables of other sessions"),
180+
errdetail("Index \"%s\" is associated with temporary relation.",
181+
RelationGetRelationName(rel))));
182+
183+
if (!rel->rd_index->indisvalid)
184+
ereport(ERROR,
185+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
186+
errmsg("cannot check index \"%s\"",
187+
RelationGetRelationName(rel)),
188+
errdetail("Index is not valid.")));
189+
190+
returnamcheck_index_mainfork_expected(rel);
191+
}

‎contrib/amcheck/verify_common.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* amcheck.h
4+
*Shared routines for amcheck verifications.
5+
*
6+
* Copyright (c) 2016-2025, PostgreSQL Global Development Group
7+
*
8+
* IDENTIFICATION
9+
* contrib/amcheck/amcheck.h
10+
*
11+
*-------------------------------------------------------------------------
12+
*/
13+
#include"storage/bufpage.h"
14+
#include"storage/lmgr.h"
15+
#include"storage/lockdefs.h"
16+
#include"utils/relcache.h"
17+
#include"miscadmin.h"
18+
19+
/* Typedefs for callback functions for amcheck_lock_relation */
20+
typedefvoid (*IndexCheckableCallback) (Relationindex);
21+
typedefvoid (*IndexDoCheckCallback) (Relationrel,
22+
Relationheaprel,
23+
void*state,
24+
boolreadonly);
25+
26+
externvoidamcheck_lock_relation_and_check(Oidindrelid,
27+
Oidam_id,
28+
IndexDoCheckCallbackcheck,
29+
LOCKMODElockmode,void*state);
30+
31+
externboolindex_checkable(Relationrel,Oidam_id);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp