PostgreSQL Source Code  git master
clog.c File Reference
#include "postgres.h"
#include "access/clog.h"
#include "access/slru.h"
#include "access/transam.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "storage/proc.h"
#include "storage/sync.h"
Include dependency graph for clog.c:

Go to the source code of this file.

Macros

#define CLOG_BITS_PER_XACT   2
 
#define CLOG_XACTS_PER_BYTE   4
 
#define CLOG_XACTS_PER_PAGE   (BLCKSZ * CLOG_XACTS_PER_BYTE)
 
#define CLOG_XACT_BITMASK   ((1 << CLOG_BITS_PER_XACT) - 1)
 
#define TransactionIdToPage(xid)   ((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)
 
#define TransactionIdToPgIndex(xid)   ((xid) % (TransactionId) CLOG_XACTS_PER_PAGE)
 
#define TransactionIdToByte(xid)   (TransactionIdToPgIndex(xid) / CLOG_XACTS_PER_BYTE)
 
#define TransactionIdToBIndex(xid)   ((xid) % (TransactionId) CLOG_XACTS_PER_BYTE)
 
#define CLOG_XACTS_PER_LSN_GROUP   32 /* keep this a power of 2 */
 
#define CLOG_LSNS_PER_PAGE   (CLOG_XACTS_PER_PAGE / CLOG_XACTS_PER_LSN_GROUP)
 
#define GetLSNIndex(slotno, xid)
 
#define THRESHOLD_SUBTRANS_CLOG_OPT   5
 
#define XactCtl   (&XactCtlData)
 

Functions

static int ZeroCLOGPage (int pageno, bool writeXlog)
 
static bool CLOGPagePrecedes (int page1, int page2)
 
static void WriteZeroPageXlogRec (int pageno)
 
static void WriteTruncateXlogRec (int pageno, TransactionId oldestXact, Oid oldestXactDb)
 
static void TransactionIdSetPageStatus (TransactionId xid, int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn, int pageno, bool all_xact_same_page)
 
static void TransactionIdSetStatusBit (TransactionId xid, XidStatus status, XLogRecPtr lsn, int slotno)
 
static void set_status_by_pages (int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn)
 
static bool TransactionGroupUpdateXidStatus (TransactionId xid, XidStatus status, XLogRecPtr lsn, int pageno)
 
static void TransactionIdSetPageStatusInternal (TransactionId xid, int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn, int pageno)
 
void TransactionIdSetTreeStatus (TransactionId xid, int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn)
 
XidStatus TransactionIdGetStatus (TransactionId xid, XLogRecPtr *lsn)
 
Size CLOGShmemBuffers (void)
 
Size CLOGShmemSize (void)
 
void CLOGShmemInit (void)
 
void BootStrapCLOG (void)
 
void StartupCLOG (void)
 
void TrimCLOG (void)
 
void CheckPointCLOG (void)
 
void ExtendCLOG (TransactionId newestXact)
 
void TruncateCLOG (TransactionId oldestXact, Oid oldestxid_datoid)
 
void clog_redo (XLogReaderState *record)
 
int clogsyncfiletag (const FileTag *ftag, char *path)
 

Variables

static SlruCtlData XactCtlData
 

Macro Definition Documentation

◆ CLOG_BITS_PER_XACT

#define CLOG_BITS_PER_XACT   2

Definition at line 60 of file clog.c.

◆ CLOG_LSNS_PER_PAGE

#define CLOG_LSNS_PER_PAGE   (CLOG_XACTS_PER_PAGE / CLOG_XACTS_PER_LSN_GROUP)

Definition at line 72 of file clog.c.

◆ CLOG_XACT_BITMASK

#define CLOG_XACT_BITMASK   ((1 << CLOG_BITS_PER_XACT) - 1)

Definition at line 63 of file clog.c.

◆ CLOG_XACTS_PER_BYTE

#define CLOG_XACTS_PER_BYTE   4

Definition at line 61 of file clog.c.

◆ CLOG_XACTS_PER_LSN_GROUP

#define CLOG_XACTS_PER_LSN_GROUP   32 /* keep this a power of 2 */

Definition at line 71 of file clog.c.

◆ CLOG_XACTS_PER_PAGE

#define CLOG_XACTS_PER_PAGE   (BLCKSZ * CLOG_XACTS_PER_BYTE)

Definition at line 62 of file clog.c.

◆ GetLSNIndex

