1. 27 Aug, 2021 2 commits
  2. 07 Aug, 2021 1 commit
  3. 21 Jun, 2021 1 commit
    • Peter Geoghegan's avatar
      Remove overzealous VACUUM failsafe assertions. · e8f201ab
      Peter Geoghegan authored
      The failsafe can trigger when index processing is already disabled.
      This can happen when VACUUM's INDEX_CLEANUP parameter is "off" and the
      failsafe happens to trigger.  Remove assertions that assume that index
      processing is directly tied to the failsafe.
      
      Oversight in commit c242baa4, which made it possible for the failsafe to
      trigger in a two-pass strategy VACUUM that has yet to make its first
      call to lazy_vacuum_all_indexes().
      e8f201ab
  4. 19 Jun, 2021 1 commit
    • Peter Geoghegan's avatar
      Support disabling index bypassing by VACUUM. · 3499df0d
      Peter Geoghegan authored
      Generalize the INDEX_CLEANUP VACUUM parameter (and the corresponding
      reloption): make it into a ternary style boolean parameter.  It now
      exposes a third option, "auto".  The "auto" option (which is now the
      default) enables the "bypass index vacuuming" optimization added by
      commit 1e55e7d1.
      
      "VACUUM (INDEX_CLEANUP TRUE)" is redefined to once again make VACUUM
      simply do any required index vacuuming, regardless of how few dead
      tuples are encountered during the first scan of the target heap relation
      (unless there are exactly zero).  This gives users a way of opting out
      of the "bypass index vacuuming" optimization, if for whatever reason
      that proves necessary.  It is also expected to be used by PostgreSQL
      developers as a testing option from time to time.
      
      "VACUUM (INDEX_CLEANUP FALSE)" does the same thing as it always has: it
      forcibly disables both index vacuuming and index cleanup.  It's not
      expected to be used much in PostgreSQL 14.  The failsafe mechanism added
      by commit 1e55e7d1 addresses the same problem in a simpler way.
      INDEX_CLEANUP can now be thought of as a testing and compatibility
      option.
      
      Author: Peter Geoghegan <pg@bowt.ie>
      Reviewed-By: default avatarMasahiko Sawada <sawada.mshk@gmail.com>
      Reviewed-By: default avatarJustin Pryzby <pryzby@telsasoft.com>
      Discussion: https://postgr.es/m/CAH2-WznrBoCST4_Gxh_G9hA8NzGUbeBGnOUC8FcXcrhqsv6OHQ@mail.gmail.com
      3499df0d
  5. 15 Jun, 2021 1 commit
    • Peter Geoghegan's avatar
      Remove unneeded field from VACUUM state. · 958cfbcf
      Peter Geoghegan authored
      Bugfix commit 5fc89376 effectively made the lock_waiter_detected field
      from vacuumlazy.c's global state struct into private state owned by
      lazy_truncate_heap().  Finish this off by replacing the struct field
      with a local variable.
      958cfbcf
  6. 03 Jun, 2021 1 commit
    • David Rowley's avatar
      Standardize usages of appendStringInfo and appendPQExpBuffer · f736e188
      David Rowley authored
      Fix a few places that were using appendStringInfo() when they should have
      been using appendStringInfoString().  Also some cases of
      appendPQExpBuffer() that would have been better suited to use
      appendPQExpBufferChar(), and finally, some places that used
      appendPQExpBuffer() when appendPQExpBufferStr() would have suited better.
      
      There are no bugs are being fixed here.  The aim is just to make the code
      use the most optimal function for the job.
      
      All the code being changed here is new to PG14.  It makes sense to fix
      these before we branch for PG15.  There are a few other places that we
      could fix, but those cases are older code so fixing those seems less
      worthwhile as it may cause unnecessary back-patching pain in the future.
      
      Author: Hou Zhijie
      Discussion: https://postgr.es/m/OS0PR01MB5716732158B1C4142C6FE375943D9@OS0PR01MB5716.jpnprd01.prod.outlook.com
      f736e188
  7. 28 May, 2021 1 commit
  8. 25 May, 2021 1 commit
  9. 13 May, 2021 1 commit
  10. 12 May, 2021 2 commits
  11. 06 May, 2021 1 commit
  12. 20 Apr, 2021 1 commit
    • Peter Geoghegan's avatar
      Document LP_DEAD accounting issues in VACUUM. · 7136bf34
      Peter Geoghegan authored
      Document VACUUM's soft assumption that any LP_DEAD items encountered
      during pruning will become LP_UNUSED items before VACUUM finishes up.
      This is integral to the accounting used by VACUUM to generate its final
      report on the table to the stats collector.  It also affects how VACUUM
      determines which heap pages are truncatable.  In both cases VACUUM is
      concerned with the likely contents of the page in the near future, not
      the current contents of the page.
      
      This state of affairs created the false impression that VACUUM's dead
      tuple accounting had significant difference with similar accounting used
      during ANALYZE.  There were and are no substantive differences, at least
      when the soft assumption completely works out.  This is far clearer now.
      
      Also document cases where things don't quite work out for VACUUM's dead
      tuple accounting.  It's possible that a significant number of LP_DEAD
      items will be left behind by VACUUM, and won't be recorded as remaining
      dead tuples in VACUUM's statistics collector report.  This behavior
      dates back to commit a96c41fe, which taught VACUUM to run without index
      and heap vacuuming at the user's request.  The failsafe mechanism added
      to VACUUM more recently by commit 1e55e7d1 takes the same approach to
      dead tuple accounting.
      Reported-By: default avatarMasahiko Sawada <sawada.mshk@gmail.com>
      Discussion: https://postgr.es/m/CAH2-Wz=Jmtu18PrsYq3EvvZJGOmZqSO2u3bvKpx9xJa5uhNp=Q@mail.gmail.com
      7136bf34
  13. 17 Apr, 2021 1 commit
  14. 13 Apr, 2021 1 commit
  15. 07 Apr, 2021 3 commits
    • Peter Geoghegan's avatar
      Teach VACUUM to bypass unnecessary index vacuuming. · 5100010e
      Peter Geoghegan authored
      VACUUM has never needed to call ambulkdelete() for each index in cases
      where there are precisely zero TIDs in its dead_tuples array by the end
      of its first pass over the heap (also its only pass over the heap in
      this scenario).  Index vacuuming is simply not required when this
      happens.  Index cleanup will still go ahead, but in practice most calls
      to amvacuumcleanup() are usually no-ops when there were zero preceding
      ambulkdelete() calls.  In short, VACUUM has generally managed to avoid
      index scans when there were clearly no index tuples to delete from
      indexes.  But cases with _close to_ no index tuples to delete were
      another matter -- a round of ambulkdelete() calls took place (one per
      index), each of which performed a full index scan.
      
      VACUUM now behaves just as if there were zero index tuples to delete in
      cases where there are in fact "virtually zero" such tuples.  That is, it
      can now bypass index vacuuming and heap vacuuming as an optimization
      (though not index cleanup).  Whether or not VACUUM bypasses indexes is
      determined dynamically, based on the just-observed number of heap pages
      in the table that have one or more LP_DEAD items (LP_DEAD items in heap
      pages have a 1:1 correspondence with index tuples that still need to be
      deleted from each index in the worst case).
      
      We only skip index vacuuming when 2% or less of the table's pages have
      one or more LP_DEAD items -- bypassing index vacuuming as an
      optimization must not noticeably impede setting bits in the visibility
      map.  As a further condition, the dead_tuples array (i.e. VACUUM's array
      of LP_DEAD item TIDs) must not exceed 32MB at the point that the first
      pass over the heap finishes, which is also when the decision to bypass
      is made.  (The VACUUM must also have been able to fit all TIDs in its
      maintenance_work_mem-bound dead_tuples space, though with a default
      maintenance_work_mem setting it can't matter.)
      
      This avoids surprising jumps in the duration and overhead of routine
      vacuuming with workloads where successive VACUUM operations consistently
      have almost zero dead index tuples.  The number of LP_DEAD items may
      well accumulate over multiple VACUUM operations, before finally the
      threshold is crossed and VACUUM performs conventional index vacuuming.
      Even then, the optimization will have avoided a great deal of largely
      unnecessary index vacuuming.
      
      In the future we may teach VACUUM to skip index vacuuming on a per-index
      basis, using a much more sophisticated approach.  For now we only
      consider the extreme cases, where we can be quite confident that index
      vacuuming just isn't worth it using simple heuristics.
      
      Also log information about how many heap pages have one or more LP_DEAD
      items when autovacuum logging is enabled.
      
      Author: Masahiko Sawada <sawada.mshk@gmail.com>
      Author: Peter Geoghegan <pg@bowt.ie>
      Discussion: https://postgr.es/m/CAD21AoD0SkE11fMw4jD4RENAwBMcw1wasVnwpJVw3tVqPOQgAw@mail.gmail.com
      Discussion: https://postgr.es/m/CAH2-WzmkebqPd4MVGuPTOS9bMFvp9MDs5cRTCOsv1rQJ3jCbXw@mail.gmail.com
      5100010e
    • Peter Geoghegan's avatar
      Add wraparound failsafe to VACUUM. · 1e55e7d1
      Peter Geoghegan authored
      Add a failsafe mechanism that is triggered by VACUUM when it notices
      that the table's relfrozenxid and/or relminmxid are dangerously far in
      the past.  VACUUM checks the age of the table dynamically, at regular
      intervals.
      
      When the failsafe triggers, VACUUM takes extraordinary measures to
      finish as quickly as possible so that relfrozenxid and/or relminmxid can
      be advanced.  VACUUM will stop applying any cost-based delay that may be
      in effect.  VACUUM will also bypass any further index vacuuming and heap
      vacuuming -- it only completes whatever remaining pruning and freezing
      is required.  Bypassing index/heap vacuuming is enabled by commit
      8523492d, which made it possible to dynamically trigger the mechanism
      already used within VACUUM when it is run with INDEX_CLEANUP off.
      
      It is expected that the failsafe will almost always trigger within an
      autovacuum to prevent wraparound, long after the autovacuum began.
      However, the failsafe mechanism can trigger in any VACUUM operation.
      Even in a non-aggressive VACUUM, where we're likely to not advance
      relfrozenxid, it still seems like a good idea to finish off remaining
      pruning and freezing.   An aggressive/anti-wraparound VACUUM will be
      launched immediately afterwards.  Note that the anti-wraparound VACUUM
      that follows will itself trigger the failsafe, usually before it even
      begins its first (and only) pass over the heap.
      
      The failsafe is controlled by two new GUCs: vacuum_failsafe_age, and
      vacuum_multixact_failsafe_age.  There are no equivalent reloptions,
      since that isn't expected to be useful.  The GUCs have rather high
      defaults (both default to 1.6 billion), and are expected to generally
      only be used to make the failsafe trigger sooner/more frequently.
      
      Author: Masahiko Sawada <sawada.mshk@gmail.com>
      Author: Peter Geoghegan <pg@bowt.ie>
      Discussion: https://postgr.es/m/CAD21AoD0SkE11fMw4jD4RENAwBMcw1wasVnwpJVw3tVqPOQgAw@mail.gmail.com
      Discussion: https://postgr.es/m/CAH2-WzmgH3ySGYeC-m-eOBsa2=sDwa292-CFghV4rESYo39FsQ@mail.gmail.com
      1e55e7d1
    • Peter Geoghegan's avatar
      Truncate line pointer array during VACUUM. · 3c3b8a4b
      Peter Geoghegan authored
      Teach VACUUM to truncate the line pointer array of each heap page when a
      contiguous group of LP_UNUSED line pointers appear at the end of the
      array -- these unused and unreferenced items are excluded.  This process
      occurs during VACUUM's second pass over the heap, right after LP_DEAD
      line pointers on the page (those encountered/pruned during the first
      pass) are marked LP_UNUSED.
      
      Truncation avoids line pointer bloat with certain workloads,
      particularly those involving continual range DELETEs and bulk INSERTs
      against the same table.
      
      Also harden heapam code to check for an out-of-range page offset number
      in places where we weren't already doing so.
      
      Author: Matthias van de Meent <boekewurm+postgres@gmail.com>
      Author: Peter Geoghegan <pg@bowt.ie>
      Reviewed-By: default avatarMasahiko Sawada <sawada.mshk@gmail.com>
      Reviewed-By: default avatarPeter Geoghegan <pg@bowt.ie>
      Discussion: https://postgr.es/m/CAEze2WjgaQc55Y5f5CQd3L=eS5CZcff2Obxp=O6pto8-f0hC4w@mail.gmail.com
      Discussion: https://postgr.es/m/CAH2-Wzn6a64PJM1Ggzm=uvx2otsopJMhFQj_g1rAj4GWr3ZSzw@mail.gmail.com
      3c3b8a4b
  16. 06 Apr, 2021 3 commits
    • Peter Geoghegan's avatar
      Remove tupgone special case from vacuumlazy.c. · 8523492d
      Peter Geoghegan authored
      Retry the call to heap_prune_page() in rare cases where there is
      disagreement between the heap_prune_page() call and the call to
      HeapTupleSatisfiesVacuum() that immediately follows.  Disagreement is
      possible when a concurrently-aborted transaction makes a tuple DEAD
      during the tiny window between each step.  This was the only case where
      a tuple considered DEAD by VACUUM still had storage following pruning.
      VACUUM's definition of dead tuples is now uniformly simple and
      unambiguous: dead tuples from each page are always LP_DEAD line pointers
      that were encountered just after we performed pruning (and just before
      we considered freezing remaining items with tuple storage).
      
      Eliminating the tupgone=true special case enables INDEX_CLEANUP=off
      style skipping of index vacuuming that takes place based on flexible,
      dynamic criteria.  The INDEX_CLEANUP=off case had to know about skipping
      indexes up-front before now, due to a subtle interaction with the
      special case (see commit dd695979) -- this was a special case unto
      itself.  Now there are no special cases.  And so now it won't matter
      when or how we decide to skip index vacuuming: it won't affect how
      pruning behaves, and it won't be affected by any of the implementation
      details of pruning or freezing.
      
      Also remove XLOG_HEAP2_CLEANUP_INFO records.  These are no longer
      necessary because we now rely entirely on heap pruning taking care of
      recovery conflicts.  There is no longer any need to generate recovery
      conflicts for DEAD tuples that pruning just missed.  This also means
      that heap vacuuming now uses exactly the same strategy for recovery
      conflicts as index vacuuming always has: REDO routines never need to
      process a latestRemovedXid from the WAL record, since earlier REDO of
      the WAL record from pruning is sufficient in all cases.  The generic
      XLOG_HEAP2_CLEAN record type is now split into two new record types to
      reflect this new division (these are called XLOG_HEAP2_PRUNE and
      XLOG_HEAP2_VACUUM).
      
      Also stop acquiring a super-exclusive lock for heap pages when they're
      vacuumed during VACUUM's second heap pass.  A regular exclusive lock is
      enough.  This is correct because heap page vacuuming is now strictly a
      matter of setting the LP_DEAD line pointers to LP_UNUSED.  No other
      backend can have a pointer to a tuple located in a pinned buffer that
      can be invalidated by a concurrent heap page vacuum operation.
      
      Heap vacuuming can now be thought of as conceptually similar to index
      vacuuming and conceptually dissimilar to heap pruning.  Heap pruning now
      has sole responsibility for anything involving the logical contents of
      the database (e.g., managing transaction status information, recovery
      conflicts, considering what to do with HOT chains).  Index vacuuming and
      heap vacuuming are now only concerned with recycling garbage items from
      physical data structures that back the logical database.
      
      Bump XLOG_PAGE_MAGIC due to pruning and heap page vacuum WAL record
      changes.
      
      Credit for the idea of retrying pruning a page to avoid the tupgone case
      goes to Andres Freund.
      
      Author: Peter Geoghegan <pg@bowt.ie>
      Reviewed-By: default avatarAndres Freund <andres@anarazel.de>
      Reviewed-By: default avatarMasahiko Sawada <sawada.mshk@gmail.com>
      Discussion: https://postgr.es/m/CAH2-WznneCXTzuFmcwx_EyRQgfsfJAAsu+CsqRFmFXCAar=nJw@mail.gmail.com
      8523492d
    • Peter Geoghegan's avatar
      Refactor lazy_scan_heap() loop. · 7ab96cf6
      Peter Geoghegan authored
      Add a lazy_scan_heap() subsidiary function that handles heap pruning and
      tuple freezing: lazy_scan_prune().  This is a great deal cleaner.  The
      code that remains in lazy_scan_heap()'s per-block loop can now be
      thought of as code that either comes before or after the call to
      lazy_scan_prune(), which is now the clear focal point.  This division is
      enforced by the way in which we now manage state.  lazy_scan_prune()
      outputs state (using its own struct) that describes what to do with the
      page following pruning and freezing (e.g., visibility map maintenance,
      recording free space in the FSM).  It doesn't get passed any special
      instructional state from the preamble code, though.
      
      Also cleanly separate the logic used by a VACUUM with INDEX_CLEANUP=off
      from the logic used by single-heap-pass VACUUMs.  The former case is now
      structured as the omission of index and heap vacuuming by a two pass
      VACUUM.  The latter case goes back to being used only when the table
      happens to have no indexes (just as it was before commit a96c41fe).
      This structure is much more natural, since the whole point of
      INDEX_CLEANUP=off is to skip the index and heap vacuuming that would
      otherwise take place.  The single-heap-pass case doesn't skip any useful
      work, though -- it just does heap pruning and heap vacuuming together
      when the table happens to have no indexes.
      
      Both of these changes are preparation for an upcoming patch that
      generalizes the mechanism used by INDEX_CLEANUP=off.  The later patch
      will allow VACUUM to give up on index and heap vacuuming dynamically, as
      problems emerge (e.g., with wraparound), so that an affected VACUUM
      operation can finish up as soon as possible.
      
      Also fix a very old bug in single-pass VACUUM VERBOSE output.  We were
      reporting the number of tuples deleted via pruning as a direct
      substitute for reporting the number of LP_DEAD items removed in a
      function that deals with the second pass over the heap.  But that
      doesn't work at all -- they're two different things.
      
      To fix, start tracking the total number of LP_DEAD items encountered
      during pruning, and use that in the report instead.  A single pass
      VACUUM will always vacuum away whatever LP_DEAD items a heap page has
      immediately after it is pruned, so the total number of LP_DEAD items
      encountered during pruning equals the total number vacuumed-away.
      (They are _not_ equal in the INDEX_CLEANUP=off case, but that's okay
      because skipping index vacuuming is now a totally orthogonal concept to
      one-pass VACUUM.)
      
      Also stop reporting the count of LP_UNUSED items in VACUUM VERBOSE
      output.  This makes the output of VACUUM VERBOSE more consistent with
      log_autovacuum's output (because it never showed information about
      LP_UNUSED items).  VACUUM VERBOSE reported LP_UNUSED items left behind
      by the last VACUUM, and LP_UNUSED items created via pruning HOT chains
      during the current VACUUM (it never included LP_UNUSED items left behind
      by the current VACUUM's second pass over the heap).  This makes it
      useless as an indicator of line pointer bloat, which must have been the
      original intention. (Like the first VACUUM VERBOSE issue, this issue was
      arguably an oversight in commit 282d2a03, which added the heap-only
      tuple optimization.)
      
      Finally, stop reporting empty_pages in VACUUM VERBOSE output, and start
      reporting pages_removed instead.  This also makes the output of VACUUM
      VERBOSE more consistent with log_autovacuum's output (which does not
      show empty_pages, but does show pages_removed).  An empty page isn't
      meaningfully different to a page that is almost empty, or a page that is
      empty but for only a small number of remaining LP_UNUSED items.
      
      Author: Peter Geoghegan <pg@bowt.ie>
      Reviewed-By: default avatarRobert Haas <robertmhaas@gmail.com>
      Reviewed-By: default avatarMasahiko Sawada <sawada.mshk@gmail.com>
      Discussion: https://postgr.es/m/CAH2-WznneCXTzuFmcwx_EyRQgfsfJAAsu+CsqRFmFXCAar=nJw@mail.gmail.com
      7ab96cf6
    • Peter Geoghegan's avatar
      Allocate access strategy in parallel VACUUM workers. · f6b8f19a
      Peter Geoghegan authored
      Commit 49f49def took entirely the wrong approach to fixing this issue.
      Just allocate a local buffer access strategy in each individual worker
      instead of trying to propagate state.  This state was never propagated
      by parallel VACUUM in the first place.
      
      It looks like the only reason that this worked following commit 40d964ec
      was that it involved static global variables, which are initialized to 0
      per the C standard.
      
      A more comprehensive fix may be necessary, even on HEAD.  This fix
      should at least get the buildfarm green once again.
      
      Thanks once again to Thomas Munro for continued off-list assistance with
      the issue.
      f6b8f19a
  17. 05 Apr, 2021 2 commits
    • Peter Geoghegan's avatar
      Propagate parallel VACUUM's buffer access strategy. · 49f49def
      Peter Geoghegan authored
      Parallel VACUUM relied on global variable state from the leader process
      being propagated to workers on fork().  Commit b4af70cb removed most
      uses of global variables inside vacuumlazy.c, but did not account for
      the buffer access strategy state.
      
      To fix, propagate the state through shared memory instead.
      
      Per buildfarm failures on elver, curculio, and morepork.
      
      Many thanks to Thomas Munro for off-list assistance with this issue.
      49f49def
    • Peter Geoghegan's avatar
      Simplify state managed by VACUUM. · b4af70cb
      Peter Geoghegan authored
      Reorganize the state struct used by VACUUM -- group related items
      together to make it easier to understand.  Also stop relying on stack
      variables inside lazy_scan_heap() -- move those into the state struct
      instead.  Doing things this way simplifies large groups of related
      functions whose function signatures had a lot of unnecessary redundancy.
      
      Switch over to using int64 for the struct fields used to count things
      that are reported to the user via log_autovacuum and VACUUM VERBOSE
      output.  We were using double, but that doesn't seem to have any
      advantages.  Using int64 makes it possible to add assertions that verify
      that the first pass over the heap (pruning) encounters precisely the
      same number of LP_DEAD items that get deleted from indexes later on, in
      the second pass over the heap.  These assertions will be added in later
      commits.
      
      Finally, adjust the signatures of functions with IndexBulkDeleteResult
      pointer arguments in cases where there was ambiguity about whether or
      not the argument relates to a single index or all indexes.  Functions
      now use the idiom that both ambulkdelete() and amvacuumcleanup() have
      always used (where appropriate): accept a mutable IndexBulkDeleteResult
      pointer argument, and return a result IndexBulkDeleteResult pointer to
      caller.
      
      Author: Peter Geoghegan <pg@bowt.ie>
      Reviewed-By: default avatarMasahiko Sawada <sawada.mshk@gmail.com>
      Reviewed-By: default avatarRobert Haas <robertmhaas@gmail.com>
      Discussion: https://postgr.es/m/CAH2-WzkeOSYwC6KNckbhk2b1aNnWum6Yyn0NKP9D-Hq1LGTDPw@mail.gmail.com
      b4af70cb
  18. 24 Mar, 2021 1 commit
  19. 23 Mar, 2021 1 commit
    • Michael Paquier's avatar
      Add per-index stats information in verbose logs of autovacuum · 5aed6a1f
      Michael Paquier authored
      Once a relation's autovacuum is completed, the logs include more
      information about this relation state if the threshold of
      log_autovacuum_min_duration (or its relation option) is reached, with
      for example contents about the statistics of the VACUUM operation for
      the relation, WAL and system usage.
      
      This commit adds more information about the statistics of the relation's
      indexes, with one line of logs generated for each index.  The index
      stats were already calculated, but not printed in the context of
      autovacuum yet.  While on it, some refactoring is done to keep track of
      the index statistics directly within LVRelStats, simplifying some
      routines related to parallel VACUUMs.
      
      Author: Masahiko Sawada
      Reviewed-by: Michael Paquier, Euler Taveira
      Discussion: https://postgr.es/m/CAD21AoAy6SxHiTivh5yAPJSUE4S=QRPpSZUdafOSz0R+fRcM6Q@mail.gmail.com
      5aed6a1f
  20. 16 Mar, 2021 1 commit
  21. 15 Mar, 2021 1 commit
    • Peter Geoghegan's avatar
      Notice that heap page has dead items during VACUUM. · 0ea71c93
      Peter Geoghegan authored
      Consistently set a flag variable that tracks whether the current heap
      page has a dead item during lazy vacuum's heap scan.  We missed the
      common case where there is an preexisting (or even a new) LP_DEAD heap
      line pointer.
      
      Also make it clear that the variable might be affected by an existing
      line pointer, say from an earlier opportunistic pruning operation.  This
      distinction is important because it's the main reason why we can't just
      use the nearby tups_vacuumed variable instead.
      
      No backpatch.  In theory failing to set the page level flag variable had
      no consequences.  Currently it is only used to defensively check if a
      page marked all visible has dead items, which should never happen anyway
      (if it does then the table must be corrupt).
      
      Author: Masahiko Sawada <sawada.mshk@gmail.com>
      Diagnosed-By: default avatarMasahiko Sawada <sawada.mshk@gmail.com>
      Discussion: https://postgr.es/m/CAD21AoAtZb4+HJT_8RoOXvu4HM-Zd4HKS3YSMCH6+-W=bDyh-w@mail.gmail.com
      0ea71c93
  22. 11 Mar, 2021 1 commit
    • Peter Geoghegan's avatar
      VACUUM ANALYZE: Always update pg_class.reltuples. · 5f8727f5
      Peter Geoghegan authored
      vacuumlazy.c sometimes fails to update pg_class entries for each index
      (to ensure that pg_class.reltuples is current), even though analyze.c
      assumed that that must have happened during VACUUM ANALYZE.  There are
      at least a couple of reasons for this.  For example, vacuumlazy.c could
      fail to update pg_class when the index AM indicated that its statistics
      are merely an estimate, per the contract for amvacuumcleanup() routines
      established by commit e5734597 back in 2006.
      
      Stop assuming that pg_class must have been updated with accurate
      statistics within VACUUM ANALYZE -- update pg_class for indexes at the
      same time as the table relation in all cases.  That way VACUUM ANALYZE
      will never fail to keep pg_class.reltuples reasonably accurate.
      
      The only downside of this approach (compared to the old approach) is
      that it might inaccurately set pg_class.reltuples for indexes whose heap
      relation ends up with the same inaccurate value anyway.  This doesn't
      seem too bad.  We already consistently called vac_update_relstats() (to
      update pg_class) for the heap/table relation twice during any VACUUM
      ANALYZE -- once in vacuumlazy.c, and once in analyze.c.  We now make
      sure that we call vac_update_relstats() at least once (though often
      twice) for each index.
      
      This is follow up work to commit 9f3665fb, which dealt with issues in
      btvacuumcleanup().  Technically this fixes an unrelated issue, though.
      btvacuumcleanup() no longer provides an accurate num_index_tuples value
      following commit 9f3665fb (when there was no btbulkdelete() call during
      the VACUUM operation in question), but hashvacuumcleanup() has worked in
      the same way for many years now.
      
      Author: Peter Geoghegan <pg@bowt.ie>
      Reviewed-By: default avatarMasahiko Sawada <sawada.mshk@gmail.com>
      Discussion: https://postgr.es/m/CAH2-WzknxdComjhqo4SUxVFk_Q1171GJO2ZgHZ1Y6pion6u8rA@mail.gmail.com
      Backpatch: 13-, just like commit 9f3665fb.
      5f8727f5
  23. 10 Mar, 2021 1 commit
  24. 25 Feb, 2021 1 commit
    • Peter Geoghegan's avatar
      VACUUM VERBOSE: Count "newly deleted" index pages. · 23763618
      Peter Geoghegan authored
      Teach VACUUM VERBOSE to report on pages deleted by the _current_ VACUUM
      operation -- these are newly deleted pages.  VACUUM VERBOSE continues to
      report on the total number of deleted pages in the entire index (no
      change there).  The former is a subset of the latter.
      
      The distinction between each category of deleted index page only arises
      with index AMs where page deletion is supported and is decoupled from
      page recycling for performance reasons.
      
      This is follow-up work to commit e5d8a999, which made nbtree store
      64-bit XIDs (not 32-bit XIDs) in pages at the point at which they're
      deleted.  Note that the btm_last_cleanup_num_delpages metapage field
      added by that commit usually gets set to pages_newly_deleted.  The
      exceptions (the scenarios in which they're not equal) all seem to be
      tricky cases for the implementation (of page deletion and recycling) in
      general.
      
      Author: Peter Geoghegan <pg@bowt.ie>
      Discussion: https://postgr.es/m/CAH2-WznpdHvujGUwYZ8sihX%3Dd5u-tRYhi-F4wnV2uN2zHpMUXw%40mail.gmail.com
      23763618
  25. 16 Feb, 2021 1 commit
  26. 15 Feb, 2021 1 commit
  27. 02 Jan, 2021 1 commit
  28. 07 Nov, 2020 1 commit
  29. 31 Oct, 2020 1 commit
  30. 29 Oct, 2020 1 commit
    • Andres Freund's avatar
      Centralize horizon determination for temp tables, fixing bug due to skew. · 94bc27b5
      Andres Freund authored
      This fixes a bug in the edge case where, for a temp table, heap_page_prune()
      can end up with a different horizon than heap_vacuum_rel(). Which can trigger
      errors like "ERROR: cannot freeze committed xmax ...".
      
      The bug was introduced due to interaction of a7212be8 "Set cutoff xmin more
      aggressively when vacuuming a temporary table." with dc7420c2 "snapshot
      scalability: Don't compute global horizons while building snapshots.".
      
      The problem is caused by lazy_scan_heap() assuming that the only reason its
      HeapTupleSatisfiesVacuum() call would return HEAPTUPLE_DEAD is if the tuple is
      a HOT tuple, or if the tuple's inserting transaction has aborted since the
      heap_page_prune() call. But after a7212be8 that was also possible in other
      cases for temp tables, because heap_page_prune() uses a different visibility
      test after dc7420c2.
      
      The fix is fairly simple: Move the special case logic for temp tables from
      vacuum_set_xid_limits() to the infrastructure introduced in dc7420c2. That
      ensures that the horizon used for pruning is at least as aggressive as the one
      used by lazy_scan_heap(). The concrete horizon used for temp tables is
      slightly different than the logic in dc7420c2, but should always be as
      aggressive as before (see comments).
      
      A significant benefit to centralizing the logic procarray.c is that now the
      more aggressive horizons for temp tables does not just apply to VACUUM but
      also to e.g. HOT pruning and the nbtree killtuples logic.
      
      Because isTopLevel is not needed by vacuum_set_xid_limits() anymore, I
      undid the the related changes from a7212be8.
      
      This commit also adds an isolation test ensuring that the more aggressive
      vacuuming and pruning of temp tables keeps working.
      Debugged-By: default avatarAmit Kapila <amit.kapila16@gmail.com>
      Debugged-By: default avatarTom Lane <tgl@sss.pgh.pa.us>
      Debugged-By: default avatarAshutosh Sharma <ashu.coek88@gmail.com>
      Author: Andres Freund <andres@anarazel.de>
      Discussion: https://postgr.es/m/20201014203103.72oke6hqywcyhx7s@alap3.anarazel.de
      Discussion: https://postgr.es/m/20201015083735.derdzysdtqdvxshp@alap3.anarazel.de
      94bc27b5
  31. 14 Sep, 2020 1 commit
  32. 01 Sep, 2020 1 commit
    • Tom Lane's avatar
      Set cutoff xmin more aggressively when vacuuming a temporary table. · a7212be8
      Tom Lane authored
      Since other sessions aren't allowed to look into a temporary table
      of our own session, we do not need to worry about the global xmin
      horizon when setting the vacuum XID cutoff.  Indeed, if we're not
      inside a transaction block, we may set oldestXmin to be the next
      XID, because there cannot be any in-doubt tuples in a temp table,
      nor any tuples that are dead but still visible to some snapshot of
      our transaction.  (VACUUM, of course, is never inside a transaction
      block; but we need to test that because CLUSTER shares the same code.)
      
      This approach allows us to always clean out a temp table completely
      during VACUUM, independently of concurrent activity.  Aside from
      being useful in its own right, that simplifies building reproducible
      test cases.
      
      Discussion: https://postgr.es/m/3490536.1598629609@sss.pgh.pa.us
      a7212be8
  33. 30 Aug, 2020 1 commit
    • Tom Lane's avatar
      Redefine pg_class.reltuples to be -1 before the first VACUUM or ANALYZE. · 3d351d91
      Tom Lane authored
      Historically, we've considered the state with relpages and reltuples
      both zero as indicating that we do not know the table's tuple density.
      This is problematic because it's impossible to distinguish "never yet
      vacuumed" from "vacuumed and seen to be empty".  In particular, a user
      cannot use VACUUM or ANALYZE to override the planner's normal heuristic
      that an empty table should not be believed to be empty because it is
      probably about to get populated.  That heuristic is a good safety
      measure, so I don't care to abandon it, but there should be a way to
      override it if the table is indeed intended to stay empty.
      
      Hence, represent the initial state of ignorance by setting reltuples
      to -1 (relpages is still set to zero), and apply the minimum-ten-pages
      heuristic only when reltuples is still -1.  If the table is empty,
      VACUUM or ANALYZE (but not CREATE INDEX) will override that to
      reltuples = relpages = 0, and then we'll plan on that basis.
      
      This requires a bunch of fiddly little changes, but we can get rid of
      some ugly kluges that were formerly needed to maintain the old definition.
      
      One notable point is that FDWs' GetForeignRelSize methods will see
      baserel->tuples = -1 when no ANALYZE has been done on the foreign table.
      That seems like a net improvement, since those methods were formerly
      also in the dark about what baserel->tuples = 0 really meant.  Still,
      it is an API change.
      
      I bumped catversion because code predating this change would get confused
      by seeing reltuples = -1.
      
      Discussion: https://postgr.es/m/F02298E0-6EF4-49A1-BCB6-C484794D9ACC@thebuild.com
      3d351d91