@@ -178,6 +178,7 @@ int MtmConnectAttempts;
178178int MtmConnectTimeout ;
179179int MtmKeepaliveTimeout ;
180180int MtmReconnectAttempts ;
181+ int MtmNodeDisableDelay ;
181182bool MtmUseRaftable ;
182183MtmConnectionInfo * MtmConnections ;
183184
@@ -992,6 +993,7 @@ void MtmRecoveryCompleted(void)
992993 MtmLock (LW_EXCLUSIVE );
993994 Mtm -> recoverySlot = 0 ;
994995 BIT_CLEAR (Mtm -> disabledNodeMask , MtmNodeId - 1 );
996+ Mtm -> nodes [MtmNodeId - 1 ].lastStatusChangeTime = time (NULL );
995997 /* Mode will be changed to online once all locagical reciever are connected */
996998 MtmSwitchClusterMode (MTM_CONNECTED );
997999 MtmUnlock ();
@@ -1080,6 +1082,7 @@ bool MtmRecoveryCaughtUp(int nodeId, XLogRecPtr slotLSN)
10801082 /* We are lucky: caugth-up without locking cluster! */
10811083 }
10821084 BIT_CLEAR (Mtm -> disabledNodeMask , nodeId - 1 );
1085+ Mtm -> nodes [nodeId - 1 ].lastStatusChangeTime = time (NULL );
10831086 Mtm -> nNodes += 1 ;
10841087 caughtUp = true;
10851088 } else if (!BIT_CHECK (Mtm -> nodeLockerMask , nodeId - 1 )
@@ -1222,13 +1225,15 @@ bool MtmRefreshClusterStatus(bool nowait)
12221225 if (mask & 1 ) {
12231226 Mtm -> nNodes -= 1 ;
12241227 BIT_SET (Mtm -> disabledNodeMask , i );
1228+ Mtm -> nodes [i ].lastStatusChangeTime = time (NULL );
12251229 }
12261230 }
12271231 mask = clique & Mtm -> disabledNodeMask ; /* new enabled nodes mask */
12281232 for (i = 0 ; mask != 0 ; i ++ , mask >>= 1 ) {
12291233 if (mask & 1 ) {
12301234 Mtm -> nNodes += 1 ;
12311235 BIT_CLEAR (Mtm -> disabledNodeMask , i );
1236+ Mtm -> nodes [i ].lastStatusChangeTime = time (NULL );
12321237 }
12331238 }
12341239 MtmCheckQuorum ();
@@ -1268,6 +1273,11 @@ void MtmOnNodeDisconnect(int nodeId)
12681273{
12691274 MtmTransState * ts ;
12701275
1276+ if (Mtm -> nodes [nodeId - 1 ].lastStatusChangeTime + MtmNodeDisableDelay > time (NULL )) {
1277+ /* Avoid false detection of node failure and prevent node status blinking */
1278+ return ;
1279+ }
1280+
12711281 BIT_SET (Mtm -> connectivityMask , nodeId - 1 );
12721282 BIT_SET (Mtm -> reconnectMask , nodeId - 1 );
12731283 RaftableSet (psprintf ("node-mask-%d" , MtmNodeId ), & Mtm -> connectivityMask , sizeof Mtm -> connectivityMask , false);
@@ -1278,6 +1288,7 @@ void MtmOnNodeDisconnect(int nodeId)
12781288 if (!MtmRefreshClusterStatus (false)) {
12791289 MtmLock (LW_EXCLUSIVE );
12801290 if (!BIT_CHECK (Mtm -> disabledNodeMask , nodeId - 1 )) {
1291+ Mtm -> nodes [nodeId - 1 ].lastStatusChangeTime = time (NULL );
12811292 BIT_SET (Mtm -> disabledNodeMask , nodeId - 1 );
12821293 Mtm -> nNodes -= 1 ;
12831294 MtmCheckQuorum ();
@@ -1445,6 +1456,7 @@ static void MtmInitialize()
14451456 for (i = 0 ; i < MtmNodes ; i ++ ) {
14461457 Mtm -> nodes [i ].oldestSnapshot = 0 ;
14471458 Mtm -> nodes [i ].transDelay = 0 ;
1459+ Mtm -> nodes [i ].lastStatusChangeTime = time (NULL );
14481460 Mtm -> nodes [i ].con = MtmConnections [i ];
14491461 }
14501462 PGSemaphoreCreate (& Mtm -> votingSemaphore );
@@ -1565,10 +1577,25 @@ _PG_init(void)
15651577 if (!process_shared_preload_libraries_in_progress )
15661578 return ;
15671579
1580+ DefineCustomIntVariable (
1581+ "multimaster.node_disable_delay" ,
1582+ "Minamal amount of time (sec) between node status change" ,
1583+ "This delay is used to avoid false detection of node failure and to prevent blinking of node status node" ,
1584+ & MtmNodeDisableDelay ,
1585+ 1 ,
1586+ 1 ,
1587+ INT_MAX ,
1588+ PGC_BACKEND ,
1589+ 0 ,
1590+ NULL ,
1591+ NULL ,
1592+ NULL
1593+ );
1594+
15681595 DefineCustomIntVariable (
15691596 "multimaster.min_recovery_lag" ,
15701597 "Minamal lag of WAL-sender performing recovery after which cluster is locked until recovery is completed" ,
1571- "When wal-sender almost catch-up WAL current position we need to stop 'Achilles tortile compeition ' and "
1598+ "When wal-sender almost catch-up WAL current position we need to stop 'Achilles tortile competition ' and "
15721599 "temporary stop commit of new transactions until node will be completely repared" ,
15731600 & MtmMinRecoveryLag ,
15741601 100000 ,
@@ -1890,6 +1917,7 @@ void MtmDropNode(int nodeId, bool dropSlot)
18901917 {
18911918 elog (ERROR , "NodeID %d is out of range [1,%d]" , nodeId , Mtm -> nNodes );
18921919 }
1920+ Mtm -> nodes [nodeId - 1 ].lastStatusChangeTime = time (NULL );
18931921 BIT_SET (Mtm -> disabledNodeMask , nodeId - 1 );
18941922 Mtm -> nNodes -= 1 ;
18951923 MtmCheckQuorum ();
@@ -1940,13 +1968,15 @@ MtmReplicationStartupHook(struct PGLogicalStartupHookArgs* args)
19401968 if (MtmIsRecoverySession ) {
19411969 MTM_LOG1 ("%d: Node %d start recovery of node %d" , MyProcPid , MtmNodeId , MtmReplicationNodeId );
19421970 if (!BIT_CHECK (Mtm -> disabledNodeMask , MtmReplicationNodeId - 1 )) {
1971+ Mtm -> nodes [MtmReplicationNodeId - 1 ].lastStatusChangeTime = time (NULL );
19431972 BIT_SET (Mtm -> disabledNodeMask , MtmReplicationNodeId - 1 );
19441973 Mtm -> nNodes -= 1 ;
19451974 MtmCheckQuorum ();
19461975 }
19471976 } else if (BIT_CHECK (Mtm -> disabledNodeMask , MtmReplicationNodeId - 1 )) {
19481977 if (recoveryCompleted ) {
19491978 MTM_LOG1 ("Node %d consider that recovery of node %d is completed: start normal replication" , MtmNodeId , MtmReplicationNodeId );
1979+ Mtm -> nodes [MtmReplicationNodeId - 1 ].lastStatusChangeTime = time (NULL );
19501980 BIT_CLEAR (Mtm -> disabledNodeMask , MtmReplicationNodeId - 1 );
19511981 Mtm -> nNodes += 1 ;
19521982 MtmCheckQuorum ();
@@ -2057,8 +2087,8 @@ typedef struct
20572087 int nodeId ;
20582088 char * connStrPtr ;
20592089 TupleDesc desc ;
2060- Datum values [7 ];
2061- bool nulls [7 ];
2090+ Datum values [8 ];
2091+ bool nulls [8 ];
20622092} MtmGetNodeStateCtx ;
20632093
20642094Datum
@@ -2095,11 +2125,12 @@ mtm_get_nodes_state(PG_FUNCTION_ARGS)
20952125 usrfctx -> values [4 ] = Int64GetDatum (lag );
20962126 usrfctx -> nulls [4 ] = lag < 0 ;
20972127 usrfctx -> values [5 ] = Int64GetDatum (Mtm -> transCount ? Mtm -> nodes [usrfctx -> nodeId - 1 ].transDelay /Mtm -> transCount : 0 );
2128+ usrfctx -> values [6 ] = TimestampTzGetDatum (time_t_to_timestamptz (Mtm -> nodes [usrfctx -> nodeId - 1 ].lastStatusChangeTime ));
20982129 p = strchr (usrfctx -> connStrPtr , ',' );
20992130 if (p != NULL ) {
21002131 * p ++ = '\0' ;
21012132 }
2102- usrfctx -> values [6 ] = CStringGetTextDatum (usrfctx -> connStrPtr );
2133+ usrfctx -> values [7 ] = CStringGetTextDatum (usrfctx -> connStrPtr );
21032134 usrfctx -> connStrPtr = p ;
21042135 usrfctx -> nodeId += 1 ;
21052136
0 commit comments