#define GetLSNIndex (   slotno,
  xid 
)
Value:
((slotno) * CLOG_LSNS_PER_PAGE + \
uint32 TransactionId
Definition: c.h:641
#define CLOG_XACTS_PER_PAGE
Definition: clog.c:62
#define CLOG_XACTS_PER_LSN_GROUP
Definition: clog.c:71
#define CLOG_LSNS_PER_PAGE
Definition: clog.c:72

Definition at line 74 of file clog.c.

◆ THRESHOLD_SUBTRANS_CLOG_OPT

#define THRESHOLD_SUBTRANS_CLOG_OPT   5

Definition at line 82 of file clog.c.

◆ TransactionIdToBIndex

#define TransactionIdToBIndex (   xid)    ((xid) % (TransactionId) CLOG_XACTS_PER_BYTE)

Definition at line 68 of file clog.c.

◆ TransactionIdToByte

#define TransactionIdToByte (   xid)    (TransactionIdToPgIndex(xid) / CLOG_XACTS_PER_BYTE)

Definition at line 67 of file clog.c.

◆ TransactionIdToPage

#define TransactionIdToPage (   xid)    ((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)

Definition at line 65 of file clog.c.

◆ TransactionIdToPgIndex

#define TransactionIdToPgIndex (   xid)    ((xid) % (TransactionId) CLOG_XACTS_PER_PAGE)

Definition at line 66 of file clog.c.

◆ XactCtl

#define XactCtl   (&XactCtlData)

Definition at line 89 of file clog.c.

Function Documentation

◆ BootStrapCLOG()

void BootStrapCLOG ( void  )

Definition at line 711 of file clog.c.

712 {
713  int slotno;
714 
715  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
716 
717  /* Create and zero the first page of the commit log */
718  slotno = ZeroCLOGPage(0, false);
719 
720  /* Make sure it's written out */
721  SimpleLruWritePage(XactCtl, slotno);
722  Assert(!XactCtl->shared->page_dirty[slotno]);
723 
724  LWLockRelease(XactSLRULock);
725 }
#define XactCtl
Definition: clog.c:89
static int ZeroCLOGPage(int pageno, bool writeXlog)
Definition: clog.c:737
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1195
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
@ LW_EXCLUSIVE
Definition: lwlock.h:116
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:615

References Assert(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SimpleLruWritePage(), XactCtl, and ZeroCLOGPage().

Referenced by BootStrapXLOG().

◆ CheckPointCLOG()

void CheckPointCLOG ( void  )

Definition at line 817 of file clog.c.

818 {
819  /*
820  * Write dirty CLOG pages to disk. This may result in sync requests
821  * queued for later handling by ProcessSyncRequests(), as part of the
822  * checkpoint.
823  */
824  TRACE_POSTGRESQL_CLOG_CHECKPOINT_START(true);
825  SimpleLruWriteAll(XactCtl, true);
826  TRACE_POSTGRESQL_CLOG_CHECKPOINT_DONE(true);
827 }
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1157

References SimpleLruWriteAll(), and XactCtl.

Referenced by CheckPointGuts().

◆ clog_redo()

void clog_redo ( XLogReaderState record)

Definition at line 985 of file clog.c.

986 {
987  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
988 
989  /* Backup blocks are not used in clog records */
990  Assert(!XLogRecHasAnyBlockRefs(record));
991 
992  if (info == CLOG_ZEROPAGE)
993  {
994  int pageno;
995  int slotno;
996 
997  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
998 
999  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
1000 
1001  slotno = ZeroCLOGPage(pageno, false);
1002  SimpleLruWritePage(XactCtl, slotno);
1003  Assert(!XactCtl->shared->page_dirty[slotno]);
1004 
1005  LWLockRelease(XactSLRULock);
1006  }
1007  else if (info == CLOG_TRUNCATE)
1008  {
1009  xl_clog_truncate xlrec;
1010 
1011  memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_clog_truncate));
1012 
1014 
1016  }
1017  else
1018  elog(PANIC, "clog_redo: unknown op code %u", info);
1019 }
unsigned char uint8
Definition: c.h:493
#define CLOG_ZEROPAGE
Definition: clog.h:56
#define CLOG_TRUNCATE
Definition: clog.h:57
#define PANIC
Definition: elog.h:42
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1227
int pageno
Definition: clog.h:34
TransactionId oldestXact
Definition: clog.h:35
void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid)
Definition: varsup.c:328
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:417
#define XLR_INFO_MASK
Definition: xlogrecord.h:62

References AdvanceOldestClogXid(), Assert(), CLOG_TRUNCATE, CLOG_ZEROPAGE, elog(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), xl_clog_truncate::oldestXact, xl_clog_truncate::pageno, PANIC, SimpleLruTruncate(), SimpleLruWritePage(), XactCtl, XLogRecGetData, XLogRecGetInfo, XLogRecHasAnyBlockRefs, XLR_INFO_MASK, and ZeroCLOGPage().

◆ CLOGPagePrecedes()

static bool CLOGPagePrecedes ( int  page1,
int  page2 
)
static

Definition at line 933 of file clog.c.

934 {
935  TransactionId xid1;
936  TransactionId xid2;
937 
938  xid1 = ((TransactionId) page1) * CLOG_XACTS_PER_PAGE;
939  xid1 += FirstNormalTransactionId + 1;
940  xid2 = ((TransactionId) page2) * CLOG_XACTS_PER_PAGE;
941  xid2 += FirstNormalTransactionId + 1;
942 
943  return (TransactionIdPrecedes(xid1, xid2) &&
944  TransactionIdPrecedes(xid1, xid2 + CLOG_XACTS_PER_PAGE - 1));
945 }
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
#define FirstNormalTransactionId
Definition: transam.h:34

References CLOG_XACTS_PER_PAGE, FirstNormalTransactionId, and TransactionIdPrecedes().

Referenced by CLOGShmemInit().

◆ CLOGShmemBuffers()

Size CLOGShmemBuffers ( void  )

Definition at line 680 of file clog.c.

681 {
682  return Min(128, Max(4, NBuffers / 512));
683 }
#define Min(x, y)
Definition: c.h:993
#define Max(x, y)
Definition: c.h:987
int NBuffers
Definition: globals.c:136

References Max, Min, and NBuffers.

Referenced by CLOGShmemInit(), and CLOGShmemSize().

