@@ -323,10 +323,9 @@ static SlruCtlData OldSerXidSlruCtlData;
323323
324324typedef 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 */
730724static void
731725OldSerXidAdd (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 */
852850static void
853851OldSerXidSetActiveSerXmin (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/*------------------------------------------------------------------------*/
0 commit comments