Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4cd3fb6

Browse files
committed
Truncate predicate lock manager's SLRU lazily at checkpoint. That's safer
than doing it aggressively whenever the tail-XID pointer is advanced, because this way we don't need to do it while holding SerializableXactHashLock. This also fixes bug #5915 spotted by YAMAMOTO Takashi, and removes an obsolete comment spotted by Kevin Grittner.
1 parent 804d13a commit 4cd3fb6

File tree

3 files changed

+69
-52
lines changed

3 files changed

+69
-52
lines changed

src/backend/access/transam/xlog.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "storage/ipc.h"
4949
#include "storage/latch.h"
5050
#include "storage/pmsignal.h"
51+
#include "storage/predicate.h"
5152
#include "storage/procarray.h"
5253
#include "storage/reinit.h"
5354
#include "storage/smgr.h"
@@ -7875,6 +7876,7 @@ CheckPointGuts(XLogRecPtr checkPointRedo, int flags)
78757876
CheckPointCLOG();
78767877
CheckPointSUBTRANS();
78777878
CheckPointMultiXact();
7879+
CheckPointPredicate();
78787880
CheckPointRelationMap();
78797881
CheckPointBuffers(flags); /* performs all required fsyncs */
78807882
/* We deliberately delay 2PC checkpointing as long as possible */

src/backend/storage/lmgr/predicate.c

Lines changed: 65 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,9 @@ static SlruCtlData OldSerXidSlruCtlData;
323323

324324
typedef struct OldSerXidControlData
325325
{
326-
int headPage;
327-
int tailSegment;
328-
TransactionId headXid;
329-
TransactionId tailXid;
326+
int headPage; /* newest initialized page */
327+
TransactionId headXid; /* newest valid Xid in the SLRU */
328+
TransactionId tailXid; /* oldest xmin we might be interested in */
330329
bool warningIssued;
331330
} OldSerXidControlData;
332331

