Thread: TransactionIdIsInProgress() cache

TransactionIdIsInProgress() cache

From
Simon Riggs
Date:
We currently have a single item cache of the last checked TransactionId,
which optimises the call to TransactionIdDidCommit() during
HeapTupleSatisfiesMVCC() and partners.

Before we call TransactionIdDidCommit() we always call
TransactionIdIsInProgress().

TransactionIdIsInProgress() doesn't check the single item cache, so even
if we have just checked for this xid, we will check it again. Since this
function takes ProcArrayLock and may be called while holding other locks
it will improve scalability if we can skip the call, for the cost of an
integer comparison.

Following patch implements fastpath in TransactionIdIsInProgress() to
utilise single item cache.

--
  Simon Riggs
  2ndQuadrant  http://www.2ndQuadrant.com

Attachment

Re: TransactionIdIsInProgress() cache

From
Bruce Momjian
Date:
Your patch has been added to the PostgreSQL unapplied patches list at:

    http://momjian.postgresql.org/cgi-bin/pgpatches

It will be applied as soon as one of the PostgreSQL committers reviews
and approves it.

---------------------------------------------------------------------------


Simon Riggs wrote:
> We currently have a single item cache of the last checked TransactionId,
> which optimises the call to TransactionIdDidCommit() during
> HeapTupleSatisfiesMVCC() and partners.
>
> Before we call TransactionIdDidCommit() we always call
> TransactionIdIsInProgress().
>
> TransactionIdIsInProgress() doesn't check the single item cache, so even
> if we have just checked for this xid, we will check it again. Since this
> function takes ProcArrayLock and may be called while holding other locks
> it will improve scalability if we can skip the call, for the cost of an
> integer comparison.
>
> Following patch implements fastpath in TransactionIdIsInProgress() to
> utilise single item cache.
>
> --
>   Simon Riggs
>   2ndQuadrant  http://www.2ndQuadrant.com

[ Attachment, skipping... ]

>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: if posting/reading through Usenet, please send an appropriate
>        subscribe-nomail command to majordomo@postgresql.org so that your
>        message can get through to the mailing list cleanly

--
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://postgres.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +

Re: TransactionIdIsInProgress() cache

From
"Heikki Linnakangas"
Date:
Simon Riggs wrote:
> We currently have a single item cache of the last checked TransactionId,
> which optimises the call to TransactionIdDidCommit() during
> HeapTupleSatisfiesMVCC() and partners.
>
> Before we call TransactionIdDidCommit() we always call
> TransactionIdIsInProgress().
>
> TransactionIdIsInProgress() doesn't check the single item cache, so even
> if we have just checked for this xid, we will check it again. Since this
> function takes ProcArrayLock and may be called while holding other locks
> it will improve scalability if we can skip the call, for the cost of an
> integer comparison.

Seems plausible. Have you done any performance testing?

I presume the case where this would help would be when you populate a
large table, with COPY for example, and the run a seq scan on it. As all
rows in the table have the same xmin, you keep testing for the same XID
over and over again.

To matter from scalability point of view, there would need to be a lot
of concurrent activity that compete for the lock. Can you formulate a
test case for that?

> Following patch implements fastpath in TransactionIdIsInProgress() to
> utilise single item cache.

Hmm. The pattern in tqual.c is:

>  if (!TransactionIdIsInProgress(xvac))
>  {
>     if (TransactionIdDidCommit(xvac))
>     {
>        /* committed */
>     }
>     else
>     {
>        /* aborted */
>     }
>  }
>  else
>  {
>      /* in-progress */
>  }

We could do this instead:

>  if (TransactionIdDidCommit(xvac))
>  {
>      /* committed */
>  }
>  else if (!TransactionIdIsInProgress(xvac))
>  {
>     if (TransactionIdDidCommit(xvac))
>     {
>        /* committed */
>     }
>     else
>     {
>        /* aborted */
>     }
>  }
>  else
>  {
>      /* in-progress */
>  }

(hopefully there would be a way to macroize that or something to avoid
bloating the code any more.)

For committed transactions, this would save the
TransactionIdIsInProgress call completely, whether or not it's in the
one-item cache. The tradeoff is that we would have to call
TransactionIdDidCommit twice for aborted transactions.

