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 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 int64 TransactionIdToPage (TransactionId xid)
 
static int ZeroCLOGPage (int64 pageno, bool writeXlog)
 
static bool CLOGPagePrecedes (int64 page1, int64 page2)
 
static void WriteZeroPageXlogRec (int64 pageno)
 
static void WriteTruncateXlogRec (int64 pageno, TransactionId oldestXact, Oid oldestXactDb)
 
static void TransactionIdSetPageStatus (TransactionId xid, int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn, int64 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, int64 pageno)
 
static void TransactionIdSetPageStatusInternal (TransactionId xid, int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn, int64 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 82 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 81 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:81
#define CLOG_LSNS_PER_PAGE
Definition: clog.c:82

Definition at line 84 of file clog.c.

◆ THRESHOLD_SUBTRANS_CLOG_OPT

#define THRESHOLD_SUBTRANS_CLOG_OPT   5

Definition at line 92 of file clog.c.

◆ TransactionIdToBIndex

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

Definition at line 78 of file clog.c.

◆ TransactionIdToByte

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

Definition at line 77 of file clog.c.

◆ TransactionIdToPgIndex

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

Definition at line 76 of file clog.c.

◆ XactCtl

#define XactCtl   (&XactCtlData)

Definition at line 99 of file clog.c.

Function Documentation

◆ BootStrapCLOG()

void BootStrapCLOG ( void  )

Definition at line 722 of file clog.c.

723 {
724  int slotno;
725 
726  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
727 
728  /* Create and zero the first page of the commit log */
729  slotno = ZeroCLOGPage(0, false);
730 
731  /* Make sure it's written out */
732  SimpleLruWritePage(XactCtl, slotno);
733  Assert(!XactCtl->shared->page_dirty[slotno]);
734 
735  LWLockRelease(XactSLRULock);
736 }
static int ZeroCLOGPage(int64 pageno, bool writeXlog)
Definition: clog.c:748
#define XactCtl
Definition: clog.c:99
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_EXCLUSIVE
Definition: lwlock.h:116
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:649

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

Referenced by BootStrapXLOG().

◆ CheckPointCLOG()

void CheckPointCLOG ( void  )

Definition at line 824 of file clog.c.

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

References SimpleLruWriteAll(), and XactCtl.

Referenced by CheckPointGuts().

◆ clog_redo()

void clog_redo ( XLogReaderState record)

Definition at line 992 of file clog.c.

993 {
994  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
995 
996  /* Backup blocks are not used in clog records */
997  Assert(!XLogRecHasAnyBlockRefs(record));
998 
999  if (info == CLOG_ZEROPAGE)
1000  {
1001  int64 pageno;
1002  int slotno;
1003 
1004  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
1005 
1006  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
1007 
1008  slotno = ZeroCLOGPage(pageno, false);
1009  SimpleLruWritePage(XactCtl, slotno);
1010  Assert(!XactCtl->shared->page_dirty[slotno]);
1011 
1012  LWLockRelease(XactSLRULock);
1013  }
1014  else if (info == CLOG_TRUNCATE)
1015  {
1016  xl_clog_truncate xlrec;
1017 
1018  memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_clog_truncate));
1019 
1021 
1023  }
1024  else
1025  elog(PANIC, "clog_redo: unknown op code %u", info);
1026 }
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, int64 cutoffPage)
Definition: slru.c:1269
int64 pageno
Definition: clog.h:34
TransactionId oldestXact
Definition: clog.h:35
void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid)
Definition: varsup.c:355
#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 ( int64  page1,
int64  page2 
)
static

Definition at line 940 of file clog.c.

941 {
942  TransactionId xid1;
943  TransactionId xid2;
944 
945  xid1 = ((TransactionId) page1) * CLOG_XACTS_PER_PAGE;
946  xid1 += FirstNormalTransactionId + 1;
947  xid2 = ((TransactionId) page2) * CLOG_XACTS_PER_PAGE;
948  xid2 += FirstNormalTransactionId + 1;
949 
950  return (TransactionIdPrecedes(xid1, xid2) &&
951  TransactionIdPrecedes(xid1, xid2 + CLOG_XACTS_PER_PAGE - 1));
952 }
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 691 of file clog.c.

692 {
693  return Min(128, Max(4, NBuffers / 512));
694 }
#define Min(x, y)
Definition: c.h:993
#define Max(x, y)
Definition: c.h:987
int NBuffers
Definition: globals.c:139

