Fix assorted bugs related to index pages.
authorRobert Haas <[email protected]>
Tue, 2 Nov 2021 19:02:49 +0000 (15:02 -0400)
committerRobert Haas <[email protected]>
Tue, 2 Nov 2021 19:02:49 +0000 (15:02 -0400)
- cb_metapage_get_insert_state needs to return
  CBM_INSERT_NEEDS_INDEX_SEGMENT not only when the latest index
  segment is full but also when there are no index segments in
  existence yet.

- cb_metapage_remove_index_entries can't treat cbm_index_start
  == cbm_index_metapage_start as an error, or we'll never be able
  to move the first set of index entries out of the metapage.

- ConveyorBeltGetNewPage can allocate a new index segment without
  having a lock on prevbuffer if there are no index segments
  yet, since there is no such things as the previous index segment
  in that case.

- When we create a new index segment and then decide that our next
  action should be to relocate index entries into it, we must use
  the correct value for next_blkno.

- When adding the very first index segment, don't try to pin the
  first page of the previous index segment, since there isn't one.

- When adding a new index segment, use the free buffer we
  identified, rather than an uninitialized variable.

All per a test case from Dilip Kumar.

src/backend/access/conveyor/cbmetapage.c
src/backend/access/conveyor/conveyor.c

index 68fdd412b6d08a403ef099295258d06ab783bf0a..d5f40af0e927108f6e48b6ffe85f45ec62fd2891 100644 (file)
@@ -197,7 +197,8 @@ cb_metapage_get_insert_state(CBMetapageData *meta,
                        elog(ERROR,
                                 "newest index segment listed as using %u of %u entries",
                                 entries, maxentries);
-               else if (entries == maxentries)
+               else if (entries == maxentries ||
+                                meta->cbm_newest_index_segment == CB_INVALID_SEGMENT)
                        return CBM_INSERT_NEEDS_INDEX_SEGMENT;
                else
                {
@@ -374,8 +375,7 @@ cb_metapage_remove_index_entries(CBMetapageData *meta, unsigned count,
                elog(ERROR, "removed index entries should be relocated if index segments exist");
        if (relocating &&
                (meta->cbm_oldest_index_segment == CB_INVALID_SEGMENT ||
-                meta->cbm_newest_index_segment == CB_INVALID_SEGMENT ||
-                meta->cbm_index_start == meta->cbm_index_metapage_start))
+                meta->cbm_newest_index_segment == CB_INVALID_SEGMENT))
                elog(ERROR, "removed index entries can't be relocated if no index segments exist");
 
        /* Move any entries that we are keeping. */
index 70935cfd9f1be57ec663199d560e90742a8dfc62..976a0292fd99997c7f67f1c0198efa6726864f2a 100644 (file)
@@ -350,7 +350,8 @@ ConveyorBeltGetNewPage(ConveyorBelt *cb, CBPageNo *pageno)
                 */
                if (can_allocate_segment &&
                        insert_state == CBM_INSERT_NEEDS_INDEX_SEGMENT &&
-                       (!BufferIsValid(indexbuffer) || !BufferIsValid(prevbuffer)))
+                       (!BufferIsValid(indexbuffer) || (!BufferIsValid(prevbuffer)
+                       && newest_index_segment != CB_INVALID_SEGMENT)))
                        can_allocate_segment = false;
 
                /*
@@ -416,6 +417,7 @@ ConveyorBeltGetNewPage(ConveyorBelt *cb, CBPageNo *pageno)
                                 * index entries to that index segment.
                                 */
                                insert_state = CBM_INSERT_NEEDS_INDEX_ENTRIES_RELOCATED;
+                               next_blkno = indexblock;
                        }
 
                        /*
@@ -533,15 +535,17 @@ ConveyorBeltGetNewPage(ConveyorBelt *cb, CBPageNo *pageno)
                }
 
                /*
-                * If we need to add a new index segment, we'll have to update the
-                * newest index page with a pointer to the index page we're going to
-                * add, so we must read and pin that page.
+                * If we need to add a new index segment and it's not the very first
+                * one, we'll have to update the newest index page with a pointer to
+                * the index page we're going to add, so we must read and pin that
+                * page.
                 *
                 * The names "prevblock" and "prevbuffer" are intended to signify that
                 * what is currently the newest index segment will become the previous
                 * segment relative to the one we're going to add.
                 */
-               if (insert_state == CBM_INSERT_NEEDS_INDEX_SEGMENT)
+               if (insert_state == CBM_INSERT_NEEDS_INDEX_SEGMENT &&
+                       newest_index_segment != CB_INVALID_SEGMENT)
                {
                        prevblock = cb_segment_to_block(cb->cb_pages_per_segment,
                                                                                        newest_index_segment, 0);
@@ -593,7 +597,7 @@ ConveyorBeltGetNewPage(ConveyorBelt *cb, CBPageNo *pageno)
                                if (insert_state == CBM_INSERT_NEEDS_INDEX_SEGMENT)
                                {
                                        indexblock = free_block;
-                                       indexbuffer = buffer;
+                                       indexbuffer = free_buffer;
                                }
                                else
                                        ReleaseBuffer(free_buffer);