◆ CLOGShmemInit()

void CLOGShmemInit ( void  )

Definition at line 695 of file clog.c.

696 {
697  XactCtl->PagePrecedes = CLOGPagePrecedes;
699  XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER,
702 }
static bool CLOGPagePrecedes(int page1, int page2)
Definition: clog.c:933
Size CLOGShmemBuffers(void)
Definition: clog.c:680
@ LWTRANCHE_XACT_BUFFER
Definition: lwlock.h:181
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id, SyncRequestHandler sync_handler)
Definition: slru.c:188
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:156
@ SYNC_HANDLER_CLOG
Definition: sync.h:38

References CLOG_LSNS_PER_PAGE, CLOG_XACTS_PER_PAGE, CLOGPagePrecedes(), CLOGShmemBuffers(), LWTRANCHE_XACT_BUFFER, SimpleLruInit(), SlruPagePrecedesUnitTests, SYNC_HANDLER_CLOG, and XactCtl.

Referenced by CreateSharedMemoryAndSemaphores().

◆ CLOGShmemSize()

Size CLOGShmemSize ( void  )

Definition at line 689 of file clog.c.

690 {
692 }
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:156

References CLOG_LSNS_PER_PAGE, CLOGShmemBuffers(), and SimpleLruShmemSize().

Referenced by CalculateShmemSize().

◆ clogsyncfiletag()

int clogsyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 1025 of file clog.c.

1026 {
1027  return SlruSyncFileTag(XactCtl, ftag, path);
1028 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1594

References SlruSyncFileTag(), and XactCtl.

◆ ExtendCLOG()

void ExtendCLOG ( TransactionId  newestXact)

Definition at line 839 of file clog.c.

840 {
841  int pageno;
842 
843  /*
844  * No work except at first XID of a page. But beware: just after
845  * wraparound, the first XID of page zero is FirstNormalTransactionId.
846  */
847  if (TransactionIdToPgIndex(newestXact) != 0 &&
849  return;
850 
851  pageno = TransactionIdToPage(newestXact);
852 
853  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
854 
855  /* Zero the page and make an XLOG entry about it */
856  ZeroCLOGPage(pageno, true);
857 
858  LWLockRelease(XactSLRULock);
859 }
#define TransactionIdToPgIndex(xid)
Definition: clog.c:66
#define TransactionIdToPage(xid)
Definition: clog.c:65
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43

References FirstNormalTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), TransactionIdEquals, TransactionIdToPage, TransactionIdToPgIndex, and ZeroCLOGPage().

Referenced by GetNewTransactionId().

◆ set_status_by_pages()

static void set_status_by_pages ( int  nsubxids,
TransactionId subxids,
XidStatus  status,
XLogRecPtr  lsn 
)
static

Definition at line 236 of file clog.c.

238 {
239  int pageno = TransactionIdToPage(subxids[0]);
240  int offset = 0;
241  int i = 0;
242 
243  Assert(nsubxids > 0); /* else the pageno fetch above is unsafe */
244 
245  while (i < nsubxids)
246  {
247  int num_on_page = 0;
248  int nextpageno;
249 
250  do
251  {
252  nextpageno = TransactionIdToPage(subxids[i]);
253  if (nextpageno != pageno)
254  break;
255  num_on_page++;
256  i++;
257  } while (i < nsubxids);
258 
260  num_on_page, subxids + offset,
261  status, lsn, pageno, false);
262  offset = i;
263  pageno = nextpageno;
264  }
265 }
static void TransactionIdSetPageStatus(TransactionId xid, int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn, int pageno, bool all_xact_same_page)
Definition: clog.c:272
int i
Definition: isn.c:73
#define InvalidTransactionId
Definition: transam.h:31

References Assert(), i, InvalidTransactionId, TransactionIdSetPageStatus(), and TransactionIdToPage.

Referenced by TransactionIdSetTreeStatus().

◆ StartupCLOG()

void StartupCLOG ( void  )

Definition at line 754 of file clog.c.

755 {
757  int pageno = TransactionIdToPage(xid);
758 
759  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
760 
761  /*
762  * Initialize our idea of the latest page number.
763  */
764  XactCtl->shared->latest_page_number = pageno;
765 
766  LWLockRelease(XactSLRULock);
767 }
FullTransactionId nextXid
Definition: transam.h:220
#define XidFromFullTransactionId(x)
Definition: transam.h:48
VariableCache ShmemVariableCache
Definition: varsup.c:34

References LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), VariableCacheData::nextXid, ShmemVariableCache, TransactionIdToPage, XactCtl, and XidFromFullTransactionId.

Referenced by StartupXLOG().

◆ TransactionGroupUpdateXidStatus()

static bool TransactionGroupUpdateXidStatus ( TransactionId  xid,
XidStatus  status,
XLogRecPtr  lsn,
int  pageno 
)
static

Definition at line 413 of file clog.c.

