@@ -305,19 +305,42 @@ rumVacuumPostingTreeLeaves(RumVacuumState * gvs, OffsetNumber attnum,
305305/*
306306 * Delete a posting tree page.
307307 */
308- static void
309- rumDeletePage (RumVacuumState * gvs ,BlockNumber deleteBlkno ,BlockNumber leftBlkno ,
308+ static bool
309+ rumDeletePage (RumVacuumState * gvs ,BlockNumber deleteBlkno ,
310310BlockNumber parentBlkno ,OffsetNumber myoff ,bool isParentRoot )
311311{
312+ BlockNumber leftBlkno ,
313+ rightBlkno ;
312314Buffer dBuffer ;
313- Buffer lBuffer ;
315+ Buffer lBuffer ,
316+ rBuffer ;
314317Buffer pBuffer ;
315318Page lPage ,
316319dPage ,
320+ rPage ,
317321parentPage ;
318- BlockNumber rightlink ;
319322GenericXLogState * state ;
320323
324+ restart :
325+
326+ dBuffer = ReadBufferExtended (gvs -> index ,MAIN_FORKNUM ,deleteBlkno ,
327+ RBM_NORMAL ,gvs -> strategy );
328+
329+ LockBuffer (dBuffer ,RUM_EXCLUSIVE );
330+
331+ dPage = BufferGetPage (dBuffer );
332+ leftBlkno = RumPageGetOpaque (dPage )-> leftlink ;
333+ rightBlkno = RumPageGetOpaque (dPage )-> rightlink ;
334+
335+ /* do not remove left/right most pages */
336+ if (leftBlkno == InvalidBlockNumber || rightBlkno == InvalidBlockNumber )
337+ {
338+ UnlockReleaseBuffer (dBuffer );
339+ return false;
340+ }
341+
342+ LockBuffer (dBuffer ,RUM_UNLOCK );
343+
321344state = GenericXLogStart (gvs -> index );
322345
323346/*
@@ -326,23 +349,44 @@ rumDeletePage(RumVacuumState * gvs, BlockNumber deleteBlkno, BlockNumber leftBlk
326349 */
327350lBuffer = ReadBufferExtended (gvs -> index ,MAIN_FORKNUM ,leftBlkno ,
328351RBM_NORMAL ,gvs -> strategy );
329- dBuffer = ReadBufferExtended (gvs -> index ,MAIN_FORKNUM ,deleteBlkno ,
352+ rBuffer = ReadBufferExtended (gvs -> index ,MAIN_FORKNUM ,rightBlkno ,
330353RBM_NORMAL ,gvs -> strategy );
331354pBuffer = ReadBufferExtended (gvs -> index ,MAIN_FORKNUM ,parentBlkno ,
332355RBM_NORMAL ,gvs -> strategy );
333356
334357LockBuffer (lBuffer ,RUM_EXCLUSIVE );
335358LockBuffer (dBuffer ,RUM_EXCLUSIVE );
359+ LockBuffer (rBuffer ,RUM_EXCLUSIVE );
336360if (!isParentRoot )/* parent is already locked by
337361 * LockBufferForCleanup() */
338362LockBuffer (pBuffer ,RUM_EXCLUSIVE );
339363
340- /* Unlink the page by changing left sibling's rightlink */
341364dPage = GenericXLogRegisterBuffer (state ,dBuffer ,0 );
342- rightlink = RumPageGetOpaque (dPage )-> rightlink ;
343-
344365lPage = GenericXLogRegisterBuffer (state ,lBuffer ,0 );
345- RumPageGetOpaque (lPage )-> rightlink = rightlink ;
366+ rPage = GenericXLogRegisterBuffer (state ,rBuffer ,0 );
367+
368+ /*
369+ * last chance to check
370+ */
371+ if (!(RumPageGetOpaque (lPage )-> rightlink == deleteBlkno &&
372+ RumPageGetOpaque (rPage )-> leftlink == deleteBlkno &&
373+ RumPageGetOpaque (dPage )-> maxoff < FirstOffsetNumber ))
374+ {
375+ if (!isParentRoot )
376+ LockBuffer (pBuffer ,RUM_UNLOCK );
377+ ReleaseBuffer (pBuffer );
378+ UnlockReleaseBuffer (lBuffer );
379+ UnlockReleaseBuffer (dBuffer );
380+ UnlockReleaseBuffer (rBuffer );
381+
382+ if (RumPageGetOpaque (dPage )-> maxoff >=FirstOffsetNumber )
383+ return false;
384+
385+ gotorestart ;
386+ }
387+
388+ RumPageGetOpaque (lPage )-> rightlink = rightBlkno ;
389+ RumPageGetOpaque (rPage )-> leftlink = leftBlkno ;
346390
347391/* Delete downlink from parent */
348392parentPage = GenericXLogRegisterBuffer (state ,pBuffer ,0 );
@@ -357,7 +401,7 @@ rumDeletePage(RumVacuumState * gvs, BlockNumber deleteBlkno, BlockNumber leftBlk
357401RumPageDeletePostingItem (parentPage ,myoff );
358402
359403/*
360- * we shouldn't changerightlink field to save workability of running
404+ * we shouldn't changeleft/right link field to save workability of running
361405 * search scan
362406 */
363407RumPageGetOpaque (dPage )-> flags = RUM_DELETED ;
@@ -369,8 +413,11 @@ rumDeletePage(RumVacuumState * gvs, BlockNumber deleteBlkno, BlockNumber leftBlk
369413ReleaseBuffer (pBuffer );
370414UnlockReleaseBuffer (lBuffer );
371415UnlockReleaseBuffer (dBuffer );
416+ UnlockReleaseBuffer (rBuffer );
372417
373418gvs -> result -> pages_deleted ++ ;
419+
420+ return true;
374421}
375422
376423typedef struct DataPageDeleteStack
@@ -379,20 +426,20 @@ typedef struct DataPageDeleteStack
379426struct DataPageDeleteStack * parent ;
380427
381428BlockNumber blkno ;/* current block number */
382- BlockNumber leftBlkno ;/* rightest non-deleted page on left */
383429bool isRoot ;
384430}DataPageDeleteStack ;
385431
386432/*
387433 * scans posting tree and deletes empty pages
388434 */
389435static bool
390- rumScanToDelete (RumVacuumState * gvs ,BlockNumber blkno ,bool isRoot ,DataPageDeleteStack * parent ,OffsetNumber myoff )
436+ rumScanToDelete (RumVacuumState * gvs ,BlockNumber blkno ,bool isRoot ,
437+ DataPageDeleteStack * parent ,OffsetNumber myoff )
391438{
392439DataPageDeleteStack * me ;
393440Buffer buffer ;
394441Page page ;
395- bool meDelete = FALSE ;
442+ bool meDelete = false ;
396443
397444if (isRoot )
398445{
@@ -405,7 +452,6 @@ rumScanToDelete(RumVacuumState * gvs, BlockNumber blkno, bool isRoot, DataPageDe
405452me = (DataPageDeleteStack * )palloc0 (sizeof (DataPageDeleteStack ));
406453me -> parent = parent ;
407454parent -> child = me ;
408- me -> leftBlkno = InvalidBlockNumber ;
409455}
410456else
411457me = parent -> child ;
@@ -431,22 +477,11 @@ rumScanToDelete(RumVacuumState * gvs, BlockNumber blkno, bool isRoot, DataPageDe
431477}
432478}
433479
434- if (RumPageGetOpaque (page )-> maxoff < FirstOffsetNumber )
435- {
436- /* we never delete the left- or rightmost branch */
437- if (me -> leftBlkno != InvalidBlockNumber && !RumPageRightMost (page ))
438- {
439- Assert (!isRoot );
440- rumDeletePage (gvs ,blkno ,me -> leftBlkno ,me -> parent -> blkno ,myoff ,me -> parent -> isRoot );
441- meDelete = TRUE;
442- }
443- }
480+ if (RumPageGetOpaque (page )-> maxoff < FirstOffsetNumber && !isRoot )
481+ meDelete = rumDeletePage (gvs ,blkno ,me -> parent -> blkno ,myoff ,me -> parent -> isRoot );
444482
445483ReleaseBuffer (buffer );
446484
447- if (!meDelete )
448- me -> leftBlkno = blkno ;
449-
450485return meDelete ;
451486}
452487
@@ -465,7 +500,6 @@ rumVacuumPostingTree(RumVacuumState * gvs, OffsetNumber attnum, BlockNumber root
465500}
466501
467502memset (& root ,0 ,sizeof (DataPageDeleteStack ));
468- root .leftBlkno = InvalidBlockNumber ;
469503root .isRoot = TRUE;
470504
471505vacuum_delay_point ();