You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2021/06/08 16:00:10 UTC

[nifi] branch main updated: NIFI-8667: When marking a Controller Service as enabled, ensure that we release the write lock before calling validation methods of referencing components. Otherwise, we can encounter a deadlock.

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

mattyb149 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 07ff4f2  NIFI-8667: When marking a Controller Service as enabled, ensure that we release the write lock before calling validation methods of referencing components. Otherwise, we can encounter a deadlock.
07ff4f2 is described below

commit 07ff4f2592b26a5b556bb1297c42325233bdb101
Author: Mark Payne <ma...@hotmail.com>
AuthorDate: Mon Jun 7 17:59:34 2021 -0400

    NIFI-8667: When marking a Controller Service as enabled, ensure that we release the write lock before calling validation methods of referencing components. Otherwise, we can encounter a deadlock.
    
    Signed-off-by: Matthew Burgess <ma...@apache.org>
    
    This closes #5134
---
 .../controller/service/ServiceStateTransition.java | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/ServiceStateTransition.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/ServiceStateTransition.java
index ae19388..afcfec4 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/ServiceStateTransition.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/ServiceStateTransition.java
@@ -77,18 +77,28 @@ public class ServiceStateTransition {
             logger.debug("{} transitioned to ENABLED", controllerServiceNode);
 
             enabledFutures.forEach(future -> future.complete(null));
+        } finally {
+            writeLock.unlock();
+        }
 
-            final List<ComponentNode> referencingComponents = controllerServiceReference.findRecursiveReferences(ComponentNode.class);
-            for (final ComponentNode component : referencingComponents) {
-                component.performValidation();
-            }
+        // We want to perform validation against other components outside of the write lock. Component validation could be expensive
+        // and more importantly could reference other controller services, which could result in a dead lock if we run the validation
+        // while holding this.writeLock.
+        final List<ComponentNode> referencingComponents = controllerServiceReference.findRecursiveReferences(ComponentNode.class);
+        for (final ComponentNode component : referencingComponents) {
+            component.performValidation();
+        }
 
+        // Now that the write lock was relinquished in order to perform validation on referencing components, we must re-acquire it
+        // in order to signal that a state change has completed.
+        writeLock.lock();
+        try {
             stateChangeCondition.signalAll();
-
-            return true;
         } finally {
             writeLock.unlock();
         }
+
+        return true;
     }
 
     public boolean transitionToDisabling(final ControllerServiceState expectedState, final CompletableFuture<?> disabledFuture) {