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();