Skip to content

Commit 15991ce

Browse files
manaldushdf7cb
authored andcommitted
Show GIN block details
Close #35.
1 parent 55a303e commit 15991ce

File tree

2 files changed

+220
-29
lines changed

2 files changed

+220
-29
lines changed

pg_filedump.c

Lines changed: 199 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* formatting heap (data), index and control files.
44
*
55
* Copyright (c) 2002-2010 Red Hat, Inc.
6-
* Copyright (c) 2011-2024, PostgreSQL Global Development Group
6+
* Copyright (c) 2011-2025, PostgreSQL Global Development Group
77
*
88
* This program is free software; you can redistribute it and/or modify
99
* it under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@
3333
#include "storage/checksum.h"
3434
#include "storage/checksum_impl.h"
3535
#include "decode.h"
36+
#include <inttypes.h>
3637

3738
/*
3839
* Global variables for ease of use mostly
@@ -149,6 +150,13 @@ static void FormatBinary(char *buffer,
149150
unsigned int numBytes, unsigned int startIndex);
150151
static void DumpBinaryBlock(char *buffer);
151152
static int PrintRelMappings(void);
153+
static ItemPointer ginPostingListDecodeAllSegmentsItems(
154+
GinPostingList *segment,
155+
int len,
156+
int *ndecoded_out);
157+
static ItemPointer ginReadTupleItems(
158+
IndexTuple itup,
159+
int *nitems);
152160

153161

154162
/* Send properly formed usage information to the user. */
@@ -825,22 +833,6 @@ IsGinMetaPage(Page page)
825833
return false;
826834
}
827835

828-
/* Check whether page is a gin leaf page */
829-
static bool
830-
IsGinLeafPage(Page page)
831-
{
832-
if ((PageGetSpecialSize(page) == (MAXALIGN(sizeof(GinPageOpaqueData))))
833-
&& (bytesToFormat == blockSize))
834-
{
835-
GinPageOpaque gpo = GinPageGetOpaque(page);
836-
837-
if (gpo->flags & GIN_LEAF)
838-
return true;
839-
}
840-
841-
return false;
842-
}
843-
844836
/* Check whether page is a SpGist meta page */
845837
static bool
846838
IsSpGistMetaPage(Page page)
@@ -976,6 +968,24 @@ FormatHeader(char *buffer, Page page, BlockNumber blkno, bool isToast)
976968
}
977969
headerBytes += sizeof(BTMetaPageData);
978970
}
971+
else if (IsGinMetaPage(page))
972+
{
973+
GinMetaPageData *gpMeta = GinPageGetMeta(buffer);
974+
if (!isToast || verbose)
975+
{
976+
printf("%s GIN Meta Data: Version (%u)\n",
977+
indent, gpMeta->ginVersion);
978+
printf("%s Pending list: Head: (%u) Tail: (%u) Tail Free Size: (%u)\n",
979+
indent, gpMeta->head, gpMeta->tail, gpMeta->tailFreeSize);
980+
printf("%s Num of Pending Pages: (%u) Num of Pending Heap Tuples: (%" PRIu64 ")\n",
981+
indent, gpMeta->nPendingPages, gpMeta->nPendingHeapTuples);
982+
printf("%s Statistic for planner: Num of Total Pages: (%u) Num of Entry Pages: (%u)\n",
983+
indent, gpMeta->nTotalPages, gpMeta->nEntryPages);
984+
printf("%s Num of Data Pages: (%u) Num of Entries: (%" PRIu64 ")\n\n",
985+
indent, gpMeta->nDataPages, gpMeta->nEntries);
986+
}
987+
headerBytes += sizeof(GinMetaPageData);
988+
}
979989

980990
/* Eye the contents of the header and alert the user to possible
981991
* problems. */
@@ -1107,6 +1117,88 @@ decode_varbyte(unsigned char **ptr)
11071117
return val;
11081118
}
11091119