415 {
416  volatile PROC_HDR *procglobal = ProcGlobal;
417  PGPROC *proc = MyProc;
418  uint32 nextidx;
419  uint32 wakeidx;
420 
421  /* We should definitely have an XID whose status needs to be updated. */
423 
424  /*
425  * Add ourselves to the list of processes needing a group XID status
426  * update.
427  */
428  proc->clogGroupMember = true;
429  proc->clogGroupMemberXid = xid;
430  proc->clogGroupMemberXidStatus = status;
431  proc->clogGroupMemberPage = pageno;
432  proc->clogGroupMemberLsn = lsn;
433 
434  nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
435 
436  while (true)
437  {
438  /*
439  * Add the proc to list, if the clog page where we need to update the
440  * current transaction status is same as group leader's clog page.
441  *
442  * There is a race condition here, which is that after doing the below
443  * check and before adding this proc's clog update to a group, the
444  * group leader might have already finished the group update for this
445  * page and becomes group leader of another group. This will lead to a
446  * situation where a single group can have different clog page
447  * updates. This isn't likely and will still work, just maybe a bit
448  * less efficiently.
449  */
450  if (nextidx != INVALID_PGPROCNO &&
452  {
453  /*
454  * Ensure that this proc is not a member of any clog group that
455  * needs an XID status update.
456  */
457  proc->clogGroupMember = false;
459  return false;
460  }
461 
462  pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
463 
465  &nextidx,
466  (uint32) proc->pgprocno))
467  break;
468  }
469 
470  /*
471  * If the list was not empty, the leader will update the status of our
472  * XID. It is impossible to have followers without a leader because the
473  * first process that has added itself to the list will always have
474  * nextidx as INVALID_PGPROCNO.
475  */
476  if (nextidx != INVALID_PGPROCNO)
477  {
478  int extraWaits = 0;
479 
480  /* Sleep until the leader updates our XID status. */
481  pgstat_report_wait_start(WAIT_EVENT_XACT_GROUP_UPDATE);
482  for (;;)
483  {
484  /* acts as a read barrier */
485  PGSemaphoreLock(proc->sem);
486  if (!proc->clogGroupMember)
487  break;
488  extraWaits++;
489  }
491 
493 
494  /* Fix semaphore count for any absorbed wakeups */
495  while (extraWaits-- > 0)
496  PGSemaphoreUnlock(proc->sem);
497  return true;
498  }
499 
500  /* We are the leader. Acquire the lock on behalf of everyone. */
501  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
502 
503  /*
504  * Now that we've got the lock, clear the list of processes waiting for
505  * group XID status update, saving a pointer to the head of the list.
506  * Trying to pop elements one at a time could lead to an ABA problem.
507  */
508  nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
510 
511  /* Remember head of list so we can perform wakeups after dropping lock. */
512  wakeidx = nextidx;
513 
514  /* Walk the list and update the status of all XIDs. */
515  while (nextidx != INVALID_PGPROCNO)
516  {
517  PGPROC *nextproc = &ProcGlobal->allProcs[nextidx];
518 
519  /*
520  * Transactions with more than THRESHOLD_SUBTRANS_CLOG_OPT sub-XIDs
521  * should not use group XID status update mechanism.
522  */
524 
526  nextproc->subxidStatus.count,
527  nextproc->subxids.xids,
528  nextproc->clogGroupMemberXidStatus,
529  nextproc->clogGroupMemberLsn,
530  nextproc->clogGroupMemberPage);
531 
532  /* Move to next proc in list. */
533  nextidx = pg_atomic_read_u32(&nextproc->clogGroupNext);
534  }
535 
536  /* We're done with the lock now. */
537  LWLockRelease(XactSLRULock);
538 
539  /*
540  * Now that we've released the lock, go back and wake everybody up. We
541  * don't do this under the lock so as to keep lock hold times to a
542  * minimum.
543  */
544  while (wakeidx != INVALID_PGPROCNO)
545  {
546  PGPROC *wakeproc = &ProcGlobal->allProcs[wakeidx];
547 
548  wakeidx = pg_atomic_read_u32(&wakeproc->clogGroupNext);
550 
551  /* ensure all previous writes are visible before follower continues. */
553 
554  wakeproc->clogGroupMember = false;
555 
556  if (wakeproc != MyProc)
557  PGSemaphoreUnlock(wakeproc->sem);
558  }
559 
560  return true;
561 }
static bool pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 *expected, uint32 newval)
Definition: atomics.h:306
#define pg_write_barrier()
Definition: atomics.h:154
static void pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:253
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:236
static uint32 pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval)
Definition: atomics.h:287
unsigned int uint32
Definition: c.h:495
#define THRESHOLD_SUBTRANS_CLOG_OPT
Definition: clog.c:82
static void TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn, int pageno)
Definition: clog.c:338
void PGSemaphoreUnlock(PGSemaphore sema)
Definition: posix_sema.c:340
void PGSemaphoreLock(PGSemaphore sema)
Definition: posix_sema.c:320
#define INVALID_PGPROCNO
Definition: proc.h:85
PGPROC * MyProc
Definition: proc.c:66
PROC_HDR * ProcGlobal
Definition: proc.c:78
Definition: proc.h:162
XLogRecPtr clogGroupMemberLsn
Definition: proc.h:280
int clogGroupMemberPage
Definition: proc.h:278
TransactionId clogGroupMemberXid
Definition: proc.h:275
bool clogGroupMember
Definition: proc.h:273
pg_atomic_uint32 clogGroupNext
Definition: proc.h:274
XidStatus clogGroupMemberXidStatus
Definition: proc.h:276
XidCacheStatus subxidStatus
Definition: proc.h:254
int pgprocno
Definition: proc.h:191
struct XidCache subxids
Definition: proc.h:256
PGSemaphore sem
Definition: proc.h:167
Definition: proc.h:360
PGPROC * allProcs
Definition: proc.h:362
pg_atomic_uint32 clogGroupFirst
Definition: proc.h:392
uint8 count
Definition: proc.h:43
TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS]
Definition: proc.h:50
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:88
static void pgstat_report_wait_end(void)
Definition: wait_event.h:104

