From: Robert Haas Date: Tue, 2 Nov 2021 19:02:49 +0000 (-0400) Subject: Fix assorted bugs related to index pages. X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=26e8dc432b6798cf51ec5cb2feb346dd58a6241e;p=users%2Frhaas%2Fpostgres.git Fix assorted bugs related to index pages. - 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. --- diff --git a/src/backend/access/conveyor/cbmetapage.c b/src/backend/access/conveyor/cbmetapage.c index 68fdd412b6..d5f40af0e9 100644 --- a/src/backend/access/conveyor/cbmetapage.c +++ b/src/backend/access/conveyor/cbmetapage.c @@ -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. */ diff --git a/src/backend/access/conveyor/conveyor.c b/src/backend/access/conveyor/conveyor.c index 70935cfd9f..976a0292fd 100644 --- a/src/backend/access/conveyor/conveyor.c +++ b/src/backend/access/conveyor/conveyor.c @@ -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);