@@ -60,11 +60,19 @@ typedef struct {
60
60
bool isReplicated ; /* transaction on replica */
61
61
bool isDistributed ; /* transaction performed INSERT/UPDATE/DELETE and has to be replicated to other nodes */
62
62
bool containsDML ; /* transaction contains DML statements */
63
+ bool isPrepared ; /* transaction was prepared for commit */
63
64
csn_t snapshot ; /* transaction snaphsot */
64
65
} MtmCurrentTrans ;
65
66
66
67
/* #define USE_SPINLOCK 1 */
67
68
69
+ typedef enum
70
+ {
71
+ HASH_LOCK_ID ,
72
+ COMMIT_LOCK_ID ,
73
+ N_LOCKS
74
+ } MtmLockIds ;
75
+
68
76
#define MTM_SHMEM_SIZE (64*1024*1024)
69
77
#define MTM_HASH_SIZE 100003
70
78
#define USEC 1000000
@@ -150,7 +158,7 @@ void MtmLock(LWLockMode mode)
150
158
#ifdef USE_SPINLOCK
151
159
SpinLockAcquire (& dtm -> spinlock );
152
160
#else
153
- LWLockAcquire (dtm -> hashLock , mode );
161
+ LWLockAcquire (dtm -> locks [ HASH_LOCK_ID ] , mode );
154
162
#endif
155
163
}
156
164
@@ -159,7 +167,7 @@ void MtmUnlock(void)
159
167
#ifdef USE_SPINLOCK
160
168
SpinLockRelease (& dtm -> spinlock );
161
169
#else
162
- LWLockRelease (dtm -> hashLock );
170
+ LWLockRelease (dtm -> locks [ HASH_LOCK_ID ] );
163
171
#endif
164
172
}
165
173
@@ -412,7 +420,7 @@ static void MtmInitialize()
412
420
{
413
421
dtm -> status = MTM_INITIALIZATION ;
414
422
dtm -> recoverySlot = 0 ;
415
- dtm -> hashLock = ( LWLock * ) GetNamedLWLockTranche (MULTIMASTER_NAME );
423
+ dtm -> locks = GetNamedLWLockTranche (MULTIMASTER_NAME );
416
424
dtm -> csn = MtmGetCurrentTime ();
417
425
dtm -> oldestXid = FirstNormalTransactionId ;
418
426
dtm -> nNodes = MtmNodes ;
@@ -423,6 +431,7 @@ static void MtmInitialize()
423
431
dtm -> transListTail = & dtm -> transListHead ;
424
432
dtm -> nReceivers = 0 ;
425
433
dtm -> timeShift = 0 ;
434
+ pg_atomic_write_u32 (& dtm -> nCommittingTrans , 0 );
426
435
PGSemaphoreCreate (& dtm -> votingSemaphore );
427
436
PGSemaphoreReset (& dtm -> votingSemaphore );
428
437
SpinLockInit (& dtm -> spinlock );
@@ -467,6 +476,7 @@ MtmBeginTransaction(MtmCurrentTrans* x)
467
476
x -> xid = GetCurrentTransactionIdIfAny ();
468
477
x -> isReplicated = false;
469
478
x -> isDistributed = IsNormalProcessingMode () && dtm -> status == MTM_ONLINE && MtmDoReplication && !am_walsender && !IsBackgroundWorker && !IsAutoVacuumWorkerProcess ();
479
+ x -> isPrepared = false;
470
480
x -> containsDML = false;
471
481
x -> snapshot = MtmAssignCSN ();
472
482
x -> gtid .xid = InvalidTransactionId ;
@@ -476,6 +486,7 @@ MtmBeginTransaction(MtmCurrentTrans* x)
476
486
}
477
487
}
478
488
489
+
479
490
/*
480
491
* We need to pass snapshot to WAL-sender, so create record in transaction status hash table
481
492
* before commit
@@ -488,8 +499,14 @@ static void MtmPrepareTransaction(MtmCurrentTrans* x)
488
499
if (!x -> isDistributed ) {
489
500
return ;
490
501
}
491
- x -> xid = GetCurrentTransactionId ();
502
+ /* Check that commits are not disabled */
503
+ LWLockAcquire (dtm -> locks [COMMIT_LOCK_ID ], LW_SHARED );
504
+ LWLockRelease (dtm -> locks [COMMIT_LOCK_ID ]);
492
505
506
+ pg_atomic_fetch_add_u32 (dtm -> nCommittingTransactions , 1 );
507
+ x -> isPrepared = true;
508
+ x -> xid = GetCurrentTransactionId ();
509
+
493
510
MtmLock (LW_EXCLUSIVE );
494
511
ts = hash_search (xid2state , & x -> xid , HASH_ENTER , NULL );
495
512
ts -> status = TRANSACTION_STATUS_IN_PROGRESS ;
@@ -500,6 +517,7 @@ static void MtmPrepareTransaction(MtmCurrentTrans* x)
500
517
ts -> procno = MyProc -> pgprocno ;
501
518
ts -> nVotes = 0 ;
502
519
ts -> done = false;
520
+
503
521
if (TransactionIdIsValid (x -> gtid .xid )) {
504
522
ts -> gtid = x -> gtid ;
505
523
} else {
@@ -528,6 +546,9 @@ MtmEndTransaction(MtmCurrentTrans* x, bool commit)
528
546
MtmAdjustSubtransactions (ts );
529
547
MtmUnlock ();
530
548
}
549
+ if (x -> isPrepared ) {
550
+ pg_atomic_fetch_add_u32 (dtm -> nCommittingTransactions , -1 );
551
+ }
531
552
x -> snapshot = INVALID_CSN ;
532
553
x -> xid = InvalidTransactionId ;
533
554
x -> gtid .xid = InvalidTransactionId ;
@@ -547,6 +568,39 @@ void MtmSendNotificationMessage(MtmTransState* ts)
547
568
}
548
569
}
549
570
571
+ void MtmUpdateStatus (bool recovered )
572
+ {
573
+ if (dtm -> status == MTM_RECOVERY ) {
574
+ MtmLock (LW_EXCLUSIVE );
575
+ dtm -> status = MTM_ONLINE ; /* Is it all we shoudl do t switch to nortmal state */
576
+ MtmUnlock ();
577
+ }
578
+ }
579
+
580
+ void MtmRecoveryCompleted (int nodeId )
581
+ {
582
+ if (BIT_CHECK (dtm -> pglogicalNodeMask , nodeId - 1 )) {
583
+ if (MyWalSnd -> sentPtr == GetXLogInsertRecPtr ()) {
584
+ /* Ok, now we done with recovery of node */
585
+ MtmLock (LW_EXCLUSIVE );
586
+ dtm -> pglogicalNodeMask &= (int64 )1 << (nodeId - 1 ); /* now node is assumed as recovered */
587
+ dtm -> nNodes += 1 ;
588
+ MtmUnlock ();
589
+
590
+ LWLockRelease (dtm -> locks [COMMIT_LOCK_ID ]); /* enable commits */
591
+
592
+ return true;
593
+ } else if (MyWalSnd -> sentPtr + MtmSlotDelayThreashold > GetXLogInsertRecPtr ()) {
594
+ /* we almost done with recovery of node.. */
595
+ LWLockAcquire (dtm -> locks [COMMIT_LOCK_ID ], LW_EXCLUSIVE ); /* disable new commits */
596
+ }
597
+ return false;
598
+ } else {
599
+ return true;
600
+ }
601
+ }
602
+
603
+
550
604
static bool
551
605
MtmCommitTransaction (TransactionId xid , int nsubxids , TransactionId * subxids )
552
606
{
@@ -803,7 +857,7 @@ _PG_init(void)
803
857
* resources in mtm_shmem_startup().
804
858
*/
805
859
RequestAddinShmemSpace (MTM_SHMEM_SIZE + MtmQueueSize );
806
- RequestNamedLWLockTranche (MULTIMASTER_NAME , 1 );
860
+ RequestNamedLWLockTranche (MULTIMASTER_NAME , N_LOCKS );
807
861
808
862
MtmNodes = MtmStartReceivers (MtmConnStrs , MtmNodeId );
809
863
if (MtmNodes < 2 ) {
0 commit comments