/* Dynamic values */ int wal_distance; /* Number of WAL bytes ahead. */ int block_distance; /* Number of block references ahead. */ int io_depth; /* Number of I/Os in progress. */
} XLogPrefetchStats;
/* How far ahead of replay are we now? */ if (prefetcher->reader->decode_queue_tail)
{
wal_distance =
prefetcher->reader->decode_queue_tail->lsn -
prefetcher->reader->decode_queue_head->lsn;
} else
{
wal_distance = 0;
}
/* How many IOs are currently in flight and completed? */
io_depth = lrq_inflight(prefetcher->streaming_read);
completed = lrq_completed(prefetcher->streaming_read);
/* Update the instantaneous stats visible in pg_stat_recovery_prefetch. */
SharedStats->io_depth = io_depth;
SharedStats->block_distance = io_depth + completed;
SharedStats->wal_distance = wal_distance;
/* Readahead is disabled until we replay past a certain point. */ if (nonblocking && replaying_lsn <= prefetcher->no_readahead_until) return LRQ_NEXT_AGAIN;
record = XLogReadAhead(prefetcher->reader, nonblocking); if (record == NULL)
{ /* *Wecan'treadanymore,duetoanerrororlackofdatain *nonblockingmode.Don'ttrytoreadaheadagainuntil *we'vereplayedeverythingalreadydecoded.
*/ if (nonblocking && prefetcher->reader->decode_queue_tail)
prefetcher->no_readahead_until =
prefetcher->reader->decode_queue_tail->lsn;
/* We have a new record to process. */
prefetcher->record = record;
prefetcher->next_block_id = 0;
} else
{ /* Continue to process from last call, or last loop. */
record = prefetcher->record;
}
#ifdef XLOGPREFETCHER_DEBUG_LEVEL
elog(XLOGPREFETCHER_DEBUG_LEVEL, "suppressing all readahead until %X/%X is replayed due to possible TLI change",
LSN_FORMAT_ARGS(record->lsn)); #endif
/* Fall through so we move past this record. */
}
} elseif (rmid == RM_DBASE_ID)
{ /* *Whendatabasesarecreatedwiththefile-copystrategy, *therearenoWALrecordstotellusaboutthecreationof *individualrelations.
*/ if (record_type == XLOG_DBASE_CREATE_FILE_COPY)
{
xl_dbase_create_file_copy_rec *xlrec =
(xl_dbase_create_file_copy_rec *) record->main_data;
RelFileLocator rlocator =
{InvalidOid, xlrec->db_id, InvalidRelFileNumber};
#ifdef XLOGPREFETCHER_DEBUG_LEVEL
elog(XLOGPREFETCHER_DEBUG_LEVEL, "suppressing prefetch in relation %u/%u/%u from block %u until %X/%X is replayed, which truncates the relation",
xlrec->rlocator.spcOid,
xlrec->rlocator.dbOid,
xlrec->rlocator.relNumber,
xlrec->blkno,
LSN_FORMAT_ARGS(record->lsn)); #endif
}
}
}
/* Scan the block references, starting where we left off last time. */ while (prefetcher->next_block_id <= record->max_block_id)
{ int block_id = prefetcher->next_block_id++;
DecodedBkpBlock *block = &record->blocks[block_id];
SMgrRelation reln;
PrefetchBufferResult result;
/* There is no point in reading a page that will be zeroed. */ if (block->flags & BKPBLOCK_WILL_INIT)
{
XLogPrefetchIncrement(&SharedStats->skip_init); return LRQ_NEXT_NO_IO;
}
/* Should we skip prefetching this block due to a filter? */ if (XLogPrefetcherIsFiltered(prefetcher, block->rlocator, block->blkno))
{
XLogPrefetchIncrement(&SharedStats->skip_new); return LRQ_NEXT_NO_IO;
}
/* There is no point in repeatedly prefetching the same block. */ for (int i = 0; i < XLOGPREFETCHER_SEQ_WINDOW_SIZE; ++i)
{ if (block->blkno == prefetcher->recent_block[i] &&
RelFileLocatorEquals(block->rlocator, prefetcher->recent_rlocator[i]))
{ /* *XXXIfwealsorememberedwhereitwas,wecouldset *recent_buffersothatrecoverycouldskipsmgropen() *andabuffertablelookup.
*/
XLogPrefetchIncrement(&SharedStats->skip_rep); return LRQ_NEXT_NO_IO;
}
}
prefetcher->recent_rlocator[prefetcher->recent_idx] = block->rlocator;
prefetcher->recent_block[prefetcher->recent_idx] = block->blkno;
prefetcher->recent_idx =
(prefetcher->recent_idx + 1) % XLOGPREFETCHER_SEQ_WINDOW_SIZE;
/* *Iftherelationfiledoesn'texistondisk,forexamplebecause *we'rereplayingafteracrashandthefilewillbecreatedand *thenunlinkedbyWALthathasn'tbeenreplayedyet,suppress *furtherprefetchingintherelationuntilthisrecordis *replayed.
*/ if (!smgrexists(reln, MAIN_FORKNUM))
{ #ifdef XLOGPREFETCHER_DEBUG_LEVEL
elog(XLOGPREFETCHER_DEBUG_LEVEL, "suppressing all prefetch in relation %u/%u/%u until %X/%X is replayed, because the relation does not exist on disk",
reln->smgr_rlocator.locator.spcOid,
reln->smgr_rlocator.locator.dbOid,
reln->smgr_rlocator.locator.relNumber,
LSN_FORMAT_ARGS(record->lsn)); #endif
XLogPrefetcherAddFilter(prefetcher, block->rlocator, 0,
record->lsn);
XLogPrefetchIncrement(&SharedStats->skip_new); return LRQ_NEXT_NO_IO;
}
/* *Iftherelationisn'tbigenoughtocontainthereferenced *blockyet,suppressprefetchingofthisblockandhigheruntil *thisrecordisreplayed.
*/ if (block->blkno >= smgrnblocks(reln, block->forknum))
{ #ifdef XLOGPREFETCHER_DEBUG_LEVEL
elog(XLOGPREFETCHER_DEBUG_LEVEL, "suppressing prefetch in relation %u/%u/%u from block %u until %X/%X is replayed, because the relation is too small",
reln->smgr_rlocator.locator.spcOid,
reln->smgr_rlocator.locator.dbOid,
reln->smgr_rlocator.locator.relNumber,
block->blkno,
LSN_FORMAT_ARGS(record->lsn)); #endif
XLogPrefetcherAddFilter(prefetcher, block->rlocator, block->blkno,
record->lsn);
XLogPrefetchIncrement(&SharedStats->skip_new); return LRQ_NEXT_NO_IO;
}
/* See if the block range is filtered. */
filter = hash_search(prefetcher->filter_table, &rlocator, HASH_FIND, NULL); if (filter && filter->filter_from_block <= blockno)
{ #ifdef XLOGPREFETCHER_DEBUG_LEVEL
elog(XLOGPREFETCHER_DEBUG_LEVEL, "prefetch of %u/%u/%u block %u suppressed; filtering until LSN %X/%X is replayed (blocks >= %u filtered)",
rlocator.spcOid, rlocator.dbOid, rlocator.relNumber, blockno,
LSN_FORMAT_ARGS(filter->filter_until_replayed),
filter->filter_from_block); #endif returntrue;
}
/* See if the whole database is filtered. */
rlocator.relNumber = InvalidRelFileNumber;
rlocator.spcOid = InvalidOid;
filter = hash_search(prefetcher->filter_table, &rlocator, HASH_FIND, NULL); if (filter)
{ #ifdef XLOGPREFETCHER_DEBUG_LEVEL
elog(XLOGPREFETCHER_DEBUG_LEVEL, "prefetch of %u/%u/%u block %u suppressed; filtering until LSN %X/%X is replayed (whole database)",
rlocator.spcOid, rlocator.dbOid, rlocator.relNumber, blockno,
LSN_FORMAT_ARGS(filter->filter_until_replayed)); #endif returntrue;
}
}
returnfalse;
}
/* *AwrapperforXLogBeginRead()thatalsoresetstheprefetcher.
*/ void
XLogPrefetcherBeginRead(XLogPrefetcher *prefetcher, XLogRecPtr recPtr)
{ /* This will forget about any in-flight IO. */
prefetcher->reconfigure_count--;
/* Book-keeping to avoid readahead on first read. */
prefetcher->begin_ptr = recPtr;
prefetcher->no_readahead_until = 0;
/* This will forget about any queued up records in the decoder. */
XLogBeginRead(prefetcher->reader, recPtr);
}
/* *Seeifit'stimetocomputesomestatistics,becauseenoughWALhas *beenprocessed.
*/ if (unlikely(record->lsn >= prefetcher->next_stats_shm_lsn))
XLogPrefetcherComputeStats(prefetcher);
Assert(record == prefetcher->reader->record);
return &record->header;
}
bool
check_recovery_prefetch(int *new_value, void **extra, GucSource source)
{ #ifndef USE_PREFETCH if (*new_value == RECOVERY_PREFETCH_ON)
{
GUC_check_errdetail("\"recovery_prefetch\" is not supported on platforms that lack support for issuing read-ahead advice."); returnfalse;
} #endif
returntrue;
}
void
assign_recovery_prefetch(int new_value, void *extra)
{ /* Reconfigure prefetching, because a setting it depends on changed. */
recovery_prefetch = new_value; if (AmStartupProcess())
XLogPrefetchReconfigure();
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.