References Max, Min, and NBuffers.

Referenced by CLOGShmemInit(), and CLOGShmemSize().

◆ CLOGShmemInit()

void CLOGShmemInit ( void  )

Definition at line 706 of file clog.c.

707 {
708  XactCtl->PagePrecedes = CLOGPagePrecedes;
710  XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER,
711  SYNC_HANDLER_CLOG, false);
713 }
Size CLOGShmemBuffers(void)
Definition: clog.c:691
static bool CLOGPagePrecedes(int64 page1, int64 page2)
Definition: clog.c:940
@ 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, bool long_segment_names)
Definition: slru.c:215
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:168
@ 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 CreateOrAttachShmemStructs().

◆ CLOGShmemSize()

Size CLOGShmemSize ( void  )

Definition at line 700 of file clog.c.

701 {
703 }
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:183

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

Referenced by CalculateShmemSize().

◆ clogsyncfiletag()

int clogsyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 1032 of file clog.c.

1033 {
1034  return SlruSyncFileTag(XactCtl, ftag, path);
1035 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1664

References SlruSyncFileTag(), and XactCtl.

◆ ExtendCLOG()

void ExtendCLOG ( TransactionId  newestXact)

Definition at line 846 of file clog.c.

847 {
848  int64 pageno;
849 
850  /*
851  * No work except at first XID of a page. But beware: just after
852  * wraparound, the first XID of page zero is FirstNormalTransactionId.
853  */
854  if (TransactionIdToPgIndex(newestXact) != 0 &&
856  return;
857 
858  pageno = TransactionIdToPage(newestXact);
859 
860  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
861 
862  /* Zero the page and make an XLOG entry about it */
863  ZeroCLOGPage(pageno, true);
864 
865  LWLockRelease(XactSLRULock);
866 }
static int64 TransactionIdToPage(TransactionId xid)
Definition: clog.c:71
#define TransactionIdToPgIndex(xid)
Definition: clog.c:76
#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 246 of file clog.c.

248 {
249  int64 pageno = TransactionIdToPage(subxids[0]);
250  int offset = 0;
251  int i = 0;
252 
253  Assert(nsubxids > 0); /* else the pageno fetch above is unsafe */
254 
255  while (i < nsubxids)
256  {
257  int num_on_page = 0;
258  int64 nextpageno;
259 
260  do
261  {
262  nextpageno = TransactionIdToPage(subxids[i]);
263  if (nextpageno != pageno)
264  break;
265  num_on_page++;
266  i++;
267  } while (i < nsubxids);
268 
270  num_on_page, subxids + offset,
271  status, lsn, pageno, false);
272  offset = i;
273  pageno = nextpageno;
274  }
275 }
static void TransactionIdSetPageStatus(TransactionId xid, int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn, int64 pageno, bool all_xact_same_page)
Definition: clog.c:282
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 765 of file clog.c.

766 {
768  int64 pageno = TransactionIdToPage(xid);
769 
770  /*
771  * Initialize our idea of the latest page number.
772  */
773  pg_atomic_write_u64(&XactCtl->shared->latest_page_number, pageno);
774 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:433
FullTransactionId nextXid
Definition: transam.h:220
#define XidFromFullTransactionId(x)
Definition: transam.h:48
TransamVariablesData * TransamVariables
Definition: varsup.c:34

References TransamVariablesData::nextXid, pg_atomic_write_u64(), TransactionIdToPage(), TransamVariables, XactCtl, and XidFromFullTransactionId.

Referenced by StartupXLOG().

◆ TransactionGroupUpdateXidStatus()

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

Definition at line 423 of file clog.c.

425 {
426  volatile PROC_HDR *procglobal = ProcGlobal;
427  PGPROC *proc = MyProc;
428  int pgprocno = MyProcNumber;
429  uint32 nextidx;
430  uint32 wakeidx;
431 
432  /* We should definitely have an XID whose status needs to be updated. */
434 
435  /*
436  * Add ourselves to the list of processes needing a group XID status
437  * update.
438  */
439  proc->clogGroupMember = true;
440  proc->clogGroupMemberXid = xid;
441  proc->clogGroupMemberXidStatus = status;
442  proc->clogGroupMemberPage = pageno;
443  proc->clogGroupMemberLsn = lsn;
444 
445  nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
446 
447  while (true)
448  {
449  /*
450  * Add the proc to list, if the clog page where we need to update the
451  * current transaction status is same as group leader's clog page.
452  *
453  * There is a race condition here, which is that after doing the below
454  * check and before adding this proc's clog update to a group, the
455  * group leader might have already finished the group update for this
456  * page and becomes group leader of another group. This will lead to a
457  * situation where a single group can have different clog page
458  * updates. This isn't likely and will still work, just maybe a bit
459  * less efficiently.
460  */
461  if (nextidx != INVALID_PGPROCNO &&
462  GetPGProcByNumber(nextidx)->clogGroupMemberPage != proc->clogGroupMemberPage)
463  {
464  /*
465  * Ensure that this proc is not a member of any clog group that
466  * needs an XID status update.
467  */
468  proc->clogGroupMember = false;
470  return false;
471  }
472 
473  pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
474 
476  &nextidx,
477  (uint32) pgprocno))
478  break;
479  }
480 
481  /*
482  * If the list was not empty, the leader will update the status of our
483  * XID. It is impossible to have followers without a leader because the
484  * first process that has added itself to the list will always have
485  * nextidx as INVALID_PGPROCNO.
486  */
487  if (nextidx != INVALID_PGPROCNO)
488  {
489  int extraWaits = 0;
490 
491  /* Sleep until the leader updates our XID status. */
492  pgstat_report_wait_start(WAIT_EVENT_XACT_GROUP_UPDATE);
493  for (;;)
494  {
495  /* acts as a read barrier */
496  PGSemaphoreLock(proc->sem);
497  if (!proc->clogGroupMember)
498  break;
499  extraWaits++;
500  }
502 
504 
505  /* Fix semaphore count for any absorbed wakeups */
506  while (extraWaits-- > 0)
507  PGSemaphoreUnlock(proc->sem);
508  return true;
509  }
510 
511  /* We are the leader. Acquire the lock on behalf of everyone. */
512  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
513 
514  /*
515  * Now that we've got the lock, clear the list of processes waiting for
516  * group XID status update, saving a pointer to the head of the list.
517  * Trying to pop elements one at a time could lead to an ABA problem.
518  */
519  nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
521 
522  /* Remember head of list so we can perform wakeups after dropping lock. */
523  wakeidx = nextidx;
524 
525  /* Walk the list and update the status of all XIDs. */
526  while (nextidx != INVALID_PGPROCNO)
527  {
528  PGPROC *nextproc = &ProcGlobal->allProcs[nextidx];
529 
530  /*
531  * Transactions with more than THRESHOLD_SUBTRANS_CLOG_OPT sub-XIDs
532  * should not use group XID status update mechanism.
533  */
535 
537  nextproc->subxidStatus.count,
538  nextproc->subxids.xids,
539  nextproc->clogGroupMemberXidStatus,
540  nextproc->clogGroupMemberLsn,
541  nextproc->clogGroupMemberPage);
542 
543  /* Move to next proc in list. */
544  nextidx = pg_atomic_read_u32(&nextproc->clogGroupNext);
545  }
546 
547  /* We're done with the lock now. */
548  LWLockRelease(XactSLRULock);
549 
550  /*
551  * Now that we've released the lock, go back and wake everybody up. We
552  * don't do this under the lock so as to keep lock hold times to a
553  * minimum.
554  */
555  while (wakeidx != INVALID_PGPROCNO)
556  {
557  PGPROC *wakeproc = &ProcGlobal->allProcs[wakeidx];
558 
559  wakeidx = pg_atomic_read_u32(&wakeproc->clogGroupNext);
561 
562  /* ensure all previous writes are visible before follower continues. */
564 
565  wakeproc->clogGroupMember = false;
566 
567  if (wakeproc != MyProc)
568  PGSemaphoreUnlock(wakeproc->sem);
569  }
570 
571  return true;
572 }
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:92
static void TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids, TransactionId *subxids, XidStatus status, XLogRecPtr lsn, int64 pageno)
Definition: clog.c:348
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
#define GetPGProcByNumber(n)
Definition: proc.h:404
PGPROC * MyProc
Definition: proc.c:68
int MyProcNumber
Definition: proc.c:69
PROC_HDR * ProcGlobal
Definition: proc.c:81
Definition: proc.h:162
XLogRecPtr clogGroupMemberLsn
Definition: proc.h:275
TransactionId clogGroupMemberXid
Definition: proc.h:270
int64 clogGroupMemberPage
Definition: proc.h:273
bool clogGroupMember
Definition: proc.h:268
pg_atomic_uint32 clogGroupNext
Definition: proc.h:269
XidStatus clogGroupMemberXidStatus
Definition: proc.h:271
XidCacheStatus subxidStatus
Definition: proc.h:249
struct XidCache subxids
Definition: proc.h:251
PGSemaphore sem
Definition: proc.h:167
Definition: proc.h:356
PGPROC * allProcs
Definition: proc.h:358
pg_atomic_uint32 clogGroupFirst
Definition: proc.h:388
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, GetPGProcByNumber, INVALID_PGPROCNO, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyProc, MyProcNumber, pg_atomic_compare_exchange_u32(), pg_atomic_exchange_u32(), pg_atomic_read_u32(), pg_atomic_write_u32(), pg_write_barrier, 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 649 of file clog.c.