1120+
static ItemPointer
1121+
ginPostingListDecodeAllSegmentsItems(GinPostingList *segment, int len, int *ndecoded_out)
1122+
{
1123+
ItemPointer result;
1124+
int nallocated;
1125+
uint64 val;
1126+
char *endseg = ((char *) segment) + len;
1127+
int ndecoded;
1128+
unsigned char *ptr;
1129+
unsigned char *endptr;
1130+
1131+
/*
1132+
* Guess an initial size of the array.
1133+
*/
1134+
nallocated = segment->nbytes * 2 + 1;
1135+
result = palloc(nallocated * sizeof(ItemPointerData));
1136+
1137+
ndecoded = 0;
1138+
while ((char *) segment < endseg)
1139+
{
1140+
/* enlarge output array if needed */
1141+
if (ndecoded >= nallocated)
1142+
{
1143+
nallocated *= 2;
1144+
result = repalloc(result, nallocated * sizeof(ItemPointerData));
1145+
}
1146+
1147+
/* copy the first item */
1148+
result[ndecoded] = segment->first;
1149+
ndecoded++;
1150+
1151+
val = itemptr_to_uint64(&segment->first);
1152+
ptr = segment->bytes;
1153+
endptr = segment->bytes + segment->nbytes;
1154+
while (ptr < endptr)
1155+
{
1156+
/* enlarge output array if needed */
1157+
if (ndecoded >= nallocated)
1158+
{
1159+
nallocated *= 2;
1160+
result = repalloc(result, nallocated * sizeof(ItemPointerData));
1161+
}
1162+
1163+
val += decode_varbyte(&ptr);
1164+
1165+
uint64_to_itemptr(val, &result[ndecoded]);
1166+
ndecoded++;
1167+
}
1168+
segment = GinNextPostingListSegment(segment);
1169+
}
1170+
1171+
if (ndecoded_out)
1172+
*ndecoded_out = ndecoded;
1173+
return result;
1174+
}
1175+
1176+
static ItemPointer
1177+
ginReadTupleItems(IndexTuple itup, int *nitems)
1178+
{
1179+
Pointer ptr = GinGetPosting(itup);
1180+
int nipd = GinGetNPosting(itup);
1181+
ItemPointer ipd;
1182+
if (GinItupIsCompressed(itup))
1183+
{
1184+
if (nipd > 0)
1185+
{
1186+
ipd = ginPostingListDecodeAllSegmentsItems((GinPostingList *)ptr, SizeOfGinPostingList((GinPostingList *)ptr), nitems);
1187+
}
1188+
else
1189+
{
1190+
ipd = palloc(0);
1191+
}
1192+
}
1193+
else
1194+
{
1195+
ipd = (ItemPointer) palloc(sizeof(ItemPointerData) * nipd);
1196+
memcpy(ipd, ptr, sizeof(ItemPointerData) * nipd);
1197+
}
1198+
*nitems = nipd;
1199+
return ipd;
1200+
}
1201+
11101202
/* Dump out gin-specific content of block */
11111203
static void
11121204
FormatGinBlock(char *buffer,
@@ -1122,18 +1214,24 @@ FormatGinBlock(char *buffer,
11221214
if (isToast && !verbose)
11231215
return;
11241216

1217+
if (GinPageIsDeleted(page))
1218+
{
1219+
printf("%s Deleted page.\n\n", indent);
1220+
return;
1221+
}
1222+
11251223
printf("%s<Data> -----\n", indent);
11261224

1127-
if (IsGinLeafPage(page))
1225+
if (GinPageIsData(page) && GinPageIsLeaf(page))
11281226
{
1227+
printf("\n%s Leaf Page of TID B-tree\n",indent);
11291228
if (GinPageIsCompressed(page))
11301229
{
11311230
GinPostingList *seg = GinDataLeafPageGetPostingList(page);
11321231
int plist_idx = 1;
11331232
Size len = GinDataLeafPageGetPostingListSize(page);
11341233
Pointer endptr = ((Pointer) seg) + len;
11351234
ItemPointer cur;
1136-
11371235
while ((Pointer) seg < endptr)
11381236
{
11391237
int item_idx = 1;
@@ -1186,24 +1284,98 @@ FormatGinBlock(char *buffer,
11861284
}
11871285
}
11881286
}
1189-
else
1287+
else if (!GinPageIsData(page) && GinPageIsLeaf(page))
1288+
{
1289+
printf("\n%s Leaf Page of Element B-tree", indent);
1290+
for (int offset = FirstOffsetNumber; offset <= PageGetMaxOffsetNumber(page); offset++)
1291+
{
1292+
IndexTuple itup;
1293+
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offset));
1294+
if (!GinIsPostingTree(itup))
1295+
{
1296+
int nitems;
1297+
ItemPointer items = ginReadTupleItems(itup, &nitems);
1298+
printf("\n%s Posting List %3d -- Length: %4u -- isCompressed: %d\n",
1299+
indent, offset, nitems, GinItupIsCompressed(itup));
1300+
for (int i = 0; i < nitems; i++)
1301+
{
1302+
printf("%s ItemPointer %d -- Block Id: %u linp Index: %u\n",
1303+
indent, i + 1,
1304+
((uint32) ((items[i].ip_blkid.bi_hi << 16) |
1305+
(uint16) items[i].ip_blkid.bi_lo)),
1306+
items[i].ip_posid);
1307+
}
1308+
pfree(items);
1309+
} else
1310+
{
1311+
BlockNumber rootPostingTree = GinGetPostingTree(itup);
1312+
printf("\n%s Root posting tree -- Block Id: %u\n",
1313+
indent, rootPostingTree);
1314+
}
1315+
}
1316+
}
1317+
else if (!GinPageIsLeaf(page) && GinPageIsData(page))
11901318
{
11911319
OffsetNumber cur,
1192-
high = GinPageGetOpaque(page)->maxoff;
1320+
high = GinPageGetOpaque(page)->maxoff; /* number of PostingItems on GIN_DATA & ~GIN_LEAF page.*/
11931321
PostingItem *pitem = NULL;
11941322

1323+
ItemPointer rightBound = GinDataPageGetRightBound(page);
1324+
1325+
printf("%s Internal Page of TID B-tree -- Block Id: %u linp Index: %u\n",
1326+
indent,
1327+
((uint32) ((rightBound->ip_blkid.bi_hi << 16) |
1328+
(uint16) rightBound->ip_blkid.bi_lo)),
1329+
rightBound->ip_posid);
11951330
for (cur = FirstOffsetNumber; cur <= high; cur = OffsetNumberNext(cur))
11961331
{
11971332
pitem = GinDataPageGetPostingItem(page, cur);
1198-
printf("%s PostingItem %d -- child Block Id: (%u) Block Id: %u linp Index: %u\n",
1333+
printf("%s PostingItem %d -- child Block Id: (%u) Key Block Id: %u Key linp Index: %u\n",
11991334
indent, cur,
1200-
((uint32) ((pitem->child_blkno.bi_hi << 16) |
1201-
(uint16) pitem->child_blkno.bi_lo)),
1202-
((uint32) ((pitem->key.ip_blkid.bi_hi << 16) |
1203-
(uint16) pitem->key.ip_blkid.bi_lo)),
1204-
pitem->key.ip_posid);
1335+
((uint32) ((pitem->child_blkno.bi_hi << 16) |
1336+
(uint16) pitem->child_blkno.bi_lo)),
1337+
((uint32) ((pitem->key.ip_blkid.bi_hi << 16) |
1338+
(uint16) pitem->key.ip_blkid.bi_lo)),
1339+
pitem->key.ip_posid);
1340+
}
1341+
}
1342+
else if (GinPageIsList(page))
1343+
{
1344+
printf("\n%s Pending List Page -- Length: %4u\n", indent, GinPageGetOpaque(page)->maxoff);
1345+
//Fast list index page, not compressed
1346+
for (OffsetNumber offset = FirstOffsetNumber; offset <= GinPageGetOpaque(page)->maxoff; offset = OffsetNumberNext(offset))
1347+
{
1348+
IndexTuple itup;
1349+
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offset));
1350+
printf("%s ItemPointer -- Block Id: %u linp Index: %u\n",
1351+
indent,
1352+
((uint32) ((itup->t_tid.ip_blkid.bi_hi << 16) |
1353+
(uint16) itup->t_tid.ip_blkid.bi_lo)),
1354+
itup->t_tid.ip_posid);
1355+
}
1356+
}
1357+
else if (GinPageGetOpaque(page)->flags == 0)
1358+
{
1359+
/*details postgrespro/src/backend/access/gin/ginentrypage::GinFormInteriorTuple,
1360+
*the specified child block number is inserted into t_tid.
1361+
*/
1362+
printf("\n%s Internal Page of Element B-tree \n", indent);
1363+
for (OffsetNumber offset = FirstOffsetNumber; offset <= PageGetMaxOffsetNumber(page); offset = OffsetNumberNext(offset))
1364+
{
1365+
IndexTuple itup;
1366+
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offset));
1367+
printf("%s ItemPointer -- Block Id: %u linp Index: %u\n",
1368+
indent,
1369+
((uint32) ((itup->t_tid.ip_blkid.bi_hi << 16) |
1370+
(uint16) itup->t_tid.ip_blkid.bi_lo)),
1371+
itup->t_tid.ip_posid);
12051372
}
12061373
}
1374+
else
1375+
{
1376+
printf("%s Error: Unknown page type.\n", indent);
1377+
exitCode = 1;
1378+
}
12071379

