Content-Length: 463084 | pFad | http://github.com/postgres/postgres/commit/cdd1a431f21dbd2b7b675a9db1c24b97d713f38b

97 amcheck: Fix parent key check in gin_index_check() · postgres/postgres@cdd1a43 · GitHub
Skip to content

Commit cdd1a43

Browse files
committed
amcheck: Fix parent key check in gin_index_check()
The checks introduced by commit 14ffaec did not get the parent key checks quite right, missing some data corruption cases. In particular: * The "rightlink" check was not working as intended, because rightlink is a BlockNumber, and InvalidBlockNumber is 0xFFFFFFFF, so !GinPageGetOpaque(page)->rightlink almost always evaluates to false (except for rightlink=0). So in most cases parenttup was left NULL, preventing any checks against parent. * Use GinGetDownlink() to retrieve child blkno to avoid triggering Assert, same as the core GIN code. Issues reported by Arseniy Mukhin, along with a proposed patch. Review by Andrey M. Borodin, cleanup and improvements by me. Author: Arseniy Mukhin <arseniy.mukhin.dev@gmail.com> Reviewed-by: Andrey M. Borodin <x4mmm@yandex-team.ru> Discussion: https://postgr.es/m/CAE7r3MJ611B9TE=YqBBncewp7-k64VWs+sjk7XF6fJUX77uFBA@mail.gmail.com
1 parent 0b54b39 commit cdd1a43

File tree

2 files changed

+82
-4
lines changed

2 files changed

+82
-4
lines changed

contrib/amcheck/t/006_verify_gin.pl

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
invalid_entry_order_leaf_page_test();
3535
invalid_entry_order_inner_page_test();
3636
invalid_entry_columns_order_test();
37+
inconsistent_with_parent_key__parent_key_corrupted_test();
38+
inconsistent_with_parent_key__child_key_corrupted_test();
3739

3840
sub invalid_entry_order_leaf_page_test
3941
{
@@ -159,6 +161,82 @@ sub invalid_entry_columns_order_test
159161
like($stderr, qr/$expected/);
160162
}
161163

164+
sub inconsistent_with_parent_key__parent_key_corrupted_test
165+
{
166+
my $relname = "test";
167+
my $indexname = "test_gin_idx";
168+
169+
# fill the table until we have a split
170+
$node->safe_psql(
171+
'postgres', qq(
172+
DROP TABLE IF EXISTS $relname;
173+
CREATE TABLE $relname (a text[]);
174+
INSERT INTO $relname (a) VALUES (('{' || 'llllllllll' || random_string($filler_size) ||'}')::text[]);
175+
INSERT INTO $relname (a) VALUES (('{' || 'mmmmmmmmmm' || random_string($filler_size) ||'}')::text[]);
176+
INSERT INTO $relname (a) VALUES (('{' || 'nnnnnnnnnn' || random_string($filler_size) ||'}')::text[]);
177+
INSERT INTO $relname (a) VALUES (('{' || 'xxxxxxxxxx' || random_string($filler_size) ||'}')::text[]);
178+
INSERT INTO $relname (a) VALUES (('{' || 'yyyyyyyyyy' || random_string($filler_size) ||'}')::text[]);
179+
CREATE INDEX $indexname ON $relname USING gin (a);
180+
));
181+
my $relpath = relation_filepath($indexname);
182+
183+
$node->stop;
184+
185+
my $blkno = 1; # root
186+
187+
# we have nnnnnnnnnn... as parent key in the root, so replace it with something smaller then child's keys
188+
string_replace_block(
189+
$relpath,
190+
'nnnnnnnnnn',
191+
'aaaaaaaaaa',
192+
$blkno
193+
);
194+
195+
$node->start;
196+
197+
my ($result, $stdout, $stderr) = $node->psql('postgres', qq(SELECT gin_index_check('$indexname')));
198+
my $expected = "index \"$indexname\" has inconsistent records on page 3 offset 3";
199+
like($stderr, qr/$expected/);
200+
}
201+
202+
sub inconsistent_with_parent_key__child_key_corrupted_test
203+
{
204+
my $relname = "test";
205+
my $indexname = "test_gin_idx";
206+
207+
# fill the table until we have a split
208+
$node->safe_psql(
209+
'postgres', qq(
210+
DROP TABLE IF EXISTS $relname;
211+
CREATE TABLE $relname (a text[]);
212+
INSERT INTO $relname (a) VALUES (('{' || 'llllllllll' || random_string($filler_size) ||'}')::text[]);
213+
INSERT INTO $relname (a) VALUES (('{' || 'mmmmmmmmmm' || random_string($filler_size) ||'}')::text[]);
214+
INSERT INTO $relname (a) VALUES (('{' || 'nnnnnnnnnn' || random_string($filler_size) ||'}')::text[]);
215+
INSERT INTO $relname (a) VALUES (('{' || 'xxxxxxxxxx' || random_string($filler_size) ||'}')::text[]);
216+
INSERT INTO $relname (a) VALUES (('{' || 'yyyyyyyyyy' || random_string($filler_size) ||'}')::text[]);
217+
CREATE INDEX $indexname ON $relname USING gin (a);
218+
));
219+
my $relpath = relation_filepath($indexname);
220+
221+
$node->stop;
222+
223+
my $blkno = 3; # leaf
224+
225+
# we have nnnnnnnnnn... as parent key in the root, so replace child key with something bigger
226+
string_replace_block(
227+
$relpath,
228+
'nnnnnnnnnn',
229+
'pppppppppp',
230+
$blkno
231+
);
232+
233+
$node->start;
234+
235+
my ($result, $stdout, $stderr) = $node->psql('postgres', qq(SELECT gin_index_check('$indexname')));
236+
my $expected = "index \"$indexname\" has inconsistent records on page 3 offset 3";
237+
like($stderr, qr/$expected/);
238+
}
239+
162240
# Returns the filesystem path for the named relation.
163241
sub relation_filepath
164242
{

contrib/amcheck/verify_gin.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -608,10 +608,10 @@ gin_check_parent_keys_consistency(Relation rel,
608608
ptr = (GinScanItem *) palloc(sizeof(GinScanItem));
609609
ptr->depth = stack->depth + 1;
610610
/* last tuple in layer has no high key */
611-
if (i != maxoff && !GinPageGetOpaque(page)->rightlink)
612-
ptr->parenttup = CopyIndexTuple(idxtuple);
613-
else
611+
if (i == maxoff && rightlink == InvalidBlockNumber)
614612
ptr->parenttup = NULL;
613+
else
614+
ptr->parenttup = CopyIndexTuple(idxtuple);
615615
ptr->parentblk = stack->blkno;
616616
ptr->blkno = GinGetDownlink(idxtuple);
617617
ptr->next = stack->next;
@@ -748,7 +748,7 @@ gin_refind_parent(Relation rel, BlockNumber parentblkno,
748748
ItemId p_iid = PageGetItemIdCareful(rel, parentblkno, parentpage, o);
749749
IndexTuple itup = (IndexTuple) PageGetItem(parentpage, p_iid);
750750

751-
if (ItemPointerGetBlockNumber(&(itup->t_tid)) == childblkno)
751+
if (GinGetDownlink(itup) == childblkno)
752752
{
753753
/* Found it! Make copy and return it */
754754
result = CopyIndexTuple(itup);

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/postgres/postgres/commit/cdd1a431f21dbd2b7b675a9db1c24b97d713f38b

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy