@@ -199,6 +199,7 @@ static int MtmMinRecoveryLag;
199
199
static int MtmMaxRecoveryLag ;
200
200
static int Mtm2PCPrepareRatio ;
201
201
static int Mtm2PCMinTimeout ;
202
+ static int MtmGcPeriod ;
202
203
static bool MtmIgnoreTablesWithoutPk ;
203
204
204
205
static ExecutorFinish_hook_type PreviousExecutorFinishHook ;
@@ -341,16 +342,20 @@ csn_t MtmTransactionSnapshot(TransactionId xid)
341
342
Snapshot MtmGetSnapshot (Snapshot snapshot )
342
343
{
343
344
snapshot = PgGetSnapshotData (snapshot );
344
- RecentGlobalDataXmin = RecentGlobalXmin = Mtm -> oldestXid ;//MtmAdjustOldestXid(RecentGlobalDataXmin);
345
+ RecentGlobalDataXmin = RecentGlobalXmin = Mtm -> oldestXid ;
345
346
return snapshot ;
346
347
}
347
348
348
349
349
350
TransactionId MtmGetOldestXmin (Relation rel , bool ignoreVacuum )
350
351
{
351
352
TransactionId xmin = PgGetOldestXmin (NULL , false); /* consider all backends */
352
- xmin = MtmAdjustOldestXid (xmin );
353
- return xmin ;
353
+ if (TransactionIdIsValid (xmin )) {
354
+ MtmLock (LW_EXCLUSIVE );
355
+ xmin = MtmAdjustOldestXid (xmin );
356
+ MtmUnlock ();
357
+ }
358
+ return xmin ;
354
359
}
355
360
356
361
bool MtmXidInMVCCSnapshot (TransactionId xid , Snapshot snapshot )
@@ -445,53 +450,50 @@ bool MtmXidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
445
450
static TransactionId
446
451
MtmAdjustOldestXid (TransactionId xid )
447
452
{
448
- if (TransactionIdIsValid (xid )) {
449
- MtmTransState * ts , * prev = NULL ;
450
- int i ;
451
-
452
- MtmLock (LW_EXCLUSIVE );
453
- ts = (MtmTransState * )hash_search (MtmXid2State , & xid , HASH_FIND , NULL );
454
- if (ts != NULL ) {
455
- csn_t oldestSnapshot = ts -> snapshot ;
456
- Mtm -> nodes [MtmNodeId - 1 ].oldestSnapshot = oldestSnapshot ;
457
- for (i = 0 ; i < Mtm -> nAllNodes ; i ++ ) {
458
- if (!BIT_CHECK (Mtm -> disabledNodeMask , i )
459
- && Mtm -> nodes [i ].oldestSnapshot < oldestSnapshot )
460
- {
461
- oldestSnapshot = Mtm -> nodes [i ].oldestSnapshot ;
462
- }
463
- }
464
- oldestSnapshot -= MtmVacuumDelay * USECS_PER_SEC ;
465
-
466
- for (ts = Mtm -> transListHead ;
467
- ts != NULL
468
- && ts -> csn < oldestSnapshot
469
- && TransactionIdPrecedes (ts -> xid , xid )
470
- && (ts -> status == TRANSACTION_STATUS_COMMITTED ||
471
- ts -> status == TRANSACTION_STATUS_ABORTED );
472
- prev = ts , ts = ts -> next )
453
+ int i ;
454
+ MtmTransState * prev = NULL ;
455
+ MtmTransState * ts = (MtmTransState * )hash_search (MtmXid2State , & xid , HASH_FIND , NULL );
456
+ MTM_LOG1 ("%d: MtmAdjustOldestXid(%d): snapshot=%ld, csn=%ld, status=%d" , MyProcPid , xid , ts != NULL ? ts -> snapshot : 0 , ts != NULL ? ts -> csn : 0 , ts != NULL ? ts -> status : -1 );
457
+ Mtm -> gcCount = 0 ;
458
+ if (ts != NULL ) {
459
+ csn_t oldestSnapshot = ts -> snapshot ;
460
+ Mtm -> nodes [MtmNodeId - 1 ].oldestSnapshot = oldestSnapshot ;
461
+ for (i = 0 ; i < Mtm -> nAllNodes ; i ++ ) {
462
+ if (!BIT_CHECK (Mtm -> disabledNodeMask , i )
463
+ && Mtm -> nodes [i ].oldestSnapshot < oldestSnapshot )
473
464
{
474
- if (prev != NULL ) {
475
- /* Remove information about too old transactions */
476
- hash_search (MtmXid2State , & prev -> xid , HASH_REMOVE , NULL );
477
- }
465
+ oldestSnapshot = Mtm -> nodes [i ].oldestSnapshot ;
478
466
}
479
- }
480
- if (MtmUseDtm )
467
+ }
468
+ oldestSnapshot -= MtmVacuumDelay * USECS_PER_SEC ;
469
+
470
+ for (ts = Mtm -> transListHead ;
471
+ ts != NULL
472
+ && ts -> csn < oldestSnapshot
473
+ && TransactionIdPrecedes (ts -> xid , xid )
474
+ && (ts -> status == TRANSACTION_STATUS_COMMITTED ||
475
+ ts -> status == TRANSACTION_STATUS_ABORTED );
476
+ prev = ts , ts = ts -> next )
481
477
{
482
478
if (prev != NULL ) {
483
- Mtm -> transListHead = prev ;
484
- Mtm -> oldestXid = xid = prev -> xid ;
485
- } else if (TransactionIdPrecedes (Mtm -> oldestXid , xid )) {
486
- xid = Mtm -> oldestXid ;
487
- }
488
- } else {
489
- if (prev != NULL ) {
490
- Mtm -> transListHead = prev ;
479
+ /* Remove information about too old transactions */
480
+ hash_search (MtmXid2State , & prev -> xid , HASH_REMOVE , NULL );
491
481
}
492
482
}
493
- MtmUnlock ();
494
- }
483
+ }
484
+ if (MtmUseDtm )
485
+ {
486
+ if (prev != NULL ) {
487
+ Mtm -> transListHead = prev ;
488
+ Mtm -> oldestXid = xid = prev -> xid ;
489
+ } else if (TransactionIdPrecedes (Mtm -> oldestXid , xid )) {
490
+ xid = Mtm -> oldestXid ;
491
+ }
492
+ } else {
493
+ if (prev != NULL ) {
494
+ Mtm -> transListHead = prev ;
495
+ }
496
+ }
495
497
return xid ;
496
498
}
497
499
/*
@@ -613,7 +615,12 @@ static void
613
615
MtmBeginTransaction (MtmCurrentTrans * x )
614
616
{
615
617
if (x -> snapshot == INVALID_CSN ) {
616
- MtmLock (LW_EXCLUSIVE );
618
+ TransactionId xmin = (Mtm -> gcCount >= MtmGcPeriod ) ? PgGetOldestXmin (NULL , false) : InvalidTransactionId ; /* Get oldest xmin outside critical section */
619
+
620
+ MtmLock (LW_EXCLUSIVE );
621
+ if (TransactionIdIsValid (xmin ) && Mtm -> gcCount >= MtmGcPeriod ) {
622
+ MtmAdjustOldestXid (xmin );
623
+ }
617
624
x -> xid = GetCurrentTransactionIdIfAny ();
618
625
x -> isReplicated = false;
619
626
x -> isDistributed = MtmIsUserTransaction ();
@@ -689,7 +696,6 @@ MtmPrePrepareTransaction(MtmCurrentTrans* x)
689
696
}
690
697
691
698
MtmLock (LW_EXCLUSIVE );
692
-
693
699
/*
694
700
* Check if there is global multimaster lock preventing new transaction from commit to make a chance to wal-senders to catch-up.
695
701
* Only "own" transactions are blacked. Transactions replicated from other nodes (including recovered transaction) should be proceeded
@@ -715,8 +721,10 @@ MtmPrePrepareTransaction(MtmCurrentTrans* x)
715
721
716
722
x -> isPrepared = true;
717
723
x -> csn = ts -> csn ;
718
-
724
+
719
725
Mtm -> transCount += 1 ;
726
+ Mtm -> gcCount += 1 ;
727
+
720
728
MtmTransactionListAppend (ts );
721
729
MtmAddSubtransactions (ts , subxids , ts -> nSubxids );
722
730
MTM_LOG3 ("%d: MtmPrePrepareTransaction prepare commit of %d (gtid.xid=%d, gtid.node=%d, CSN=%ld)" ,
@@ -1465,8 +1473,9 @@ static void MtmInitialize()
1465
1473
Mtm -> transListHead = NULL ;
1466
1474
Mtm -> transListTail = & Mtm -> transListHead ;
1467
1475
Mtm -> nReceivers = 0 ;
1468
- Mtm -> timeShift = 0 ;
1476
+ Mtm -> timeShift = 0 ;
1469
1477
Mtm -> transCount = 0 ;
1478
+ Mtm -> gcCount = 0 ;
1470
1479
Mtm -> nConfigChanges = 0 ;
1471
1480
Mtm -> localTablesHashLoaded = false;
1472
1481
for (i = 0 ; i < MtmNodes ; i ++ ) {
@@ -1599,6 +1608,21 @@ _PG_init(void)
1599
1608
if (!process_shared_preload_libraries_in_progress )
1600
1609
return ;
1601
1610
1611
+ DefineCustomIntVariable (
1612
+ "multimaster.gc_period" ,
1613
+ "Number of distributed transactions after which garbage collection is started" ,
1614
+ "Multimaster is building xid->csn hash map which has to be cleaned to avoid hash overflow. This parameter specifies interval of invoking garbage collector for this map" ,
1615
+ & MtmGcPeriod ,
1616
+ MTM_HASH_SIZE /10 ,
1617
+ 1 ,
1618
+ INT_MAX ,
1619
+ PGC_BACKEND ,
1620
+ 0 ,
1621
+ NULL ,
1622
+ NULL ,
1623
+ NULL
1624
+ );
1625
+
1602
1626
DefineCustomIntVariable (
1603
1627
"multimaster.max_nodes" ,
1604
1628
"Maximal number of cluster nodes" ,
@@ -2338,7 +2362,7 @@ mtm_get_cluster_state(PG_FUNCTION_ARGS)
2338
2362
values [11 ] = Int32GetDatum (Mtm -> recoverySlot );
2339
2363
values [12 ] = Int64GetDatum (hash_get_num_entries (MtmXid2State ));
2340
2364
values [13 ] = Int64GetDatum (hash_get_num_entries (MtmGid2State ));
2341
- values [14 ] = Int64GetDatum (Mtm -> oldestSnapshot );
2365
+ values [14 ] = Int32GetDatum (Mtm -> oldestXid );
2342
2366
values [15 ] = Int32GetDatum (Mtm -> nConfigChanges );
2343
2367
2344
2368
PG_RETURN_DATUM (HeapTupleGetDatum (heap_form_tuple (desc , values , nulls )));
0 commit comments