References PROC_HDR::allProcs, Assert(), PROC_HDR::clogGroupFirst, PGPROC::clogGroupMember, PGPROC::clogGroupMemberLsn, PGPROC::clogGroupMemberPage, PGPROC::clogGroupMemberXid, PGPROC::clogGroupMemberXidStatus, PGPROC::clogGroupNext, XidCacheStatus::count, INVALID_PGPROCNO, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyProc, pg_atomic_compare_exchange_u32(), pg_atomic_exchange_u32(), pg_atomic_read_u32(), pg_atomic_write_u32(), pg_write_barrier, PGPROC::pgprocno, PGSemaphoreLock(), PGSemaphoreUnlock(), pgstat_report_wait_end(), pgstat_report_wait_start(), ProcGlobal, PGPROC::sem, PGPROC::subxids, PGPROC::subxidStatus, THRESHOLD_SUBTRANS_CLOG_OPT, TransactionIdIsValid, TransactionIdSetPageStatusInternal(), and XidCache::xids.

Referenced by TransactionIdSetPageStatus().

◆ TransactionIdGetStatus()

XidStatus TransactionIdGetStatus ( TransactionId  xid,
XLogRecPtr lsn 
)

Definition at line 638 of file clog.c.

639 {
640  int pageno = TransactionIdToPage(xid);
641  int byteno = TransactionIdToByte(xid);
642  int bshift = TransactionIdToBIndex(xid) * CLOG_BITS_PER_XACT;
643  int slotno;
644  int lsnindex;
645  char *byteptr;
646  XidStatus status;
647 
648  /* lock is acquired by SimpleLruReadPage_ReadOnly */
649 
650  slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
651  byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
652 
653  status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
654 
655  lsnindex = GetLSNIndex(slotno, xid);
656  *lsn = XactCtl->shared->group_lsn[lsnindex];
657 
658  LWLockRelease(XactSLRULock);
659 
660  return status;
661 }
#define CLOG_XACT_BITMASK
Definition: clog.c:63
#define TransactionIdToBIndex(xid)
Definition: clog.c:68
#define CLOG_BITS_PER_XACT
Definition: clog.c:60
#define TransactionIdToByte(xid)
Definition: clog.c:67
#define GetLSNIndex(slotno, xid)
Definition: clog.c:74
int XidStatus
Definition: clog.h:25
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:496

References CLOG_BITS_PER_XACT, CLOG_XACT_BITMASK, GetLSNIndex, LWLockRelease(), SimpleLruReadPage_ReadOnly(), TransactionIdToBIndex, TransactionIdToByte, TransactionIdToPage, and XactCtl.

Referenced by TransactionIdGetCommitLSN(), and TransactionLogFetch().

◆ TransactionIdSetPageStatus()

static void TransactionIdSetPageStatus ( TransactionId  xid,
int  nsubxids,
TransactionId subxids,
XidStatus  status,
XLogRecPtr  lsn,
int  pageno,
bool  all_xact_same_page 
)
static

Definition at line 272 of file clog.c.

276 {
277  /* Can't use group update when PGPROC overflows. */
279  "group clog threshold less than PGPROC cached subxids");
280 
281  /*
282  * When there is contention on XactSLRULock, we try to group multiple
283  * updates; a single leader process will perform transaction status
284  * updates for multiple backends so that the number of times XactSLRULock
285  * needs to be acquired is reduced.
286  *
287  * For this optimization to be safe, the XID and subxids in MyProc must be
288  * the same as the ones for which we're setting the status. Check that
289  * this is the case.
290  *
291  * For this optimization to be efficient, we shouldn't have too many
292  * sub-XIDs and all of the XIDs for which we're adjusting clog should be
293  * on the same page. Check those conditions, too.
294  */
295  if (all_xact_same_page && xid == MyProc->xid &&
296  nsubxids <= THRESHOLD_SUBTRANS_CLOG_OPT &&
297  nsubxids == MyProc->subxidStatus.count &&
298  (nsubxids == 0 ||
299  memcmp(subxids, MyProc->subxids.xids,
300  nsubxids * sizeof(TransactionId)) == 0))
301  {
302  /*
303  * If we can immediately acquire XactSLRULock, we update the status of
304  * our own XID and release the lock. If not, try use group XID
305  * update. If that doesn't work out, fall back to waiting for the
306  * lock to perform an update for this transaction only.
307  */
308  if (LWLockConditionalAcquire(XactSLRULock, LW_EXCLUSIVE))
309  {
310  /* Got the lock without waiting! Do the update. */
311  TransactionIdSetPageStatusInternal(xid, nsubxids, subxids, status,
312  lsn, pageno);
313  LWLockRelease(XactSLRULock);
314  return;
315  }
316  else if (TransactionGroupUpdateXidStatus(xid, status, lsn, pageno))
317  {
318  /* Group update mechanism has done the work. */
319  return;
320  }
321 
322  /* Fall through only if update isn't done yet. */
323  }
324 
325  /* Group update not applicable, or couldn't accept this page number. */
326  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
327  TransactionIdSetPageStatusInternal(xid, nsubxids, subxids, status,
328  lsn, pageno);
329  LWLockRelease(XactSLRULock);
330 }
#define StaticAssertDecl(condition, errmessage)
Definition: c.h:925
static bool TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status, XLogRecPtr lsn, int pageno)
Definition: clog.c:413
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1366
#define PGPROC_MAX_CACHED_SUBXIDS
Definition: proc.h:38
TransactionId xid
Definition: proc.h:173

