This is an automated email from the ASF dual-hosted git repository.

ibessonov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 7a10df1a996 IGNITE-28456 Fix race in NodeImpl.init() causing double 
electSelf() for single-node Raft groups (#7934)
7a10df1a996 is described below

commit 7a10df1a9965347cf19c274de5781a0bb79985f0
Author: Mirza Aliev <[email protected]>
AuthorDate: Wed Apr 8 18:40:40 2026 +0400

    IGNITE-28456 Fix race in NodeImpl.init() causing double electSelf() for 
single-node Raft groups (#7934)
---
 .../java/org/apache/ignite/raft/jraft/core/NodeImpl.java   | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/core/NodeImpl.java 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/core/NodeImpl.java
index 7e5be3b033f..60aa117772c 100644
--- a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/core/NodeImpl.java
+++ b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/core/NodeImpl.java
@@ -50,11 +50,8 @@ import org.apache.ignite.internal.hlc.HybridTimestamp;
 import org.apache.ignite.internal.logger.IgniteLogger;
 import org.apache.ignite.internal.logger.Loggers;
 import org.apache.ignite.internal.metrics.MetricManager;
-import org.apache.ignite.internal.metrics.sources.FsmCallerMetricSource;
-import org.apache.ignite.internal.metrics.sources.LogManagerMetricSource;
 import org.apache.ignite.internal.metrics.sources.NodeMetricSource;
 import org.apache.ignite.internal.metrics.sources.RaftMetricSource;
-import org.apache.ignite.internal.metrics.sources.ReadOnlyServiceMetricSource;
 import org.apache.ignite.internal.raft.JraftGroupEventsListener;
 import org.apache.ignite.internal.raft.WriteCommand;
 import org.apache.ignite.internal.raft.service.SafeTimeAwareCommandClosure;
@@ -1159,8 +1156,15 @@ public class NodeImpl implements Node, RaftServerService 
{
             this.writeLock.lock();
             if (this.conf.isStable() && this.conf.getConf().size() == 1 && 
this.conf.getConf().contains(this.serverId)) {
                 // The group contains only this server which must be the 
LEADER, trigger
-                // the timer immediately.
-                electSelf();
+                // the timer immediately. Skip if already a leader — the 
election timer may have
+                // fired and completed a full election between stepDown() and 
this lock acquisition,
+                // in which case calling electSelf() again would corrupt 
BallotBox / confCtx state.
+                if (this.state != State.STATE_LEADER) {
+                    electSelf();
+                }
+                else {
+                    this.writeLock.unlock();
+                }
             }
             else {
                 this.writeLock.unlock();

Reply via email to