12081380
printf("\n");
12091381
}

t/001_basic.pl

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
$node->start;
1919

2020
my $query = qq(
21+
drop table if exists t1;
22+
checkpoint;
2123
create table t1(a int, b text, c bigint, filler char(400));
2224
insert into t1 values (1, 'asdasd1', 29347293874234444);
2325
insert into t1 values (2, 'asdasd2', 29347293874234445);
@@ -29,6 +31,12 @@
2931

3032
note "running tests";
3133

34+
sub setup_test
35+
{
36+
# for test isolation purposes
37+
$node->safe_psql('postgres', $query);
38+
}
39+
3240
test_basic_output();
3341
test_btree_output();
3442
test_spgist_output();
@@ -62,6 +70,7 @@ sub run_pg_filedump
6270

6371
sub test_basic_output
6472
{
73+
setup_test();
6574
my $out_ = run_pg_filedump('t1', ("-D", "int,text,bigint"));
6675

6776
ok($out_ =~ qr/Header/, "Header found");
@@ -75,6 +84,7 @@ sub test_basic_output
7584

7685
sub test_btree_output
7786
{
87+
setup_test();
7888
my $query = qq(
7989
insert into t1 select * FROM generate_series(1, 10000);
8090
create index i1 on t1(b);
@@ -104,6 +114,7 @@ sub test_btree_output
104114

105115
sub test_spgist_output
106116
{
117+
setup_test();
107118
$node->safe_psql('postgres', "create index i2 on t1 using spgist(b); checkpoint;");
108119

109120
my $out_ = run_pg_filedump('i2');
@@ -115,6 +126,7 @@ sub test_spgist_output
115126

116127
sub test_gin_output
117128
{
129+
setup_test();
118130
my $query = qq(
119131
create extension btree_gin;
120132
create index i3 on t1 using gin(b);
@@ -124,7 +136,14 @@ sub test_gin_output
124136

125137
my $out_ = run_pg_filedump('i3');
126138

127-
ok($out_ =~ qr/Header/, "Header found");
139+
ok($out_ =~ qr/GIN Meta Data/, "Metadata found");
140+
ok($out_ =~ qr/Leaf Page of Element B-tree/, "Leaf Page of Element B-tree found");
141+
ok($out_ =~ qr/Posting List 1/, "Posting List 1 found");
142+
ok($out_ =~ qr/ItemPointer 1/, "ItemPointer 1 found");
143+
ok($out_ =~ qr/ItemPointer 2/, "ItemPointer 2 found");
144+
ok($out_ =~ qr/Posting List 2/, "Posting List 2 found");
145+
ok($out_ =~ qr/ItemPointer 1/, "ItemPointer 3 found");
146+
ok($out_ =~ qr/Posting List 3/, "Posting List 3 found");
147+
ok($out_ =~ qr/ItemPointer 1/, "ItemPointer 4 found");
128148
ok($out_ =~ qr/GIN Index Section/, "GIN Index Section found");
129-
ok($out_ =~ qr/ItemPointer 3/, "Item found");
130149
}

0 commit comments

Comments
 (0)