References XidCacheStatus::count, LW_EXCLUSIVE, LWLockAcquire(), LWLockConditionalAcquire(), LWLockRelease(), MyProc, PGPROC_MAX_CACHED_SUBXIDS, StaticAssertDecl, PGPROC::subxids, PGPROC::subxidStatus, THRESHOLD_SUBTRANS_CLOG_OPT, TransactionGroupUpdateXidStatus(), TransactionIdSetPageStatusInternal(), PGPROC::xid, and XidCache::xids.

Referenced by set_status_by_pages(), and TransactionIdSetTreeStatus().

◆ TransactionIdSetPageStatusInternal()

static void TransactionIdSetPageStatusInternal ( TransactionId  xid,
int  nsubxids,
TransactionId subxids,
XidStatus  status,
XLogRecPtr  lsn,
int  pageno 
)
static

Definition at line 338 of file clog.c.

341 {
342  int slotno;
343  int i;
344 
346  status == TRANSACTION_STATUS_ABORTED ||
348  Assert(LWLockHeldByMeInMode(XactSLRULock, LW_EXCLUSIVE));
349 
350  /*
351  * If we're doing an async commit (ie, lsn is valid), then we must wait
352  * for any active write on the page slot to complete. Otherwise our
353  * update could reach disk in that write, which will not do since we
354  * mustn't let it reach disk until we've done the appropriate WAL flush.
355  * But when lsn is invalid, it's OK to scribble on a page while it is
356  * write-busy, since we don't care if the update reaches disk sooner than
357  * we think.
358  */
359  slotno = SimpleLruReadPage(XactCtl, pageno, XLogRecPtrIsInvalid(lsn), xid);
360 
361  /*
362  * Set the main transaction id, if any.
363  *
364  * If we update more than one xid on this page while it is being written
365  * out, we might find that some of the bits go to disk and others don't.
366  * If we are updating commits on the page with the top-level xid that
367  * could break atomicity, so we subcommit the subxids first before we mark
368  * the top-level commit.
369  */
370  if (TransactionIdIsValid(xid))
371  {
372  /* Subtransactions first, if needed ... */
373  if (status == TRANSACTION_STATUS_COMMITTED)
374  {
375  for (i = 0; i < nsubxids; i++)
376  {
377  Assert(XactCtl->shared->page_number[slotno] == TransactionIdToPage(subxids[i]));
378  TransactionIdSetStatusBit(subxids[i],
380  lsn, slotno);
381  }
382  }
383 
384  /* ... then the main transaction */
385  TransactionIdSetStatusBit(xid, status, lsn, slotno);
386  }
387 
388  /* Set the subtransactions */
389  for (i = 0; i < nsubxids; i++)
390  {
391  Assert(XactCtl->shared->page_number[slotno] == TransactionIdToPage(subxids[i]));
392  TransactionIdSetStatusBit(subxids[i], status, lsn, slotno);
393  }
394 
395  XactCtl->shared->page_dirty[slotno] = true;
396 }
static void TransactionIdSetStatusBit(TransactionId xid, XidStatus status, XLogRecPtr lsn, int slotno)
Definition: clog.c:569
#define TRANSACTION_STATUS_ABORTED
Definition: clog.h:29
#define TRANSACTION_STATUS_SUB_COMMITTED
Definition: clog.h:30
#define TRANSACTION_STATUS_COMMITTED
Definition: clog.h:28
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1964
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:396
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29

References Assert(), i, LW_EXCLUSIVE, LWLockHeldByMeInMode(), SimpleLruReadPage(), TRANSACTION_STATUS_ABORTED, TRANSACTION_STATUS_COMMITTED, TRANSACTION_STATUS_SUB_COMMITTED, TransactionIdIsValid, TransactionIdSetStatusBit(), TransactionIdToPage, XactCtl, and XLogRecPtrIsInvalid.

Referenced by TransactionGroupUpdateXidStatus(), and TransactionIdSetPageStatus().

◆ TransactionIdSetStatusBit()

static void TransactionIdSetStatusBit ( TransactionId  xid,
XidStatus  status,
XLogRecPtr  lsn,
int  slotno 
)
static

Definition at line 569 of file clog.c.

