szaszm commented on a change in pull request #1252: URL: https://github.com/apache/nifi-minifi-cpp/pull/1252#discussion_r809213842
########## File path: libminifi/include/FlowController.h ########## @@ -87,13 +91,8 @@ class FlowController : public core::controller::ForwardingControllerServiceProvi return this->provenance_repo_; } - // Get the flowfile repository - virtual std::shared_ptr<core::Repository> getFlowFileRepository() { - return this->flow_file_repo_; - } - // Load flow xml from disk, after that, create the root process group and its children, initialize the flows - virtual void load(const std::shared_ptr<core::ProcessGroup> &root = nullptr, bool reload = false); + virtual void load(std::unique_ptr<core::ProcessGroup>&& root = nullptr, bool reload = false); Review comment: Pass the pointer by value instead of rvalue reference. Since it's move-only, the usage will be the same, but the implementation will have to move out from the parameter. It's not a big deal, though, we might even save some time by moving twice, but without an extra level of indirection. ########## File path: libminifi/include/core/state/nodes/QueueMetrics.h ########## @@ -57,16 +57,16 @@ class QueueMetrics : public ResponseNode { return "QueueMetrics"; } - void addConnection(const std::shared_ptr<minifi::Connection> &connection) { + void addConnection(std::unique_ptr<minifi::Connection>&& connection) { Review comment: Consider pass-by-value for unique_ptr's. They are not too expensive to move. More details, if you're interested: https://youtu.be/rHIkrotSwcc?t=1050 ########## File path: libminifi/src/core/ProcessSession.cpp ########## @@ -1034,14 +1030,18 @@ void ProcessSession::ensureNonNullResourceClaim( } std::shared_ptr<core::FlowFile> ProcessSession::get() { - std::shared_ptr<Connectable> first = process_context_->getProcessorNode()->pickIncomingConnection(); + const auto first = process_context_->getProcessorNode()->pickIncomingConnection(); if (first == nullptr) { logger_->log_trace("Get is null for %s", process_context_->getProcessorNode()->getName()); return nullptr; } - std::shared_ptr<Connection> current = std::static_pointer_cast<Connection>(first); + auto current = dynamic_cast<Connection*>(first); + if (!current) { + logger_->log_error("Get could not find current Connection for %s", process_context_->getProcessorNode()->getName()); Review comment: I suggest a more detailed error message: ```suggestion logger_->log_error("The incoming connection [%s] of the processor [%s] \"%s\" is not actually a Connection.", first->getUUIDStr(), process_context_->getProcessorNode()->getUUIDStr(), process_context_->getProcessorNode()->getName()); ``` ########## File path: libminifi/src/core/ProcessGroup.cpp ########## @@ -91,33 +91,16 @@ ProcessGroup::~ProcessGroup() { } } -bool ProcessGroup::isRootProcessGroup() { - return (type_ == ROOT_PROCESS_GROUP); -} - bool ProcessGroup::isRemoteProcessGroup() { return (type_ == REMOTE_PROCESS_GROUP); } -void ProcessGroup::addProcessor(const std::shared_ptr<Processor>& processor) { +void ProcessGroup::addProcessor(std::unique_ptr<Processor>&& processor) { Review comment: Consider pass-by-value and a precondition to check that it's not null ########## File path: libminifi/include/utils/GeneralUtils.h ########## @@ -34,6 +34,16 @@ constexpr T intdiv_ceil(T numerator, T denominator) { : numerator / denominator + (numerator % denominator != 0)); } +/** + * safely converts unique_ptr from one type to another + * if conversion succeeds, an desired valid unique_ptr is returned, the "from" object released and invalidated + * if conversion fails, an empty unique_ptr is returned + */ +template <typename T_To, typename T_From> +std::unique_ptr<T_To> dynamic_unique_cast(std::unique_ptr<T_From>&& obj) { Review comment: I think it would be cleaner semantics to pass-by-value. This would mean that we release the object regardless of the success of the cast, which is a downside, but reading the client code will be simpler, because when we see passing with `std::move`, we know that the old object WILL be null. ########## File path: libminifi/src/core/Connectable.cpp ########## @@ -141,39 +141,37 @@ void Connectable::notifyWork() { } } -std::set<std::shared_ptr<Connectable>> Connectable::getOutGoingConnections(const std::string &relationship) const { - std::set<std::shared_ptr<Connectable>> empty; - - const auto &&it = out_going_connections_.find(relationship); - if (it != out_going_connections_.end()) { +std::set<Connectable*> Connectable::getOutGoingConnections(const std::string &relationship) const { + const auto &&it = outgoing_connections_.find(relationship); Review comment: Would you mind removing the `&&`? This only works because of temporary lifetime extension, but there is no reason why we wouldn't just store the iterator by value like normal. ########## File path: libminifi/include/processors/ProcessorUtils.h ########## @@ -47,10 +45,10 @@ class ProcessorUtils { if (ptr == nullptr) { ptr = core::ClassLoader::getDefaultClassLoader().instantiate("ExecuteJavaClass", uuid); if (ptr != nullptr) { - std::shared_ptr<core::Processor> processor = std::dynamic_pointer_cast<core::Processor>(ptr); - if (processor == nullptr) { + if (dynamic_cast<core::Processor*>(ptr.get()) == nullptr) { throw std::runtime_error("Invalid return from the classloader"); } + auto processor = std::unique_ptr<core::Processor>{dynamic_cast<core::Processor*>(ptr.release())}; Review comment: Use the dynamic unique cast utility here as well. ########## File path: libminifi/include/processors/ProcessorUtils.h ########## @@ -61,25 +59,15 @@ class ProcessorUtils { if (ptr == nullptr) { return nullptr; } - auto returnPtr = std::dynamic_pointer_cast<core::Processor>(ptr); - - if (returnPtr == nullptr) { + if (dynamic_cast<core::Processor*>(ptr.get()) == nullptr) { throw std::runtime_error("Invalid return from the classloader"); } + auto returnPtr = std::unique_ptr<core::Processor>{dynamic_cast<core::Processor*>(ptr.release())}; Review comment: and here. ```suggestion auto returnPtr = utils::dynamic_unique_cast<core::Processor>(std::move(ptr)); if (!returnPtr) { throw std::runtime_error("Invalid return from the classloader"); } ``` ########## File path: libminifi/src/FlowController.cpp ########## @@ -271,7 +271,7 @@ std::unique_ptr<core::ProcessGroup> FlowController::loadInitialFlow() { return root; } -void FlowController::load(const std::shared_ptr<core::ProcessGroup> &root, bool reload) { +void FlowController::load(std::unique_ptr<core::ProcessGroup>&& root, bool reload) { Review comment: Consider pass-by-value ########## File path: libminifi/src/c2/C2Client.cpp ########## @@ -115,7 +116,8 @@ void C2Client::initialize(core::controller::ControllerServiceProvider *controlle flowMonitor->setFlowVersion(flow_configuration_->getFlowVersion()); } std::lock_guard<std::mutex> guard(metrics_mutex_); - root_response_nodes_[response_node->getName()] = response_node; + std::unique_ptr<state::response::ResponseNode> responseNodeToStore{dynamic_cast<state::response::ResponseNode*>(instance.release())}; Review comment: use `utils::dynamic_unique_cast` Whenever `release()` is called on a unique_ptr, it requires extra attention. Just by looking around for `release()` in our codebase, I found a memory leak (in the openwsman extension). I find this separation of the check (line 91) and the release (here) to be very error-prone. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: issues-unsubscr...@nifi.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org