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:587
#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 712 of file clog.c.

713 {
714  int slotno;
715 
716  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
717 
718  /* Create and zero the first page of the commit log */
719  slotno = ZeroCLOGPage(0, false);
720 
721  /* Make sure it's written out */
722  SimpleLruWritePage(XactCtl, slotno);
723  Assert(!XactCtl->shared->page_dirty[slotno]);
724 
725  LWLockRelease(XactSLRULock);
726 }
#define XactCtl
Definition: clog.c:89
static int ZeroCLOGPage(int pageno, bool writeXlog)
Definition: clog.c:738
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
@ 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 818 of file clog.c.

819 {
820  /*
821  * Write dirty CLOG pages to disk. This may result in sync requests
822  * queued for later handling by ProcessSyncRequests(), as part of the
823  * checkpoint.
824  */
825  TRACE_POSTGRESQL_CLOG_CHECKPOINT_START(true);
826  SimpleLruWriteAll(XactCtl, true);
827  TRACE_POSTGRESQL_CLOG_CHECKPOINT_DONE(true);
828 }
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 986 of file clog.c.

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

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

References CLOG_XACTS_PER_PAGE, FirstNormalTransactionId, and TransactionIdPrecedes().

Referenced by CLOGShmemInit().

◆ CLOGShmemBuffers()

Size CLOGShmemBuffers ( void  )

Definition at line 681 of file clog.c.

682 {
683  return Min(128, Max(4, NBuffers / 512));
684 }
#define Min(x, y)
Definition: c.h:986
#define Max(x, y)
Definition: c.h:980
int NBuffers
Definition: globals.c:135

References Max, Min, and NBuffers.

Referenced by CLOGShmemInit(), and CLOGShmemSize().

◆ CLOGShmemInit()

void CLOGShmemInit ( void  )

Definition at line 696 of file clog.c.

697 {
698  XactCtl->PagePrecedes = CLOGPagePrecedes;
700  XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER,
703 }
static bool CLOGPagePrecedes(int page1, int page2)
Definition: clog.c:934
Size CLOGShmemBuffers(void)
Definition: clog.c:681
@ 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 690 of file clog.c.

691 {
693 }
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 1026 of file clog.c.

1027 {
1028  return SlruSyncFileTag(XactCtl, ftag, path);
1029 }
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 840 of file clog.c.

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

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

416 {
417  volatile PROC_HDR *procglobal = ProcGlobal;
418  PGPROC *proc = MyProc;
419  uint32 nextidx;
420  uint32 wakeidx;
421 
422  /* We should definitely have an XID whose status needs to be updated. */
424 
425  /*
426  * Add ourselves to the list of processes needing a group XID status
427  * update.
428  */
429  proc->clogGroupMember = true;
430  proc->clogGroupMemberXid = xid;
432  proc->clogGroupMemberPage = pageno;
433  proc->clogGroupMemberLsn = lsn;
434 
435  nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
436 
437  while (true)
438  {
439  /*
440  * Add the proc to list, if the clog page where we need to update the
441  * current transaction status is same as group leader's clog page.
442  *
443  * There is a race condition here, which is that after doing the below
444  * check and before adding this proc's clog update to a group, the
445  * group leader might have already finished the group update for this
446  * page and becomes group leader of another group. This will lead to a
447  * situation where a single group can have different clog page
448  * updates. This isn't likely and will still work, just maybe a bit
449  * less efficiently.
450  */
451  if (nextidx != INVALID_PGPROCNO &&
453  {
454  /*
455  * Ensure that this proc is not a member of any clog group that
456  * needs an XID status update.
457  */
458  proc->clogGroupMember = false;
460  return false;
461  }
462 
463  pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
464 
466  &nextidx,
467  (uint32) proc->pgprocno))
468  break;
469  }
470 
471  /*
472  * If the list was not empty, the leader will update the status of our
473  * XID. It is impossible to have followers without a leader because the
474  * first process that has added itself to the list will always have
475  * nextidx as INVALID_PGPROCNO.
476  */
477  if (nextidx != INVALID_PGPROCNO)
478  {
479  int extraWaits = 0;
480 
481  /* Sleep until the leader updates our XID status. */
483  for (;;)
484  {
485  /* acts as a read barrier */
486  PGSemaphoreLock(proc->sem);
487  if (!proc->clogGroupMember)
488  break;
489  extraWaits++;
490  }
492 
494 
495  /* Fix semaphore count for any absorbed wakeups */
496  while (extraWaits-- > 0)
497  PGSemaphoreUnlock(proc->sem);
498  return true;
499  }
500 
501  /* We are the leader. Acquire the lock on behalf of everyone. */
502  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
503 
504  /*
505  * Now that we've got the lock, clear the list of processes waiting for
506  * group XID status update, saving a pointer to the head of the list.
507  * Trying to pop elements one at a time could lead to an ABA problem.
508  */
509  nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
511 
512  /* Remember head of list so we can perform wakeups after dropping lock. */
513  wakeidx = nextidx;
514 
515  /* Walk the list and update the status of all XIDs. */
516  while (nextidx != INVALID_PGPROCNO)
517  {
518  PGPROC *proc = &ProcGlobal->allProcs[nextidx];
519 
520  /*
521  * Transactions with more than THRESHOLD_SUBTRANS_CLOG_OPT sub-XIDs
522  * should not use group XID status update mechanism.
523  */
525 
527  proc->subxidStatus.count,
528  proc->subxids.xids,
530  proc->clogGroupMemberLsn,
531  proc->clogGroupMemberPage);
532 
533  /* Move to next proc in list. */
534  nextidx = pg_atomic_read_u32(&proc->clogGroupNext);
535  }
536 
537  /* We're done with the lock now. */
538  LWLockRelease(XactSLRULock);
539 
540  /*
541  * Now that we've released the lock, go back and wake everybody up. We
542  * don't do this under the lock so as to keep lock hold times to a
543  * minimum.
544  */
545  while (wakeidx != INVALID_PGPROCNO)
546  {
547  PGPROC *proc = &ProcGlobal->allProcs[wakeidx];
548 
549  wakeidx = pg_atomic_read_u32(&proc->clogGroupNext);
551 
552  /* ensure all previous writes are visible before follower continues. */
554 
555  proc->clogGroupMember = false;
556 
557  if (proc != MyProc)
558  PGSemaphoreUnlock(proc->sem);
559  }
560 
561  return true;
562 }
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:441
#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:339
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:125
XLogRecPtr clogGroupMemberLsn
Definition: proc.h:239
int clogGroupMemberPage
Definition: proc.h:237
TransactionId clogGroupMemberXid
Definition: proc.h:234
bool clogGroupMember
Definition: proc.h:232
pg_atomic_uint32 clogGroupNext
Definition: proc.h:233
XidStatus clogGroupMemberXidStatus
Definition: proc.h:235
XidCacheStatus subxidStatus
Definition: proc.h:213
int pgprocno
Definition: proc.h:153
struct XidCache subxids
Definition: proc.h:215
PGSemaphore sem
Definition: proc.h:130
Definition: proc.h:319
PGPROC * allProcs
Definition: proc.h:321
pg_atomic_uint32 clogGroupFirst
Definition: proc.h:351
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:132
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:264
static void pgstat_report_wait_end(void)
Definition: wait_event.h:280

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