570 {
571  int byteno = TransactionIdToByte(xid);
572  int bshift = TransactionIdToBIndex(xid) * CLOG_BITS_PER_XACT;
573  char *byteptr;
574  char byteval;
575  char curval;
576 
577  byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
578  curval = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
579 
580  /*
581  * When replaying transactions during recovery we still need to perform
582  * the two phases of subcommit and then commit. However, some transactions
583  * are already correctly marked, so we just treat those as a no-op which
584  * allows us to keep the following Assert as restrictive as possible.
585  */
586  if (InRecovery && status == TRANSACTION_STATUS_SUB_COMMITTED &&
588  return;
589 
590  /*
591  * Current state change should be from 0 or subcommitted to target state
592  * or we should already be there when replaying changes during recovery.
593  */
594  Assert(curval == 0 ||
596  status != TRANSACTION_STATUS_IN_PROGRESS) ||
597  curval == status);
598 
599  /* note this assumes exclusive access to the clog page */
600  byteval = *byteptr;
601  byteval &= ~(((1 << CLOG_BITS_PER_XACT) - 1) << bshift);
602  byteval |= (status << bshift);
603  *byteptr = byteval;
604 
605  /*
606  * Update the group LSN if the transaction completion LSN is higher.
607  *
608  * Note: lsn will be invalid when supplied during InRecovery processing,
609  * so we don't need to do anything special to avoid LSN updates during
610  * recovery. After recovery completes the next clog change will set the
611  * LSN correctly.
612  */
613  if (!XLogRecPtrIsInvalid(lsn))
614  {
615  int lsnindex = GetLSNIndex(slotno, xid);
616 
617  if (XactCtl->shared->group_lsn[lsnindex] < lsn)
618  XactCtl->shared->group_lsn[lsnindex] = lsn;
619  }
620 }
#define TRANSACTION_STATUS_IN_PROGRESS
Definition: clog.h:27
bool InRecovery
Definition: xlogutils.c:53

References Assert(), CLOG_BITS_PER_XACT, CLOG_XACT_BITMASK, GetLSNIndex, InRecovery, TRANSACTION_STATUS_COMMITTED, TRANSACTION_STATUS_IN_PROGRESS, TRANSACTION_STATUS_SUB_COMMITTED, TransactionIdToBIndex, TransactionIdToByte, XactCtl, and XLogRecPtrIsInvalid.

Referenced by TransactionIdSetPageStatusInternal().

◆ TransactionIdSetTreeStatus()

void TransactionIdSetTreeStatus ( TransactionId  xid,
int  nsubxids,
TransactionId subxids,
XidStatus  status,
XLogRecPtr  lsn 
)

Definition at line 162 of file clog.c.

164 {
165  int pageno = TransactionIdToPage(xid); /* get page of parent */
166  int i;
167 
169  status == TRANSACTION_STATUS_ABORTED);
170 
171  /*
172  * See how many subxids, if any, are on the same page as the parent, if
173  * any.
174  */
175  for (i = 0; i < nsubxids; i++)
176  {
177  if (TransactionIdToPage(subxids[i]) != pageno)
178  break;
179  }
180 
181  /*
182  * Do all items fit on a single page?
183  */
184  if (i == nsubxids)
185  {
186  /*
187  * Set the parent and all subtransactions in a single call
188  */
189  TransactionIdSetPageStatus(xid, nsubxids, subxids, status, lsn,
190  pageno, true);
191  }
192  else
193  {
194  int nsubxids_on_first_page = i;
195 
196  /*
197  * If this is a commit then we care about doing this correctly (i.e.
198  * using the subcommitted intermediate status). By here, we know
199  * we're updating more than one page of clog, so we must mark entries
200  * that are *not* on the first page so that they show as subcommitted
201  * before we then return to update the status to fully committed.
202  *
203  * To avoid touching the first page twice, skip marking subcommitted
204  * for the subxids on that first page.
205  */
206  if (status == TRANSACTION_STATUS_COMMITTED)
207  set_status_by_pages(nsubxids - nsubxids_on_first_page,
208  subxids + nsubxids_on_first_page,
210 
211  /*
212  * Now set the parent and subtransactions on same page as the parent,
213  * if any
214  */
215  pageno = TransactionIdToPage(xid);
216  TransactionIdSetPageStatus(xid, nsubxids_on_first_page, subxids, status,
217  lsn, pageno, false);
218 
219  /*
220  * Now work through the rest of the subxids one clog page at a time,
221  * starting from the second page onwards, like we did above.
222  */
223  set_status_by_pages(nsubxids - nsubxids_on_first_page,
224  subxids + nsubxids_on_first_page,
225  status, lsn);
226  }
227 }
static void set_status_by_pages(int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn)
Definition: clog.c:236

References Assert(), i, set_status_by_pages(), TRANSACTION_STATUS_ABORTED, TRANSACTION_STATUS_COMMITTED, TRANSACTION_STATUS_SUB_COMMITTED, TransactionIdSetPageStatus(), and TransactionIdToPage.

Referenced by TransactionIdAbortTree(), TransactionIdAsyncCommitTree(), and TransactionIdCommitTree().

◆ TrimCLOG()

void TrimCLOG ( void  )

Definition at line 773 of file clog.c.

774 {
776  int pageno = TransactionIdToPage(xid);
777 
778  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
779 
780  /*
781  * Zero out the remainder of the current clog page. Under normal
782  * circumstances it should be zeroes already, but it seems at least
783  * theoretically possible that XLOG replay will have settled on a nextXID
784  * value that is less than the last XID actually used and marked by the
785  * previous database lifecycle (since subtransaction commit writes clog
786  * but makes no WAL entry). Let's just be safe. (We need not worry about
787  * pages beyond the current one, since those will be zeroed when first
788  * used. For the same reason, there is no need to do anything when
789  * nextXid is exactly at a page boundary; and it's likely that the
790  * "current" page doesn't exist yet in that case.)
791  */
792  if (TransactionIdToPgIndex(xid) != 0)
793  {
794  int byteno = TransactionIdToByte(xid);
795  int bshift = TransactionIdToBIndex(xid) * CLOG_BITS_PER_XACT;
796  int slotno;
797  char *byteptr;
798 
799  slotno = SimpleLruReadPage(XactCtl, pageno, false, xid);
800  byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
801 
802  /* Zero so-far-unused positions in the current byte */
803  *byteptr &= (1 << bshift) - 1;
804  /* Zero the rest of the page */
805  MemSet(byteptr + 1, 0, BLCKSZ - byteno - 1);
806 
807  XactCtl->shared->page_dirty[slotno] = true;
808  }
809 
810  LWLockRelease(XactSLRULock);
811 }
#define MemSet(start, val, len)
Definition: c.h:1009

