Tom Lane wrote:
> Alvaro Herrera <[EMAIL PROTECTED]> writes:
> > Tom Lane wrote:
> >> But the patch changes things so that *everyone* excludes the vacuum from
> >> their xmin.  Or at least I thought that was the plan.
> 
> > We shouldn't do that, because that Xmin is also used to truncate
> > SUBTRANS.
> 
> Yeah, but you were going to change that, no?  Truncating SUBTRANS will
> need to include the vacuum xact's xmin, but we don't need it for any
> other purpose.

That's correct.

> > but it means
> > lazy vacuum will never be able to use subtransactions.
> 
> This patch already depends on the assumption that lazy vacuum will never
> do any transactional updates, so I don't see what it would need
> subtransactions for.

Here is a patch pursuant to there ideas.  The main change is that in
GetSnapshotData, a backend is skipped entirely if inVacuum is found to
be true.

I've been trying to update my SSH CVS several times today but I can't
reach the server.  Maybe it's the DoS attach that it's been under, I
don't know.

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Index: src/backend/access/transam/twophase.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/access/transam/twophase.c,v
retrieving revision 1.21
diff -c -p -r1.21 twophase.c
*** src/backend/access/transam/twophase.c       14 Jul 2006 14:52:17 -0000      
1.21
--- src/backend/access/transam/twophase.c       28 Jul 2006 21:59:42 -0000
*************** MarkAsPreparing(TransactionId xid, const
*** 279,284 ****
--- 279,285 ----
        gxact->proc.pid = 0;
        gxact->proc.databaseId = databaseid;
        gxact->proc.roleId = owner;
+       gxact->proc.inVacuum = false;
        gxact->proc.lwWaiting = false;
        gxact->proc.lwExclusive = false;
        gxact->proc.lwWaitLink = NULL;
Index: src/backend/access/transam/xact.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/access/transam/xact.c,v
retrieving revision 1.224
diff -c -p -r1.224 xact.c
*** src/backend/access/transam/xact.c   24 Jul 2006 16:32:44 -0000      1.224
--- src/backend/access/transam/xact.c   28 Jul 2006 21:59:42 -0000
*************** CommitTransaction(void)
*** 1529,1534 ****
--- 1529,1535 ----
                LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
                MyProc->xid = InvalidTransactionId;
                MyProc->xmin = InvalidTransactionId;
+               MyProc->inVacuum = false;       /* must be cleared with 
xid/xmin */
  
                /* Clear the subtransaction-XID cache too while holding the 
lock */
                MyProc->subxids.nxids = 0;
*************** PrepareTransaction(void)
*** 1764,1769 ****
--- 1765,1771 ----
        LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
        MyProc->xid = InvalidTransactionId;
        MyProc->xmin = InvalidTransactionId;
+       MyProc->inVacuum = false;       /* must be cleared with xid/xmin */
  
        /* Clear the subtransaction-XID cache too while holding the lock */
        MyProc->subxids.nxids = 0;
*************** AbortTransaction(void)
*** 1927,1932 ****
--- 1929,1935 ----
                LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
                MyProc->xid = InvalidTransactionId;
                MyProc->xmin = InvalidTransactionId;
+               MyProc->inVacuum = false;       /* must be cleared with 
xid/xmin */
  
                /* Clear the subtransaction-XID cache too while holding the 
lock */
                MyProc->subxids.nxids = 0;
Index: src/backend/access/transam/xlog.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/access/transam/xlog.c,v
retrieving revision 1.244
diff -c -p -r1.244 xlog.c
*** src/backend/access/transam/xlog.c   14 Jul 2006 14:52:17 -0000      1.244
--- src/backend/access/transam/xlog.c   28 Jul 2006 21:59:42 -0000
*************** CreateCheckPoint(bool shutdown, bool for
*** 5413,5419 ****
         * StartupSUBTRANS hasn't been called yet.
         */
        if (!InRecovery)
!               TruncateSUBTRANS(GetOldestXmin(true));
  
        if (!shutdown)
                ereport(DEBUG2,
--- 5413,5419 ----
         * StartupSUBTRANS hasn't been called yet.
         */
        if (!InRecovery)
!               TruncateSUBTRANS(GetOldestXmin(true, false));
  
        if (!shutdown)
                ereport(DEBUG2,
Index: src/backend/catalog/index.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/index.c,v
retrieving revision 1.269
diff -c -p -r1.269 index.c
*** src/backend/catalog/index.c 13 Jul 2006 16:49:13 -0000      1.269
--- src/backend/catalog/index.c 28 Jul 2006 21:59:42 -0000
*************** IndexBuildHeapScan(Relation heapRelation
*** 1367,1373 ****
        else
        {
                snapshot = SnapshotAny;
!               OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared);
        }
  
        scan = heap_beginscan(heapRelation, /* relation */
--- 1367,1374 ----
        else
        {
                snapshot = SnapshotAny;
!               /* okay to ignore lazy VACUUMs here */
!               OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared, 
true);
        }
  
        scan = heap_beginscan(heapRelation, /* relation */
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.335
diff -c -p -r1.335 vacuum.c
*** src/backend/commands/vacuum.c       14 Jul 2006 14:52:18 -0000      1.335
--- src/backend/commands/vacuum.c       28 Jul 2006 21:59:42 -0000
***************
*** 37,42 ****
--- 37,43 ----
  #include "postmaster/autovacuum.h"
  #include "storage/freespace.h"
  #include "storage/pmsignal.h"
+ #include "storage/proc.h"
  #include "storage/procarray.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
*************** vacuum_set_xid_limits(VacuumStmt *vacstm
*** 589,595 ****
  {
        TransactionId limit;
  
!       *oldestXmin = GetOldestXmin(sharedRel);
  
        Assert(TransactionIdIsNormal(*oldestXmin));
  
--- 590,605 ----
  {
        TransactionId limit;
  
!       /*
!        * We can always ignore processes running lazy vacuum.  This is because 
we
!        * use these values only for deciding which tuples we must keep in the
!        * tables.  Since lazy vacuum doesn't write its xid to the table, it's
!        * safe to ignore it.  In theory it could be problematic to ignore lazy
!        * vacuums on a full vacuum, but keep in mind that only one vacuum 
process
!        * can be working on a particular table at any time, and that each 
vacuum
!        * is always an independent transaction.
!        */
!       *oldestXmin = GetOldestXmin(sharedRel, true);
  
        Assert(TransactionIdIsNormal(*oldestXmin));
  
*************** vacuum_set_xid_limits(VacuumStmt *vacstm
*** 645,650 ****
--- 655,665 ----
   *            pg_class would've been obsoleted.  Of course, this only works 
for
   *            fixed-size never-null columns, but these are.
   *
+  *            Another reason for doing it this way is that when we are in a 
lazy
+  *            VACUUM and have inVacuum set, we mustn't do any updates --- 
somebody
+  *            vacuuming pg_class might think they could delete a tuple marked 
with
+  *            xmin = our xid.
+  *
   *            This routine is shared by full VACUUM, lazy VACUUM, and 
stand-alone
   *            ANALYZE.
   */
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 996,1003 ****
  
        /* Begin a transaction for vacuuming this relation */
        StartTransactionCommand();
!       /* functions in indexes may want a snapshot set */
!       ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
  
        /*
         * Tell the cache replacement strategy that vacuum is causing all
--- 1011,1045 ----
  
        /* Begin a transaction for vacuuming this relation */
        StartTransactionCommand();
! 
!       if (vacstmt->full)
!       {
!               /* functions in indexes may want a snapshot set */
!               ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
!       }
!       else
!       {
!               /*
!                * During a lazy VACUUM we do not run any user-supplied 
functions,
!                * and so it should be safe to not create a transaction 
snapshot.
!                *
!                * We can furthermore set the inVacuum flag, which lets other
!                * concurrent VACUUMs know that they can ignore this one while
!                * determining their OldestXmin.  (The reason we don't set 
inVacuum
!                * during a full VACUUM is exactly that we may have to run user-
!                * defined functions for functional indexes, and we want to make
!                * sure that if they use the snapshot set above, any tuples it
!                * requires can't get removed from other tables.  An index 
function
!                * that depends on the contents of other tables is arguably 
broken,
!                * but we won't break it here by violating transaction 
semantics.)
!                *
!                * Note: the inVacuum flag remains set until CommitTransaction 
or
!                * AbortTransaction.  We don't want to clear it until we reset
!                * MyProc->xid/xmin, else OldestXmin might appear to go 
backwards,
!                * which is probably Not Good.
!                */
!               MyProc->inVacuum = true;
!       }
  
        /*
         * Tell the cache replacement strategy that vacuum is causing all
Index: src/backend/storage/ipc/procarray.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/ipc/procarray.c,v
retrieving revision 1.14
diff -c -p -r1.14 procarray.c
*** src/backend/storage/ipc/procarray.c 14 Jul 2006 14:52:22 -0000      1.14
--- src/backend/storage/ipc/procarray.c 28 Jul 2006 21:59:42 -0000
*************** TransactionIdIsActive(TransactionId xid)
*** 388,407 ****
   * If allDbs is TRUE then all backends are considered; if allDbs is FALSE
   * then only backends running in my own database are considered.
   *
   * This is used by VACUUM to decide which deleted tuples must be preserved
   * in a table.        allDbs = TRUE is needed for shared relations, but 
allDbs =
   * FALSE is sufficient for non-shared relations, since only backends in my
!  * own database could ever see the tuples in them.
   *
   * This is also used to determine where to truncate pg_subtrans.  allDbs
!  * must be TRUE for that case.
   *
   * Note: we include the currently running xids in the set of considered xids.
   * This ensures that if a just-started xact has not yet set its snapshot,
   * when it does set the snapshot it cannot set xmin less than what we compute.
   */
  TransactionId
! GetOldestXmin(bool allDbs)
  {
        ProcArrayStruct *arrayP = procArray;
        TransactionId result;
--- 388,411 ----
   * If allDbs is TRUE then all backends are considered; if allDbs is FALSE
   * then only backends running in my own database are considered.
   *
+  * If ignoreVacuum is TRUE then backends with inVacuum set are ignored.
+  *
   * This is used by VACUUM to decide which deleted tuples must be preserved
   * in a table.        allDbs = TRUE is needed for shared relations, but 
allDbs =
   * FALSE is sufficient for non-shared relations, since only backends in my
!  * own database could ever see the tuples in them.  Also, we can ignore
!  * concurrently running lazy VACUUMs because (a) they must be working on other
!  * tables, and (b) they don't need to do snapshot-based lookups.
   *
   * This is also used to determine where to truncate pg_subtrans.  allDbs
!  * must be TRUE for that case, and ignoreVacuum FALSE.
   *
   * Note: we include the currently running xids in the set of considered xids.
   * This ensures that if a just-started xact has not yet set its snapshot,
   * when it does set the snapshot it cannot set xmin less than what we compute.
   */
  TransactionId
! GetOldestXmin(bool allDbs, bool ignoreVacuum)
  {
        ProcArrayStruct *arrayP = procArray;
        TransactionId result;
*************** GetOldestXmin(bool allDbs)
*** 425,430 ****
--- 429,437 ----
        {
                PGPROC     *proc = arrayP->procs[index];
  
+               if (ignoreVacuum && proc->inVacuum)
+                       continue;
+ 
                if (allDbs || proc->databaseId == MyDatabaseId)
                {
                        /* Fetch xid just once - see GetNewTransactionId */
*************** GetOldestXmin(bool allDbs)
*** 432,439 ****
--- 439,456 ----
  
                        if (TransactionIdIsNormal(xid))
                        {
+                               /* First consider the transaction own's Xid */
                                if (TransactionIdPrecedes(xid, result))
                                        result = xid;
+ 
+                               /*
+                                * Also consider the transaction's Xmin, if set.
+                                *
+                                * Note that this Xmin may seem to be 
guaranteed to be always
+                                * lower than the transaction's Xid, but this 
is not so because
+                                * there is a time window on which the Xid is 
already assigned
+                                * but the Xmin has not being calculated yet.
+                                */
                                xid = proc->xmin;
                                if (TransactionIdIsNormal(xid))
                                        if (TransactionIdPrecedes(xid, result))
*************** GetOldestXmin(bool allDbs)
*** 471,478 ****
   *            RecentXmin: the xmin computed for the most recent snapshot.  
XIDs
   *                    older than this are known not running any more.
   *            RecentGlobalXmin: the global xmin (oldest TransactionXmin 
across all
!  *                    running transactions).  This is the same computation 
done by
!  *                    GetOldestXmin(TRUE).
   *----------
   */
  Snapshot
--- 488,495 ----
   *            RecentXmin: the xmin computed for the most recent snapshot.  
XIDs
   *                    older than this are known not running any more.
   *            RecentGlobalXmin: the global xmin (oldest TransactionXmin 
across all
!  *                    running transactions, except those running LAZY 
VACUUM).  This is
!  *                    the same computation done by GetOldestXmin(true, false).
   *----------
   */
  Snapshot
*************** GetSnapshotData(Snapshot snapshot, bool 
*** 561,575 ****
  
                /*
                 * Ignore my own proc (dealt with my xid above), procs not 
running a
!                * transaction, and xacts started since we read the next 
transaction
!                * ID.  There's no need to store XIDs above what we got from
!                * ReadNewTransactionId, since we'll treat them as running 
anyway.  We
!                * also assume that such xacts can't compute an xmin older than 
ours,
!                * so they needn't be considered in computing globalxmin.
                 */
                if (proc == MyProc ||
                        !TransactionIdIsNormal(xid) ||
!                       TransactionIdFollowsOrEquals(xid, xmax))
                        continue;
  
                if (TransactionIdPrecedes(xid, xmin))
--- 578,594 ----
  
                /*
                 * Ignore my own proc (dealt with my xid above), procs not 
running a
!                * transaction, xacts started since we read the next transaction
!                * ID, and xacts executing LAZY VACUUM. There's no need to 
store XIDs
!                * above what we got from ReadNewTransactionId, since we'll 
treat them
!                * as running anyway.  We also assume that such xacts can't 
compute an
!                * xmin older than ours, so they needn't be considered in 
computing
!                * globalxmin.
                 */
                if (proc == MyProc ||
                        !TransactionIdIsNormal(xid) ||
!                       TransactionIdFollowsOrEquals(xid, xmax) ||
!                       proc->inVacuum)
                        continue;
  
                if (TransactionIdPrecedes(xid, xmin))
Index: src/backend/storage/lmgr/proc.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/lmgr/proc.c,v
retrieving revision 1.178
diff -c -p -r1.178 proc.c
*** src/backend/storage/lmgr/proc.c     23 Jul 2006 23:08:46 -0000      1.178
--- src/backend/storage/lmgr/proc.c     28 Jul 2006 21:59:42 -0000
*************** InitProcess(void)
*** 257,262 ****
--- 257,263 ----
        /* databaseId and roleId will be filled in later */
        MyProc->databaseId = InvalidOid;
        MyProc->roleId = InvalidOid;
+       MyProc->inVacuum = false;
        MyProc->lwWaiting = false;
        MyProc->lwExclusive = false;
        MyProc->lwWaitLink = NULL;
*************** InitDummyProcess(void)
*** 388,393 ****
--- 389,395 ----
        MyProc->xmin = InvalidTransactionId;
        MyProc->databaseId = InvalidOid;
        MyProc->roleId = InvalidOid;
+       MyProc->inVacuum = false;
        MyProc->lwWaiting = false;
        MyProc->lwExclusive = false;
        MyProc->lwWaitLink = NULL;
Index: src/include/storage/proc.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/storage/proc.h,v
retrieving revision 1.89
diff -c -p -r1.89 proc.h
*** src/include/storage/proc.h  13 Jul 2006 16:49:20 -0000      1.89
--- src/include/storage/proc.h  28 Jul 2006 21:59:42 -0000
*************** struct PGPROC
*** 66,78 ****
                                                                 * this proc */
  
        TransactionId xmin;                     /* minimal running XID as it 
was when we were
!                                                                * starting our 
xact: vacuum must not remove
!                                                                * tuples 
deleted by xid >= xmin ! */
  
        int                     pid;                    /* This backend's 
process id, or 0 */
        Oid                     databaseId;             /* OID of database this 
backend is using */
        Oid                     roleId;                 /* OID of role using 
this backend */
  
        /* Info about LWLock the process is currently waiting for, if any. */
        bool            lwWaiting;              /* true if waiting for an LW 
lock */
        bool            lwExclusive;    /* true if waiting for exclusive access 
*/
--- 66,81 ----
                                                                 * this proc */
  
        TransactionId xmin;                     /* minimal running XID as it 
was when we were
!                                                                * starting our 
xact, excluding LAZY VACUUM:
!                                                                * vacuum must 
not remove tuples deleted by
!                                                                * xid >= xmin 
! */
  
        int                     pid;                    /* This backend's 
process id, or 0 */
        Oid                     databaseId;             /* OID of database this 
backend is using */
        Oid                     roleId;                 /* OID of role using 
this backend */
  
+       bool            inVacuum;               /* true if current xact is a 
LAZY VACUUM */
+       
        /* Info about LWLock the process is currently waiting for, if any. */
        bool            lwWaiting;              /* true if waiting for an LW 
lock */
        bool            lwExclusive;    /* true if waiting for exclusive access 
*/
Index: src/include/storage/procarray.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/storage/procarray.h,v
retrieving revision 1.9
diff -c -p -r1.9 procarray.h
*** src/include/storage/procarray.h     19 Jun 2006 01:51:22 -0000      1.9
--- src/include/storage/procarray.h     28 Jul 2006 21:59:42 -0000
*************** extern void ProcArrayRemove(PGPROC *proc
*** 24,30 ****
  
  extern bool TransactionIdIsInProgress(TransactionId xid);
  extern bool TransactionIdIsActive(TransactionId xid);
! extern TransactionId GetOldestXmin(bool allDbs);
  
  extern PGPROC *BackendPidGetProc(int pid);
  extern int    BackendXidGetPid(TransactionId xid);
--- 24,30 ----
  
  extern bool TransactionIdIsInProgress(TransactionId xid);
  extern bool TransactionIdIsActive(TransactionId xid);
! extern TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum);
  
  extern PGPROC *BackendPidGetProc(int pid);
  extern int    BackendXidGetPid(TransactionId xid);
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

Reply via email to