--
   Heikki Linnakangas
   EnterpriseDB   http://www.enterprisedb.com


Re: TransactionIdIsInProgress() cache

From
Alvaro Herrera
Date:
I didn't check whether your transformation is correct, but if so then it
can be changed like this and save the extra XidDidCommit call:

    xvac_committed = TransactionIdDidCommit(xvac);
    if (xvac_committed)
    {
        /* committed */
    }
    else if (!TransactionIdIsInProgress(xvac))
    {
       if (xvac_committed)
       {
          /* committed */
       }
       else
       {
          /* aborted */
       }
    }
    else
    {
        /* in-progress */
    }


--
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.

Re: TransactionIdIsInProgress() cache

From
"Pavan Deolasee"
Date:
On Tue, Mar 11, 2008 at 6:37 PM, Alvaro Herrera
<alvherre@commandprompt.com> wrote:
> I didn't check whether your transformation is correct, but if so then it
>  can be changed like this and save the extra XidDidCommit call:
>
>     xvac_committed = TransactionIdDidCommit(xvac);
>     if (xvac_committed)
>
>     {
>         /* committed */
>     }
>     else if (!TransactionIdIsInProgress(xvac))
>     {
>        if (xvac_committed)
>
>        {
>           /* committed */
>        }
>        else
>        {
>           /* aborted */
>        }
>     }
>     else
>     {
>         /* in-progress */
>     }
>


I doubt if the transformation is correct. If xvac_committed is true, why would
one even get into the else part ?

Thanks,
Pavan

--
Pavan Deolasee
EnterpriseDB http://www.enterprisedb.com

Re: TransactionIdIsInProgress() cache

From
"Heikki Linnakangas"
Date:
Alvaro Herrera wrote:
> I didn't check whether your transformation is correct, but if so then it
> can be changed like this and save the extra XidDidCommit call:
>
>     xvac_committed = TransactionIdDidCommit(xvac);
>     if (xvac_committed)
>     {
>         /* committed */
>     }
>     else if (!TransactionIdIsInProgress(xvac))
>     {
>        if (xvac_committed)
>        {
>           /* committed */
>        }
>        else
>        {
>           /* aborted */
>        }
>     }
>     else
>     {
>         /* in-progress */
>     }

Nope, that's not good. Per comments in tqual.c, you have to call
TransactionIdIsInProgress *before* TransactionIdDidCommit, to avoid this
race condition:

1. Xact A inserts a record
2. Xact B does TransactionIdDidCommit, which retuns false because it's
still in progress
3. Xact B commits
4. Xact B does TransactionIdIsInProgress to see if A is still in
progress. It returns false. We conclude that A aborted, while it
actually committed.

My proposal was basically to add an extra TransactionIdDidCommit call
before the TransactionIdIsInProgress call, in the hope that it returns
true and we can skip the rest.

--
   Heikki Linnakangas
   EnterpriseDB   http://www.enterprisedb.com

Re: TransactionIdIsInProgress() cache

From
Alvaro Herrera
Date:
Heikki Linnakangas wrote:

> Nope, that's not good. Per comments in tqual.c, you have to call
> TransactionIdIsInProgress *before* TransactionIdDidCommit, to avoid this
> race condition:
>
> 1. Xact A inserts a record
> 2. Xact B does TransactionIdDidCommit, which retuns false because it's
> still in progress
> 3. Xact B commits
> 4. Xact B does TransactionIdIsInProgress to see if A is still in
> progress. It returns false. We conclude that A aborted, while it
> actually committed.

Ah, right -- I knew there was a reason for the other coding, I just
didn't remember what it was and based my transformation purely on the
snippet you posted.

--
Alvaro Herrera                                http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

Re: TransactionIdIsInProgress() cache

From
Tom Lane
Date:
"Heikki Linnakangas" <heikki@enterprisedb.com> writes:
> I presume the case where this would help would be when you populate a
> large table, with COPY for example, and the run a seq scan on it. As all
> rows in the table have the same xmin, you keep testing for the same XID
> over and over again.

Yeah, that's the reasoning for having the single-element cache in
transam.c in the first place.  Mass updates and mass deletes would
also result in a lot of probes of the same XID on the next examination
of the table.

