&index_metapage_start,
&newest_index_segment);
+ /*
+ * All existing segments must be on disk.
+ *
+ * (The last one might be partial, but that's OK.)
+ */
+ if (next_segno > possibly_not_on_disk_segno)
+ possibly_not_on_disk_segno = next_segno;
+
/*
* If we need to allocate a payload or index segment, and we don't
* currently have a candidate, check whether the metapage knows of a
|| insert_state == CBM_INSERT_NEEDS_INDEX_SEGMENT) &&
mode == BUFFER_LOCK_EXCLUSIVE &&
(free_segno != CB_INVALID_SEGMENT) &&
- (free_segno < next_segno ||
- free_segno < possibly_not_on_disk_segno);
+ (free_segno < possibly_not_on_disk_segno);
/*
* If it still looks like we can allocate, check for the case where we
fsmbuffer = InvalidBuffer;
}
- /*
- * If, according to the metapage, there is a current payload segment
- * that is not full, we can just lock the target buffer. If it's still
- * new, we're done. Otherwise, someone else grabbed that page before
- * we did, so we must retry.
- */
- if (insert_state == CBM_INSERT_OK)
+ if (insert_state != CBM_INSERT_OK)
{
- buffer = ConveyorBeltRead(cb, next_blkno, BUFFER_LOCK_EXCLUSIVE);
+ /*
+ * Some sort of preparatory work will be needed in order to insert
+ * a new page, which will require modifying the metapage.
+ * Therefore, next time we lock it, we had better grab an
+ * exclusive lock.
+ */
+ mode = BUFFER_LOCK_EXCLUSIVE;
+ }
+ else
+ {
+ BlockNumber possibly_not_on_disk_blkno;
+
+ /*
+ * The current payload segment is not full, but if it's the last
+ * segment in the conveyor belt, the page we need may not yet exist
+ * on disk.
+ *
+ * We know if we get to this point that at least one segment
+ * exists, so possibly_not_on_disk_segno can't be 0. The previous
+ * segment's first page must exist on disk, but the later pages
+ * may not.
+ */
+ Assert(possibly_not_on_disk_segno > 0);
+ possibly_not_on_disk_blkno =
+ cb_segment_to_block(cb->cb_pages_per_segment,
+ possibly_not_on_disk_segno - 1, 1);
+
+ /* Extend the relation if needed. */
+ buffer = InvalidBuffer;
+ if (next_blkno >= possibly_not_on_disk_blkno)
+ {
+ BlockNumber nblocks;
+
+ /* Allocating the next segment so might need to extend. */
+ LockRelationForExtension(cb->cb_rel, ExclusiveLock);
+ nblocks = RelationGetNumberOfBlocksInFork(cb->cb_rel,
+ cb->cb_fork);
+ if (next_blkno > nblocks)
+ ereport(ERROR,
+ errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg_internal("next block should be %u but relation has only %u blocks",
+ next_blkno, nblocks));
+ else if (next_blkno == nblocks)
+ buffer = ReadBufferExtended(cb->cb_rel, cb->cb_fork,
+ P_NEW, RBM_NORMAL, NULL);
+ UnlockRelationForExtension(cb->cb_rel, ExclusiveLock);
+ }
+
+ /* If we didn't extend the relation, just read the buffer. */
+ if (!BufferIsValid(buffer))
+ buffer =
+ ConveyorBeltRead(cb, next_blkno, BUFFER_LOCK_EXCLUSIVE);
+
+ /*
+ * If the target buffer is still new, we're done. Otherwise,
+ * someone else grabbed that page before we did, so we must fall
+ * through and retry.
+ */
if (PageIsNew(BufferGetPage(buffer)))
{
/*
break;
}
}
- else
- {
- /*
- * Some sort of preparatory work will be needed in order to insert
- * a new page, which will require modifying the metapage.
- * Therefore, next time we lock it, we had better grab an
- * exclusive lock.
- */
- mode = BUFFER_LOCK_EXCLUSIVE;
- }
/*
* If the metapage has no more space for index entries, we must move
BlockNumber free_block;
/* Allocating the next segment so might need to extend. */
+ LockRelationForExtension(cb->cb_rel, ExclusiveLock);
nblocks = RelationGetNumberOfBlocksInFork(cb->cb_rel,
cb->cb_fork);
free_block = cb_segment_to_block(cb->cb_pages_per_segment,
++nblocks;
}
}
+ UnlockRelationForExtension(cb->cb_rel, ExclusiveLock);
/*
* The first page of this segment, at least, is now known to