mirror of https://github.com/Icinga/icinga2.git
Add ConfigType::BeforeOnAllConfigLoaded signal
Allows to hook into the config loading process just before OnAllConfigLoaded() is called on a bunch of individual config objects. Allows doing some operations more efficiently at once for all objects. Intended use: when adding a number of dependencies, it has to be checked whether this uses any cycles. This can be done more efficiently if all dependencies are checked at once. So far, this is with a case-distinction for initially loaded files in DaemonUtility::LoadConfigFiles() and for dependencies created by runtime updates in Dependency::OnAllConfigLoaded(). The mechanism added by this commit allows to unify the handling of both cases (done in a following commit).
This commit is contained in:
parent
5c651e45a3
commit
4b18f62a11
|
@ -9,11 +9,13 @@
|
|||
#include "base/dictionary.hpp"
|
||||
#include <shared_mutex>
|
||||
#include <unordered_map>
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class ConfigObject;
|
||||
class ConfigItems;
|
||||
|
||||
class ConfigType
|
||||
{
|
||||
|
@ -48,6 +50,13 @@ for (const auto& object : objects) {
|
|||
|
||||
int GetObjectCount() const;
|
||||
|
||||
/**
|
||||
* Signal that allows hooking into the config loading process just before ConfigObject::OnAllConfigLoaded() is
|
||||
* called for a bunch of objects. A vector of pointers to these objects is passed as an argument. All elements
|
||||
* are of the object type the signal is called on.
|
||||
*/
|
||||
boost::signals2::signal<void (const ConfigItems&)> BeforeOnAllConfigLoaded;
|
||||
|
||||
private:
|
||||
typedef std::unordered_map<String, intrusive_ptr<ConfigObject> > ObjectMap;
|
||||
typedef std::vector<intrusive_ptr<ConfigObject> > ObjectVector;
|
||||
|
|
|
@ -499,6 +499,23 @@ bool ConfigItem::CommitNewItems(const ActivationContext::Ptr& context, WorkQueue
|
|||
auto items (itemsByType.find(type.get()));
|
||||
|
||||
if (items != itemsByType.end()) {
|
||||
auto configType = dynamic_cast<ConfigType*>(type.get());
|
||||
|
||||
// Skip the call if no handlers are connected (signal::empty()) or there are no items (vector::empty()).
|
||||
if (configType && !configType->BeforeOnAllConfigLoaded.empty() && !items->second.empty()) {
|
||||
// Call the signal in the WorkQueue so that if an exception is thrown, it is caught by the WorkQueue
|
||||
// and then reported like any other config validation error.
|
||||
upq.Enqueue([&configType, &items]() {
|
||||
configType->BeforeOnAllConfigLoaded(ConfigItems(items->second));
|
||||
});
|
||||
|
||||
upq.Join();
|
||||
|
||||
if (upq.HasExceptions()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
upq.ParallelFor(items->second, [¬ified_items](const ItemPair& ip) {
|
||||
const ConfigItem::Ptr& item = ip.first;
|
||||
|
||||
|
@ -525,6 +542,10 @@ bool ConfigItem::CommitNewItems(const ActivationContext::Ptr& context, WorkQueue
|
|||
});
|
||||
|
||||
upq.Join();
|
||||
|
||||
if (upq.HasExceptions()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -534,9 +555,6 @@ bool ConfigItem::CommitNewItems(const ActivationContext::Ptr& context, WorkQueue
|
|||
<< "Sent OnAllConfigLoaded to " << notified_items << " items of type '" << type->GetName() << "'.";
|
||||
#endif /* I2_DEBUG */
|
||||
|
||||
if (upq.HasExceptions())
|
||||
return false;
|
||||
|
||||
notified_items = 0;
|
||||
for (auto loadDep : type->GetLoadDependencies()) {
|
||||
auto items (itemsByType.find(loadDep));
|
||||
|
|
|
@ -101,6 +101,39 @@ private:
|
|||
static bool CommitNewItems(const ActivationContext::Ptr& context, WorkQueue& upq, std::vector<ConfigItem::Ptr>& newItems);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class for exposing config items being committed to the ConfigType::BeforeOnAllConfigLoaded callback.
|
||||
*
|
||||
* This class wraps a reference to an internal data structure used in ConfigItem::CommitNewItems() and provides
|
||||
* functions useful for the callbacks without exposing the internals of CommitNewItems().
|
||||
*/
|
||||
class ConfigItems
|
||||
{
|
||||
explicit ConfigItems(std::vector<std::pair<ConfigItem::Ptr, bool>>& items) : m_Items(items) {}
|
||||
|
||||
std::vector<std::pair<ConfigItem::Ptr, bool>>& m_Items;
|
||||
|
||||
friend ConfigItem;
|
||||
|
||||
public:
|
||||
/**
|
||||
* ForEachObject<T>(f) calls f(t) for each object T::Ptr t in vector of underlying config items.
|
||||
*
|
||||
* @tparam T ConfigObject type to iterate over
|
||||
* @tparam F Callback functor type (usually automatically deduced from func)
|
||||
* @param func Functor accepting T::Ptr as an argument to be called for each object
|
||||
*/
|
||||
template<typename T, typename F>
|
||||
void ForEachObject(F func) const
|
||||
{
|
||||
for (const auto& item : m_Items) {
|
||||
if (typename T::Ptr obj = dynamic_pointer_cast<T>(item.first->GetObject()); obj) {
|
||||
func(std::move(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* CONFIGITEM_H */
|
||||
|
|
Loading…
Reference in New Issue