6363#include "utils/pg_rusage.h"
6464#include "utils/sampling.h"
6565#include "utils/sortsupport.h"
66+ #include "utils/spccache.h"
6667#include "utils/syscache.h"
6768#include "utils/timestamp.h"
6869
@@ -1127,6 +1128,7 @@ acquire_sample_rows(Relation onerel, int elevel,
11271128 double liverows = 0 ; /* # live rows seen */
11281129 double deadrows = 0 ; /* # dead rows seen */
11291130 double rowstoskip = -1 ; /* -1 means not set yet */
1131+ long randseed ; /* Seed for block sampler(s) */
11301132 BlockNumber totalblocks ;
11311133 TransactionId OldestXmin ;
11321134 BlockSamplerData bs ;
@@ -1135,6 +1137,10 @@ acquire_sample_rows(Relation onerel, int elevel,
11351137 TableScanDesc scan ;
11361138 BlockNumber nblocks ;
11371139 BlockNumber blksdone = 0 ;
1140+ #ifdef USE_PREFETCH
1141+ int prefetch_maximum = 0 ; /* blocks to prefetch if enabled */
1142+ BlockSamplerData prefetch_bs ;
1143+ #endif
11381144
11391145 Assert (targrows > 0 );
11401146
@@ -1144,7 +1150,15 @@ acquire_sample_rows(Relation onerel, int elevel,
11441150 OldestXmin = GetOldestNonRemovableTransactionId (onerel );
11451151
11461152 /* Prepare for sampling block numbers */
1147- nblocks = BlockSampler_Init (& bs , totalblocks , targrows , random ());
1153+ randseed = random ();
1154+ nblocks = BlockSampler_Init (& bs , totalblocks , targrows , randseed );
1155+
1156+ #ifdef USE_PREFETCH
1157+ prefetch_maximum = get_tablespace_io_concurrency (onerel -> rd_rel -> reltablespace );
1158+ /* Create another BlockSampler, using the same seed, for prefetching */
1159+ if (prefetch_maximum )
1160+ (void ) BlockSampler_Init (& prefetch_bs , totalblocks , targrows , randseed );
1161+ #endif
11481162
11491163 /* Report sampling block numbers */
11501164 pgstat_progress_update_param (PROGRESS_ANALYZE_BLOCKS_TOTAL ,
@@ -1156,14 +1170,69 @@ acquire_sample_rows(Relation onerel, int elevel,
11561170 scan = table_beginscan_analyze (onerel );
11571171 slot = table_slot_create (onerel , NULL );
11581172
1173+ #ifdef USE_PREFETCH
1174+
1175+ /*
1176+ * If we are doing prefetching, then go ahead and tell the kernel about
1177+ * the first set of pages we are going to want. This also moves our
1178+ * iterator out ahead of the main one being used, where we will keep it so
1179+ * that we're always pre-fetching out prefetch_maximum number of blocks
1180+ * ahead.
1181+ */
1182+ if (prefetch_maximum )
1183+ {
1184+ for (int i = 0 ; i < prefetch_maximum ; i ++ )
1185+ {
1186+ BlockNumber prefetch_block ;
1187+
1188+ if (!BlockSampler_HasMore (& prefetch_bs ))
1189+ break ;
1190+
1191+ prefetch_block = BlockSampler_Next (& prefetch_bs );
1192+ PrefetchBuffer (scan -> rs_rd , MAIN_FORKNUM , prefetch_block );
1193+ }
1194+ }
1195+ #endif
1196+
11591197 /* Outer loop over blocks to sample */
11601198 while (BlockSampler_HasMore (& bs ))
11611199 {
1200+ bool block_accepted ;
11621201 BlockNumber targblock = BlockSampler_Next (& bs );
1202+ #ifdef USE_PREFETCH
1203+ BlockNumber prefetch_targblock = InvalidBlockNumber ;
1204+
1205+ /*
1206+ * Make sure that every time the main BlockSampler is moved forward
1207+ * that our prefetch BlockSampler also gets moved forward, so that we
1208+ * always stay out ahead.
1209+ */
1210+ if (prefetch_maximum && BlockSampler_HasMore (& prefetch_bs ))
1211+ prefetch_targblock = BlockSampler_Next (& prefetch_bs );
1212+ #endif
11631213
11641214 vacuum_delay_point ();
11651215
1166- if (!table_scan_analyze_next_block (scan , targblock , vac_strategy ))
1216+ block_accepted = table_scan_analyze_next_block (scan , targblock , vac_strategy );
1217+
1218+ #ifdef USE_PREFETCH
1219+
1220+ /*
1221+ * When pre-fetching, after we get a block, tell the kernel about the
1222+ * next one we will want, if there's any left.
1223+ *
1224+ * We want to do this even if the table_scan_analyze_next_block() call
1225+ * above decides against analyzing the block it picked.
1226+ */
1227+ if (prefetch_maximum && prefetch_targblock != InvalidBlockNumber )
1228+ PrefetchBuffer (scan -> rs_rd , MAIN_FORKNUM , prefetch_targblock );
1229+ #endif
1230+
1231+ /*
1232+ * Don't analyze if table_scan_analyze_next_block() indicated this
1233+ * block is unsuitable for analyzing.
1234+ */
1235+ if (!block_accepted )
11671236 continue ;
11681237
11691238 while (table_scan_analyze_next_tuple (scan , OldestXmin , & liverows , & deadrows , slot ))
0 commit comments