@@ -480,18 +480,99 @@ static int ckpt_buforder_comparator(const void *pa, const void *pb);
480
480
static int ts_ckpt_progress_comparator (Datum a , Datum b , void * arg );
481
481
482
482
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
+
483
549
/*
484
550
* PrefetchBuffer -- initiate asynchronous read of a block of a relation
485
551
*
486
552
* This is named by analogy to ReadBuffer but doesn't actually allocate a
487
553
* buffer. Instead it tries to ensure that a future ReadBuffer for the given
488
554
* 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).
490
572
*/
491
- void
573
+ PrefetchBufferResult
492
574
PrefetchBuffer (Relation reln , ForkNumber forkNum , BlockNumber blockNum )
493
575
{
494
- #ifdef USE_PREFETCH
495
576
Assert (RelationIsValid (reln ));
496
577
Assert (BlockNumberIsValid (blockNum ));
497
578
@@ -507,45 +588,13 @@ PrefetchBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
507
588
errmsg ("cannot access temporary tables of other sessions" )));
508
589
509
590
/* pass it off to localbuf.c */
510
- LocalPrefetchBuffer (reln -> rd_smgr , forkNum , blockNum );
591
+ return PrefetchLocalBuffer (reln -> rd_smgr , forkNum , blockNum );
511
592
}
512
593
else
513
594
{
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 );
547
597
}
548
- #endif /* USE_PREFETCH */
549
598
}
550
599
551
600
0 commit comments