@ -168,9 +168,12 @@ brinSetHeapBlockItemptr(Buffer buf, BlockNumber pagesPerRange,
iptr = ( ItemPointerData * ) contents - > rm_tids ;
iptr + = HEAPBLK_TO_REVMAP_INDEX ( pagesPerRange , heapBlk ) ;
ItemPointerSet ( iptr ,
ItemPointerGetBlockNumber ( & tid ) ,
ItemPointerGetOffsetNumber ( & tid ) ) ;
if ( ItemPointerIsValid ( & tid ) )
ItemPointerSet ( iptr ,
ItemPointerGetBlockNumber ( & tid ) ,
ItemPointerGetOffsetNumber ( & tid ) ) ;
else
ItemPointerSetInvalid ( iptr ) ;
}
/*
@ -304,6 +307,137 @@ brinGetTupleForHeapBlock(BrinRevmap *revmap, BlockNumber heapBlk,
return NULL ;
}
/*
* Delete an index tuple , marking a page range as unsummarized .
*
* Index must be locked in ShareUpdateExclusiveLock mode .
*
* Return FALSE if caller should retry .
*/
bool
brinRevmapDesummarizeRange ( Relation idxrel , BlockNumber heapBlk )
{
BrinRevmap * revmap ;
BlockNumber pagesPerRange ;
RevmapContents * contents ;
ItemPointerData * iptr ;
ItemPointerData invalidIptr ;
BlockNumber revmapBlk ;
Buffer revmapBuf ;
Buffer regBuf ;
Page revmapPg ;
Page regPg ;
OffsetNumber revmapOffset ;
OffsetNumber regOffset ;
ItemId lp ;
BrinTuple * tup ;
revmap = brinRevmapInitialize ( idxrel , & pagesPerRange , NULL ) ;
revmapBlk = revmap_get_blkno ( revmap , heapBlk ) ;
if ( ! BlockNumberIsValid ( revmapBlk ) )
{
/* revmap page doesn't exist: range not summarized, we're done */
brinRevmapTerminate ( revmap ) ;
return true ;
}
/* Lock the revmap page, obtain the index tuple pointer from it */
revmapBuf = brinLockRevmapPageForUpdate ( revmap , heapBlk ) ;
revmapPg = BufferGetPage ( revmapBuf ) ;
revmapOffset = HEAPBLK_TO_REVMAP_INDEX ( revmap - > rm_pagesPerRange , heapBlk ) ;
contents = ( RevmapContents * ) PageGetContents ( revmapPg ) ;
iptr = contents - > rm_tids ;
iptr + = revmapOffset ;
if ( ! ItemPointerIsValid ( iptr ) )
{
/* no index tuple: range not summarized, we're done */
LockBuffer ( revmapBuf , BUFFER_LOCK_UNLOCK ) ;
brinRevmapTerminate ( revmap ) ;
return true ;
}
regBuf = ReadBuffer ( idxrel , ItemPointerGetBlockNumber ( iptr ) ) ;
LockBuffer ( regBuf , BUFFER_LOCK_EXCLUSIVE ) ;
regPg = BufferGetPage ( regBuf ) ;
/* if this is no longer a regular page, tell caller to start over */
if ( ! BRIN_IS_REGULAR_PAGE ( regPg ) )
{
LockBuffer ( revmapBuf , BUFFER_LOCK_UNLOCK ) ;
LockBuffer ( regBuf , BUFFER_LOCK_UNLOCK ) ;
brinRevmapTerminate ( revmap ) ;
return false ;
}
regOffset = ItemPointerGetOffsetNumber ( iptr ) ;
if ( regOffset > PageGetMaxOffsetNumber ( regPg ) )
ereport ( ERROR ,
( errcode ( ERRCODE_INDEX_CORRUPTED ) ,
errmsg ( " corrupted BRIN index: inconsistent range map " ) ) ) ;
lp = PageGetItemId ( regPg , regOffset ) ;
if ( ! ItemIdIsUsed ( lp ) )
ereport ( ERROR ,
( errcode ( ERRCODE_INDEX_CORRUPTED ) ,
errmsg ( " corrupted BRIN index: inconsistent range map " ) ) ) ;
tup = ( BrinTuple * ) PageGetItem ( regPg , lp ) ;
/* XXX apply sanity checks? Might as well delete a bogus tuple ... */
/*
* We ' re only removing data , not reading it , so there ' s no need to
* TestForOldSnapshot here .
*/
/*
* Because of SUE lock , this function shouldn ' t run concurrently with
* summarization . Placeholder tuples can only exist as leftovers from
* crashed summarization , so if we detect any , we complain but proceed .
*/
if ( BrinTupleIsPlaceholder ( tup ) )
ereport ( WARNING ,
( errmsg ( " leftover placeholder tuple detected in BRIN index \" %s \" , deleting " ,
RelationGetRelationName ( idxrel ) ) ) ) ;
START_CRIT_SECTION ( ) ;
ItemPointerSetInvalid ( & invalidIptr ) ;
brinSetHeapBlockItemptr ( revmapBuf , revmap - > rm_pagesPerRange , heapBlk ,
invalidIptr ) ;
PageIndexTupleDeleteNoCompact ( regPg , regOffset ) ;
/* XXX record free space in FSM? */
MarkBufferDirty ( regBuf ) ;
MarkBufferDirty ( revmapBuf ) ;
if ( RelationNeedsWAL ( idxrel ) )
{
xl_brin_desummarize xlrec ;
XLogRecPtr recptr ;
xlrec . heapBlk = heapBlk ;
xlrec . regOffset = regOffset ;
XLogBeginInsert ( ) ;
XLogRegisterData ( ( char * ) & xlrec , SizeOfBrinDesummarize ) ;
XLogRegisterBuffer ( 0 , revmapBuf , 0 ) ;
XLogRegisterBuffer ( 1 , regBuf , REGBUF_STANDARD ) ;
recptr = XLogInsert ( RM_BRIN_ID , XLOG_BRIN_DESUMMARIZE ) ;
PageSetLSN ( revmapPg , recptr ) ;
PageSetLSN ( regPg , recptr ) ;
}
END_CRIT_SECTION ( ) ;
UnlockReleaseBuffer ( regBuf ) ;
LockBuffer ( revmapBuf , BUFFER_LOCK_UNLOCK ) ;
brinRevmapTerminate ( revmap ) ;
return true ;
}
/*
* Given a heap block number , find the corresponding physical revmap block
* number and return it . If the revmap page hasn ' t been allocated yet , return