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

szaszm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git


The following commit(s) were added to refs/heads/main by this push:
     new b1137d2b7 MINIFICPP-2736 Add checks of library unload result for class 
description removal
b1137d2b7 is described below

commit b1137d2b74a3ce187e6a3ccc299d8e5dcf120ed3
Author: Gabor Gyimesi <[email protected]>
AuthorDate: Mon Mar 2 20:38:33 2026 +0100

    MINIFICPP-2736 Add checks of library unload result for class description 
removal
    
    Closes #2126
    
    Signed-off-by: Marton Szasz <[email protected]>
---
 libminifi/include/core/extension/ExtensionManager.h |  4 ++--
 libminifi/src/agent/agent_docs.cpp                  |  6 ++++--
 libminifi/src/core/extension/Extension.cpp          | 19 +++++++++++++++++++
 libminifi/src/core/extension/ExtensionManager.cpp   |  7 -------
 minifi-api/include/minifi-cpp/agent/agent_docs.h    |  2 +-
 5 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/libminifi/include/core/extension/ExtensionManager.h 
b/libminifi/include/core/extension/ExtensionManager.h
index 60af1229b..c610bd70a 100644
--- a/libminifi/include/core/extension/ExtensionManager.h
+++ b/libminifi/include/core/extension/ExtensionManager.h
@@ -30,11 +30,11 @@ namespace org::apache::nifi::minifi::core::extension {
 class ExtensionManager {
  public:
   explicit ExtensionManager(const std::shared_ptr<Configure>& config);
-  ~ExtensionManager();
+  ~ExtensionManager() = default;
 
   ExtensionManager(const ExtensionManager&) = delete;
-  ExtensionManager& operator=(const ExtensionManager&) = delete;
   ExtensionManager(ExtensionManager&&) = delete;
+  ExtensionManager& operator=(const ExtensionManager&) = delete;
   ExtensionManager& operator=(ExtensionManager&&) = delete;
 
  private:
diff --git a/libminifi/src/agent/agent_docs.cpp 
b/libminifi/src/agent/agent_docs.cpp
index 057e9188b..2fd8e71f6 100644
--- a/libminifi/src/agent/agent_docs.cpp
+++ b/libminifi/src/agent/agent_docs.cpp
@@ -34,8 +34,10 @@ std::map<BundleIdentifier, Components>& 
ClassDescriptionRegistry::getMutableClas
   return getAgentDocsClassMappings();
 }
 
-void ClassDescriptionRegistry::clearClassDescriptions() {
-  getAgentDocsClassMappings().clear();
+void ClassDescriptionRegistry::clearClassDescriptionsForBundle(const 
std::string& bundle_name) {
+  std::erase_if(getAgentDocsClassMappings(), [&bundle_name](const auto& entry) 
{
+    return entry.first.name == bundle_name;
+  });
 }
 
 }  // namespace org::apache::nifi::minifi
diff --git a/libminifi/src/core/extension/Extension.cpp 
b/libminifi/src/core/extension/Extension.cpp
index ac3675b57..8b7b7f740 100644
--- a/libminifi/src/core/extension/Extension.cpp
+++ b/libminifi/src/core/extension/Extension.cpp
@@ -37,6 +37,7 @@
 #include "utils/GeneralUtils.h"
 #include "core/logging/LoggerFactory.h"
 #include "minifi-c/minifi-c.h"
+#include "minifi-cpp/agent/agent_docs.h"
 
 namespace org::apache::nifi::minifi::core::extension {
 
@@ -90,6 +91,24 @@ Extension::~Extension() {
     info_->deinit(info_->user_data);
   }
   unload();
+
+  // Check if library was truly unloaded and clear class descriptions if it 
was.
+  // On Linux/GCC, STB_GNU_UNIQUE symbols can prevent dlclose from actually 
unloading the library.
+  // Some libraries could prevent unloading like RocksDB where Env::Default() 
creates a global singleton where background threads hold references which 
prevents unloading
+#ifdef RTLD_NOLOAD
+  void* check = dlopen(library_path_.c_str(), RTLD_NOW | RTLD_NOLOAD);
+  if (check) {
+    // Keep class descriptions if library is still in memory
+    dlclose(check);
+  } else {
+    ClassDescriptionRegistry::clearClassDescriptionsForBundle(name_);
+  }
+#else
+  HMODULE handle = GetModuleHandleA(name_.c_str());
+  if (handle == nullptr) {
+    ClassDescriptionRegistry::clearClassDescriptionsForBundle(name_);
+  }
+#endif
 }
 
 bool Extension::initialize(const std::shared_ptr<minifi::Configure>& 
configure) {
diff --git a/libminifi/src/core/extension/ExtensionManager.cpp 
b/libminifi/src/core/extension/ExtensionManager.cpp
index a8ef38caa..b0ce8882f 100644
--- a/libminifi/src/core/extension/ExtensionManager.cpp
+++ b/libminifi/src/core/extension/ExtensionManager.cpp
@@ -87,11 +87,4 @@ ExtensionManager::ExtensionManager(const 
std::shared_ptr<Configure>& config): lo
   }
 }
 
-ExtensionManager::~ExtensionManager() {
-  // Clear the class description registry to avoid dangling pointers
-  // to validator objects that live in extension DLLs to be unloaded.
-  minifi::ClassDescriptionRegistry::clearClassDescriptions();
-  extensions_.clear();
-}
-
 }  // namespace org::apache::nifi::minifi::core::extension
diff --git a/minifi-api/include/minifi-cpp/agent/agent_docs.h 
b/minifi-api/include/minifi-cpp/agent/agent_docs.h
index 82e84f876..61a759bed 100644
--- a/minifi-api/include/minifi-cpp/agent/agent_docs.h
+++ b/minifi-api/include/minifi-cpp/agent/agent_docs.h
@@ -73,7 +73,7 @@ class ClassDescriptionRegistry {
  public:
   static const std::map<minifi::BundleIdentifier, Components>& 
getClassDescriptions();
   static std::map<minifi::BundleIdentifier, Components>& 
getMutableClassDescriptions();
-  static void clearClassDescriptions();
+  static void clearClassDescriptionsForBundle(const std::string& bundle_name);
 
   template<typename Class, ResourceType Type>
   static void createClassDescription(std::string bundle_name, std::string 
class_name, std::string version);

Reply via email to