640 {
641  int pageno = TransactionIdToPage(xid);
642  int byteno = TransactionIdToByte(xid);
643  int bshift = TransactionIdToBIndex(xid) * CLOG_BITS_PER_XACT;
644  int slotno;
645  int lsnindex;
646  char *byteptr;
648 
649  /* lock is acquired by SimpleLruReadPage_ReadOnly */
650 
651  slotno = SimpleLruReadPage_ReadOnly(XactCtl, pageno, xid);
652  byteptr = XactCtl->shared->page_buffer[slotno] + byteno;
653 
654  status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
655 
656  lsnindex = GetLSNIndex(slotno, xid);
657  *lsn = XactCtl->shared->group_lsn[lsnindex];
658 
659  LWLockRelease(XactSLRULock);
660 
661  return status;
662 }
#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  memcmp(subxids, MyProc->subxids.xids,
301  nsubxids * sizeof(TransactionId)) == 0)
302  {
303  /*
304  * If we can immediately acquire XactSLRULock, we update the status of
305  * our own XID and release the lock. If not, try use group XID
306  * update. If that doesn't work out, fall back to waiting for the
307  * lock to perform an update for this transaction only.
308  */
309  if (LWLockConditionalAcquire(XactSLRULock, LW_EXCLUSIVE))
310  {
311  /* Got the lock without waiting! Do the update. */
312  TransactionIdSetPageStatusInternal(xid, nsubxids, subxids, status,
313  lsn, pageno);
314  LWLockRelease(XactSLRULock);
315  return;
316  }
317  else if (TransactionGroupUpdateXidStatus(xid, status, lsn, pageno))
318  {
319  /* Group update mechanism has done the work. */
320  return;
321  }
322 
323  /* Fall through only if update isn't done yet. */
324  }
325 
326  /* Group update not applicable, or couldn't accept this page number. */
327  LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
328  TransactionIdSetPageStatusInternal(xid, nsubxids, subxids, status,
329  lsn, pageno);
330  LWLockRelease(XactSLRULock);
331 }
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:918
static bool TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status, XLogRecPtr lsn, int pageno)
Definition: clog.c:414
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1370
#define PGPROC_MAX_CACHED_SUBXIDS
Definition: proc.h:36
TransactionId xid
Definition: proc.h:136

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

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

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

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

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

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

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

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

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

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

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

Referenced by ZeroCLOGPage().

◆ ZeroCLOGPage()

static int ZeroCLOGPage ( int  pageno,
bool  writeXlog 
)
static

Definition at line 738 of file clog.c.

739 {
740  int slotno;
741 
742  slotno = SimpleLruZeroPage(XactCtl, pageno);
743 
744  if (writeXlog)
745  WriteZeroPageXlogRec(pageno);
746 
747  return slotno;
748 }
static void WriteZeroPageXlogRec(int pageno)
Definition: clog.c:953
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.