112
112
113
113
typedef struct LVRelStats
114
114
{
115
- /* hasindex = true means two-pass strategy; false means one-pass */
116
- bool hasindex ;
115
+ /* useindex = true means two-pass strategy; false means one-pass */
116
+ bool useindex ;
117
117
/* Overall statistics about rel */
118
118
BlockNumber old_rel_pages ; /* previous value of pg_class.relpages */
119
119
BlockNumber rel_pages ; /* total number of pages */
@@ -125,6 +125,8 @@ typedef struct LVRelStats
125
125
double new_rel_tuples ; /* new estimated total # of tuples */
126
126
double new_live_tuples ; /* new estimated total # of live tuples */
127
127
double new_dead_tuples ; /* new estimated total # of dead tuples */
128
+ double nleft_dead_tuples ; /* # of dead tuples we left */
129
+ double nleft_dead_itemids ; /* # of dead item pointers we left */
128
130
BlockNumber pages_removed ;
129
131
double tuples_deleted ;
130
132
BlockNumber nonempty_pages ; /* actually, last nonempty page + 1 */
@@ -150,7 +152,7 @@ static BufferAccessStrategy vac_strategy;
150
152
151
153
152
154
/* non-export function prototypes */
153
- static void lazy_scan_heap (Relation onerel , int options ,
155
+ static void lazy_scan_heap (Relation onerel , VacuumParams * params ,
154
156
LVRelStats * vacrelstats , Relation * Irel , int nindexes ,
155
157
bool aggressive );
156
158
static void lazy_vacuum_heap (Relation onerel , LVRelStats * vacrelstats , BlockNumber nblocks );
@@ -209,6 +211,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
209
211
MultiXactId new_min_multi ;
210
212
211
213
Assert (params != NULL );
214
+ Assert (params -> index_cleanup != VACOPT_TERNARY_DEFAULT );
212
215
213
216
/* measure elapsed time iff autovacuum logging requires it */
214
217
if (IsAutoVacuumWorkerProcess () && params -> log_min_duration >= 0 )
@@ -275,10 +278,11 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
275
278
276
279
/* Open all indexes of the relation */
277
280
vac_open_indexes (onerel , RowExclusiveLock , & nindexes , & Irel );
278
- vacrelstats -> hasindex = (nindexes > 0 );
281
+ vacrelstats -> useindex = (nindexes > 0 &&
282
+ params -> index_cleanup == VACOPT_TERNARY_ENABLED );
279
283
280
284
/* Do the vacuuming */
281
- lazy_scan_heap (onerel , params -> options , vacrelstats , Irel , nindexes , aggressive );
285
+ lazy_scan_heap (onerel , params , vacrelstats , Irel , nindexes , aggressive );
282
286
283
287
/* Done with indexes */
284
288
vac_close_indexes (nindexes , Irel , NoLock );
@@ -349,7 +353,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
349
353
new_rel_pages ,
350
354
new_live_tuples ,
351
355
new_rel_allvisible ,
352
- vacrelstats -> hasindex ,
356
+ nindexes > 0 ,
353
357
new_frozen_xid ,
354
358
new_min_multi ,
355
359
false);
@@ -419,6 +423,12 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
419
423
vacrelstats -> new_rel_tuples ,
420
424
vacrelstats -> new_dead_tuples ,
421
425
OldestXmin );
426
+ if (vacrelstats -> nleft_dead_tuples > 0 ||
427
+ vacrelstats -> nleft_dead_itemids > 0 )
428
+ appendStringInfo (& buf ,
429
+ _ ("%.0f tuples and %.0f item identifiers are left as dead.\n" ),
430
+ vacrelstats -> nleft_dead_tuples ,
431
+ vacrelstats -> nleft_dead_itemids );
422
432
appendStringInfo (& buf ,
423
433
_ ("buffer usage: %d hits, %d misses, %d dirtied\n" ),
424
434
VacuumPageHit ,
@@ -485,7 +495,7 @@ vacuum_log_cleanup_info(Relation rel, LVRelStats *vacrelstats)
485
495
* reference them have been killed.
486
496
*/
487
497
static void
488
- lazy_scan_heap (Relation onerel , int options , LVRelStats * vacrelstats ,
498
+ lazy_scan_heap (Relation onerel , VacuumParams * params , LVRelStats * vacrelstats ,
489
499
Relation * Irel , int nindexes , bool aggressive )
490
500
{
491
501
BlockNumber nblocks ,
@@ -501,7 +511,10 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
501
511
live_tuples , /* live tuples (reltuples estimate) */
502
512
tups_vacuumed , /* tuples cleaned up by vacuum */
503
513
nkeep , /* dead-but-not-removable tuples */
504
- nunused ; /* unused item pointers */
514
+ nunused , /* unused item pointers */
515
+ nleft_dead_tuples , /* tuples we left as dead */
516
+ nleft_dead_itemids ; /* item pointers we left as dead,
517
+ * includes nleft_dead_tuples. */
505
518
IndexBulkDeleteResult * * indstats ;
506
519
int i ;
507
520
PGRUsage ru0 ;
@@ -534,6 +547,7 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
534
547
empty_pages = vacuumed_pages = 0 ;
535
548
next_fsm_block_to_vacuum = (BlockNumber ) 0 ;
536
549
num_tuples = live_tuples = tups_vacuumed = nkeep = nunused = 0 ;
550
+ nleft_dead_itemids = nleft_dead_tuples = 0 ;
537
551
538
552
indstats = (IndexBulkDeleteResult * * )
539
553
palloc0 (nindexes * sizeof (IndexBulkDeleteResult * ));
@@ -599,7 +613,7 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
599
613
* be replayed on any hot standby, where it can be disruptive.
600
614
*/
601
615
next_unskippable_block = 0 ;
602
- if ((options & VACOPT_DISABLE_PAGE_SKIPPING ) == 0 )
616
+ if ((params -> options & VACOPT_DISABLE_PAGE_SKIPPING ) == 0 )
603
617
{
604
618
while (next_unskippable_block < nblocks )
605
619
{
@@ -654,7 +668,7 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
654
668
{
655
669
/* Time to advance next_unskippable_block */
656
670
next_unskippable_block ++ ;
657
- if ((options & VACOPT_DISABLE_PAGE_SKIPPING ) == 0 )
671
+ if ((params -> options & VACOPT_DISABLE_PAGE_SKIPPING ) == 0 )
658
672
{
659
673
while (next_unskippable_block < nblocks )
660
674
{
@@ -1070,7 +1084,17 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
1070
1084
HeapTupleIsHeapOnly (& tuple ))
1071
1085
nkeep += 1 ;
1072
1086
else
1087
+ {
1073
1088
tupgone = true; /* we can delete the tuple */
1089
+
1090
+ /*
1091
+ * Since this dead tuple will not be vacuumed and
1092
+ * ignored when index cleanup is disabled we count
1093
+ * count it for reporting.
1094
+ */
1095
+ if (params -> index_cleanup == VACOPT_TERNARY_ENABLED )
1096
+ nleft_dead_tuples ++ ;
1097
+ }
1074
1098
all_visible = false;
1075
1099
break ;
1076
1100
case HEAPTUPLE_LIVE :
@@ -1222,23 +1246,40 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
1222
1246
}
1223
1247
1224
1248
/*
1225
- * If there are no indexes then we can vacuum the page right now
1226
- * instead of doing a second scan.
1249
+ * If there are no indexes we can vacuum the page right now instead of
1250
+ * doing a second scan. Also we don't do that but forget dead tuples
1251
+ * when index cleanup is disabled.
1227
1252
*/
1228
- if (nindexes == 0 &&
1229
- vacrelstats -> num_dead_tuples > 0 )
1253
+ if (!vacrelstats -> useindex && vacrelstats -> num_dead_tuples > 0 )
1230
1254
{
1231
- /* Remove tuples from heap */
1232
- lazy_vacuum_page (onerel , blkno , buf , 0 , vacrelstats , & vmbuffer );
1233
- has_dead_tuples = false;
1255
+ if (nindexes == 0 )
1256
+ {
1257
+ /* Remove tuples from heap if the table has no index */
1258
+ lazy_vacuum_page (onerel , blkno , buf , 0 , vacrelstats , & vmbuffer );
1259
+ vacuumed_pages ++ ;
1260
+ has_dead_tuples = false;
1261
+ }
1262
+ else
1263
+ {
1264
+ /*
1265
+ * Here, we have indexes but index cleanup is disabled. Instead of
1266
+ * vacuuming the dead tuples on the heap, we just forget them.
1267
+ *
1268
+ * Note that vacrelstats->dead_tuples could have tuples which
1269
+ * became dead after HOT-pruning but are not marked dead yet.
1270
+ * We do not process them because it's a very rare condition, and
1271
+ * the next vacuum will process them anyway.
1272
+ */
1273
+ Assert (params -> index_cleanup == VACOPT_TERNARY_DISABLED );
1274
+ nleft_dead_itemids += vacrelstats -> num_dead_tuples ;
1275
+ }
1234
1276
1235
1277
/*
1236
1278
* Forget the now-vacuumed tuples, and press on, but be careful
1237
1279
* not to reset latestRemovedXid since we want that value to be
1238
1280
* valid.
1239
1281
*/
1240
1282
vacrelstats -> num_dead_tuples = 0 ;
1241
- vacuumed_pages ++ ;
1242
1283
1243
1284
/*
1244
1285
* Periodically do incremental FSM vacuuming to make newly-freed
@@ -1357,14 +1398,21 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
1357
1398
RecordPageWithFreeSpace (onerel , blkno , freespace , nblocks );
1358
1399
}
1359
1400
1401
+ /* No dead tuples should be left if index cleanup is enabled */
1402
+ Assert ((params -> index_cleanup == VACOPT_TERNARY_ENABLED &&
1403
+ nleft_dead_tuples == 0 && nleft_dead_itemids == 0 ) ||
1404
+ params -> index_cleanup == VACOPT_TERNARY_DISABLED );
1405
+
1360
1406
/* report that everything is scanned and vacuumed */
1361
1407
pgstat_progress_update_param (PROGRESS_VACUUM_HEAP_BLKS_SCANNED , blkno );
1362
1408
1363
1409
pfree (frozen );
1364
1410
1365
1411
/* save stats for use later */
1366
1412
vacrelstats -> tuples_deleted = tups_vacuumed ;
1367
- vacrelstats -> new_dead_tuples = nkeep ;
1413
+ vacrelstats -> new_dead_tuples = nkeep + nleft_dead_tuples ;
1414
+ vacrelstats -> nleft_dead_tuples = nleft_dead_tuples ;
1415
+ vacrelstats -> nleft_dead_itemids = nleft_dead_itemids ;
1368
1416
1369
1417
/* now we can compute the new value for pg_class.reltuples */
1370
1418
vacrelstats -> new_live_tuples = vac_estimate_reltuples (onerel ,
@@ -1433,8 +1481,11 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
1433
1481
PROGRESS_VACUUM_PHASE_INDEX_CLEANUP );
1434
1482
1435
1483
/* Do post-vacuum cleanup and statistics update for each index */
1436
- for (i = 0 ; i < nindexes ; i ++ )
1437
- lazy_cleanup_index (Irel [i ], indstats [i ], vacrelstats );
1484
+ if (vacrelstats -> useindex )
1485
+ {
1486
+ for (i = 0 ; i < nindexes ; i ++ )
1487
+ lazy_cleanup_index (Irel [i ], indstats [i ], vacrelstats );
1488
+ }
1438
1489
1439
1490
/* If no indexes, make log report that lazy_vacuum_heap would've made */
1440
1491
if (vacuumed_pages )
@@ -1465,6 +1516,8 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
1465
1516
"%u pages are entirely empty.\n" ,
1466
1517
empty_pages ),
1467
1518
empty_pages );
1519
+ appendStringInfo (& buf , "%.0f tuples and %.0f item identifiers are left as dead.\n" ,
1520
+ nleft_dead_tuples , nleft_dead_itemids );
1468
1521
appendStringInfo (& buf , _ ("%s." ), pg_rusage_show (& ru0 ));
1469
1522
1470
1523
ereport (elevel ,
@@ -2110,7 +2163,7 @@ lazy_space_alloc(LVRelStats *vacrelstats, BlockNumber relblocks)
2110
2163
autovacuum_work_mem != -1 ?
2111
2164
autovacuum_work_mem : maintenance_work_mem ;
2112
2165
2113
- if (vacrelstats -> hasindex )
2166
+ if (vacrelstats -> useindex )
2114
2167
{
2115
2168
maxtuples = (vac_work_mem * 1024L ) / sizeof (ItemPointerData );
2116
2169
maxtuples = Min (maxtuples , INT_MAX );
0 commit comments