LTP GCOV extension - code coverage report
Current view: directory - access/transam - subtrans.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 79
Code covered: 72.2 % Executed lines: 57
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * subtrans.c
       4                 :  *              PostgreSQL subtransaction-log manager
       5                 :  *
       6                 :  * The pg_subtrans manager is a pg_clog-like manager that stores the parent
       7                 :  * transaction Id for each transaction.  It is a fundamental part of the
       8                 :  * nested transactions implementation.  A main transaction has a parent
       9                 :  * of InvalidTransactionId, and each subtransaction has its immediate parent.
      10                 :  * The tree can easily be walked from child to parent, but not in the
      11                 :  * opposite direction.
      12                 :  *
      13                 :  * This code is based on clog.c, but the robustness requirements
      14                 :  * are completely different from pg_clog, because we only need to remember
      15                 :  * pg_subtrans information for currently-open transactions.  Thus, there is
      16                 :  * no need to preserve data over a crash and restart.
      17                 :  *
      18                 :  * There are no XLOG interactions since we do not care about preserving
      19                 :  * data across crashes.  During database startup, we simply force the
      20                 :  * currently-active page of SUBTRANS to zeroes.
      21                 :  *
      22                 :  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
      23                 :  * Portions Copyright (c) 1994, Regents of the University of California
      24                 :  *
      25                 :  * $PostgreSQL: pgsql/src/backend/access/transam/subtrans.c,v 1.19 2007/08/01 22:45:07 tgl Exp $
      26                 :  *
      27                 :  *-------------------------------------------------------------------------
      28                 :  */
      29                 : #include "postgres.h"
      30                 : 
      31                 : #include "access/slru.h"
      32                 : #include "access/subtrans.h"
      33                 : #include "access/transam.h"
      34                 : #include "utils/tqual.h"
      35                 : 
      36                 : 
      37                 : /*
      38                 :  * Defines for SubTrans page sizes.  A page is the same BLCKSZ as is used
      39                 :  * everywhere else in Postgres.
      40                 :  *
      41                 :  * Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF,
      42                 :  * SubTrans page numbering also wraps around at
      43                 :  * 0xFFFFFFFF/SUBTRANS_XACTS_PER_PAGE, and segment numbering at
      44                 :  * 0xFFFFFFFF/SUBTRANS_XACTS_PER_PAGE/SLRU_SEGMENTS_PER_PAGE.  We need take no
      45                 :  * explicit notice of that fact in this module, except when comparing segment
      46                 :  * and page numbers in TruncateSUBTRANS (see SubTransPagePrecedes).
      47                 :  */
      48                 : 
      49                 : /* We need four bytes per xact */
      50                 : #define SUBTRANS_XACTS_PER_PAGE (BLCKSZ / sizeof(TransactionId))
      51                 : 
      52                 : #define TransactionIdToPage(xid) ((xid) / (TransactionId) SUBTRANS_XACTS_PER_PAGE)
      53                 : #define TransactionIdToEntry(xid) ((xid) % (TransactionId) SUBTRANS_XACTS_PER_PAGE)
      54                 : 
      55                 : 
      56                 : /*
      57                 :  * Link to shared-memory data structures for SUBTRANS control
      58                 :  */
      59                 : static SlruCtlData SubTransCtlData;
      60                 : 
      61                 : #define SubTransCtl  (&SubTransCtlData)
      62                 : 
      63                 : 
      64                 : static int      ZeroSUBTRANSPage(int pageno);
      65                 : static bool SubTransPagePrecedes(int page1, int page2);
      66                 : 
      67                 : 
      68                 : /*
      69                 :  * Record the parent of a subtransaction in the subtrans log.
      70                 :  */
      71                 : void
      72                 : SubTransSetParent(TransactionId xid, TransactionId parent)
      73              40 : {
      74              40 :         int                     pageno = TransactionIdToPage(xid);
      75              40 :         int                     entryno = TransactionIdToEntry(xid);
      76                 :         int                     slotno;
      77                 :         TransactionId *ptr;
      78                 : 
      79              40 :         LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);
      80                 : 
      81              40 :         slotno = SimpleLruReadPage(SubTransCtl, pageno, true, xid);
      82              40 :         ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
      83              40 :         ptr += entryno;
      84                 : 
      85                 :         /* Current state should be 0 */
      86                 :         Assert(*ptr == InvalidTransactionId);
      87                 : 
      88              40 :         *ptr = parent;
      89                 : 
      90              40 :         SubTransCtl->shared->page_dirty[slotno] = true;
      91                 : 
      92              40 :         LWLockRelease(SubtransControlLock);
      93              40 : }
      94                 : 
      95                 : /*
      96                 :  * Interrogate the parent of a transaction in the subtrans log.
      97                 :  */
      98                 : TransactionId
      99                 : SubTransGetParent(TransactionId xid)
     100               0 : {
     101               0 :         int                     pageno = TransactionIdToPage(xid);
     102               0 :         int                     entryno = TransactionIdToEntry(xid);
     103                 :         int                     slotno;
     104                 :         TransactionId *ptr;
     105                 :         TransactionId parent;
     106                 : 
     107                 :         /* Can't ask about stuff that might not be around anymore */
     108                 :         Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
     109                 : 
     110                 :         /* Bootstrap and frozen XIDs have no parent */
     111               0 :         if (!TransactionIdIsNormal(xid))
     112               0 :                 return InvalidTransactionId;
     113                 : 
     114                 :         /* lock is acquired by SimpleLruReadPage_ReadOnly */
     115                 : 
     116               0 :         slotno = SimpleLruReadPage_ReadOnly(SubTransCtl, pageno, xid);
     117               0 :         ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];
     118               0 :         ptr += entryno;
     119                 : 
     120               0 :         parent = *ptr;
     121                 : 
     122               0 :         LWLockRelease(SubtransControlLock);
     123                 : 
     124               0 :         return parent;
     125                 : }
     126                 : 
     127                 : /*
     128                 :  * SubTransGetTopmostTransaction
     129                 :  *
     130                 :  * Returns the topmost transaction of the given transaction id.
     131                 :  *
     132                 :  * Because we cannot look back further than TransactionXmin, it is possible
     133                 :  * that this function will lie and return an intermediate subtransaction ID
     134                 :  * instead of the true topmost parent ID.  This is OK, because in practice
     135                 :  * we only care about detecting whether the topmost parent is still running
     136                 :  * or is part of a current snapshot's list of still-running transactions.
     137                 :  * Therefore, any XID before TransactionXmin is as good as any other.
     138                 :  */
     139                 : TransactionId
     140                 : SubTransGetTopmostTransaction(TransactionId xid)
     141               0 : {
     142               0 :         TransactionId parentXid = xid,
     143               0 :                                 previousXid = xid;
     144                 : 
     145                 :         /* Can't ask about stuff that might not be around anymore */
     146                 :         Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
     147                 : 
     148               0 :         while (TransactionIdIsValid(parentXid))
     149                 :         {
     150               0 :                 previousXid = parentXid;
     151               0 :                 if (TransactionIdPrecedes(parentXid, TransactionXmin))
     152               0 :                         break;
     153               0 :                 parentXid = SubTransGetParent(parentXid);
     154                 :         }
     155                 : 
     156                 :         Assert(TransactionIdIsValid(previousXid));
     157                 : 
     158               0 :         return previousXid;
     159                 : }
     160                 : 
     161                 : 
     162                 : /*
     163                 :  * Initialization of shared memory for SUBTRANS
     164                 :  */
     165                 : Size
     166                 : SUBTRANSShmemSize(void)
     167              18 : {
     168              18 :         return SimpleLruShmemSize(NUM_SUBTRANS_BUFFERS, 0);
     169                 : }
     170                 : 
     171                 : void
     172                 : SUBTRANSShmemInit(void)
     173              16 : {
     174              16 :         SubTransCtl->PagePrecedes = SubTransPagePrecedes;
     175              16 :         SimpleLruInit(SubTransCtl, "SUBTRANS Ctl", NUM_SUBTRANS_BUFFERS, 0,
     176                 :                                   SubtransControlLock, "pg_subtrans");
     177                 :         /* Override default assumption that writes should be fsync'd */
     178              16 :         SubTransCtl->do_fsync = false;
     179              16 : }
     180                 : 
     181                 : /*
     182                 :  * This func must be called ONCE on system install.  It creates
     183                 :  * the initial SUBTRANS segment.  (The SUBTRANS directory is assumed to
     184                 :  * have been created by the initdb shell script, and SUBTRANSShmemInit
     185                 :  * must have been called already.)
     186                 :  *
     187                 :  * Note: it's not really necessary to create the initial segment now,
     188                 :  * since slru.c would create it on first write anyway.  But we may as well
     189                 :  * do it to be sure the directory is set up correctly.
     190                 :  */
     191                 : void
     192                 : BootStrapSUBTRANS(void)
     193               1 : {
     194                 :         int                     slotno;
     195                 : 
     196               1 :         LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);
     197                 : 
     198                 :         /* Create and zero the first page of the subtrans log */
     199               1 :         slotno = ZeroSUBTRANSPage(0);
     200                 : 
     201                 :         /* Make sure it's written out */
     202               1 :         SimpleLruWritePage(SubTransCtl, slotno, NULL);
     203                 :         Assert(!SubTransCtl->shared->page_dirty[slotno]);
     204                 : 
     205               1 :         LWLockRelease(SubtransControlLock);
     206               1 : }
     207                 : 
     208                 : /*
     209                 :  * Initialize (or reinitialize) a page of SUBTRANS to zeroes.
     210                 :  *
     211                 :  * The page is not actually written, just set up in shared memory.
     212                 :  * The slot number of the new page is returned.
     213                 :  *
     214                 :  * Control lock must be held at entry, and will be held at exit.
     215                 :  */
     216                 : static int
     217                 : ZeroSUBTRANSPage(int pageno)
     218              18 : {
     219              18 :         return SimpleLruZeroPage(SubTransCtl, pageno);
     220                 : }
     221                 : 
     222                 : /*
     223                 :  * This must be called ONCE during postmaster or standalone-backend startup,
     224                 :  * after StartupXLOG has initialized ShmemVariableCache->nextXid.
     225                 :  *
     226                 :  * oldestActiveXID is the oldest XID of any prepared transaction, or nextXid
     227                 :  * if there are none.
     228                 :  */
     229                 : void
     230                 : StartupSUBTRANS(TransactionId oldestActiveXID)
     231              14 : {
     232                 :         int                     startPage;
     233                 :         int                     endPage;
     234                 : 
     235                 :         /*
     236                 :          * Since we don't expect pg_subtrans to be valid across crashes, we
     237                 :          * initialize the currently-active page(s) to zeroes during startup.
     238                 :          * Whenever we advance into a new page, ExtendSUBTRANS will likewise zero
     239                 :          * the new page without regard to whatever was previously on disk.
     240                 :          */
     241              14 :         LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);
     242                 : 
     243              14 :         startPage = TransactionIdToPage(oldestActiveXID);
     244              14 :         endPage = TransactionIdToPage(ShmemVariableCache->nextXid);
     245                 : 
     246              28 :         while (startPage != endPage)
     247                 :         {
     248               0 :                 (void) ZeroSUBTRANSPage(startPage);
     249               0 :                 startPage++;
     250                 :         }
     251              14 :         (void) ZeroSUBTRANSPage(startPage);
     252                 : 
     253              14 :         LWLockRelease(SubtransControlLock);
     254              14 : }
     255                 : 
     256                 : /*
     257                 :  * This must be called ONCE during postmaster or standalone-backend shutdown
     258                 :  */
     259                 : void
     260                 : ShutdownSUBTRANS(void)
     261              13 : {
     262                 :         /*
     263                 :          * Flush dirty SUBTRANS pages to disk
     264                 :          *
     265                 :          * This is not actually necessary from a correctness point of view. We do
     266                 :          * it merely as a debugging aid.
     267                 :          */
     268              13 :         SimpleLruFlush(SubTransCtl, false);
     269              13 : }
     270                 : 
     271                 : /*
     272                 :  * Perform a checkpoint --- either during shutdown, or on-the-fly
     273                 :  */
     274                 : void
     275                 : CheckPointSUBTRANS(void)
     276              19 : {
     277                 :         /*
     278                 :          * Flush dirty SUBTRANS pages to disk
     279                 :          *
     280                 :          * This is not actually necessary from a correctness point of view. We do
     281                 :          * it merely to improve the odds that writing of dirty pages is done by
     282                 :          * the checkpoint process and not by backends.
     283                 :          */
     284              19 :         SimpleLruFlush(SubTransCtl, true);
     285              19 : }
     286                 : 
     287                 : 
     288                 : /*
     289                 :  * Make sure that SUBTRANS has room for a newly-allocated XID.
     290                 :  *
     291                 :  * NB: this is called while holding XidGenLock.  We want it to be very fast
     292                 :  * most of the time; even when it's not so fast, no actual I/O need happen
     293                 :  * unless we're forced to write out a dirty subtrans page to make room
     294                 :  * in shared memory.
     295                 :  */
     296                 : void
     297                 : ExtendSUBTRANS(TransactionId newestXact)
     298            4430 : {
     299                 :         int                     pageno;
     300                 : 
     301                 :         /*
     302                 :          * No work except at first XID of a page.  But beware: just after
     303                 :          * wraparound, the first XID of page zero is FirstNormalTransactionId.
     304                 :          */
     305            4430 :         if (TransactionIdToEntry(newestXact) != 0 &&
     306                 :                 !TransactionIdEquals(newestXact, FirstNormalTransactionId))
     307            4427 :                 return;
     308                 : 
     309               3 :         pageno = TransactionIdToPage(newestXact);
     310                 : 
     311               3 :         LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);
     312                 : 
     313                 :         /* Zero the page */
     314               3 :         ZeroSUBTRANSPage(pageno);
     315                 : 
     316               3 :         LWLockRelease(SubtransControlLock);
     317                 : }
     318                 : 
     319                 : 
     320                 : /*
     321                 :  * Remove all SUBTRANS segments before the one holding the passed transaction ID
     322                 :  *
     323                 :  * This is normally called during checkpoint, with oldestXact being the
     324                 :  * oldest TransactionXmin of any running transaction.
     325                 :  */
     326                 : void
     327                 : TruncateSUBTRANS(TransactionId oldestXact)
     328              19 : {
     329                 :         int                     cutoffPage;
     330                 : 
     331                 :         /*
     332                 :          * The cutoff point is the start of the segment containing oldestXact. We
     333                 :          * pass the *page* containing oldestXact to SimpleLruTruncate.
     334                 :          */
     335              19 :         cutoffPage = TransactionIdToPage(oldestXact);
     336                 : 
     337              19 :         SimpleLruTruncate(SubTransCtl, cutoffPage);
     338              19 : }
     339                 : 
     340                 : 
     341                 : /*
     342                 :  * Decide which of two SUBTRANS page numbers is "older" for truncation purposes.
     343                 :  *
     344                 :  * We need to use comparison of TransactionIds here in order to do the right
     345                 :  * thing with wraparound XID arithmetic.  However, if we are asked about
     346                 :  * page number zero, we don't want to hand InvalidTransactionId to
     347                 :  * TransactionIdPrecedes: it'll get weird about permanent xact IDs.  So,
     348                 :  * offset both xids by FirstNormalTransactionId to avoid that.
     349                 :  */
     350                 : static bool
     351                 : SubTransPagePrecedes(int page1, int page2)
     352              63 : {
     353                 :         TransactionId xid1;
     354                 :         TransactionId xid2;
     355                 : 
     356              63 :         xid1 = ((TransactionId) page1) * SUBTRANS_XACTS_PER_PAGE;
     357              63 :         xid1 += FirstNormalTransactionId;
     358              63 :         xid2 = ((TransactionId) page2) * SUBTRANS_XACTS_PER_PAGE;
     359              63 :         xid2 += FirstNormalTransactionId;
     360                 : 
     361              63 :         return TransactionIdPrecedes(xid1, xid2);
     362                 : }

Generated by: LTP GCOV extension version 1.5