650 {
651  int64 pageno = TransactionIdToPage(xid);
652  int byteno = TransactionIdToByte(xid);
653  int bshift = TransactionIdToBIndex(xid) * CLOG_BITS_PER_XACT;
654  int slotno;
655  int lsnindex;
656  char *byteptr;
657  XidStatus status;
658 
659  /* lock is acquired by SimpleLruReadPage_ReadOnly */
660 
661  slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
662  byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
663 
664  status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
665 
666  lsnindex = GetLSNIndex(slotno, xid);
667  *lsn = XactCtl->shared->group_lsn[lsnindex];
668 
669  LWLockRelease(XactSLRULock);
670 
671  return status;
672 }
#define CLOG_XACT_BITMASK
Definition: clog.c:63
#define TransactionIdToBIndex(xid)
Definition: clog.c:78
#define CLOG_BITS_PER_XACT
Definition: clog.c:60
#define TransactionIdToByte(xid)
Definition: clog.c:77
#define GetLSNIndex(slotno, xid)
Definition: clog.c:84
int XidStatus
Definition: clog.h:25
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:530

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,
int64  pageno,
bool  all_xact_same_page 
)
static

Definition at line 282 of file clog.c.

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

Definition at line 348 of file clog.c.

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

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

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

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().

◆ TransactionIdToPage()

