@@ -480,18 +480,99 @@ static int ckpt_buforder_comparator(const void *pa, const void *pb);
480480static int ts_ckpt_progress_comparator (Datum a , Datum b , void * arg );
481481
482482
483+ /*
484+ * Implementation of PrefetchBuffer() for shared buffers.
485+ */
486+ PrefetchBufferResult
487+ PrefetchSharedBuffer (SMgrRelation smgr_reln ,
488+ ForkNumber forkNum ,
489+ BlockNumber blockNum )
490+ {
491+ PrefetchBufferResult result = {InvalidBuffer , false};
492+ BufferTag newTag ; /* identity of requested block */
493+ uint32 newHash ; /* hash value for newTag */
494+ LWLock * newPartitionLock ; /* buffer partition lock for it */
495+ int buf_id ;
496+
497+ Assert (BlockNumberIsValid (blockNum ));
498+
499+ /* create a tag so we can lookup the buffer */
500+ INIT_BUFFERTAG (newTag , smgr_reln -> smgr_rnode .node ,
501+ forkNum , blockNum );
502+
503+ /* determine its hash code and partition lock ID */
504+ newHash = BufTableHashCode (& newTag );
505+ newPartitionLock = BufMappingPartitionLock (newHash );
506+
507+ /* see if the block is in the buffer pool already */
508+ LWLockAcquire (newPartitionLock , LW_SHARED );
509+ buf_id = BufTableLookup (& newTag , newHash );
510+ LWLockRelease (newPartitionLock );
511+
512+ /* If not in buffers, initiate prefetch */
513+ if (buf_id < 0 )
514+ {
515+ #ifdef USE_PREFETCH
516+ /*
517+ * Try to initiate an asynchronous read. This returns false in
518+ * recovery if the relation file doesn't exist.
519+ */
520+ if (smgrprefetch (smgr_reln , forkNum , blockNum ))
521+ result .initiated_io = true;
522+ #endif /* USE_PREFETCH */
523+ }
524+ else
525+ {
526+ /*
527+ * Report the buffer it was in at that time. The caller may be able
528+ * to avoid a buffer table lookup, but it's not pinned and it must be
529+ * rechecked!
530+ */
531+ result .recent_buffer = buf_id + 1 ;
532+ }
533+
534+ /*
535+ * If the block *is* in buffers, we do nothing. This is not really ideal:
536+ * the block might be just about to be evicted, which would be stupid
537+ * since we know we are going to need it soon. But the only easy answer
538+ * is to bump the usage_count, which does not seem like a great solution:
539+ * when the caller does ultimately touch the block, usage_count would get
540+ * bumped again, resulting in too much favoritism for blocks that are
541+ * involved in a prefetch sequence. A real fix would involve some
542+ * additional per-buffer state, and it's not clear that there's enough of
543+ * a problem to justify that.
544+ */
545+
546+ return result ;
547+ }
548+
483549/*
484550 * PrefetchBuffer -- initiate asynchronous read of a block of a relation
485551 *
486552 * This is named by analogy to ReadBuffer but doesn't actually allocate a
487553 * buffer. Instead it tries to ensure that a future ReadBuffer for the given
488554 * block will not be delayed by the I/O. Prefetching is optional.
489- * No-op if prefetching isn't compiled in.
555+ *
556+ * There are three possible outcomes:
557+ *
558+ * 1. If the block is already cached, the result includes a valid buffer that
559+ * could be used by the caller to avoid the need for a later buffer lookup, but
560+ * it's not pinned, so the caller must recheck it.
561+ *
562+ * 2. If the kernel has been asked to initiate I/O, the initated_io member is
563+ * true. Currently there is no way to know if the data was already cached by
564+ * the kernel and therefore didn't really initiate I/O, and no way to know when
565+ * the I/O completes other than using synchronous ReadBuffer().
566+ *
567+ * 3. Otherwise, the buffer wasn't already cached by PostgreSQL, and either
568+ * USE_PREFETCH is not defined (this build doesn't support prefetching due to
569+ * lack of a kernel facility), or the underlying relation file wasn't found and
570+ * we are in recovery. (If the relation file wasn't found and we are not in
571+ * recovery, an error is raised).
490572 */
491- void
573+ PrefetchBufferResult
492574PrefetchBuffer (Relation reln , ForkNumber forkNum , BlockNumber blockNum )
493575{
494- #ifdef USE_PREFETCH
495576 Assert (RelationIsValid (reln ));
496577 Assert (BlockNumberIsValid (blockNum ));
497578
@@ -507,45 +588,13 @@ PrefetchBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
507588 errmsg ("cannot access temporary tables of other sessions" )));
508589
509590 /* pass it off to localbuf.c */
510- LocalPrefetchBuffer (reln -> rd_smgr , forkNum , blockNum );
591+ return PrefetchLocalBuffer (reln -> rd_smgr , forkNum , blockNum );
511592 }
512593 else
513594 {
514- BufferTag newTag ; /* identity of requested block */
515- uint32 newHash ; /* hash value for newTag */
516- LWLock * newPartitionLock ; /* buffer partition lock for it */
517- int buf_id ;
518-
519- /* create a tag so we can lookup the buffer */
520- INIT_BUFFERTAG (newTag , reln -> rd_smgr -> smgr_rnode .node ,
521- forkNum , blockNum );
522-
523- /* determine its hash code and partition lock ID */
524- newHash = BufTableHashCode (& newTag );
525- newPartitionLock = BufMappingPartitionLock (newHash );
526-
527- /* see if the block is in the buffer pool already */
528- LWLockAcquire (newPartitionLock , LW_SHARED );
529- buf_id = BufTableLookup (& newTag , newHash );
530- LWLockRelease (newPartitionLock );
531-
532- /* If not in buffers, initiate prefetch */
533- if (buf_id < 0 )
534- smgrprefetch (reln -> rd_smgr , forkNum , blockNum );
535-
536- /*
537- * If the block *is* in buffers, we do nothing. This is not really
538- * ideal: the block might be just about to be evicted, which would be
539- * stupid since we know we are going to need it soon. But the only
540- * easy answer is to bump the usage_count, which does not seem like a
541- * great solution: when the caller does ultimately touch the block,
542- * usage_count would get bumped again, resulting in too much
543- * favoritism for blocks that are involved in a prefetch sequence. A
544- * real fix would involve some additional per-buffer state, and it's
545- * not clear that there's enough of a problem to justify that.
546- */
595+ /* pass it to the shared buffer version */
596+ return PrefetchSharedBuffer (reln -> rd_smgr , forkNum , blockNum );
547597 }
548- #endif /* USE_PREFETCH */
549598}
550599
551600
0 commit comments