@@ -711,7 +710,6 @@ OldSerXidInit(void)
711710
* Set control information to reflect empty SLRU.
712711
*/
713712
oldSerXidControl->headPage = -1;
714-
oldSerXidControl->tailSegment = -1;
715713
oldSerXidControl->headXid = InvalidTransactionId;
716714
oldSerXidControl->tailXid = InvalidTransactionId;
717715
oldSerXidControl->warningIssued = false;
@@ -722,18 +720,14 @@ OldSerXidInit(void)
722720
* Record a committed read write serializable xid and the minimum
723721
* commitSeqNo of any transactions to which this xid had a rw-conflict out.
724722
* A zero seqNo means that there were no conflicts out from xid.
725-
*
726-
* The return value is normally false -- true means that we're about to
727-
* wrap around our space for tracking these xids, so the caller might want
728-
* to take action to prevent that.
729723
*/
730724
static void
731725
OldSerXidAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
732726
{
733727
TransactionId tailXid;
734728
int targetPage;
735729
int slotno;
736-
int page;
730+
int firstZeroPage;
737731
int xidSpread;
738732
bool isNewPage;
739733

@@ -745,30 +739,34 @@ OldSerXidAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
745739

746740
/*
747741
* If no serializable transactions are active, there shouldn't be anything
748-
* to push out to this SLRU. Hitting this assert would mean there's
742+
* to push out to the SLRU. Hitting this assert would mean there's
749743
* something wrong with the earlier cleanup logic.
750744
*/
751745
tailXid = oldSerXidControl->tailXid;
752746
Assert(TransactionIdIsValid(tailXid));
753747

748+
/*
749+
* If the SLRU is currently unused, zero out the whole active region
750+
* from tailXid to headXid before taking it into use. Otherwise zero
751+
* out only any new pages that enter the tailXid-headXid range as we
752+
* advance headXid.
753+
*/
754754
if (oldSerXidControl->headPage < 0)
755755
{
756-
page = OldSerXidPage(tailXid);
757-
oldSerXidControl->tailSegment = OldSerXidSegment(page);
758-
page = oldSerXidControl->tailSegment * OLDSERXID_ENTRIESPERPAGE;
756+
firstZeroPage = OldSerXidPage(tailXid);
759757
isNewPage = true;
760758
}
761759
else
762760
{
763-
page = OldSerXidNextPage(oldSerXidControl->headPage);
764-
isNewPage = OldSerXidPagePrecedesLogically(oldSerXidControl->headPage, targetPage);
761+
firstZeroPage = OldSerXidNextPage(oldSerXidControl->headPage);
762+
isNewPage = OldSerXidPagePrecedesLogically(oldSerXidControl->headPage,
763+
targetPage);
765764
}
766765

767766
if (!TransactionIdIsValid(oldSerXidControl->headXid)
768767
|| TransactionIdFollows(xid, oldSerXidControl->headXid))
769768
oldSerXidControl->headXid = xid;
770-
if (oldSerXidControl->headPage < 0
771-
|| OldSerXidPagePrecedesLogically(oldSerXidControl->headPage, targetPage))
769+
if (isNewPage)
772770
oldSerXidControl->headPage = targetPage;
773771

774772
xidSpread = (((uint32) xid) - ((uint32) tailXid));
@@ -788,10 +786,10 @@ OldSerXidAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
788786
if (isNewPage)
789787
{
790788
/* Initialize intervening pages. */
791-
while (page != targetPage)
789+
while (firstZeroPage != targetPage)
792790
{
793-
(void) SimpleLruZeroPage(OldSerXidSlruCtl, page);
794-
page = OldSerXidNextPage(page);
791+
(void) SimpleLruZeroPage(OldSerXidSlruCtl, firstZeroPage);
792+
firstZeroPage = OldSerXidNextPage(firstZeroPage);
795793
}
796794
slotno = SimpleLruZeroPage(OldSerXidSlruCtl, targetPage);
797795
}
@@ -846,31 +844,24 @@ OldSerXidGetMinConflictCommitSeqNo(TransactionId xid)
846844
/*
847845
* Call this whenever there is a new xmin for active serializable
848846
* transactions. We don't need to keep information on transactions which
849-
* preceed that. InvalidTransactionId means none active, so everything in
850-
* the SLRU should be discarded.
847+
* precede that. InvalidTransactionId means none active, so everything in
848+
* the SLRU can be discarded.
851849
*/
852850
static void
853851
OldSerXidSetActiveSerXmin(TransactionId xid)
854852
{
855-
int newTailPage;
856-
int newTailSegment;
857-
858853
LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
859854

860855
/*
861856
* When no sxacts are active, nothing overlaps, set the xid values to
862-
* invalid to show that there are no valid entries. Don't clear the
863-
* segment/page information, though. A new xmin might still land in an
864-
* existing segment, and we don't want to repeatedly delete and re-create
865-
* the same segment file.
857+
* invalid to show that there are no valid entries. Don't clear headPage,
858+
* though. A new xmin might still land on that page, and we don't want
859+
* to repeatedly zero out the same page.
866860
*/
867861
if (!TransactionIdIsValid(xid))
868862
{
869-
if (TransactionIdIsValid(oldSerXidControl->tailXid))
870-
{
871-
oldSerXidControl->headXid = InvalidTransactionId;
872-
oldSerXidControl->tailXid = InvalidTransactionId;
873-
}
863+
oldSerXidControl->tailXid = InvalidTransactionId;
864+
oldSerXidControl->headXid = InvalidTransactionId;
874865
LWLockRelease(OldSerXidLock);
875866
return;
876867
}
@@ -886,7 +877,9 @@ OldSerXidSetActiveSerXmin(TransactionId xid)
886877
Assert(oldSerXidControl->headPage < 0);
887878
if (!TransactionIdIsValid(oldSerXidControl->tailXid)
888879
|| TransactionIdPrecedes(xid, oldSerXidControl->tailXid))
880+
{
889881
oldSerXidControl->tailXid = xid;
882+
}
890883
LWLockRelease(OldSerXidLock);
891884
return;
892885
}
@@ -896,37 +889,57 @@ OldSerXidSetActiveSerXmin(TransactionId xid)
896889

897890
oldSerXidControl->tailXid = xid;
898891

899-
/* Exit quickly if there are no segments active. */
892+
LWLockRelease(OldSerXidLock);
893+
}
894+
895+
/*
896+
* Perform a checkpoint --- either during shutdown, or on-the-fly
897+
*
898+
* We don't have any data that needs to survive a restart, but this is a
899+
* convenient place to truncate the SLRU.
900+
*/
901+
void
902+
CheckPointPredicate(void)
903+
{
904+
int tailPage;
905+
906+
LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
907+
908+
/* Exit quickly if the SLRU is currently not in use. */
900909
if (oldSerXidControl->headPage < 0)
901910
{
902911
LWLockRelease(OldSerXidLock);
903912
return;
904913
}
905914

906-
newTailPage = OldSerXidPage(xid);
907-
newTailSegment = OldSerXidSegment(newTailPage);
908-
909-
/* Exit quickly if we're still on the same segment. */
910-
if (newTailSegment == oldSerXidControl->tailSegment)
915+
if (TransactionIdIsValid(oldSerXidControl->tailXid))
911916
{
912-
LWLockRelease(OldSerXidLock);
913-
return;
917+
/* We can truncate the SLRU up to the page containing tailXid */
918+
tailPage = OldSerXidPage(oldSerXidControl->tailXid);
914919
}
915-
916-
oldSerXidControl->tailSegment = newTailSegment;
917-
918-
/* See if that has cleared the last segment. */
919-
if (OldSerXidPagePrecedesLogically(oldSerXidControl->headPage,
920-
newTailSegment * SLRU_PAGES_PER_SEGMENT))
920+
else
921921
{
922-
oldSerXidControl->headXid = InvalidTransactionId;
922+
/*
923+
* The SLRU is no longer needed. Truncate everything but the last
924+
* page. We don't dare to touch the last page in case the SLRU is
925+
* taken back to use, and the new tail falls on the same page.
926+
*/
927+
tailPage = oldSerXidControl->headPage;
923928
oldSerXidControl->headPage = -1;
924-
oldSerXidControl->tailSegment = -1;
925929
}
926930

927931
LWLockRelease(OldSerXidLock);
928932

929-
SimpleLruTruncate(OldSerXidSlruCtl, newTailPage);
933+
/*
934+
* Flush dirty SLRU pages to disk
935+
*
936+
* This is not actually necessary from a correctness point of view. We do
937+
* it merely as a debugging aid.
938+
*/
939+
SimpleLruFlush(OldSerXidSlruCtl, true);
940+
941+
/* Truncate away pages that are no longer required */
942+
SimpleLruTruncate(OldSerXidSlruCtl, tailPage);
930943
}
931944

932945
/*------------------------------------------------------------------------*/

src/include/storage/predicate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ extern int max_predicate_locks_per_xact;
3636
extern void InitPredicateLocks(void);
3737
extern Size PredicateLockShmemSize(void);
3838

39+
extern void CheckPointPredicate(void);
40+
3941
/* predicate lock reporting */
4042
extern bool PageIsPredicateLocked(const Relation relation, const BlockNumber blkno);
4143

0 commit comments

Comments
 (0)