diff --git a/pgxn/neon/pagestore_smgr.c b/pgxn/neon/pagestore_smgr.c index b0712468f5..a7745713cf 100644 --- a/pgxn/neon/pagestore_smgr.c +++ b/pgxn/neon/pagestore_smgr.c @@ -681,7 +681,26 @@ prefetch_do_request(PrefetchRequest *slot, bool *force_latest, XLogRecPtr *force Assert(slot->my_ring_index == MyPState->ring_unused); page_server->send((NeonRequest *) &request); - /* Remember request LSN for the prefetched page to avoid false pefetch invalidations */ + /* + * Remember request LSN in the last-written LSN cache to avoid false + * prefetch invalidations. + * + * Imagine what would happen without this, when you perform a large + * sequential scan with UPDATE. The sequential scan issues a prefetch + * request for each page in order, and every page is also dirtied. On + * each page, the oldest page in the last-written LSN cache is evicted, + * which advances the global last-written LSN. The pages being scanned are + * not in the last-written cache, so each prefetch request will use the + * global last-written LSN in the request and memorize that in the + * slot. However, when we receive the response to the prefetch request, + * the global last-written LSN has already moved forwards, and the + * cross-check we make that the last-written LSN matches will fail, and we + * discard the prefetched response unnecessary. + * + * Inserting the LSN we use in the prefetch request to the last-written LSN + * cache avoids that problem. With that, we will use the cached value in + * the cross-check, instead of the more recent global last-written LSN value. + */ SetLastWrittenLSNForBlock( request.req.lsn, slot->buftag.rnode,