00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "postgres.h"
00022
00023 #include <math.h>
00024
00025 #include "access/clog.h"
00026 #include "access/genam.h"
00027 #include "access/heapam.h"
00028 #include "access/htup_details.h"
00029 #include "access/multixact.h"
00030 #include "access/transam.h"
00031 #include "access/xact.h"
00032 #include "catalog/namespace.h"
00033 #include "catalog/pg_database.h"
00034 #include "catalog/pg_namespace.h"
00035 #include "commands/cluster.h"
00036 #include "commands/vacuum.h"
00037 #include "miscadmin.h"
00038 #include "pgstat.h"
00039 #include "postmaster/autovacuum.h"
00040 #include "storage/bufmgr.h"
00041 #include "storage/lmgr.h"
00042 #include "storage/proc.h"
00043 #include "storage/procarray.h"
00044 #include "utils/acl.h"
00045 #include "utils/fmgroids.h"
00046 #include "utils/guc.h"
00047 #include "utils/memutils.h"
00048 #include "utils/snapmgr.h"
00049 #include "utils/syscache.h"
00050 #include "utils/tqual.h"
00051
00052
00053
00054
00055
00056 int vacuum_freeze_min_age;
00057 int vacuum_freeze_table_age;
00058
00059
00060
00061 static MemoryContext vac_context = NULL;
00062 static BufferAccessStrategy vac_strategy;
00063
00064
00065
00066 static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
00067 static void vac_truncate_clog(TransactionId frozenXID, MultiXactId frozenMulti);
00068 static bool vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast,
00069 bool for_wraparound);
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 void
00095 vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
00096 BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel)
00097 {
00098 const char *stmttype;
00099 volatile bool in_outer_xact,
00100 use_own_xacts;
00101 List *relations;
00102
00103
00104 Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE));
00105 Assert((vacstmt->options & VACOPT_VACUUM) ||
00106 !(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE)));
00107 Assert((vacstmt->options & VACOPT_ANALYZE) || vacstmt->va_cols == NIL);
00108
00109 stmttype = (vacstmt->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 if (vacstmt->options & VACOPT_VACUUM)
00120 {
00121 PreventTransactionChain(isTopLevel, stmttype);
00122 in_outer_xact = false;
00123 }
00124 else
00125 in_outer_xact = IsInTransactionChain(isTopLevel);
00126
00127
00128
00129
00130
00131 if ((vacstmt->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
00132 pgstat_vacuum_stat();
00133
00134
00135
00136
00137
00138
00139
00140 vac_context = AllocSetContextCreate(PortalContext,
00141 "Vacuum",
00142 ALLOCSET_DEFAULT_MINSIZE,
00143 ALLOCSET_DEFAULT_INITSIZE,
00144 ALLOCSET_DEFAULT_MAXSIZE);
00145
00146
00147
00148
00149
00150 if (bstrategy == NULL)
00151 {
00152 MemoryContext old_context = MemoryContextSwitchTo(vac_context);
00153
00154 bstrategy = GetAccessStrategy(BAS_VACUUM);
00155 MemoryContextSwitchTo(old_context);
00156 }
00157 vac_strategy = bstrategy;
00158
00159
00160
00161
00162
00163 relations = get_rel_oids(relid, vacstmt->relation);
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 if (vacstmt->options & VACOPT_VACUUM)
00180 use_own_xacts = true;
00181 else
00182 {
00183 Assert(vacstmt->options & VACOPT_ANALYZE);
00184 if (IsAutoVacuumWorkerProcess())
00185 use_own_xacts = true;
00186 else if (in_outer_xact)
00187 use_own_xacts = false;
00188 else if (list_length(relations) > 1)
00189 use_own_xacts = true;
00190 else
00191 use_own_xacts = false;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202 if (use_own_xacts)
00203 {
00204
00205 if (ActiveSnapshotSet())
00206 PopActiveSnapshot();
00207
00208
00209 CommitTransactionCommand();
00210 }
00211
00212
00213 PG_TRY();
00214 {
00215 ListCell *cur;
00216
00217 VacuumCostActive = (VacuumCostDelay > 0);
00218 VacuumCostBalance = 0;
00219 VacuumPageHit = 0;
00220 VacuumPageMiss = 0;
00221 VacuumPageDirty = 0;
00222
00223
00224
00225
00226 foreach(cur, relations)
00227 {
00228 Oid relid = lfirst_oid(cur);
00229
00230 if (vacstmt->options & VACOPT_VACUUM)
00231 {
00232 if (!vacuum_rel(relid, vacstmt, do_toast, for_wraparound))
00233 continue;
00234 }
00235
00236 if (vacstmt->options & VACOPT_ANALYZE)
00237 {
00238
00239
00240
00241
00242 if (use_own_xacts)
00243 {
00244 StartTransactionCommand();
00245
00246 PushActiveSnapshot(GetTransactionSnapshot());
00247 }
00248
00249 analyze_rel(relid, vacstmt, vac_strategy);
00250
00251 if (use_own_xacts)
00252 {
00253 PopActiveSnapshot();
00254 CommitTransactionCommand();
00255 }
00256 }
00257 }
00258 }
00259 PG_CATCH();
00260 {
00261
00262 VacuumCostActive = false;
00263 PG_RE_THROW();
00264 }
00265 PG_END_TRY();
00266
00267
00268 VacuumCostActive = false;
00269
00270
00271
00272
00273 if (use_own_xacts)
00274 {
00275
00276
00277
00278
00279
00280
00281 StartTransactionCommand();
00282 }
00283
00284 if ((vacstmt->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())
00285 {
00286
00287
00288
00289
00290 vac_update_datfrozenxid();
00291 }
00292
00293
00294
00295
00296
00297
00298 MemoryContextDelete(vac_context);
00299 vac_context = NULL;
00300 }
00301
00302
00303
00304
00305
00306
00307
00308 static List *
00309 get_rel_oids(Oid relid, const RangeVar *vacrel)
00310 {
00311 List *oid_list = NIL;
00312 MemoryContext oldcontext;
00313
00314
00315 if (OidIsValid(relid))
00316 {
00317 oldcontext = MemoryContextSwitchTo(vac_context);
00318 oid_list = lappend_oid(oid_list, relid);
00319 MemoryContextSwitchTo(oldcontext);
00320 }
00321 else if (vacrel)
00322 {
00323
00324 Oid relid;
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 relid = RangeVarGetRelid(vacrel, NoLock, false);
00336
00337
00338 oldcontext = MemoryContextSwitchTo(vac_context);
00339 oid_list = lappend_oid(oid_list, relid);
00340 MemoryContextSwitchTo(oldcontext);
00341 }
00342 else
00343 {
00344
00345
00346
00347
00348 Relation pgclass;
00349 HeapScanDesc scan;
00350 HeapTuple tuple;
00351
00352 pgclass = heap_open(RelationRelationId, AccessShareLock);
00353
00354 scan = heap_beginscan(pgclass, SnapshotNow, 0, NULL);
00355
00356 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
00357 {
00358 Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
00359
00360 if (classForm->relkind != RELKIND_RELATION &&
00361 classForm->relkind != RELKIND_MATVIEW)
00362 continue;
00363
00364
00365 oldcontext = MemoryContextSwitchTo(vac_context);
00366 oid_list = lappend_oid(oid_list, HeapTupleGetOid(tuple));
00367 MemoryContextSwitchTo(oldcontext);
00368 }
00369
00370 heap_endscan(scan);
00371 heap_close(pgclass, AccessShareLock);
00372 }
00373
00374 return oid_list;
00375 }
00376
00377
00378
00379
00380 void
00381 vacuum_set_xid_limits(int freeze_min_age,
00382 int freeze_table_age,
00383 bool sharedRel,
00384 TransactionId *oldestXmin,
00385 TransactionId *freezeLimit,
00386 TransactionId *freezeTableLimit,
00387 MultiXactId *multiXactFrzLimit)
00388 {
00389 int freezemin;
00390 TransactionId limit;
00391 TransactionId safeLimit;
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 *oldestXmin = GetOldestXmin(sharedRel, true);
00403
00404 Assert(TransactionIdIsNormal(*oldestXmin));
00405
00406
00407
00408
00409
00410
00411
00412 freezemin = freeze_min_age;
00413 if (freezemin < 0)
00414 freezemin = vacuum_freeze_min_age;
00415 freezemin = Min(freezemin, autovacuum_freeze_max_age / 2);
00416 Assert(freezemin >= 0);
00417
00418
00419
00420
00421 limit = *oldestXmin - freezemin;
00422 if (!TransactionIdIsNormal(limit))
00423 limit = FirstNormalTransactionId;
00424
00425
00426
00427
00428
00429
00430 safeLimit = ReadNewTransactionId() - autovacuum_freeze_max_age;
00431 if (!TransactionIdIsNormal(safeLimit))
00432 safeLimit = FirstNormalTransactionId;
00433
00434 if (TransactionIdPrecedes(limit, safeLimit))
00435 {
00436 ereport(WARNING,
00437 (errmsg("oldest xmin is far in the past"),
00438 errhint("Close open transactions soon to avoid wraparound problems.")));
00439 limit = *oldestXmin;
00440 }
00441
00442 *freezeLimit = limit;
00443
00444 if (freezeTableLimit != NULL)
00445 {
00446 int freezetable;
00447
00448
00449
00450
00451
00452
00453
00454
00455 freezetable = freeze_table_age;
00456 if (freezetable < 0)
00457 freezetable = vacuum_freeze_table_age;
00458 freezetable = Min(freezetable, autovacuum_freeze_max_age * 0.95);
00459 Assert(freezetable >= 0);
00460
00461
00462
00463
00464
00465 limit = ReadNewTransactionId() - freezetable;
00466 if (!TransactionIdIsNormal(limit))
00467 limit = FirstNormalTransactionId;
00468
00469 *freezeTableLimit = limit;
00470 }
00471
00472 if (multiXactFrzLimit != NULL)
00473 {
00474 MultiXactId mxLimit;
00475
00476
00477
00478
00479
00480 mxLimit = GetOldestMultiXactId() - freezemin;
00481 if (mxLimit < FirstMultiXactId)
00482 mxLimit = FirstMultiXactId;
00483
00484 *multiXactFrzLimit = mxLimit;
00485 }
00486 }
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500 double
00501 vac_estimate_reltuples(Relation relation, bool is_analyze,
00502 BlockNumber total_pages,
00503 BlockNumber scanned_pages,
00504 double scanned_tuples)
00505 {
00506 BlockNumber old_rel_pages = relation->rd_rel->relpages;
00507 double old_rel_tuples = relation->rd_rel->reltuples;
00508 double old_density;
00509 double new_density;
00510 double multiplier;
00511 double updated_density;
00512
00513
00514 if (scanned_pages >= total_pages)
00515 return scanned_tuples;
00516
00517
00518
00519
00520
00521
00522
00523 if (scanned_pages == 0)
00524 return old_rel_tuples;
00525
00526
00527
00528
00529
00530 if (old_rel_pages == 0)
00531 return floor((scanned_tuples / scanned_pages) * total_pages + 0.5);
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 old_density = old_rel_tuples / old_rel_pages;
00556 new_density = scanned_tuples / scanned_pages;
00557 multiplier = (double) scanned_pages / (double) total_pages;
00558 updated_density = old_density + (new_density - old_density) * multiplier;
00559 return floor(updated_density * total_pages + 0.5);
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 void
00593 vac_update_relstats(Relation relation,
00594 BlockNumber num_pages, double num_tuples,
00595 BlockNumber num_all_visible_pages,
00596 bool hasindex, TransactionId frozenxid,
00597 MultiXactId minmulti)
00598 {
00599 Oid relid = RelationGetRelid(relation);
00600 Relation rd;
00601 HeapTuple ctup;
00602 Form_pg_class pgcform;
00603 bool dirty;
00604
00605 rd = heap_open(RelationRelationId, RowExclusiveLock);
00606
00607
00608 ctup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
00609 if (!HeapTupleIsValid(ctup))
00610 elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
00611 relid);
00612 pgcform = (Form_pg_class) GETSTRUCT(ctup);
00613
00614
00615
00616 dirty = false;
00617 if (pgcform->relpages != (int32) num_pages)
00618 {
00619 pgcform->relpages = (int32) num_pages;
00620 dirty = true;
00621 }
00622 if (pgcform->reltuples != (float4) num_tuples)
00623 {
00624 pgcform->reltuples = (float4) num_tuples;
00625 dirty = true;
00626 }
00627 if (pgcform->relallvisible != (int32) num_all_visible_pages)
00628 {
00629 pgcform->relallvisible = (int32) num_all_visible_pages;
00630 dirty = true;
00631 }
00632 if (pgcform->relhasindex != hasindex)
00633 {
00634 pgcform->relhasindex = hasindex;
00635 dirty = true;
00636 }
00637
00638
00639
00640
00641
00642 if (pgcform->relhaspkey && !hasindex)
00643 {
00644 pgcform->relhaspkey = false;
00645 dirty = true;
00646 }
00647
00648
00649 if (pgcform->relhasrules && relation->rd_rules == NULL)
00650 {
00651 pgcform->relhasrules = false;
00652 dirty = true;
00653 }
00654 if (pgcform->relhastriggers && relation->trigdesc == NULL)
00655 {
00656 pgcform->relhastriggers = false;
00657 dirty = true;
00658 }
00659
00660
00661
00662
00663
00664 if (TransactionIdIsNormal(frozenxid) &&
00665 TransactionIdPrecedes(pgcform->relfrozenxid, frozenxid))
00666 {
00667 pgcform->relfrozenxid = frozenxid;
00668 dirty = true;
00669 }
00670
00671
00672 if (MultiXactIdIsValid(minmulti) &&
00673 MultiXactIdPrecedes(pgcform->relminmxid, minmulti))
00674 {
00675 pgcform->relminmxid = minmulti;
00676 dirty = true;
00677 }
00678
00679
00680 if (dirty)
00681 heap_inplace_update(rd, ctup);
00682
00683 heap_close(rd, RowExclusiveLock);
00684 }
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 void
00706 vac_update_datfrozenxid(void)
00707 {
00708 HeapTuple tuple;
00709 Form_pg_database dbform;
00710 Relation relation;
00711 SysScanDesc scan;
00712 HeapTuple classTup;
00713 TransactionId newFrozenXid;
00714 MultiXactId newFrozenMulti;
00715 bool dirty = false;
00716
00717
00718
00719
00720
00721
00722
00723 newFrozenXid = GetOldestXmin(true, true);
00724
00725
00726
00727
00728
00729 newFrozenMulti = GetOldestMultiXactId();
00730
00731
00732
00733
00734
00735 relation = heap_open(RelationRelationId, AccessShareLock);
00736
00737 scan = systable_beginscan(relation, InvalidOid, false,
00738 SnapshotNow, 0, NULL);
00739
00740 while ((classTup = systable_getnext(scan)) != NULL)
00741 {
00742 Form_pg_class classForm = (Form_pg_class) GETSTRUCT(classTup);
00743
00744
00745
00746
00747
00748 if (classForm->relkind != RELKIND_RELATION &&
00749 classForm->relkind != RELKIND_MATVIEW &&
00750 classForm->relkind != RELKIND_TOASTVALUE)
00751 continue;
00752
00753 Assert(TransactionIdIsNormal(classForm->relfrozenxid));
00754 Assert(MultiXactIdIsValid(classForm->relminmxid));
00755
00756 if (TransactionIdPrecedes(classForm->relfrozenxid, newFrozenXid))
00757 newFrozenXid = classForm->relfrozenxid;
00758
00759 if (MultiXactIdPrecedes(classForm->relminmxid, newFrozenMulti))
00760 newFrozenMulti = classForm->relminmxid;
00761 }
00762
00763
00764 systable_endscan(scan);
00765 heap_close(relation, AccessShareLock);
00766
00767 Assert(TransactionIdIsNormal(newFrozenXid));
00768 Assert(MultiXactIdIsValid(newFrozenMulti));
00769
00770
00771 relation = heap_open(DatabaseRelationId, RowExclusiveLock);
00772
00773
00774 tuple = SearchSysCacheCopy1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
00775 if (!HeapTupleIsValid(tuple))
00776 elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
00777 dbform = (Form_pg_database) GETSTRUCT(tuple);
00778
00779
00780
00781
00782
00783 if (TransactionIdPrecedes(dbform->datfrozenxid, newFrozenXid))
00784 {
00785 dbform->datfrozenxid = newFrozenXid;
00786 dirty = true;
00787 }
00788
00789
00790 if (MultiXactIdPrecedes(dbform->datminmxid, newFrozenMulti))
00791 {
00792 dbform->datminmxid = newFrozenMulti;
00793 dirty = true;
00794 }
00795
00796 if (dirty)
00797 heap_inplace_update(relation, tuple);
00798
00799 heap_freetuple(tuple);
00800 heap_close(relation, RowExclusiveLock);
00801
00802
00803
00804
00805
00806
00807 if (dirty || ForceTransactionIdLimitUpdate())
00808 vac_truncate_clog(newFrozenXid, newFrozenMulti);
00809 }
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826 static void
00827 vac_truncate_clog(TransactionId frozenXID, MultiXactId frozenMulti)
00828 {
00829 TransactionId myXID = GetCurrentTransactionId();
00830 Relation relation;
00831 HeapScanDesc scan;
00832 HeapTuple tuple;
00833 Oid oldestxid_datoid;
00834 Oid oldestmulti_datoid;
00835 bool frozenAlreadyWrapped = false;
00836
00837
00838 oldestxid_datoid = MyDatabaseId;
00839 oldestmulti_datoid = MyDatabaseId;
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853 relation = heap_open(DatabaseRelationId, AccessShareLock);
00854
00855 scan = heap_beginscan(relation, SnapshotNow, 0, NULL);
00856
00857 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
00858 {
00859 Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
00860
00861 Assert(TransactionIdIsNormal(dbform->datfrozenxid));
00862 Assert(MultiXactIdIsValid(dbform->datminmxid));
00863
00864 if (TransactionIdPrecedes(myXID, dbform->datfrozenxid))
00865 frozenAlreadyWrapped = true;
00866 else if (TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
00867 {
00868 frozenXID = dbform->datfrozenxid;
00869 oldestxid_datoid = HeapTupleGetOid(tuple);
00870 }
00871
00872 if (MultiXactIdPrecedes(dbform->datminmxid, frozenMulti))
00873 {
00874 frozenMulti = dbform->datminmxid;
00875 oldestmulti_datoid = HeapTupleGetOid(tuple);
00876 }
00877 }
00878
00879 heap_endscan(scan);
00880
00881 heap_close(relation, AccessShareLock);
00882
00883
00884
00885
00886
00887
00888
00889 if (frozenAlreadyWrapped)
00890 {
00891 ereport(WARNING,
00892 (errmsg("some databases have not been vacuumed in over 2 billion transactions"),
00893 errdetail("You might have already suffered transaction-wraparound data loss.")));
00894 return;
00895 }
00896
00897
00898 TruncateCLOG(frozenXID);
00899 TruncateMultiXact(frozenMulti);
00900
00901
00902
00903
00904
00905
00906
00907 SetTransactionIdLimit(frozenXID, oldestxid_datoid);
00908 MultiXactAdvanceOldest(frozenMulti, oldestmulti_datoid);
00909 }
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923 static bool
00924 vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
00925 {
00926 LOCKMODE lmode;
00927 Relation onerel;
00928 LockRelId onerelid;
00929 Oid toast_relid;
00930 Oid save_userid;
00931 int save_sec_context;
00932 int save_nestlevel;
00933
00934
00935 StartTransactionCommand();
00936
00937
00938
00939
00940
00941 PushActiveSnapshot(GetTransactionSnapshot());
00942
00943 if (!(vacstmt->options & VACOPT_FULL))
00944 {
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
00966 MyPgXact->vacuumFlags |= PROC_IN_VACUUM;
00967 if (for_wraparound)
00968 MyPgXact->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
00969 LWLockRelease(ProcArrayLock);
00970 }
00971
00972
00973
00974
00975
00976 CHECK_FOR_INTERRUPTS();
00977
00978
00979
00980
00981
00982
00983 lmode = (vacstmt->options & VACOPT_FULL) ? AccessExclusiveLock : ShareUpdateExclusiveLock;
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994 if (!(vacstmt->options & VACOPT_NOWAIT))
00995 onerel = try_relation_open(relid, lmode);
00996 else if (ConditionalLockRelationOid(relid, lmode))
00997 onerel = try_relation_open(relid, NoLock);
00998 else
00999 {
01000 onerel = NULL;
01001 if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
01002 ereport(LOG,
01003 (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
01004 errmsg("skipping vacuum of \"%s\" --- lock not available",
01005 vacstmt->relation->relname)));
01006 }
01007
01008 if (!onerel)
01009 {
01010 PopActiveSnapshot();
01011 CommitTransactionCommand();
01012 return false;
01013 }
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025 if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
01026 (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !onerel->rd_rel->relisshared)))
01027 {
01028 if (onerel->rd_rel->relisshared)
01029 ereport(WARNING,
01030 (errmsg("skipping \"%s\" --- only superuser can vacuum it",
01031 RelationGetRelationName(onerel))));
01032 else if (onerel->rd_rel->relnamespace == PG_CATALOG_NAMESPACE)
01033 ereport(WARNING,
01034 (errmsg("skipping \"%s\" --- only superuser or database owner can vacuum it",
01035 RelationGetRelationName(onerel))));
01036 else
01037 ereport(WARNING,
01038 (errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
01039 RelationGetRelationName(onerel))));
01040 relation_close(onerel, lmode);
01041 PopActiveSnapshot();
01042 CommitTransactionCommand();
01043 return false;
01044 }
01045
01046
01047
01048
01049
01050
01051 if (onerel->rd_rel->relkind != RELKIND_RELATION &&
01052 onerel->rd_rel->relkind != RELKIND_MATVIEW &&
01053 onerel->rd_rel->relkind != RELKIND_TOASTVALUE)
01054 {
01055 ereport(WARNING,
01056 (errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
01057 RelationGetRelationName(onerel))));
01058 relation_close(onerel, lmode);
01059 PopActiveSnapshot();
01060 CommitTransactionCommand();
01061 return false;
01062 }
01063
01064
01065
01066
01067
01068
01069
01070
01071 if (RELATION_IS_OTHER_TEMP(onerel))
01072 {
01073 relation_close(onerel, lmode);
01074 PopActiveSnapshot();
01075 CommitTransactionCommand();
01076 return false;
01077 }
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089 onerelid = onerel->rd_lockInfo.lockRelId;
01090 LockRelationIdForSession(&onerelid, lmode);
01091
01092
01093
01094
01095
01096
01097 if (do_toast && !(vacstmt->options & VACOPT_FULL))
01098 toast_relid = onerel->rd_rel->reltoastrelid;
01099 else
01100 toast_relid = InvalidOid;
01101
01102
01103
01104
01105
01106
01107
01108 GetUserIdAndSecContext(&save_userid, &save_sec_context);
01109 SetUserIdAndSecContext(onerel->rd_rel->relowner,
01110 save_sec_context | SECURITY_RESTRICTED_OPERATION);
01111 save_nestlevel = NewGUCNestLevel();
01112
01113
01114
01115
01116 if (vacstmt->options & VACOPT_FULL)
01117 {
01118
01119 relation_close(onerel, NoLock);
01120 onerel = NULL;
01121
01122
01123 cluster_rel(relid, InvalidOid, false,
01124 (vacstmt->options & VACOPT_VERBOSE) != 0,
01125 vacstmt->freeze_min_age, vacstmt->freeze_table_age);
01126 }
01127 else
01128 lazy_vacuum_rel(onerel, vacstmt, vac_strategy);
01129
01130
01131 AtEOXact_GUC(false, save_nestlevel);
01132
01133
01134 SetUserIdAndSecContext(save_userid, save_sec_context);
01135
01136
01137 if (onerel)
01138 relation_close(onerel, NoLock);
01139
01140
01141
01142
01143 PopActiveSnapshot();
01144 CommitTransactionCommand();
01145
01146
01147
01148
01149
01150
01151
01152
01153 if (toast_relid != InvalidOid)
01154 vacuum_rel(toast_relid, vacstmt, false, for_wraparound);
01155
01156
01157
01158
01159 UnlockRelationIdForSession(&onerelid, lmode);
01160
01161
01162 return true;
01163 }
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178 void
01179 vac_open_indexes(Relation relation, LOCKMODE lockmode,
01180 int *nindexes, Relation **Irel)
01181 {
01182 List *indexoidlist;
01183 ListCell *indexoidscan;
01184 int i;
01185
01186 Assert(lockmode != NoLock);
01187
01188 indexoidlist = RelationGetIndexList(relation);
01189
01190
01191 i = list_length(indexoidlist);
01192
01193 if (i > 0)
01194 *Irel = (Relation *) palloc(i * sizeof(Relation));
01195 else
01196 *Irel = NULL;
01197
01198
01199 i = 0;
01200 foreach(indexoidscan, indexoidlist)
01201 {
01202 Oid indexoid = lfirst_oid(indexoidscan);
01203 Relation indrel;
01204
01205 indrel = index_open(indexoid, lockmode);
01206 if (IndexIsReady(indrel->rd_index))
01207 (*Irel)[i++] = indrel;
01208 else
01209 index_close(indrel, lockmode);
01210 }
01211
01212 *nindexes = i;
01213
01214 list_free(indexoidlist);
01215 }
01216
01217
01218
01219
01220
01221 void
01222 vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode)
01223 {
01224 if (Irel == NULL)
01225 return;
01226
01227 while (nindexes--)
01228 {
01229 Relation ind = Irel[nindexes];
01230
01231 index_close(ind, lockmode);
01232 }
01233 pfree(Irel);
01234 }
01235
01236
01237
01238
01239
01240
01241
01242 void
01243 vacuum_delay_point(void)
01244 {
01245
01246 CHECK_FOR_INTERRUPTS();
01247
01248
01249 if (VacuumCostActive && !InterruptPending &&
01250 VacuumCostBalance >= VacuumCostLimit)
01251 {
01252 int msec;
01253
01254 msec = VacuumCostDelay * VacuumCostBalance / VacuumCostLimit;
01255 if (msec > VacuumCostDelay * 4)
01256 msec = VacuumCostDelay * 4;
01257
01258 pg_usleep(msec * 1000L);
01259
01260 VacuumCostBalance = 0;
01261
01262
01263 AutoVacuumUpdateDelay();
01264
01265
01266 CHECK_FOR_INTERRUPTS();
01267 }
01268 }