References CLOG_BITS_PER_XACT, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MemSet, VariableCacheData::nextXid, ShmemVariableCache, SimpleLruReadPage(), TransactionIdToBIndex, TransactionIdToByte, TransactionIdToPage, TransactionIdToPgIndex, XactCtl, and XidFromFullTransactionId.

Referenced by StartupXLOG().

◆ TruncateCLOG()

void TruncateCLOG ( TransactionId  oldestXact,
Oid  oldestxid_datoid 
)

Definition at line 878 of file clog.c.

879 {
880  int cutoffPage;
881 
882  /*
883  * The cutoff point is the start of the segment containing oldestXact. We
884  * pass the *page* containing oldestXact to SimpleLruTruncate.
885  */
886  cutoffPage = TransactionIdToPage(oldestXact);
887 
888  /* Check to see if there's any files that could be removed */
890  return; /* nothing to remove */
891 
892  /*
893  * Advance oldestClogXid before truncating clog, so concurrent xact status
894  * lookups can ensure they don't attempt to access truncated-away clog.
895  *
896  * It's only necessary to do this if we will actually truncate away clog
897  * pages.
898  */
899  AdvanceOldestClogXid(oldestXact);
900 
901  /*
902  * Write XLOG record and flush XLOG to disk. We record the oldest xid
903  * we're keeping information about here so we can ensure that it's always
904  * ahead of clog truncation in case we crash, and so a standby finds out
905  * the new valid xid before the next checkpoint.
906  */
907  WriteTruncateXlogRec(cutoffPage, oldestXact, oldestxid_datoid);
908 
909  /* Now we can remove the old CLOG segment(s) */
910  SimpleLruTruncate(XactCtl, cutoffPage);
911 }
static void WriteTruncateXlogRec(int pageno, TransactionId oldestXact, Oid oldestXactDb)
Definition: clog.c:966
bool SlruScanDirCbReportPresence(SlruCtl ctl, char *filename, int segpage, void *data)
Definition: slru.c:1501
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1554

References AdvanceOldestClogXid(), SimpleLruTruncate(), SlruScanDirCbReportPresence(), SlruScanDirectory(), TransactionIdToPage, WriteTruncateXlogRec(), and XactCtl.

Referenced by vac_truncate_clog().

◆ WriteTruncateXlogRec()

static void WriteTruncateXlogRec ( int  pageno,
TransactionId  oldestXact,
Oid  oldestXactDb 
)
static

Definition at line 966 of file clog.c.

967 {
968  XLogRecPtr recptr;
969  xl_clog_truncate xlrec;
970 
971  xlrec.pageno = pageno;
972  xlrec.oldestXact = oldestXact;
973  xlrec.oldestXactDb = oldestXactDb;
974 
975  XLogBeginInsert();
976  XLogRegisterData((char *) (&xlrec), sizeof(xl_clog_truncate));
977  recptr = XLogInsert(RM_CLOG_ID, CLOG_TRUNCATE);
978  XLogFlush(recptr);
979 }
Oid oldestXactDb
Definition: clog.h:36
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2535
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:351
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:461
void XLogBeginInsert(void)
Definition: xloginsert.c:150

References CLOG_TRUNCATE, xl_clog_truncate::oldestXact, xl_clog_truncate::oldestXactDb, xl_clog_truncate::pageno, XLogBeginInsert(), XLogFlush(), XLogInsert(), and XLogRegisterData().

Referenced by TruncateCLOG().

◆ WriteZeroPageXlogRec()

static void WriteZeroPageXlogRec ( int  pageno)
static

Definition at line 952 of file clog.c.

953 {
954  XLogBeginInsert();
955  XLogRegisterData((char *) (&pageno), sizeof(int));
956  (void) XLogInsert(RM_CLOG_ID, CLOG_ZEROPAGE);
957 }

References CLOG_ZEROPAGE, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by ZeroCLOGPage().

◆ ZeroCLOGPage()

static int ZeroCLOGPage ( int  pageno,
bool  writeXlog 
)
static

Definition at line 737 of file clog.c.

738 {
739  int slotno;
740 
741  slotno = SimpleLruZeroPage(XactCtl, pageno);
742 
743  if (writeXlog)
744  WriteZeroPageXlogRec(pageno);
745 
746  return slotno;
747 }
static void WriteZeroPageXlogRec(int pageno)
Definition: clog.c:952
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:281

References SimpleLruZeroPage(), WriteZeroPageXlogRec(), and XactCtl.

Referenced by BootStrapCLOG(), clog_redo(), and ExtendCLOG().

Variable Documentation

◆ XactCtlData

SlruCtlData XactCtlData
static

Definition at line 87 of file clog.c.