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

Commitc655899

Browse files
committed
BRIN de-summarization
When the BRIN summary tuple for a page range becomes too "wide" for thevalues actually stored in the table (because the tuples that werepresent originally are no longer present due to updates or deletes), itcan be useful to remove the outdated summary tuple, so that a futuresummarization can install a tighter summary.This commit introduces a SQL-callable interface to do so.Author: Álvaro HerreraReviewed-by: Eiji SekiDiscussion:https://postgr.es/m/20170228045643.n2ri74ara4fhhfxf@alvherre.pgsql
1 parent3a82129 commitc655899

File tree

12 files changed

+340
-5
lines changed

12 files changed

+340
-5
lines changed

‎doc/src/sgml/brin.sgml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@
8080
or by automatic summarization executed by autovacuum, as insertions
8181
occur. (This last trigger is disabled by default and can be enabled
8282
with the <literal>autosummarize</literal> parameter.)
83+
Conversely, a range can be de-summarized using the
84+
<function>brin_desummarize_range(regclass, bigint)</function> range,
85+
which is useful when the index tuple is no longer a very good
86+
representation because the existing values have changed.
8387
</para>
8488

8589
</sect2>

‎doc/src/sgml/func.sgml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19660,6 +19660,14 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
1966019660
<primary>gin_clean_pending_list</primary>
1966119661
</indexterm>
1966219662

19663+
<indexterm>
19664+
<primary>brin_summarize_range</primary>
19665+
</indexterm>
19666+
19667+
<indexterm>
19668+
<primary>brin_desummarize_range</primary>
19669+
</indexterm>
19670+
1966319671
<para>
1966419672
<xref linkend="functions-admin-index-table"> shows the functions
1966519673
available for index maintenance tasks.
@@ -19690,6 +19698,13 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
1969019698
<entry><type>integer</type></entry>
1969119699
<entry>summarize the page range covering the given block, if not already summarized</entry>
1969219700
</row>
19701+
<row>
19702+
<entry>
19703+
<literal><function>brin_desummarize_range(<parameter>index</> <type>regclass</>, <parameter>blockNumber</> <type>bigint</type>)</function></literal>
19704+
</entry>
19705+
<entry><type>integer</type></entry>
19706+
<entry>de-summarize the page range covering the given block, if summarized</entry>
19707+
</row>
1969319708
<row>
1969419709
<entry>
1969519710
<literal><function>gin_clean_pending_list(<parameter>index</> <type>regclass</>)</function></literal>

‎src/backend/access/brin/brin.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,80 @@ brin_summarize_range(PG_FUNCTION_ARGS)
908908
PG_RETURN_INT32((int32)numSummarized);
909909
}
910910

911+
/*
912+
* SQL-callable interface to mark a range as no longer summarized
913+
*/
914+
Datum
915+
brin_desummarize_range(PG_FUNCTION_ARGS)
916+
{
917+
Oidindexoid=PG_GETARG_OID(0);
918+
int64heapBlk64=PG_GETARG_INT64(1);
919+
BlockNumberheapBlk;
920+
Oidheapoid;
921+
RelationheapRel;
922+
RelationindexRel;
923+
booldone;
924+
925+
if (heapBlk64>MaxBlockNumber||heapBlk64<0)
926+
{
927+
char*blk=psprintf(INT64_FORMAT,heapBlk64);
928+
929+
ereport(ERROR,
930+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
931+
errmsg("block number out of range: %s",blk)));
932+
}
933+
heapBlk= (BlockNumber)heapBlk64;
934+
935+
/*
936+
* We must lock table before index to avoid deadlocks. However, if the
937+
* passed indexoid isn't an index then IndexGetRelation() will fail.
938+
* Rather than emitting a not-very-helpful error message, postpone
939+
* complaining, expecting that the is-it-an-index test below will fail.
940+
*/
941+
heapoid=IndexGetRelation(indexoid, true);
942+
if (OidIsValid(heapoid))
943+
heapRel=heap_open(heapoid,ShareUpdateExclusiveLock);
944+
else
945+
heapRel=NULL;
946+
947+
indexRel=index_open(indexoid,ShareUpdateExclusiveLock);
948+
949+
/* Must be a BRIN index */
950+
if (indexRel->rd_rel->relkind!=RELKIND_INDEX||
951+
indexRel->rd_rel->relam!=BRIN_AM_OID)
952+
ereport(ERROR,
953+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
954+
errmsg("\"%s\" is not a BRIN index",
955+
RelationGetRelationName(indexRel))));
956+
957+
/* User must own the index (comparable to privileges needed for VACUUM) */
958+
if (!pg_class_ownercheck(indexoid,GetUserId()))
959+
aclcheck_error(ACLCHECK_NOT_OWNER,ACL_KIND_CLASS,
960+
RelationGetRelationName(indexRel));
961+
962+
/*
963+
* Since we did the IndexGetRelation call above without any lock, it's
964+
* barely possible that a race against an index drop/recreation could have
965+
* netted us the wrong table. Recheck.
966+
*/
967+
if (heapRel==NULL||heapoid!=IndexGetRelation(indexoid, false))
968+
ereport(ERROR,
969+
(errcode(ERRCODE_UNDEFINED_TABLE),
970+
errmsg("could not open parent table of index %s",
971+
RelationGetRelationName(indexRel))));
972+
973+
/* the revmap does the hard work */
974+
do {
975+
done=brinRevmapDesummarizeRange(indexRel,heapBlk);
976+
}
977+
while (!done);
978+
979+
relation_close(indexRel,ShareUpdateExclusiveLock);
980+
relation_close(heapRel,ShareUpdateExclusiveLock);
981+
982+
PG_RETURN_VOID();
983+
}
984+
911985
/*
912986
* Build a BrinDesc used to create or scan a BRIN index
913987
*/

