63
63
#include "utils/pg_rusage.h"
64
64
#include "utils/sampling.h"
65
65
#include "utils/sortsupport.h"
66
+ #include "utils/spccache.h"
66
67
#include "utils/syscache.h"
67
68
#include "utils/timestamp.h"
68
69
@@ -1127,6 +1128,7 @@ acquire_sample_rows(Relation onerel, int elevel,
1127
1128
double liverows = 0 ; /* # live rows seen */
1128
1129
double deadrows = 0 ; /* # dead rows seen */
1129
1130
double rowstoskip = -1 ; /* -1 means not set yet */
1131
+ long randseed ; /* Seed for block sampler(s) */
1130
1132
BlockNumber totalblocks ;
1131
1133
TransactionId OldestXmin ;
1132
1134
BlockSamplerData bs ;
@@ -1135,6 +1137,10 @@ acquire_sample_rows(Relation onerel, int elevel,
1135
1137
TableScanDesc scan ;
1136
1138
BlockNumber nblocks ;
1137
1139
BlockNumber blksdone = 0 ;
1140
+ #ifdef USE_PREFETCH
1141
+ int prefetch_maximum = 0 ; /* blocks to prefetch if enabled */
1142
+ BlockSamplerData prefetch_bs ;
1143
+ #endif
1138
1144
1139
1145
Assert (targrows > 0 );
1140
1146
@@ -1144,7 +1150,15 @@ acquire_sample_rows(Relation onerel, int elevel,
1144
1150
OldestXmin = GetOldestNonRemovableTransactionId (onerel );
1145
1151
1146
1152
/* 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
1148
1162
1149
1163
/* Report sampling block numbers */
1150
1164
pgstat_progress_update_param (PROGRESS_ANALYZE_BLOCKS_TOTAL ,
@@ -1156,14 +1170,69 @@ acquire_sample_rows(Relation onerel, int elevel,
1156
1170
scan = table_beginscan_analyze (onerel );
1157
1171
slot = table_slot_create (onerel , NULL );
1158
1172
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
+
1159
1197
/* Outer loop over blocks to sample */
1160
1198
while (BlockSampler_HasMore (& bs ))
1161
1199
{
1200
+ bool block_accepted ;
1162
1201
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
1163
1213
1164
1214
vacuum_delay_point ();
1165
1215
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 )
1167
1236
continue ;
1168
1237
1169
1238
while (table_scan_analyze_next_tuple (scan , OldestXmin , & liverows , & deadrows , slot ))
0 commit comments