@@ -1126,4 +1126,232 @@ SELECT pg_stat_get_subscription_stats(NULL);
1126
1126
1127
1127
(1 row)
1128
1128
1129
+ -- Test that the following operations are tracked in pg_stat_io:
1130
+ -- - reads of target blocks into shared buffers
1131
+ -- - writes of shared buffers to permanent storage
1132
+ -- - extends of relations using shared buffers
1133
+ -- - fsyncs done to ensure the durability of data dirtying shared buffers
1134
+ -- There is no test for blocks evicted from shared buffers, because we cannot
1135
+ -- be sure of the state of shared buffers at the point the test is run.
1136
+ -- Create a regular table and insert some data to generate IOCONTEXT_NORMAL
1137
+ -- extends.
1138
+ SELECT sum(extends) AS io_sum_shared_before_extends
1139
+ FROM pg_stat_io WHERE io_context = 'normal' AND io_object = 'relation' \gset
1140
+ CREATE TABLE test_io_shared(a int);
1141
+ INSERT INTO test_io_shared SELECT i FROM generate_series(1,100)i;
1142
+ SELECT pg_stat_force_next_flush();
1143
+ pg_stat_force_next_flush
1144
+ --------------------------
1145
+
1146
+ (1 row)
1147
+
1148
+ SELECT sum(extends) AS io_sum_shared_after_extends
1149
+ FROM pg_stat_io WHERE io_context = 'normal' AND io_object = 'relation' \gset
1150
+ SELECT :io_sum_shared_after_extends > :io_sum_shared_before_extends;
1151
+ ?column?
1152
+ ----------
1153
+ t
1154
+ (1 row)
1155
+
1156
+ -- After a checkpoint, there should be some additional IOCONTEXT_NORMAL writes
1157
+ -- and fsyncs.
1158
+ SELECT sum(writes) AS writes, sum(fsyncs) AS fsyncs
1159
+ FROM pg_stat_io
1160
+ WHERE io_context = 'normal' AND io_object = 'relation' \gset io_sum_shared_before_
1161
+ -- See comment above for rationale for two explicit CHECKPOINTs.
1162
+ CHECKPOINT;
1163
+ CHECKPOINT;
1164
+ SELECT sum(writes) AS writes, sum(fsyncs) AS fsyncs
1165
+ FROM pg_stat_io
1166
+ WHERE io_context = 'normal' AND io_object = 'relation' \gset io_sum_shared_after_
1167
+ SELECT :io_sum_shared_after_writes > :io_sum_shared_before_writes;
1168
+ ?column?
1169
+ ----------
1170
+ t
1171
+ (1 row)
1172
+
1173
+ SELECT current_setting('fsync') = 'off'
1174
+ OR :io_sum_shared_after_fsyncs > :io_sum_shared_before_fsyncs;
1175
+ ?column?
1176
+ ----------
1177
+ t
1178
+ (1 row)
1179
+
1180
+ -- Change the tablespace so that the table is rewritten directly, then SELECT
1181
+ -- from it to cause it to be read back into shared buffers.
1182
+ SELECT sum(reads) AS io_sum_shared_before_reads
1183
+ FROM pg_stat_io WHERE io_context = 'normal' AND io_object = 'relation' \gset
1184
+ ALTER TABLE test_io_shared SET TABLESPACE regress_tblspace;
1185
+ -- SELECT from the table so that the data is read into shared buffers and
1186
+ -- io_context 'normal', io_object 'relation' reads are counted.
1187
+ SELECT COUNT(*) FROM test_io_shared;
1188
+ count
1189
+ -------
1190
+ 100
1191
+ (1 row)
1192
+
1193
+ SELECT pg_stat_force_next_flush();
1194
+ pg_stat_force_next_flush
1195
+ --------------------------
1196
+
1197
+ (1 row)
1198
+
1199
+ SELECT sum(reads) AS io_sum_shared_after_reads
1200
+ FROM pg_stat_io WHERE io_context = 'normal' AND io_object = 'relation' \gset
1201
+ SELECT :io_sum_shared_after_reads > :io_sum_shared_before_reads;
1202
+ ?column?
1203
+ ----------
1204
+ t
1205
+ (1 row)
1206
+
1207
+ DROP TABLE test_io_shared;
1208
+ -- Test that the follow IOCONTEXT_LOCAL IOOps are tracked in pg_stat_io:
1209
+ -- - eviction of local buffers in order to reuse them
1210
+ -- - reads of temporary table blocks into local buffers
1211
+ -- - writes of local buffers to permanent storage
1212
+ -- - extends of temporary tables
1213
+ -- Set temp_buffers to its minimum so that we can trigger writes with fewer
1214
+ -- inserted tuples. Do so in a new session in case temporary tables have been
1215
+ -- accessed by previous tests in this session.
1216
+ \c
1217
+ SET temp_buffers TO 100;
1218
+ CREATE TEMPORARY TABLE test_io_local(a int, b TEXT);
1219
+ SELECT sum(extends) AS extends, sum(evictions) AS evictions, sum(writes) AS writes
1220
+ FROM pg_stat_io
1221
+ WHERE io_context = 'normal' AND io_object = 'temp relation' \gset io_sum_local_before_
1222
+ -- Insert tuples into the temporary table, generating extends in the stats.
1223
+ -- Insert enough values that we need to reuse and write out dirty local
1224
+ -- buffers, generating evictions and writes.
1225
+ INSERT INTO test_io_local SELECT generate_series(1, 5000) as id, repeat('a', 200);
1226
+ -- Ensure the table is large enough to exceed our temp_buffers setting.
1227
+ SELECT pg_relation_size('test_io_local') / current_setting('block_size')::int8 > 100;
1228
+ ?column?
1229
+ ----------
1230
+ t
1231
+ (1 row)
1232
+
1233
+ SELECT sum(reads) AS io_sum_local_before_reads
1234
+ FROM pg_stat_io WHERE io_context = 'normal' AND io_object = 'temp relation' \gset
1235
+ -- Read in evicted buffers, generating reads.
1236
+ SELECT COUNT(*) FROM test_io_local;
1237
+ count
1238
+ -------
1239
+ 5000
1240
+ (1 row)
1241
+
1242
+ SELECT pg_stat_force_next_flush();
1243
+ pg_stat_force_next_flush
1244
+ --------------------------
1245
+
1246
+ (1 row)
1247
+
1248
+ SELECT sum(evictions) AS evictions,
1249
+ sum(reads) AS reads,
1250
+ sum(writes) AS writes,
1251
+ sum(extends) AS extends
1252
+ FROM pg_stat_io
1253
+ WHERE io_context = 'normal' AND io_object = 'temp relation' \gset io_sum_local_after_
1254
+ SELECT :io_sum_local_after_evictions > :io_sum_local_before_evictions,
1255
+ :io_sum_local_after_reads > :io_sum_local_before_reads,
1256
+ :io_sum_local_after_writes > :io_sum_local_before_writes,
1257
+ :io_sum_local_after_extends > :io_sum_local_before_extends;
1258
+ ?column? | ?column? | ?column? | ?column?
1259
+ ----------+----------+----------+----------
1260
+ t | t | t | t
1261
+ (1 row)
1262
+
1263
+ -- Change the tablespaces so that the temporary table is rewritten to other
1264
+ -- local buffers, exercising a different codepath than standard local buffer
1265
+ -- writes.
1266
+ ALTER TABLE test_io_local SET TABLESPACE regress_tblspace;
1267
+ SELECT pg_stat_force_next_flush();
1268
+ pg_stat_force_next_flush
1269
+ --------------------------
1270
+
1271
+ (1 row)
1272
+
1273
+ SELECT sum(writes) AS io_sum_local_new_tblspc_writes
1274
+ FROM pg_stat_io WHERE io_context = 'normal' AND io_object = 'temp relation' \gset
1275
+ SELECT :io_sum_local_new_tblspc_writes > :io_sum_local_after_writes;
1276
+ ?column?
1277
+ ----------
1278
+ t
1279
+ (1 row)
1280
+
1281
+ RESET temp_buffers;
1282
+ -- Test that reuse of strategy buffers and reads of blocks into these reused
1283
+ -- buffers while VACUUMing are tracked in pg_stat_io.
1284
+ -- Set wal_skip_threshold smaller than the expected size of
1285
+ -- test_io_vac_strategy so that, even if wal_level is minimal, VACUUM FULL will
1286
+ -- fsync the newly rewritten test_io_vac_strategy instead of writing it to WAL.
1287
+ -- Writing it to WAL will result in the newly written relation pages being in
1288
+ -- shared buffers -- preventing us from testing BAS_VACUUM BufferAccessStrategy
1289
+ -- reads.
1290
+ SET wal_skip_threshold = '1 kB';
1291
+ SELECT sum(reuses) AS reuses, sum(reads) AS reads
1292
+ FROM pg_stat_io WHERE io_context = 'vacuum' \gset io_sum_vac_strategy_before_
1293
+ CREATE TABLE test_io_vac_strategy(a int, b int) WITH (autovacuum_enabled = 'false');
1294
+ INSERT INTO test_io_vac_strategy SELECT i, i from generate_series(1, 8000)i;
1295
+ -- Ensure that the next VACUUM will need to perform IO by rewriting the table
1296
+ -- first with VACUUM (FULL).
1297
+ VACUUM (FULL) test_io_vac_strategy;
1298
+ VACUUM (PARALLEL 0) test_io_vac_strategy;
1299
+ SELECT pg_stat_force_next_flush();
1300
+ pg_stat_force_next_flush
1301
+ --------------------------
1302
+
1303
+ (1 row)
1304
+
1305
+ SELECT sum(reuses) AS reuses, sum(reads) AS reads
1306
+ FROM pg_stat_io WHERE io_context = 'vacuum' \gset io_sum_vac_strategy_after_
1307
+ SELECT :io_sum_vac_strategy_after_reads > :io_sum_vac_strategy_before_reads,
1308
+ :io_sum_vac_strategy_after_reuses > :io_sum_vac_strategy_before_reuses;
1309
+ ?column? | ?column?
1310
+ ----------+----------
1311
+ t | t
1312
+ (1 row)
1313
+
1314
+ RESET wal_skip_threshold;
1315
+ -- Test that extends done by a CTAS, which uses a BAS_BULKWRITE
1316
+ -- BufferAccessStrategy, are tracked in pg_stat_io.
1317
+ SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_before
1318
+ FROM pg_stat_io WHERE io_context = 'bulkwrite' \gset
1319
+ CREATE TABLE test_io_bulkwrite_strategy AS SELECT i FROM generate_series(1,100)i;
1320
+ SELECT pg_stat_force_next_flush();
1321
+ pg_stat_force_next_flush
1322
+ --------------------------
1323
+
1324
+ (1 row)
1325
+
1326
+ SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_after
1327
+ FROM pg_stat_io WHERE io_context = 'bulkwrite' \gset
1328
+ SELECT :io_sum_bulkwrite_strategy_extends_after > :io_sum_bulkwrite_strategy_extends_before;
1329
+ ?column?
1330
+ ----------
1331
+ t
1332
+ (1 row)
1333
+
1334
+ -- Test IO stats reset
1335
+ SELECT pg_stat_have_stats('io', 0, 0);
1336
+ pg_stat_have_stats
1337
+ --------------------
1338
+ t
1339
+ (1 row)
1340
+
1341
+ SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) AS io_stats_pre_reset
1342
+ FROM pg_stat_io \gset
1343
+ SELECT pg_stat_reset_shared('io');
1344
+ pg_stat_reset_shared
1345
+ ----------------------
1346
+
1347
+ (1 row)
1348
+
1349
+ SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) AS io_stats_post_reset
1350
+ FROM pg_stat_io \gset
1351
+ SELECT :io_stats_post_reset < :io_stats_pre_reset;
1352
+ ?column?
1353
+ ----------
1354
+ t
1355
+ (1 row)
1356
+
1129
1357
-- End of Stats Test
0 commit comments