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:598
#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 713 of file clog.c.

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

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

Referenced by BootStrapXLOG().

◆ CheckPointCLOG()

void CheckPointCLOG ( void  )

Definition at line 819 of file clog.c.

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

References SimpleLruWriteAll(), and XactCtl.

Referenced by CheckPointGuts().

◆ clog_redo()

void clog_redo ( XLogReaderState record)

Definition at line 987 of file clog.c.

988 {
989  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
990 
991  /* Backup blocks are not used in clog records */
992  Assert(!XLogRecHasAnyBlockRefs(record));
993 
994  if (info == CLOG_ZEROPAGE)
995  {
996  int pageno;
997  int slotno;
998 
999  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
1000 
1001  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
1002 
1003  slotno = ZeroCLOGPage(pageno, false);
1004  SimpleLruWritePage(XactCtl, slotno);
1005  Assert(!XactCtl->shared->page_dirty[slotno]);
1006 
1007  LWLockRelease(XactSLRULock);
1008  }
1009  else if (info == CLOG_TRUNCATE)
1010  {
1011  xl_clog_truncate xlrec;
1012 
1013  memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_clog_truncate));
1014 
1016 
1018  }
1019  else
1020  elog(PANIC, "clog_redo: unknown op code %u", info);
1021 }
unsigned char uint8
Definition: c.h:450
#define CLOG_ZEROPAGE
Definition: clog.h:56
#define CLOG_TRUNCATE
Definition: clog.h:57
#define PANIC
Definition: elog.h:36
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1226
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:408
#define XLogRecGetData(decoder)
Definition: xlogreader.h:413
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:415
#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 935 of file clog.c.

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

References CLOG_XACTS_PER_PAGE, FirstNormalTransactionId, and TransactionIdPrecedes().

Referenced by CLOGShmemInit().

◆ CLOGShmemBuffers()

Size CLOGShmemBuffers ( void  )

Definition at line 682 of file clog.c.

683 {
684  return Min(128, Max(4, NBuffers / 512));
685 }
#define Min(x, y)
Definition: c.h:997
#define Max(x, y)
Definition: c.h:991
int NBuffers
Definition: globals.c:136

References Max, Min, and NBuffers.

Referenced by CLOGShmemInit(), and CLOGShmemSize().

◆ CLOGShmemInit()

void CLOGShmemInit ( void  )

Definition at line 697 of file clog.c.

698 {
699  XactCtl->PagePrecedes = CLOGPagePrecedes;
701  XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER,
704 }
static bool CLOGPagePrecedes(int page1, int page2)
Definition: clog.c:935
Size CLOGShmemBuffers(void)
Definition: clog.c:682
@ LWTRANCHE_XACT_BUFFER
Definition: lwlock.h:168
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:187
#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 691 of file clog.c.

692 {
694 }
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 1027 of file clog.c.

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

References SlruSyncFileTag(), and XactCtl.

◆ ExtendCLOG()

void ExtendCLOG ( TransactionId  newestXact)

Definition at line 841 of file clog.c.

842 {
843  int pageno;
844 
845  /*
846  * No work except at first XID of a page. But beware: just after
847  * wraparound, the first XID of page zero is FirstNormalTransactionId.
848  */
849  if (TransactionIdToPgIndex(newestXact) != 0 &&
851  return;
852 
853  pageno = TransactionIdToPage(newestXact);
854 
855  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
856 
857  /* Zero the page and make an XLOG entry about it */
858  ZeroCLOGPage(pageno, true);
859 
860  LWLockRelease(XactSLRULock);
861 }
#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 238 of file clog.c.

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

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

Referenced by TransactionIdSetTreeStatus().

◆ StartupCLOG()

void StartupCLOG ( void  )

Definition at line 756 of file clog.c.

757 {
759  int pageno = TransactionIdToPage(xid);
760 
761  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
762 
763  /*
764  * Initialize our idea of the latest page number.
765  */
766  XactCtl->shared->latest_page_number = pageno;
767 
768  LWLockRelease(XactSLRULock);
769 }
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 415 of file clog.c.

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

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, status(), PGPROC::subxids, PGPROC::subxidStatus, THRESHOLD_SUBTRANS_CLOG_OPT, TransactionIdIsValid, TransactionIdSetPageStatusInternal(), WAIT_EVENT_XACT_GROUP_UPDATE, and XidCache::xids.

Referenced by TransactionIdSetPageStatus().

◆ TransactionIdGetStatus()

XidStatus TransactionIdGetStatus ( TransactionId  xid,
XLogRecPtr lsn 
)

Definition at line 640 of file clog.c.

641 {
642  int pageno = TransactionIdToPage(xid);
643  int byteno = TransactionIdToByte(xid);
644  int bshift = TransactionIdToBIndex(xid) * CLOG_BITS_PER_XACT;
645  int slotno;
646  int lsnindex;
647  char *byteptr;
649 
650  /* lock is acquired by SimpleLruReadPage_ReadOnly */
651 
652  slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
653  byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
654 
655  status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
656 
657  lsnindex = GetLSNIndex(slotno, xid);
658  *lsn = XactCtl->shared->group_lsn[lsnindex];
659 
660  LWLockRelease(XactSLRULock);
661 
662  return status;
663 }
#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:495

References CLOG_BITS_PER_XACT, CLOG_XACT_BITMASK, GetLSNIndex, LWLockRelease(), SimpleLruReadPage_ReadOnly(), status(), 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 274 of file clog.c.

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

References XidCacheStatus::count, LW_EXCLUSIVE, LWLockAcquire(), LWLockConditionalAcquire(), LWLockRelease(), MyProc, PGPROC_MAX_CACHED_SUBXIDS, StaticAssertStmt, status(), 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 340 of file clog.c.

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

References Assert(), i, LW_EXCLUSIVE, LWLockHeldByMeInMode(), SimpleLruReadPage(), status(), 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 571 of file clog.c.

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

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

References Assert(), i, set_status_by_pages(), status(), 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 775 of file clog.c.

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

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 880 of file clog.c.

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

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 968 of file clog.c.

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

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 954 of file clog.c.

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

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

Referenced by ZeroCLOGPage().

◆ ZeroCLOGPage()

static int ZeroCLOGPage ( int  pageno,
bool  writeXlog 
)
static

Definition at line 739 of file clog.c.

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

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.