/* * This must be called ONCE during postmaster or standalone-backend startup, * after StartupXLOG has initialized ShmemVariableCache->nextXid. * * oldestActiveXID is the oldest XID of any prepared transaction, or nextXid * if there are none. */ void StartupSUBTRANS(TransactionId oldestActiveXID) { int startPage; int endPage; /* * Since we don't expect pg_subtrans to be valid across crashes, we * initialize the currently-active page(s) to zeroes during startup. * Whenever we advance into a new page, ExtendSUBTRANS will likewise zero * the new page without regard to whatever was previously on disk. */ LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE); startPage = TransactionIdToPage(oldestActiveXID); endPage = TransactionIdToPage(ShmemVariableCache->nextXid); while (startPage != endPage) { (void) ZeroSUBTRANSPage(startPage); startPage++; } (void) ZeroSUBTRANSPage(startPage); LWLockRelease(SubtransControlLock); }
/* * Make sure that SUBTRANS has room for a newly-allocated XID. * * NB: this is called while holding XidGenLock. We want it to be very fast * most of the time; even when it's not so fast, no actual I/O need happen * unless we're forced to write out a dirty subtrans page to make room * in shared memory. */ void ExtendSUBTRANS(TransactionId newestXact) { int pageno; /* * Caller must have already taken mirrored lock shared. */ /* * No work except at first XID of a page. But beware: just after * wraparound, the first XID of page zero is FirstNormalTransactionId. */ if (TransactionIdToEntry(newestXact) != 0 && !TransactionIdEquals(newestXact, FirstNormalTransactionId)) return; pageno = TransactionIdToPage(newestXact); LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE); /* Zero the page */ ZeroSUBTRANSPage(pageno); LWLockRelease(SubtransControlLock); }
/* * Make sure that SUBTRANS has room for a newly-allocated XID. * * NB: this is called while holding XidGenLock. We want it to be very fast * most of the time; even when it's not so fast, no actual I/O need happen * unless we're forced to write out a dirty subtrans page to make room * in shared memory. */ void ExtendSUBTRANS(TransactionId newestXact) { int pageno; /* * No work except at first XID of a page. But beware: just after * wraparound, the first XID of page zero is FirstNormalTransactionId. */ #ifdef PGXC /* PGXC_COORD || PGXC_DATANODE */ /* * In PGXC, it may be that a node is not involved in a transaction, * and therefore will be skipped, so we need to detect this by using * the latest_page_number instead of the pg index. * * Also, there is a special case of when transactions wrap-around that * we need to detect. */ pageno = TransactionIdToPage(newestXact); /* * The first condition makes sure we did not wrap around * The second checks if we are still using the same page. * Note that this value can change and we are not holding a lock, * so we repeat the check below. We do it this way instead of * grabbing the lock to avoid lock contention. */ if (SubTransCtl->shared->latest_page_number - pageno <= SUBTRANS_WRAP_CHECK_DELTA && pageno <= SubTransCtl->shared->latest_page_number) return; #else if (TransactionIdToEntry(newestXact) != 0 && !TransactionIdEquals(newestXact, FirstNormalTransactionId)) return; pageno = TransactionIdToPage(newestXact); #endif LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE); #ifdef PGXC /* * We repeat the check. Another process may have written * out the page already and advanced the latest_page_number * while we were waiting for the lock. */ if (SubTransCtl->shared->latest_page_number - pageno <= SUBTRANS_WRAP_CHECK_DELTA && pageno <= SubTransCtl->shared->latest_page_number) { LWLockRelease(SubtransControlLock); return; } #endif /* Zero the page */ ZeroSUBTRANSPage(pageno); LWLockRelease(SubtransControlLock); }
/* * This func must be called ONCE on system install. It creates * the initial SUBTRANS segment. (The SUBTRANS directory is assumed to * have been created by the initdb shell script, and SUBTRANSShmemInit * must have been called already.) * * Note: it's not really necessary to create the initial segment now, * since slru.c would create it on first write anyway. But we may as well * do it to be sure the directory is set up correctly. */ void BootStrapSUBTRANS(void) { int slotno; LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE); /* Create and zero the first page of the subtrans log */ slotno = ZeroSUBTRANSPage(0); /* Make sure it's written out */ SimpleLruWritePage(SubTransCtl, slotno); Assert(!SubTransCtl->shared->page_dirty[slotno]); LWLockRelease(SubtransControlLock); }