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