‎src/backend/access/brin/brin_revmap.c

Lines changed: 137 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,12 @@ brinSetHeapBlockItemptr(Buffer buf, BlockNumber pagesPerRange,
168168
iptr= (ItemPointerData*)contents->rm_tids;
169169
iptr+=HEAPBLK_TO_REVMAP_INDEX(pagesPerRange,heapBlk);
170170

171-
ItemPointerSet(iptr,
172-
ItemPointerGetBlockNumber(&tid),
173-
ItemPointerGetOffsetNumber(&tid));
171+
if (ItemPointerIsValid(&tid))
172+
ItemPointerSet(iptr,
173+
ItemPointerGetBlockNumber(&tid),
174+
ItemPointerGetOffsetNumber(&tid));
175+
else
176+
ItemPointerSetInvalid(iptr);
174177
}
175178

176179
/*
@@ -304,6 +307,137 @@ brinGetTupleForHeapBlock(BrinRevmap *revmap, BlockNumber heapBlk,
304307
returnNULL;
305308
}
306309

310+
/*
311+
* Delete an index tuple, marking a page range as unsummarized.
312+
*
313+
* Index must be locked in ShareUpdateExclusiveLock mode.
314+
*
315+
* Return FALSE if caller should retry.
316+
*/
317+
bool
318+
brinRevmapDesummarizeRange(Relationidxrel,BlockNumberheapBlk)
319+
{
320+
BrinRevmap*revmap;
321+
BlockNumberpagesPerRange;
322+
RevmapContents*contents;
323+
ItemPointerData*iptr;
324+
ItemPointerDatainvalidIptr;
325+
BlockNumberrevmapBlk;
326+
BufferrevmapBuf;
327+
BufferregBuf;
328+
PagerevmapPg;
329+
PageregPg;
330+
OffsetNumberrevmapOffset;
331+
OffsetNumberregOffset;
332+
ItemIdlp;
333+
BrinTuple*tup;
334+
335+
revmap=brinRevmapInitialize(idxrel,&pagesPerRange,NULL);
336+
337+
revmapBlk=revmap_get_blkno(revmap,heapBlk);
338+
if (!BlockNumberIsValid(revmapBlk))
339+
{
340+
/* revmap page doesn't exist: range not summarized, we're done */
341+
brinRevmapTerminate(revmap);
342+
return true;
343+
}
344+
345+
/* Lock the revmap page, obtain the index tuple pointer from it */
346+
revmapBuf=brinLockRevmapPageForUpdate(revmap,heapBlk);
347+
revmapPg=BufferGetPage(revmapBuf);
348+
revmapOffset=HEAPBLK_TO_REVMAP_INDEX(revmap->rm_pagesPerRange,heapBlk);
349+
350+
contents= (RevmapContents*)PageGetContents(revmapPg);
351+
iptr=contents->rm_tids;
352+
iptr+=revmapOffset;
353+
354+
if (!ItemPointerIsValid(iptr))
355+
{
356+
/* no index tuple: range not summarized, we're done */
357+
LockBuffer(revmapBuf,BUFFER_LOCK_UNLOCK);
358+
brinRevmapTerminate(revmap);
359+
return true;
360+
}
361+
362+
regBuf=ReadBuffer(idxrel,ItemPointerGetBlockNumber(iptr));
363+
LockBuffer(regBuf,BUFFER_LOCK_EXCLUSIVE);
364+
regPg=BufferGetPage(regBuf);
365+
366+
/* if this is no longer a regular page, tell caller to start over */
367+
if (!BRIN_IS_REGULAR_PAGE(regPg))
368+
{
369+
LockBuffer(revmapBuf,BUFFER_LOCK_UNLOCK);
370+
LockBuffer(regBuf,BUFFER_LOCK_UNLOCK);
371+
brinRevmapTerminate(revmap);
372+
return false;
373+
}
374+
375+
regOffset=ItemPointerGetOffsetNumber(iptr);
376+
if (regOffset>PageGetMaxOffsetNumber(regPg))
377+
ereport(ERROR,
378+
(errcode(ERRCODE_INDEX_CORRUPTED),
379+
errmsg("corrupted BRIN index: inconsistent range map")));
380+
381+
lp=PageGetItemId(regPg,regOffset);
382+
if (!ItemIdIsUsed(lp))
383+
ereport(ERROR,
384+
(errcode(ERRCODE_INDEX_CORRUPTED),
385+
errmsg("corrupted BRIN index: inconsistent range map")));
386+
tup= (BrinTuple*)PageGetItem(regPg,lp);
387+
/* XXX apply sanity checks? Might as well delete a bogus tuple ... */
388+
389+
/*
390+
* We're only removing data, not reading it, so there's no need to
391+
* TestForOldSnapshot here.
392+
*/
393+
394+
/*
395+
* Because of SUE lock, this function shouldn't run concurrently with
396+
* summarization. Placeholder tuples can only exist as leftovers from
397+
* crashed summarization, so if we detect any, we complain but proceed.
398+
*/
399+
if (BrinTupleIsPlaceholder(tup))
400+
ereport(WARNING,
401+
(errmsg("leftover placeholder tuple detected in BRIN index \"%s\", deleting",
402+
RelationGetRelationName(idxrel))));
403+
404+
START_CRIT_SECTION();
405+
406+
ItemPointerSetInvalid(&invalidIptr);
407+
brinSetHeapBlockItemptr(revmapBuf,revmap->rm_pagesPerRange,heapBlk,
408+
invalidIptr);
409+
PageIndexTupleDeleteNoCompact(regPg,regOffset);
410+
/* XXX record free space in FSM? */
411+
412+
MarkBufferDirty(regBuf);
413+
MarkBufferDirty(revmapBuf);
414+
415+
if (RelationNeedsWAL(idxrel))
416+
{
417+
xl_brin_desummarizexlrec;
418+
XLogRecPtrrecptr;
419+
420+
xlrec.heapBlk=heapBlk;
421+
xlrec.regOffset=regOffset;
422+
423+
XLogBeginInsert();
424+
XLogRegisterData((char*)&xlrec,SizeOfBrinDesummarize);
425+
XLogRegisterBuffer(0,revmapBuf,0);
426+
XLogRegisterBuffer(1,regBuf,REGBUF_STANDARD);
427+
recptr=XLogInsert(RM_BRIN_ID,XLOG_BRIN_DESUMMARIZE);
428+
PageSetLSN(revmapPg,recptr);
429+
PageSetLSN(regPg,recptr);
430+
}
431+
432+
END_CRIT_SECTION();
433+
434+
UnlockReleaseBuffer(regBuf);
435+
LockBuffer(revmapBuf,BUFFER_LOCK_UNLOCK);
436+
brinRevmapTerminate(revmap);
437+
438+
return true;
439+
}
440+
307441
/*
308442
* Given a heap block number, find the corresponding physical revmap block
309443
* number and return it. If the revmap page hasn't been allocated yet, return

‎src/backend/access/brin/brin_xlog.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,46 @@ brin_xlog_revmap_extend(XLogReaderState *record)
254254
UnlockReleaseBuffer(metabuf);
255255
}
256256

257+
staticvoid
258+
brin_xlog_desummarize_page(XLogReaderState*record)
259+
{
260+
XLogRecPtrlsn=record->EndRecPtr;
261+
xl_brin_desummarize*xlrec;
262+
Bufferbuffer;
263+
XLogRedoActionaction;
264+
265+
xlrec= (xl_brin_desummarize*)XLogRecGetData(record);
266+
267+
/* Update the revmap */
268+
action=XLogReadBufferForRedo(record,0,&buffer);
269+
if (action==BLK_NEEDS_REDO)
270+
{
271+
ItemPointerDataiptr;
272+
273+
ItemPointerSetInvalid(&iptr);
274+
brinSetHeapBlockItemptr(buffer,xlrec->pagesPerRange,xlrec->heapBlk,iptr);
275+
276+
PageSetLSN(BufferGetPage(buffer),lsn);
277+
MarkBufferDirty(buffer);
278+
}
279+
if (BufferIsValid(buffer))
280+
UnlockReleaseBuffer(buffer);
281+
282+
/* remove the leftover entry from the regular page */
283+
action=XLogReadBufferForRedo(record,1,&buffer);
284+
if (action==BLK_NEEDS_REDO)
285+
{
286+
PageregPg=BufferGetPage(buffer);
287+
288+
PageIndexTupleDeleteNoCompact(regPg,xlrec->regOffset);
289+
290+
PageSetLSN(regPg,lsn);
291+
MarkBufferDirty(buffer);
292+
}
293+
if (BufferIsValid(buffer))
294+
UnlockReleaseBuffer(buffer);
295+
}
296+
257297
void
258298
brin_redo(XLogReaderState*record)
259299
{
@@ -276,6 +316,9 @@ brin_redo(XLogReaderState *record)
276316
caseXLOG_BRIN_REVMAP_EXTEND:
277317
brin_xlog_revmap_extend(record);
278318
break;
319+
caseXLOG_BRIN_DESUMMARIZE:
320+
brin_xlog_desummarize_page(record);
321+
break;
279322
default:
280323
elog(PANIC,"brin_redo: unknown op code %u",info);
281324
}