static int64 TransactionIdToPage ( TransactionId  xid)
inlinestatic

◆ TrimCLOG()

void TrimCLOG ( void  )

Definition at line 780 of file clog.c.

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

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

Referenced by StartupXLOG().

◆ TruncateCLOG()

void TruncateCLOG ( TransactionId  oldestXact,
Oid  oldestxid_datoid 
)

Definition at line 885 of file clog.c.

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

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

Referenced by vac_truncate_clog().

◆ WriteTruncateXlogRec()

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

Definition at line 973 of file clog.c.

974 {
975  XLogRecPtr recptr;
976  xl_clog_truncate xlrec;
977 
978  xlrec.pageno = pageno;
979  xlrec.oldestXact = oldestXact;
980  xlrec.oldestXactDb = oldestXactDb;
981 
982  XLogBeginInsert();
983  XLogRegisterData((char *) (&xlrec), sizeof(xl_clog_truncate));
984  recptr = XLogInsert(RM_CLOG_ID, CLOG_TRUNCATE);
985  XLogFlush(recptr);
986 }
Oid oldestXactDb
Definition: clog.h:36
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2733
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:365
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:475
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 ( int64  pageno)
static

Definition at line 959 of file clog.c.

960 {
961  XLogBeginInsert();
962  XLogRegisterData((char *) (&pageno), sizeof(pageno));
963  (void) XLogInsert(RM_CLOG_ID, CLOG_ZEROPAGE);
964 }

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

Referenced by ZeroCLOGPage().

◆ ZeroCLOGPage()

static int ZeroCLOGPage ( int64  pageno,
bool  writeXlog 
)
static

Definition at line 748 of file clog.c.

749 {
750  int slotno;
751 
752  slotno = SimpleLruZeroPage(XactCtl, pageno);
753 
754  if (writeXlog)
755  WriteZeroPageXlogRec(pageno);
756 
757  return slotno;
758 }
static void WriteZeroPageXlogRec(int64 pageno)
Definition: clog.c:959
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:308

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

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

Variable Documentation

◆ XactCtlData

SlruCtlData XactCtlData
static

Definition at line 97 of file clog.c.