Simon's idea looks sane, although "TransactionIdIsKnownNotInProgress"
seems a kinda weird name ... it feels like a double negative to me,
although strictly speaking it's not.  Maybe instead
TransactionIdIsKnownCompleted?

> To matter from scalability point of view, there would need to be a lot
> of concurrent activity that compete for the lock.

I think it's probably useful just from a cycles-saved point of view.
And we do know that ProcArrayLock is a hot spot.

> Hmm. The pattern in tqual.c is:
> ...
> We could do this instead:
> ...

I dislike this alternative because tqual.c is mind-bendingly complex
already.  Simon's approach hides the issue somewhere else where there
aren't so many code paths to keep straight.

            regards, tom lane

Re: TransactionIdIsInProgress() cache

From
Simon Riggs
Date:
On Tue, 2008-03-11 at 12:57 +0000, Heikki Linnakangas wrote:

> We could do this instead:
>
> >  if (TransactionIdDidCommit(xvac))
> >  {
> >      /* committed */
> >  }
> >  else if (!TransactionIdIsInProgress(xvac))
> >  {
> >     if (TransactionIdDidCommit(xvac))
> >     {
> >        /* committed */
> >     }
> >     else
> >     {
> >        /* aborted */
> >     }
> >  }
> >  else
> >  {
> >      /* in-progress */
> >  }
>
> (hopefully there would be a way to macroize that or something to avoid
> bloating the code any more.)
>
> For committed transactions, this would save the
> TransactionIdIsInProgress call completely, whether or not it's in the
> one-item cache. The tradeoff is that we would have to call
> TransactionIdDidCommit twice for aborted transactions.

I thought about doing it the way you suggest but
TransactionIdIsInProgress is the offending code, so thats the part I
tuned. TransactionIdDidCommit uses the single item cache so it seemed
easier to make isolated changes as proposed rather than touching tqual
code in multiple places to do exactly the same thing.

No, I haven't done any formal performance testing on it. It seemed an
obvious hole that everyone would agree we should avoid, since we can do
it so cheaply: one integer comparison against scanning the whole
procarray and taking an LWlock.

--
  Simon Riggs
  2ndQuadrant  http://www.2ndQuadrant.com

  PostgreSQL UK 2008 Conference: http://www.postgresql.org.uk


Re: TransactionIdIsInProgress() cache

From
Simon Riggs
Date:
On Tue, 2008-03-11 at 13:15 -0400, Tom Lane wrote:
> Maybe instead TransactionIdIsKnownCompleted?

Works for me.

--
  Simon Riggs
  2ndQuadrant  http://www.2ndQuadrant.com

  PostgreSQL UK 2008 Conference: http://www.postgresql.org.uk


Re: TransactionIdIsInProgress() cache

From
Tom Lane
Date:
Simon Riggs <simon@2ndquadrant.com> writes:
> No, I haven't done any formal performance testing on it. It seemed an
> obvious hole that everyone would agree we should avoid, since we can do
> it so cheaply: one integer comparison against scanning the whole
> procarray and taking an LWlock.

[ after reading the patch a bit closer... ]  Actually, it's not as
obvious as all that.  TransactionIdIsInProgress already falls out before
the proposed test for any XID < RecentXmin, which means that in reality
it's fairly probable that the target XID is running.  So while this test
may not cost much, it's not clear that it really buys much either.

I'm going to go ahead and apply it, but it'd be good if someone would
verify that it at least doesn't cost anything on some real benchmarks.

