return allindexes;
 }
 
+/*
+ * Read stream callback for vacuum's third phase (second pass over the heap).
+ * Gets the next block from the TID store and returns it or InvalidBlockNumber
+ * if there are no further blocks to vacuum.
+ */
+static BlockNumber
+vacuum_reap_lp_read_stream_next(ReadStream *stream,
+                               void *callback_private_data,
+                               void *per_buffer_data)
+{
+   TidStoreIter *iter = callback_private_data;
+   TidStoreIterResult *iter_result;
+
+   iter_result = TidStoreIterateNext(iter);
+   if (iter_result == NULL)
+       return InvalidBlockNumber;
+
+   /*
+    * Save the TidStoreIterResult for later, so we can extract the offsets.
+    * It is safe to copy the result, according to TidStoreIterateNext().
+    */
+   memcpy(per_buffer_data, iter_result, sizeof(*iter_result));
+
+   return iter_result->blkno;
+}
+
 /*
  * lazy_vacuum_heap_rel() -- second pass over the heap for two pass strategy
  *
 static void
 lazy_vacuum_heap_rel(LVRelState *vacrel)
 {
+   ReadStream *stream;
    BlockNumber vacuumed_pages = 0;
    Buffer      vmbuffer = InvalidBuffer;
    LVSavedErrInfo saved_err_info;
    TidStoreIter *iter;
-   TidStoreIterResult *iter_result;
 
    Assert(vacrel->do_index_vacuuming);
    Assert(vacrel->do_index_cleanup);
                             InvalidBlockNumber, InvalidOffsetNumber);
 
    iter = TidStoreBeginIterate(vacrel->dead_items);
-   while ((iter_result = TidStoreIterateNext(iter)) != NULL)
+
+   /* Set up the read stream for vacuum's second pass through the heap */
+   stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE,
+                                       vacrel->bstrategy,
+                                       vacrel->rel,
+                                       MAIN_FORKNUM,
+                                       vacuum_reap_lp_read_stream_next,
+                                       iter,
+                                       sizeof(TidStoreIterResult));
+
+   while (true)
    {
        BlockNumber blkno;
        Buffer      buf;
        Page        page;
+       TidStoreIterResult *iter_result;
        Size        freespace;
        OffsetNumber offsets[MaxOffsetNumber];
        int         num_offsets;
 
        vacuum_delay_point(false);
 
-       blkno = iter_result->blkno;
-       vacrel->blkno = blkno;
+       buf = read_stream_next_buffer(stream, (void **) &iter_result);
 
+       /* The relation is exhausted */
+       if (!BufferIsValid(buf))
+           break;
+
+       vacrel->blkno = blkno = BufferGetBlockNumber(buf);
+
+       Assert(iter_result);
        num_offsets = TidStoreGetBlockOffsets(iter_result, offsets, lengthof(offsets));
        Assert(num_offsets <= lengthof(offsets));
 
        visibilitymap_pin(vacrel->rel, blkno, &vmbuffer);
 
        /* We need a non-cleanup exclusive lock to mark dead_items unused */
-       buf = ReadBufferExtended(vacrel->rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
-                                vacrel->bstrategy);
        LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
        lazy_vacuum_heap_page(vacrel, blkno, buf, offsets,
                              num_offsets, vmbuffer);
        RecordPageWithFreeSpace(vacrel->rel, blkno, freespace);
        vacuumed_pages++;
    }
+
+   read_stream_end(stream);
    TidStoreEndIterate(iter);
 
    vacrel->blkno = InvalidBlockNumber;