‎src/backend/access/rmgrdesc/brindesc.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ brin_desc(StringInfo buf, XLogReaderState *record)
6161

6262
appendStringInfo(buf,"targetBlk %u",xlrec->targetBlk);
6363
}
64+
elseif (info==XLOG_BRIN_DESUMMARIZE)
65+
{
66+
xl_brin_desummarize*xlrec= (xl_brin_desummarize*)rec;
67+
68+
appendStringInfo(buf,"pagesPerRange %u, heapBlk %u, page offset %u",
69+
xlrec->pagesPerRange,xlrec->heapBlk,xlrec->regOffset);
70+
}
6471
}
6572

6673
constchar*
@@ -91,6 +98,9 @@ brin_identify(uint8 info)
9198
caseXLOG_BRIN_REVMAP_EXTEND:
9299
id="REVMAP_EXTEND";
93100
break;
101+
caseXLOG_BRIN_DESUMMARIZE:
102+
id="DESUMMARIZE";
103+
break;
94104
}
95105

96106
returnid;

‎src/include/access/brin_revmap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ extern void brinSetHeapBlockItemptr(Buffer rmbuf, BlockNumber pagesPerRange,
3636
externBrinTuple*brinGetTupleForHeapBlock(BrinRevmap*revmap,
3737
BlockNumberheapBlk,Buffer*buf,OffsetNumber*off,
3838
Size*size,intmode,Snapshotsnapshot);
39+
externboolbrinRevmapDesummarizeRange(Relationidxrel,BlockNumberheapBlk);
3940

4041
#endif/* BRIN_REVMAP_H */

‎src/include/access/brin_xlog.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
#defineXLOG_BRIN_UPDATE0x20
3434
#defineXLOG_BRIN_SAMEPAGE_UPDATE0x30
3535
#defineXLOG_BRIN_REVMAP_EXTEND0x40
36-
#defineXLOG_BRIN_REVMAP_VACUUM0x50
36+
#defineXLOG_BRIN_DESUMMARIZE0x50
3737

3838
#defineXLOG_BRIN_OPMASK0x70
3939
/*
@@ -124,6 +124,24 @@ typedef struct xl_brin_revmap_extend
124124
#defineSizeOfBrinRevmapExtend(offsetof(xl_brin_revmap_extend, targetBlk) + \
125125
sizeof(BlockNumber))
126126

127+
/*
128+
* This is what we need to know about a range de-summarization
129+
*
130+
* Backup block 0: revmap page
131+
* Backup block 1: regular page
132+
*/
133+
typedefstructxl_brin_desummarize
134+
{
135+
BlockNumberpagesPerRange;
136+
/* page number location to set to invalid */
137+
OffsetNumberheapBlk;
138+
/* offset of item to delete in regular index page */
139+
OffsetNumberregOffset;
140+
}xl_brin_desummarize;
141+
142+
#defineSizeOfBrinDesummarize(offsetof(xl_brin_desummarize, regOffset) + \
143+
sizeof(OffsetNumber))
144+
127145

128146
externvoidbrin_redo(XLogReaderState*record);
129147
externvoidbrin_desc(StringInfobuf,XLogReaderState*record);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp