10
10
*
11
11
*
12
12
* IDENTIFICATION
13
- * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.3 2005/08/11 21:11:44 tgl Exp $
13
+ * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.4 2005/08/15 16:25:17 tgl Exp $
14
14
*
15
15
*-------------------------------------------------------------------------
16
16
*/
17
17
#include "postgres.h"
18
18
19
19
#include <signal.h>
20
- #include <time.h>
21
20
#include <sys/types.h>
21
+ #include <time.h>
22
22
#include <unistd.h>
23
23
24
24
#include "access/genam.h"
@@ -86,6 +86,7 @@ typedef struct autovac_dbase
86
86
typedef struct autovac_table
87
87
{
88
88
Oid relid ;
89
+ Oid toastrelid ;
89
90
bool dovacuum ;
90
91
bool doanalyze ;
91
92
int vacuum_cost_delay ;
@@ -101,8 +102,10 @@ static void process_whole_db(void);
101
102
static void do_autovacuum (PgStat_StatDBEntry * dbentry );
102
103
static List * autovac_get_database_list (void );
103
104
static void test_rel_for_autovac (Oid relid , PgStat_StatTabEntry * tabentry ,
104
- Form_pg_class classForm , Form_pg_autovacuum avForm ,
105
- List * * vacuum_tables );
105
+ Form_pg_class classForm ,
106
+ Form_pg_autovacuum avForm ,
107
+ List * * vacuum_tables ,
108
+ List * * toast_table_ids );
106
109
static void autovacuum_do_vac_analyze (List * relids , bool dovacuum ,
107
110
bool doanalyze , bool freeze );
108
111
@@ -386,12 +389,21 @@ AutoVacMain(int argc, char *argv[])
386
389
387
390
if (db )
388
391
{
392
+ /*
393
+ * Report autovac startup to the stats collector. We deliberately
394
+ * do this before InitPostgres, so that the last_autovac_time will
395
+ * get updated even if the connection attempt fails. This is to
396
+ * prevent autovac from getting "stuck" repeatedly selecting an
397
+ * unopenable database, rather than making any progress on stuff
398
+ * it can connect to.
399
+ */
400
+ pgstat_report_autovac (db -> oid );
401
+
389
402
/*
390
403
* Connect to the selected database
391
404
*/
392
405
InitPostgres (db -> name , NULL );
393
406
SetProcessingMode (NormalProcessing );
394
- pgstat_report_autovac ();
395
407
set_ps_display (db -> name );
396
408
ereport (LOG ,
397
409
(errmsg ("autovacuum: processing database \"%s\"" , db -> name )));
@@ -538,6 +550,7 @@ do_autovacuum(PgStat_StatDBEntry *dbentry)
538
550
HeapTuple tuple ;
539
551
HeapScanDesc relScan ;
540
552
List * vacuum_tables = NIL ;
553
+ List * toast_table_ids = NIL ;
541
554
ListCell * cell ;
542
555
PgStat_StatDBEntry * shared ;
543
556
@@ -558,9 +571,25 @@ do_autovacuum(PgStat_StatDBEntry *dbentry)
558
571
classRel = heap_open (RelationRelationId , AccessShareLock );
559
572
avRel = heap_open (AutovacuumRelationId , AccessShareLock );
560
573
574
+ /*
575
+ * Scan pg_class and determine which tables to vacuum.
576
+ *
577
+ * The stats subsystem collects stats for toast tables independently
578
+ * of the stats for their parent tables. We need to check those stats
579
+ * since in cases with short, wide tables there might be proportionally
580
+ * much more activity in the toast table than in its parent.
581
+ *
582
+ * Since we can only issue VACUUM against the parent table, we need to
583
+ * transpose a decision to vacuum a toast table into a decision to vacuum
584
+ * its parent. There's no point in considering ANALYZE on a toast table,
585
+ * either. To support this, we keep a list of OIDs of toast tables that
586
+ * need vacuuming alongside the list of regular tables. Regular tables
587
+ * will be entered into the table list even if they appear not to need
588
+ * vacuuming; we go back and re-mark them after finding all the
589
+ * vacuumable toast tables.
590
+ */
561
591
relScan = heap_beginscan (classRel , SnapshotNow , 0 , NULL );
562
592
563
- /* Scan pg_class looking for tables to vacuum */
564
593
while ((tuple = heap_getnext (relScan , ForwardScanDirection )) != NULL )
565
594
{
566
595
Form_pg_class classForm = (Form_pg_class ) GETSTRUCT (tuple );
@@ -571,9 +600,9 @@ do_autovacuum(PgStat_StatDBEntry *dbentry)
571
600
ScanKeyData entry [1 ];
572
601
Oid relid ;
573
602
574
- /* Skip non-table entries . */
575
- /* XXX possibly allow RELKIND_TOASTVALUE entries here too? */
576
- if ( classForm -> relkind != RELKIND_RELATION )
603
+ /* Consider only regular and toast tables . */
604
+ if ( classForm -> relkind != RELKIND_RELATION &&
605
+ classForm -> relkind != RELKIND_TOASTVALUE )
577
606
continue ;
578
607
579
608
/*
@@ -607,7 +636,7 @@ do_autovacuum(PgStat_StatDBEntry *dbentry)
607
636
HASH_FIND , NULL );
608
637
609
638
test_rel_for_autovac (relid , tabentry , classForm , avForm ,
610
- & vacuum_tables );
639
+ & vacuum_tables , & toast_table_ids );
611
640
612
641
systable_endscan (avScan );
613
642
}
@@ -625,6 +654,22 @@ do_autovacuum(PgStat_StatDBEntry *dbentry)
625
654
626
655
CHECK_FOR_INTERRUPTS ();
627
656
657
+ /*
658
+ * Check to see if we need to force vacuuming of this table because
659
+ * its toast table needs it.
660
+ */
661
+ if (OidIsValid (tab -> toastrelid ) && !tab -> dovacuum &&
662
+ list_member_oid (toast_table_ids , tab -> toastrelid ))
663
+ {
664
+ tab -> dovacuum = true;
665
+ elog (DEBUG2 , "autovac: VACUUM %u because of TOAST table" ,
666
+ tab -> relid );
667
+ }
668
+
669
+ /* Otherwise, ignore table if it needs no work */
670
+ if (!tab -> dovacuum && !tab -> doanalyze )
671
+ continue ;
672
+
628
673
/* Set the vacuum cost parameters for this table */
629
674
VacuumCostDelay = tab -> vacuum_cost_delay ;
630
675
VacuumCostLimit = tab -> vacuum_cost_limit ;
@@ -643,7 +688,7 @@ do_autovacuum(PgStat_StatDBEntry *dbentry)
643
688
* test_rel_for_autovac
644
689
*
645
690
* Check whether a table needs to be vacuumed or analyzed. Add it to the
646
- * output list if so.
691
+ * appropriate output list if so.
647
692
*
648
693
* A table needs to be vacuumed if the number of dead tuples exceeds a
649
694
* threshold. This threshold is calculated as
@@ -670,7 +715,8 @@ static void
670
715
test_rel_for_autovac (Oid relid , PgStat_StatTabEntry * tabentry ,
671
716
Form_pg_class classForm ,
672
717
Form_pg_autovacuum avForm ,
673
- List * * vacuum_tables )
718
+ List * * vacuum_tables ,
719
+ List * * toast_table_ids )
674
720
{
675
721
Relation rel ;
676
722
float4 reltuples ; /* pg_class.reltuples */
@@ -764,12 +810,10 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
764
810
* will be reset too.
765
811
*/
766
812
767
- elog (DEBUG2 , "%s: vac: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)" ,
813
+ elog (DEBUG3 , "%s: vac: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)" ,
768
814
RelationGetRelationName (rel ),
769
815
vactuples , vacthresh , anltuples , anlthresh );
770
816
771
- Assert (CurrentMemoryContext == AutovacMemCxt );
772
-
773
817
/* Determine if this table needs vacuum or analyze. */
774
818
dovacuum = (vactuples > vacthresh );
775
819
doanalyze = (anltuples > anlthresh );
@@ -778,23 +822,40 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
778
822
if (relid == StatisticRelationId )
779
823
doanalyze = false;
780
824
781
- if (dovacuum || doanalyze )
825
+ Assert (CurrentMemoryContext == AutovacMemCxt );
826
+
827
+ if (classForm -> relkind == RELKIND_RELATION )
782
828
{
783
- autovac_table * tab ;
829
+ if (dovacuum || doanalyze )
830
+ elog (DEBUG2 , "autovac: will%s%s %s" ,
831
+ (dovacuum ? " VACUUM" : "" ),
832
+ (doanalyze ? " ANALYZE" : "" ),
833
+ RelationGetRelationName (rel ));
784
834
785
- elog (DEBUG2 , "will%s%s %s" ,
786
- (dovacuum ? " VACUUM" : "" ),
787
- (doanalyze ? " ANALYZE" : "" ),
788
- RelationGetRelationName (rel ));
835
+ /*
836
+ * we must record tables that have a toast table, even if we currently
837
+ * don't think they need vacuuming.
838
+ */
839
+ if (dovacuum || doanalyze || OidIsValid (classForm -> reltoastrelid ))
840
+ {
841
+ autovac_table * tab ;
789
842
790
- tab = (autovac_table * ) palloc (sizeof (autovac_table ));
791
- tab -> relid = relid ;
792
- tab -> dovacuum = dovacuum ;
793
- tab -> doanalyze = doanalyze ;
794
- tab -> vacuum_cost_limit = vac_cost_limit ;
795
- tab -> vacuum_cost_delay = vac_cost_delay ;
843
+ tab = (autovac_table * ) palloc (sizeof (autovac_table ));
844
+ tab -> relid = relid ;
845
+ tab -> toastrelid = classForm -> reltoastrelid ;
846
+ tab -> dovacuum = dovacuum ;
847
+ tab -> doanalyze = doanalyze ;
848
+ tab -> vacuum_cost_limit = vac_cost_limit ;
849
+ tab -> vacuum_cost_delay = vac_cost_delay ;
796
850
797
- * vacuum_tables = lappend (* vacuum_tables , tab );
851
+ * vacuum_tables = lappend (* vacuum_tables , tab );
852
+ }
853
+ }
854
+ else
855
+ {
856
+ Assert (classForm -> relkind == RELKIND_TOASTVALUE );
857
+ if (dovacuum )
858
+ * toast_table_ids = lappend_oid (* toast_table_ids , relid );
798
859
}
799
860
800
861
RelationClose (rel );
0 commit comments