@@ -168,9 +168,12 @@ brinSetHeapBlockItemptr(Buffer buf, BlockNumber pagesPerRange,
168
168
iptr = (ItemPointerData * ) contents -> rm_tids ;
169
169
iptr += HEAPBLK_TO_REVMAP_INDEX (pagesPerRange , heapBlk );
170
170
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 );
174
177
}
175
178
176
179
/*
@@ -304,6 +307,137 @@ brinGetTupleForHeapBlock(BrinRevmap *revmap, BlockNumber heapBlk,
304
307
return NULL ;
305
308
}
306
309
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 (Relation idxrel , BlockNumber heapBlk )
319
+ {
320
+ BrinRevmap * revmap ;
321
+ BlockNumber pagesPerRange ;
322
+ RevmapContents * contents ;
323
+ ItemPointerData * iptr ;
324
+ ItemPointerData invalidIptr ;
325
+ BlockNumber revmapBlk ;
326
+ Buffer revmapBuf ;
327
+ Buffer regBuf ;
328
+ Page revmapPg ;
329
+ Page regPg ;
330
+ OffsetNumber revmapOffset ;
331
+ OffsetNumber regOffset ;
332
+ ItemId lp ;
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_desummarize xlrec ;
418
+ XLogRecPtr recptr ;
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
+
307
441
/*
308
442
* Given a heap block number, find the corresponding physical revmap block
309
443
* number and return it. If the revmap page hasn't been allocated yet, return
0 commit comments