BTW, I think we should put it in front of, not after, the
TransactionIdIsCurrentTransactionId test, since as was just being
discussed that could have nontrivial execution time.  (I'll go look at
Heikki's improvement on that next, but it'll still be not-free if
there's lots of subtransactions.)

            regards, tom lane

Re: TransactionIdIsInProgress() cache

From
Tom Lane
Date:
I wrote:
> [ after reading the patch a bit closer... ]  Actually, it's not as
> obvious as all that.  TransactionIdIsInProgress already falls out before
> the proposed test for any XID < RecentXmin, which means that in reality
> it's fairly probable that the target XID is running.  So while this test
> may not cost much, it's not clear that it really buys much either.

I realized that a pretty simple test was already built into the code:
look at the stats gathered by XIDCACHE_DEBUG.  Here are the totals for
a set of parallel regression tests:

xmin:        185668
known:        25728
myxact:        5521
latest:        239
mainxid:    484
childxid:    0
nooflo:        3331
slow:        0

So even though the xmin test takes out a lot, this seems worth doing.
Some more-formal performance testing might still be a good idea though.

For completeness, the raw per-backend stats are attached.
Unsurprisingly, the wins come in bunches.

            regards, tom lane


XidCache: xmin: 1, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 1, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 0, known: 0, myxact: 4, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 0, known: 9, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 0, known: 14, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 17, slow: 0
XidCache: xmin: 1, known: 3, myxact: 1, latest: 0, mainxid: 0, childxid: 0, nooflo: 3, slow: 0
XidCache: xmin: 0, known: 11, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 11, slow: 0
XidCache: xmin: 18, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 0, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 0, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 0, known: 2, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 0, known: 6, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 8, slow: 0
XidCache: xmin: 32, known: 4, myxact: 2, latest: 0, mainxid: 0, childxid: 0, nooflo: 5, slow: 0
XidCache: xmin: 0, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 15, slow: 0
XidCache: xmin: 25, known: 2, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 2, slow: 0
XidCache: xmin: 6, known: 5, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 13, slow: 0
XidCache: xmin: 103, known: 2, myxact: 0, latest: 2, mainxid: 0, childxid: 0, nooflo: 5, slow: 0
XidCache: xmin: 174, known: 0, myxact: 13, latest: 0, mainxid: 1, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 94, known: 54, myxact: 1, latest: 2, mainxid: 0, childxid: 0, nooflo: 28, slow: 0
XidCache: xmin: 97, known: 89, myxact: 19, latest: 0, mainxid: 2, childxid: 0, nooflo: 50, slow: 0
XidCache: xmin: 2401, known: 12, myxact: 17, latest: 2, mainxid: 0, childxid: 0, nooflo: 16, slow: 0
XidCache: xmin: 156, known: 11, myxact: 15, latest: 0, mainxid: 0, childxid: 0, nooflo: 5, slow: 0
XidCache: xmin: 137, known: 6, myxact: 9, latest: 0, mainxid: 0, childxid: 0, nooflo: 4, slow: 0
XidCache: xmin: 8, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 6, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 59, known: 3, myxact: 5, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 7, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 5, slow: 0
XidCache: xmin: 0, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 43, known: 1, myxact: 7, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 1, known: 3, myxact: 1, latest: 0, mainxid: 0, childxid: 0, nooflo: 5, slow: 0
XidCache: xmin: 1, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 0, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 8, slow: 0
XidCache: xmin: 0, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 14, slow: 0
XidCache: xmin: 0, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 6, known: 4, myxact: 1, latest: 0, mainxid: 0, childxid: 0, nooflo: 19, slow: 0
XidCache: xmin: 0, known: 3, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 11, slow: 0
XidCache: xmin: 12, known: 8, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 14, slow: 0
XidCache: xmin: 0, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 42, known: 7, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 35, slow: 0
XidCache: xmin: 15, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 2, slow: 0
XidCache: xmin: 308, known: 8, myxact: 67, latest: 0, mainxid: 0, childxid: 0, nooflo: 2, slow: 0
XidCache: xmin: 51, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 33, slow: 0
XidCache: xmin: 54, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 27, known: 1, myxact: 1, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 62, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 120, known: 7, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 79, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 38, known: 8, myxact: 15, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 34, known: 0, myxact: 3, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 81, known: 2, myxact: 1, latest: 0, mainxid: 0, childxid: 0, nooflo: 3, slow: 0
XidCache: xmin: 344, known: 0, myxact: 42, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 17, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 139, known: 12, myxact: 24, latest: 0, mainxid: 0, childxid: 0, nooflo: 3, slow: 0
XidCache: xmin: 0, known: 1, myxact: 0, latest: 2, mainxid: 0, childxid: 0, nooflo: 10, slow: 0
XidCache: xmin: 1220, known: 5, myxact: 31, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 1, known: 0, myxact: 6, latest: 4, mainxid: 0, childxid: 0, nooflo: 5, slow: 0
XidCache: xmin: 19, known: 8189, myxact: 0, latest: 1, mainxid: 16, childxid: 0, nooflo: 57, slow: 0
XidCache: xmin: 0, known: 69, myxact: 8, latest: 2, mainxid: 2, childxid: 0, nooflo: 23, slow: 0
XidCache: xmin: 443, known: 291, myxact: 122, latest: 6, mainxid: 17, childxid: 0, nooflo: 87, slow: 0
XidCache: xmin: 408, known: 195, myxact: 89, latest: 11, mainxid: 27, childxid: 0, nooflo: 140, slow: 0
XidCache: xmin: 20655, known: 498, myxact: 2, latest: 4, mainxid: 2, childxid: 0, nooflo: 5, slow: 0
XidCache: xmin: 1545, known: 197, myxact: 252, latest: 16, mainxid: 103, childxid: 0, nooflo: 82, slow: 0
XidCache: xmin: 780, known: 220, myxact: 330, latest: 2, mainxid: 4, childxid: 0, nooflo: 76, slow: 0
XidCache: xmin: 0, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 103040, known: 15, myxact: 32, latest: 0, mainxid: 0, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 4028, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 0, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 55, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 2, slow: 0
XidCache: xmin: 1000, known: 4, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 61, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 0, known: 43, myxact: 8, latest: 0, mainxid: 0, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 21, known: 4, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 0, known: 11, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 6, slow: 0
XidCache: xmin: 36, known: 20, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 5, slow: 0
XidCache: xmin: 0, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 32, known: 22, myxact: 6, latest: 0, mainxid: 0, childxid: 0, nooflo: 9, slow: 0
XidCache: xmin: 3, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 3, slow: 0
XidCache: xmin: 1, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 35, known: 17, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 4, slow: 0
XidCache: xmin: 13, known: 74, myxact: 18, latest: 0, mainxid: 8, childxid: 0, nooflo: 17, slow: 0
XidCache: xmin: 2, known: 4, myxact: 2, latest: 0, mainxid: 0, childxid: 0, nooflo: 5, slow: 0
XidCache: xmin: 26, known: 14, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 5, slow: 0
XidCache: xmin: 12, known: 14, myxact: 1, latest: 7, mainxid: 13, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 111, known: 63, myxact: 10, latest: 2, mainxid: 5, childxid: 0, nooflo: 60, slow: 0
XidCache: xmin: 1, known: 106, myxact: 16, latest: 0, mainxid: 0, childxid: 0, nooflo: 31, slow: 0
XidCache: xmin: 30, known: 0, myxact: 0, latest: 0, mainxid: 1, childxid: 0, nooflo: 2, slow: 0
XidCache: xmin: 191, known: 106, myxact: 26, latest: 0, mainxid: 0, childxid: 0, nooflo: 58, slow: 0
XidCache: xmin: 257, known: 19, myxact: 44, latest: 0, mainxid: 0, childxid: 0, nooflo: 10, slow: 0
XidCache: xmin: 10519, known: 59, myxact: 19, latest: 0, mainxid: 1, childxid: 0, nooflo: 53, slow: 0
XidCache: xmin: 2, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 29, known: 1, myxact: 2, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 119, known: 14, myxact: 13, latest: 0, mainxid: 0, childxid: 0, nooflo: 6, slow: 0
XidCache: xmin: 23, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 151, known: 0, myxact: 23, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 6392, known: 9, myxact: 69, latest: 0, mainxid: 0, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 1940, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 17, known: 19, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 0, known: 173, myxact: 62, latest: 0, mainxid: 11, childxid: 0, nooflo: 12, slow: 0
XidCache: xmin: 92, known: 23, myxact: 11, latest: 0, mainxid: 10, childxid: 0, nooflo: 14, slow: 0
XidCache: xmin: 176, known: 252, myxact: 97, latest: 3, mainxid: 19, childxid: 0, nooflo: 88, slow: 0
XidCache: xmin: 455, known: 133, myxact: 199, latest: 11, mainxid: 8, childxid: 0, nooflo: 104, slow: 0
XidCache: xmin: 45, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 22, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 15, known: 31, myxact: 4, latest: 0, mainxid: 0, childxid: 0, nooflo: 12, slow: 0
XidCache: xmin: 1415, known: 468, myxact: 408, latest: 14, mainxid: 20, childxid: 0, nooflo: 325, slow: 0
XidCache: xmin: 3568, known: 631, myxact: 1507, latest: 38, mainxid: 21, childxid: 0, nooflo: 231, slow: 0
XidCache: xmin: 3, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 62, known: 51, myxact: 7, latest: 1, mainxid: 0, childxid: 0, nooflo: 27, slow: 0
XidCache: xmin: 89, known: 5, myxact: 5, latest: 2, mainxid: 19, childxid: 0, nooflo: 7, slow: 0
XidCache: xmin: 35, known: 228, myxact: 44, latest: 4, mainxid: 2, childxid: 0, nooflo: 48, slow: 0
XidCache: xmin: 3, known: 4, myxact: 0, latest: 0, mainxid: 2, childxid: 0, nooflo: 9, slow: 0
XidCache: xmin: 61, known: 32, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 2, slow: 0
XidCache: xmin: 84, known: 23, myxact: 2, latest: 2, mainxid: 6, childxid: 0, nooflo: 69, slow: 0
XidCache: xmin: 182, known: 324, myxact: 46, latest: 2, mainxid: 2, childxid: 0, nooflo: 27, slow: 0
XidCache: xmin: 60, known: 97, myxact: 31, latest: 0, mainxid: 2, childxid: 0, nooflo: 24, slow: 0
XidCache: xmin: 66, known: 187, myxact: 52, latest: 0, mainxid: 29, childxid: 0, nooflo: 38, slow: 0
XidCache: xmin: 114, known: 163, myxact: 209, latest: 0, mainxid: 0, childxid: 0, nooflo: 50, slow: 0
XidCache: xmin: 178, known: 96, myxact: 147, latest: 10, mainxid: 27, childxid: 0, nooflo: 45, slow: 0
XidCache: xmin: 107, known: 31, myxact: 23, latest: 4, mainxid: 8, childxid: 0, nooflo: 20, slow: 0
XidCache: xmin: 8084, known: 10445, myxact: 0, latest: 13, mainxid: 30, childxid: 0, nooflo: 80, slow: 0
XidCache: xmin: 128, known: 205, myxact: 74, latest: 6, mainxid: 18, childxid: 0, nooflo: 155, slow: 0
XidCache: xmin: 670, known: 14, myxact: 8, latest: 0, mainxid: 4, childxid: 0, nooflo: 10, slow: 0
XidCache: xmin: 290, known: 286, myxact: 72, latest: 2, mainxid: 15, childxid: 0, nooflo: 155, slow: 0
XidCache: xmin: 2231, known: 4, myxact: 198, latest: 8, mainxid: 0, childxid: 0, nooflo: 2, slow: 0
XidCache: xmin: 3142, known: 1040, myxact: 741, latest: 48, mainxid: 20, childxid: 0, nooflo: 373, slow: 0
XidCache: xmin: 0, known: 0, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 1225, known: 166, myxact: 122, latest: 8, mainxid: 9, childxid: 0, nooflo: 214, slow: 0
XidCache: xmin: 157, known: 0, myxact: 7, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0
XidCache: xmin: 125, known: 1, myxact: 0, latest: 0, mainxid: 0, childxid: 0, nooflo: 1, slow: 0
XidCache: xmin: 4766, known: 0, myxact: 68, latest: 0, mainxid: 0, childxid: 0, nooflo: 0, slow: 0

Re: TransactionIdIsInProgress() cache

From
Tom Lane
Date:
Simon Riggs <simon@2ndquadrant.com> writes:
> We currently have a single item cache of the last checked TransactionId,
> which optimises the call to TransactionIdDidCommit() during
> HeapTupleSatisfiesMVCC() and partners.

> Before we call TransactionIdDidCommit() we always call
> TransactionIdIsInProgress().

> TransactionIdIsInProgress() doesn't check the single item cache, so even
> if we have just checked for this xid, we will check it again. Since this
> function takes ProcArrayLock and may be called while holding other locks
> it will improve scalability if we can skip the call, for the cost of an
> integer comparison.

> Following patch implements fastpath in TransactionIdIsInProgress() to
> utilise single item cache.

Applied with minor adjustments and some desultory comment-improvement.

            regards, tom lane