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

rpuch 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 cf7cbf33851 IGNITE-26680 Avoid NullPointerException on metastorage 
recovery (#6745)
cf7cbf33851 is described below

commit cf7cbf33851464dbe7af562e940cd66bcfa10fae
Author: Roman Puchkovskiy <[email protected]>
AuthorDate: Mon Oct 13 11:27:22 2025 +0400

    IGNITE-26680 Avoid NullPointerException on metastorage recovery (#6745)
---
 .../metastorage/impl/RecoveryRevisionsListenerImpl.java        |  5 +++--
 .../internal/metastorage/server/AbstractKeyValueStorage.java   | 10 +++++++---
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git 
a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/RecoveryRevisionsListenerImpl.java
 
b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/RecoveryRevisionsListenerImpl.java
index 8147d916d72..6453ced227a 100644
--- 
a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/RecoveryRevisionsListenerImpl.java
+++ 
b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/RecoveryRevisionsListenerImpl.java
@@ -20,19 +20,20 @@ package org.apache.ignite.internal.metastorage.impl;
 import static org.apache.ignite.internal.util.ExceptionUtils.sneakyThrow;
 
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 import org.apache.ignite.internal.lang.NodeStoppingException;
 import org.apache.ignite.internal.metastorage.Revisions;
 import org.apache.ignite.internal.metastorage.server.RecoveryRevisionsListener;
 import org.apache.ignite.internal.util.IgniteSpinBusyLock;
 
-/** Implementation of {@link RecoveryRevisionsListener}. */
+/** Listener that completes the Metastorage 'recovery finish' future. */
 class RecoveryRevisionsListenerImpl implements RecoveryRevisionsListener {
     private final IgniteSpinBusyLock busyLock;
 
     private final CompletableFuture<Revisions> recoveryFinishFuture;
 
-    private final ReentrantLock lock = new ReentrantLock();
+    private final Lock lock = new ReentrantLock();
 
     /** Guarded by {@link #lock}. */
     private Revisions targetRevisions;
diff --git 
a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/server/AbstractKeyValueStorage.java
 
b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/server/AbstractKeyValueStorage.java
index 0d25ed549bf..292de6fe285 100644
--- 
a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/server/AbstractKeyValueStorage.java
+++ 
b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/server/AbstractKeyValueStorage.java
@@ -305,9 +305,13 @@ public abstract class AbstractKeyValueStorage implements 
KeyValueStorage {
 
     /** Notifies of revision update. */
     protected void notifyRevisionsUpdate() {
-        if (recoveryRevisionListener != null) {
-            // Listener must be invoked only on recovery, after recovery 
listener must be null.
-            recoveryRevisionListener.onUpdate(createCurrentRevisions());
+        RecoveryRevisionsListener listener = recoveryRevisionListener;
+
+        if (listener != null) {
+            // The listener should be invoked only on recovery, after recovery 
listener will be null.
+            // Currently, there is a race that allows the listener to be 
invoked after recovery is complete, but this race is benign
+            // as it will simply lead to a second attempt to complete the 
recovery future, which will be ignored.
+            listener.onUpdate(createCurrentRevisions());
         }
     }
 

Reply via email to