Make attribute lookups O(1).

This commit is contained in:
Gunnar Beutner 2013-02-26 10:13:54 +01:00
parent 8f11e0412d
commit 35c79a76c1
36 changed files with 733 additions and 439 deletions

View File

@ -121,7 +121,6 @@ void CheckerComponent::CheckThreadProc(void)
}
service->SetForceNextCheck(false);
service->SetFirstCheck(false);
Logger::Write(LogDebug, "checker", "Executing service check for '" + service->GetName() + "'");
@ -177,7 +176,7 @@ void CheckerComponent::CheckerChangedHandler(const Service::Ptr& service)
boost::mutex::scoped_lock lock(m_Mutex);
ObjectLock olock(service); /* also required for the key extractor */
String checker = service->GetChecker();
String checker = service->GetCurrentChecker();
if (checker == EndpointManager::GetInstance()->GetIdentity() || checker == m_Endpoint->GetName()) {
if (m_PendingServices.find(service) != m_PendingServices.end())

View File

@ -534,12 +534,14 @@ void CompatComponent::StatusTimerHandler(void)
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Host")) {
Host::Ptr host = static_pointer_cast<Host>(object);
stringstream tempstatusfp, tempobjectfp;
stringstream tempstatusfp;
tempstatusfp << std::fixed;
DumpHostStatus(tempstatusfp, host);
DumpHostObject(tempobjectfp, host);
statusfp << tempstatusfp.str();
stringstream tempobjectfp;
tempobjectfp << std::fixed;
DumpHostObject(tempobjectfp, host);
objectfp << tempobjectfp.str();
}
@ -547,6 +549,7 @@ void CompatComponent::StatusTimerHandler(void)
HostGroup::Ptr hg = static_pointer_cast<HostGroup>(object);
stringstream tempobjectfp;
tempobjectfp << std::fixed;
{
ObjectLock olock(hg);
@ -568,12 +571,14 @@ void CompatComponent::StatusTimerHandler(void)
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = static_pointer_cast<Service>(object);
stringstream tempstatusfp, tempobjectfp;
DumpServiceStatus(statusfp, service);
DumpServiceObject(objectfp, service);
stringstream tempstatusfp;
tempstatusfp << std::fixed;
DumpServiceStatus(tempstatusfp, service);
statusfp << tempstatusfp.str();
stringstream tempobjectfp;
tempobjectfp << std::fixed;
DumpServiceObject(tempobjectfp, service);
objectfp << tempobjectfp.str();
}
@ -581,6 +586,7 @@ void CompatComponent::StatusTimerHandler(void)
ServiceGroup::Ptr sg = static_pointer_cast<ServiceGroup>(object);
stringstream tempobjectfp;
tempobjectfp << std::fixed;
{
ObjectLock olock(sg);

View File

@ -102,7 +102,7 @@ void DelegationComponent::DelegationTimerHandler(void)
services.push_back(service);
ObjectLock olock(service);
String checker = service->GetChecker();
String checker = service->GetCurrentChecker();
if (checker.IsEmpty())
continue;
@ -122,7 +122,7 @@ void DelegationComponent::DelegationTimerHandler(void)
BOOST_FOREACH(const Service::Ptr& service, services) {
ObjectLock olock(service);
String checker = service->GetChecker();
String checker = service->GetCurrentChecker();
Endpoint::Ptr oldEndpoint;
if (Endpoint::Exists(checker))
@ -160,7 +160,7 @@ void DelegationComponent::DelegationTimerHandler(void)
/* clear the service's current checker */
if (!checker.IsEmpty()) {
service->SetChecker("");
service->SetCurrentChecker("");
if (oldEndpoint)
histogram[oldEndpoint]--;
@ -173,7 +173,7 @@ void DelegationComponent::DelegationTimerHandler(void)
continue;
ObjectLock clock(candidate);
service->SetChecker(candidate->GetName());
service->SetCurrentChecker(candidate->GetName());
histogram[candidate]++;
/* reschedule the service; this avoids "check floods"
@ -207,7 +207,7 @@ void DelegationComponent::DelegationTimerHandler(void)
continue;
}
assert(!service->GetChecker().IsEmpty());
assert(!service->GetCurrentChecker().IsEmpty());
}
Endpoint::Ptr endpoint;

View File

@ -68,7 +68,7 @@ void ReplicationComponent::CheckResultRequestHandler(const RequestMessage& reque
if (!cr)
return;
if (cr->Contains("checker") && cr->Get("checker") == EndpointManager::GetInstance()->GetIdentity())
if (cr->Contains("current_checker") && cr->Get("current_checker") == EndpointManager::GetInstance()->GetIdentity())
return;
Service::UpdateStatistics(cr);

View File

@ -75,8 +75,11 @@ AC_CHECK_FUNCS([backtrace_symbols execvpe pipe2])
AC_MSG_CHECKING(whether to enable debugging)
AC_ARG_ENABLE(debug, [ --enable-debug=[no/yes] turn on debugging (default=no)],, enable_debug=no)
if test "x$enable_debug" = "xyes"; then
CFLAGS="$CFLAGS -g -O0 -rdynamic"
CXXFLAGS="$CXXFLAGS -g -O0 -rdynamic"
CFLAGS="$CFLAGS -g -O0 -D_DEBUG"
CXXFLAGS="$CXXFLAGS -g -O0 -D_DEBUG"
else
CFLAGS="$CFLAGS -DNDEBUG"
CXXFLAGS="$CXXFLAGS -DNDEBUG"
fi
AC_MSG_RESULT($enable_debug)

View File

@ -35,12 +35,12 @@ signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnFlushObject;
DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject)
: m_EventSafe(false), m_ConfigTx(0)
{
RegisterAttribute("__name", Attribute_Config);
RegisterAttribute("__type", Attribute_Config);
RegisterAttribute("__local", Attribute_Config);
RegisterAttribute("__abstract", Attribute_Config);
RegisterAttribute("__source", Attribute_Local);
RegisterAttribute("methods", Attribute_Config);
RegisterAttribute("__name", Attribute_Config, &m_Name);
RegisterAttribute("__type", Attribute_Config, &m_Type);
RegisterAttribute("__local", Attribute_Config, &m_Local);
RegisterAttribute("__abstract", Attribute_Config, &m_Abstract);
RegisterAttribute("__source", Attribute_Local, &m_Source);
RegisterAttribute("methods", Attribute_Config, &m_Methods);
{
ObjectLock olock(serializedObject);
@ -50,7 +50,7 @@ DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject)
}
/* apply config state from the config item/remote update;
* The DynamicObject::Create function takes care of restoring
* The DynamicType::CreateObject function takes care of restoring
* non-config state after the object has been fully constructed */
{
ObjectLock olock(this);
@ -102,22 +102,22 @@ Dictionary::Ptr DynamicObject::BuildUpdate(double sinceTx, int attributeTypes) c
Dictionary::Ptr attrs = boost::make_shared<Dictionary>();
for (it = m_Attributes.begin(); it != m_Attributes.end(); it++) {
if (it->second.Type == Attribute_Transient)
if (it->second.GetType() == Attribute_Transient)
continue;
if ((it->second.Type & attributeTypes) == 0)
if ((it->second.GetType() & attributeTypes) == 0)
continue;
if (it->second.Tx == 0)
if (it->second.GetTx() == 0)
continue;
if (it->second.Tx < sinceTx && !(it->second.Type == Attribute_Config && m_ConfigTx >= sinceTx))
if (it->second.GetTx() < sinceTx && !(it->second.GetType() == Attribute_Config && m_ConfigTx >= sinceTx))
continue;
Dictionary::Ptr attr = boost::make_shared<Dictionary>();
attr->Set("data", it->second.Data);
attr->Set("type", it->second.Type);
attr->Set("tx", it->second.Tx);
attr->Set("data", it->second.GetValue());
attr->Set("type", it->second.GetType());
attr->Set("tx", it->second.GetTx());
attrs->Set(it->first, attr);
}
@ -180,7 +180,7 @@ void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate,
RegisterAttribute(it->first, Attribute_Config);
if (!HasAttribute(it->first))
RegisterAttribute(it->first, static_cast<DynamicAttributeType>(type));
RegisterAttribute(it->first, static_cast<AttributeType>(type));
InternalSetAttribute(it->first, data, tx, true);
}
@ -188,17 +188,19 @@ void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate,
}
void DynamicObject::RegisterAttribute(const String& name,
DynamicAttributeType type)
AttributeType type, AttributeBase *boundAttribute)
{
DynamicAttribute attr;
attr.Type = type;
attr.Tx = 0;
AttributeHolder attr(type, boundAttribute);
pair<DynamicObject::AttributeIterator, bool> tt;
tt = m_Attributes.insert(make_pair(name, attr));
if (!tt.second)
tt.first->second.Type = type;
if (!tt.second) {
tt.first->second.SetType(type);
if (boundAttribute)
tt.first->second.Bind(boundAttribute);
}
}
void DynamicObject::Set(const String& name, const Value& data)
@ -219,28 +221,27 @@ Value DynamicObject::Get(const String& name) const
void DynamicObject::InternalSetAttribute(const String& name, const Value& data,
double tx, bool allowEditConfig)
{
DynamicAttribute attr;
attr.Type = Attribute_Transient;
attr.Data = data;
attr.Tx = tx;
pair<DynamicObject::AttributeIterator, bool> tt;
tt = m_Attributes.insert(make_pair(name, attr));
DynamicObject::AttributeIterator it;
it = m_Attributes.find(name);
Value oldValue;
if (!allowEditConfig && (tt.first->second.Type & Attribute_Config))
BOOST_THROW_EXCEPTION(runtime_error("Config properties are immutable: '" + name + "'."));
if (it == m_Attributes.end()) {
AttributeHolder attr(Attribute_Transient);
attr.SetValue(tx, data);
if (!tt.second && tx >= tt.first->second.Tx) {
oldValue = tt.first->second.Data;
tt.first->second.Data = data;
tt.first->second.Tx = tx;
m_Attributes.insert(make_pair(name, attr));
} else {
if (!allowEditConfig && (it->second.GetType() & Attribute_Config))
BOOST_THROW_EXCEPTION(runtime_error("Config properties are immutable: '" + name + "'."));
oldValue = it->second.GetValue();
it->second.SetValue(tx, data);
if (it->second.GetType() & Attribute_Config)
m_ConfigTx = tx;
}
if (tt.first->second.Type & Attribute_Config)
m_ConfigTx = tx;
if (GetEventSafe()) {
/* We can't call GetSelf() in the constructor or destructor.
* The OnConstructionCompleted() function will take care of adding this
@ -269,7 +270,7 @@ Value DynamicObject::InternalGetAttribute(const String& name) const
if (it == m_Attributes.end())
return Empty;
return it->second.Data;
return it->second.GetValue();
}
bool DynamicObject::HasAttribute(const String& name) const
@ -277,57 +278,46 @@ bool DynamicObject::HasAttribute(const String& name) const
return (m_Attributes.find(name) != m_Attributes.end());
}
void DynamicObject::ClearAttributesByType(DynamicAttributeType type)
void DynamicObject::ClearAttributesByType(AttributeType type)
{
DynamicObject::AttributeIterator at;
for (at = m_Attributes.begin(); at != m_Attributes.end(); at++) {
if (at->second.Type != type)
if (at->second.GetType() != type)
continue;
at->second.Tx = 0;
at->second.Data = Empty;
at->second.SetValue(0, Empty);
}
}
DynamicType::Ptr DynamicObject::GetType(void) const
{
String name = Get("__type");
return DynamicType::GetByName(name);
return DynamicType::GetByName(m_Type);
}
String DynamicObject::GetName(void) const
{
return Get("__name");
return m_Name;
}
bool DynamicObject::IsLocal(void) const
{
Value value = Get("__local");
if (value.IsEmpty())
return false;
return (value != 0);
return m_Local;
}
bool DynamicObject::IsAbstract(void) const
{
Value value = Get("__abstract");
if (value.IsEmpty())
return false;
return (value != 0);
return m_Abstract;
}
void DynamicObject::SetSource(const String& value)
{
Set("__source", value);
m_Source = value;
Touch("__source");
}
String DynamicObject::GetSource(void) const
{
return Get("__source");
return m_Source;
}
void DynamicObject::Register(void)
@ -371,13 +361,9 @@ void DynamicObject::Unregister(void)
ScriptTask::Ptr DynamicObject::MakeMethodTask(const String& method,
const vector<Value>& arguments)
{
Value value = Get("methods");
if (!value.IsObjectType<Dictionary>())
return ScriptTask::Ptr();
String funcName;
Dictionary::Ptr methods = value;
Dictionary::Ptr methods = m_Methods;
{
ObjectLock olock(methods);

View File

@ -28,7 +28,7 @@ namespace icinga
*
* @ingroup base
*/
enum DynamicAttributeType
enum AttributeType
{
Attribute_Transient = 1,
@ -48,16 +48,142 @@ enum DynamicAttributeType
Attribute_All = Attribute_Transient | Attribute_Local | Attribute_Replicated | Attribute_Config
};
class AttributeBase
{
public:
AttributeBase(void)
: m_Value()
{ }
void InternalSet(const Value& value)
{
m_Value = value;
}
const Value& InternalGet(void) const
{
return m_Value;
}
operator Value(void) const
{
return InternalGet();
}
bool IsEmpty(void) const
{
return InternalGet().IsEmpty();
}
private:
Value m_Value;
};
template<typename T>
class Attribute : public AttributeBase
{
public:
void Set(const T& value)
{
InternalSet(value);
}
Attribute<T>& operator=(const T& rhs)
{
Set(rhs);
}
T Get(void) const
{
if (IsEmpty())
return T();
return InternalGet();
}
operator T(void) const
{
return Get();
}
};
/**
* An attribute for a DynamicObject.
*
* @ingroup base
*/
struct DynamicAttribute
struct AttributeHolder
{
Value Data; /**< The current value of the attribute. */
DynamicAttributeType Type; /**< The type of the attribute. */
double Tx; /**< The timestamp of the last value change. */
AttributeType m_Type; /**< The type of the attribute. */
double m_Tx; /**< The timestamp of the last value change. */
bool m_OwnsAttribute; /**< Whether we own the Data pointer. */
AttributeBase *m_Attribute; /**< The current value of the attribute. */
AttributeHolder(AttributeType type, AttributeBase *boundAttribute = NULL)
: m_Type(type), m_Tx(0)
{
if (boundAttribute) {
m_Attribute = boundAttribute;
m_OwnsAttribute = false;
} else {
m_Attribute = new Attribute<Value>();
m_OwnsAttribute = true;
}
}
AttributeHolder(const AttributeHolder& other)
{
m_Type = other.m_Type;
m_Tx = other.m_Tx;
m_OwnsAttribute = other.m_OwnsAttribute;
if (other.m_OwnsAttribute) {
m_Attribute = new Attribute<Value>();
m_Attribute->InternalSet(other.m_Attribute->InternalGet());
} else {
m_Attribute = other.m_Attribute;
}
}
~AttributeHolder(void)
{
if (m_OwnsAttribute)
delete m_Attribute;
}
void Bind(AttributeBase *boundAttribute)
{
assert(m_OwnsAttribute);
boundAttribute->InternalSet(m_Attribute->InternalGet());
m_Attribute = boundAttribute;
m_OwnsAttribute = false;
}
void SetValue(double tx, const Value& value)
{
m_Tx = tx;
m_Attribute->InternalSet(value);
}
Value GetValue(void) const
{
return m_Attribute->InternalGet();
}
void SetType(AttributeType type)
{
m_Type = type;
}
AttributeType GetType(void) const
{
return m_Type;
}
double GetTx(void) const
{
return m_Tx;
}
};
class DynamicType;
@ -74,7 +200,7 @@ public:
typedef shared_ptr<DynamicObject> Ptr;
typedef weak_ptr<DynamicObject> WeakPtr;
typedef map<String, DynamicAttribute, string_iless> AttributeMap;
typedef map<String, AttributeHolder, string_iless> AttributeMap;
typedef AttributeMap::iterator AttributeIterator;
typedef AttributeMap::const_iterator AttributeConstIterator;
@ -86,7 +212,7 @@ public:
Dictionary::Ptr BuildUpdate(double sinceTx, int attributeTypes) const;
void ApplyUpdate(const Dictionary::Ptr& serializedUpdate, int allowedTypes);
void RegisterAttribute(const String& name, DynamicAttributeType type);
void RegisterAttribute(const String& name, AttributeType type, AttributeBase *boundAttribute = NULL);
void Set(const String& name, const Value& data);
void Touch(const String& name);
@ -94,7 +220,9 @@ public:
bool HasAttribute(const String& name) const;
void ClearAttributesByType(DynamicAttributeType type);
void BindAttribute(const String& name, Value *boundValue);
void ClearAttributesByType(AttributeType type);
static signals2::signal<void (const DynamicObject::Ptr&)> OnRegistered;
static signals2::signal<void (const DynamicObject::Ptr&)> OnUnregistered;
@ -150,6 +278,13 @@ private:
map<String, Value, string_iless> m_ModifiedAttributes;
double m_ConfigTx;
Attribute<String> m_Name;
Attribute<String> m_Type;
Attribute<bool> m_Local;
Attribute<bool> m_Abstract;
Attribute<String> m_Source;
Attribute<Dictionary::Ptr> m_Methods;
bool m_EventSafe;
static double m_CurrentTx;

View File

@ -101,6 +101,12 @@ void DynamicType::RegisterObject(const DynamicObject::Ptr& object)
/* notify the object that it's been registered */
object->OnRegistrationCompleted();
{
ObjectLock olock(object);
object->Flush();
}
}
void DynamicType::UnregisterObject(const DynamicObject::Ptr& object)
@ -148,7 +154,7 @@ DynamicObject::Ptr DynamicType::CreateObject(const Dictionary::Ptr& serializedUp
/* register attributes */
String name;
DynamicAttributeType type;
AttributeType type;
BOOST_FOREACH(tuples::tie(name, type), m_Attributes)
object->RegisterAttribute(name, type);
@ -169,7 +175,7 @@ bool DynamicType::TypeExists(const String& name)
return (GetByName(name));
}
void DynamicType::AddAttribute(const String& name, DynamicAttributeType type)
void DynamicType::AddAttribute(const String& name, AttributeType type)
{
m_Attributes[name] = type;
}

View File

@ -26,7 +26,7 @@ namespace icinga
struct AttributeDescription
{
String Name;
DynamicAttributeType Type;
AttributeType Type;
};
class I2_BASE_API DynamicType : public Object
@ -57,7 +57,7 @@ public:
static set<DynamicObject::Ptr> GetObjects(const String& type);
void AddAttribute(const String& name, DynamicAttributeType type);
void AddAttribute(const String& name, AttributeType type);
void RemoveAttribute(const String& name);
bool HasAttribute(const String& name);
@ -66,7 +66,7 @@ public:
private:
String m_Name;
ObjectFactory m_ObjectFactory;
map<String, DynamicAttributeType> m_Attributes;
map<String, AttributeType> m_Attributes;
typedef map<String, DynamicObject::Ptr, string_iless> ObjectMap;
typedef set<DynamicObject::Ptr> ObjectSet;

View File

@ -34,6 +34,11 @@ EventQueue::EventQueue(void)
for (int i = 0; i < thread_count; i++)
m_Threads.create_thread(boost::bind(&EventQueue::QueueThreadProc, this));
m_ReportTimer = boost::make_shared<Timer>();
m_ReportTimer->OnTimerExpired.connect(boost::bind(&EventQueue::ReportTimerHandler, this));
m_ReportTimer->SetInterval(5);
m_ReportTimer->Start();
}
/**
@ -41,6 +46,8 @@ EventQueue::EventQueue(void)
*/
EventQueue::~EventQueue(void)
{
m_ReportTimer->Stop();
Stop();
Join();
}
@ -114,11 +121,17 @@ void EventQueue::Post(const EventQueue::Callback& callback)
boost::mutex::scoped_lock lock(m_Mutex);
m_Events.push_back(callback);
m_CV.notify_one();
int pending = m_Events.size();
double now = Utility::GetTime();
if (pending > 1000 && now - m_LastReport > 5) {
Logger::Write(LogCritical, "base", "More than 1000 pending events: " + Convert::ToString(pending));
m_LastReport = now;
}
}
void EventQueue::ReportTimerHandler(void)
{
int pending;
{
boost::mutex::scoped_lock lock(m_Mutex);
pending = m_Events.size();
}
if (pending > 1000)
Logger::Write(LogCritical, "base", "More than 1000 pending events: " + Convert::ToString(pending));
}

View File

@ -23,6 +23,8 @@
namespace icinga
{
class Timer;
/**
* An event queue.
*
@ -48,10 +50,13 @@ private:
condition_variable m_CV;
double m_LastReport;
shared_ptr<Timer> m_ReportTimer;
bool m_Stopped;
vector<Callback> m_Events;
void QueueThreadProc(void);
void ReportTimerHandler(void);
};
}

View File

@ -31,10 +31,14 @@ REGISTER_TYPE(Logger, NULL);
Logger::Logger(const Dictionary::Ptr& properties)
: DynamicObject(properties)
{
RegisterAttribute("type", Attribute_Config, &m_Type);
RegisterAttribute("path", Attribute_Config, &m_Path);
RegisterAttribute("severity", Attribute_Config, &m_Severity);
if (!IsLocal())
BOOST_THROW_EXCEPTION(runtime_error("Logger objects must be local."));
String type = Get("type");
String type = m_Type;
if (type.IsEmpty())
BOOST_THROW_EXCEPTION(runtime_error("Logger objects must have a 'type' property."));
@ -47,7 +51,7 @@ Logger::Logger(const Dictionary::Ptr& properties)
BOOST_THROW_EXCEPTION(invalid_argument("Syslog is not supported on Windows."));
#endif /* _WIN32 */
} else if (type == "file") {
String path = Get("path");
String path = m_Path;
if (path.IsEmpty())
BOOST_THROW_EXCEPTION(invalid_argument("'log' object of type 'file' must have a 'path' property"));
@ -91,7 +95,7 @@ void Logger::Write(LogSeverity severity, const String& facility,
*/
LogSeverity Logger::GetMinSeverity(void) const
{
String severity = Get("severity");
String severity = m_Severity;
if (severity.IsEmpty())
return LogInformation;
else

View File

@ -98,6 +98,10 @@ public:
LogSeverity GetMinSeverity(void) const;
private:
Attribute<String> m_Type;
Attribute<String> m_Path;
Attribute<String> m_Severity;
LogSeverity m_MinSeverity;
ILogger::Ptr m_Impl;

View File

@ -30,7 +30,10 @@ REGISTER_TYPE(Script, NULL);
*/
Script::Script(const Dictionary::Ptr& properties)
: DynamicObject(properties)
{ }
{
RegisterAttribute("language", Attribute_Config, &m_Language);
RegisterAttribute("code", Attribute_Config, &m_Code);
}
void Script::OnRegistrationCompleted(void)
{
@ -41,12 +44,12 @@ void Script::OnRegistrationCompleted(void)
String Script::GetLanguage(void) const
{
return Get("language");
return m_Language;
}
String Script::GetCode(void) const
{
return Get("code");
return m_Code;
}
void Script::OnAttributeUpdate(const String& name, const Value& oldValue)

View File

@ -46,6 +46,9 @@ protected:
virtual void OnAttributeUpdate(const String& name, const Value& oldValue);
private:
Attribute<String> m_Language;
Attribute<String> m_Code;
shared_ptr<ScriptInterpreter> m_Interpreter;
void SpawnInterpreter(void);

View File

@ -270,6 +270,8 @@ void Timer::TimerThreadProc(void)
timer->m_Started = false;
m_Timers.erase(timer);
lock.unlock();
/* Asynchronously call the timer. */
Application::GetEQ().Post(boost::bind(&Timer::Call, timer));
}

View File

@ -21,42 +21,41 @@
using namespace icinga;
boost::mutex Host::m_Mutex;
map<String, map<String, weak_ptr<Service> > > Host::m_ServicesCache;
bool Host::m_ServicesCacheValid = true;
REGISTER_SCRIPTFUNCTION("ValidateServiceDictionary", &Host::ValidateServiceDictionary);
static AttributeDescription hostAttributes[] = {
{ "slave_services", Attribute_Transient }
};
REGISTER_TYPE(Host, hostAttributes);
REGISTER_TYPE(Host, NULL);
Host::Host(const Dictionary::Ptr& properties)
: DynamicObject(properties)
{ }
{
RegisterAttribute("display_name", Attribute_Config, &m_DisplayName);
RegisterAttribute("hostgroups", Attribute_Config, &m_HostGroups);
RegisterAttribute("macros", Attribute_Config, &m_Macros);
RegisterAttribute("hostdependencies", Attribute_Config, &m_HostDependencies);
RegisterAttribute("servicedependencies", Attribute_Config, &m_ServiceDependencies);
RegisterAttribute("hostcheck", Attribute_Config, &m_HostCheck);
}
void Host::OnRegistrationCompleted(void)
{
DynamicObject::OnRegistrationCompleted();
HostGroup::InvalidateMembersCache();
{
ObjectLock olock(this);
UpdateSlaveServices();
}
Host::UpdateSlaveServices(GetSelf());
}
Host::~Host(void)
{
HostGroup::InvalidateMembersCache();
Dictionary::Ptr services = Get("slave_services");
if (services) {
if (m_SlaveServices) {
ConfigItem::Ptr service;
BOOST_FOREACH(tie(tuples::ignore, service), services) {
BOOST_FOREACH(tie(tuples::ignore, service), m_SlaveServices) {
service->Unregister();
}
}
@ -64,9 +63,8 @@ Host::~Host(void)
String Host::GetDisplayName(void) const
{
String value = Get("display_name");
if (!value.IsEmpty())
return value;
if (!m_DisplayName.IsEmpty())
return m_DisplayName;
else
return GetName();
}
@ -94,27 +92,27 @@ Host::Ptr Host::GetByName(const String& name)
Dictionary::Ptr Host::GetGroups(void) const
{
return Get("hostgroups");
return m_HostGroups;;
}
Dictionary::Ptr Host::GetMacros(void) const
{
return Get("macros");
return m_Macros;
}
Dictionary::Ptr Host::GetHostDependencies(void) const
{
return Get("hostdependencies");
return m_HostDependencies;;
}
Dictionary::Ptr Host::GetServiceDependencies(void) const
{
return Get("servicedependencies");
return m_ServiceDependencies;
}
String Host::GetHostCheck(void) const
{
return Get("hostcheck");
return m_HostCheck;
}
bool Host::IsReachable(const Host::Ptr& self)
@ -213,21 +211,36 @@ static void CopyServiceAttributes(TDict serviceDesc, const ConfigItemBuilder::Pt
}
}
void Host::UpdateSlaveServices(void)
void Host::UpdateSlaveServices(const Host::Ptr& self)
{
ConfigItem::Ptr item = ConfigItem::GetObject("Host", GetName());
ConfigItem::Ptr item;
Dictionary::Ptr oldServices, newServices, serviceDescs;
String host_name;
/* Don't create slave services unless we own this object
* and it's not a template. */
if (!item || IsAbstract())
return;
{
ObjectLock olock(self);
Dictionary::Ptr oldServices = Get("slave_services");
host_name = self->GetName();
item = ConfigItem::GetObject("Host", host_name);
/* Don't create slave services unless we own this object
* and it's not a template. */
if (!item || self->IsAbstract())
return;
oldServices = self->m_SlaveServices;
serviceDescs = self->Get("services");
}
Dictionary::Ptr newServices;
newServices = boost::make_shared<Dictionary>();
Dictionary::Ptr serviceDescs = Get("services");
DebugInfo debug_info;
{
ObjectLock olock(item);
debug_info = item->GetDebugInfo();
}
if (serviceDescs) {
String svcname;
@ -237,17 +250,17 @@ void Host::UpdateSlaveServices(void)
svcname = svcdesc;
stringstream namebuf;
namebuf << GetName() << "-" << svcname;
namebuf << host_name << "-" << svcname;
String name = namebuf.str();
ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(item->GetDebugInfo());
ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(debug_info);
builder->SetType("Service");
builder->SetName(name);
builder->AddExpression("host_name", OperatorSet, GetName());
builder->AddExpression("host_name", OperatorSet, host_name);
builder->AddExpression("display_name", OperatorSet, svcname);
builder->AddExpression("short_name", OperatorSet, svcname);
CopyServiceAttributes<false>(this, builder);
CopyServiceAttributes<false>(self, builder);
if (svcdesc.IsScalar()) {
builder->AddParent(svcdesc);
@ -271,7 +284,7 @@ void Host::UpdateSlaveServices(void)
}
ConfigItem::Ptr serviceItem = builder->Compile();
ConfigItem::Commit(serviceItem);
DynamicObject::Ptr dobj = ConfigItem::Commit(serviceItem);
newServices->Set(name, serviceItem);
}
@ -290,7 +303,7 @@ void Host::UpdateSlaveServices(void)
newServices->Seal();
Set("slave_services", newServices);
self->Set("slave_services", newServices);
}
void Host::OnAttributeChanged(const String& name, const Value&)
@ -298,8 +311,7 @@ void Host::OnAttributeChanged(const String& name, const Value&)
if (name == "hostgroups")
HostGroup::InvalidateMembersCache();
else if (name == "services") {
ObjectLock olock(this);
UpdateSlaveServices();
UpdateSlaveServices(GetSelf());
} else if (name == "notifications") {
set<Service::Ptr> services;
@ -309,9 +321,11 @@ void Host::OnAttributeChanged(const String& name, const Value&)
}
BOOST_FOREACH(const Service::Ptr& service, services) {
ObjectLock olock(service);
service->UpdateSlaveNotifications();
Service::UpdateSlaveNotifications(service);
}
} else if (name == "hostcheck") {
ObjectLock olock(this);
m_HostCheckService = GetServiceByShortName(GetHostCheck());
}
}
@ -319,6 +333,8 @@ set<Service::Ptr> Host::GetServices(void) const
{
set<Service::Ptr> services;
boost::mutex::scoped_lock lock(m_Mutex);
ValidateServicesCache();
Service::WeakPtr wservice;
@ -336,10 +352,14 @@ set<Service::Ptr> Host::GetServices(void) const
void Host::InvalidateServicesCache(void)
{
boost::mutex::scoped_lock lock(m_Mutex);
m_ServicesCacheValid = false;
m_ServicesCache.clear();
}
/**
* @threadsafety Caller must hold m_Mutex.
*/
void Host::ValidateServicesCache(void)
{
if (m_ServicesCacheValid)
@ -350,9 +370,25 @@ void Host::ValidateServicesCache(void)
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
const Service::Ptr& service = static_pointer_cast<Service>(object);
Host::Ptr host;
String short_name;
{
ObjectLock olock(service);
host = service->GetHost();
short_name = service->GetShortName();
}
String host_name;
{
ObjectLock olock(host);
host_name = host->GetName();
}
// TODO: assert for duplicate short_names
m_ServicesCache[service->GetHost()->GetName()][service->GetShortName()] = service;
m_ServicesCache[host_name][short_name] = service;
}
m_ServicesCacheValid = true;
@ -411,15 +447,20 @@ void Host::ValidateServiceDictionary(const ScriptTask::Ptr& task, const vector<V
Service::Ptr Host::GetServiceByShortName(const Value& name) const
{
if (name.IsScalar()) {
ValidateServicesCache();
map<String, weak_ptr<Service> >& services = m_ServicesCache[GetName()];
map<String, weak_ptr<Service> >::iterator it = services.find(name);
{
boost::mutex::scoped_lock lock(m_Mutex);
if (it != services.end()) {
Service::Ptr service = it->second.lock();
assert(service);
return service;
ValidateServicesCache();
map<String, weak_ptr<Service> >& services = m_ServicesCache[GetName()];
map<String, weak_ptr<Service> >::iterator it = services.find(name);
if (it != services.end()) {
Service::Ptr service = it->second.lock();
assert(service);
return service;
}
}
return Service::GetByName(name);
@ -452,17 +493,7 @@ set<Host::Ptr> Host::GetParentHosts(void) const
Service::Ptr Host::GetHostCheckService(void) const
{
String hostcheck = GetHostCheck();
if (hostcheck.IsEmpty())
return Service::Ptr();
Service::Ptr service = GetServiceByShortName(hostcheck);
if (service->GetHost()->GetName() != GetName())
BOOST_THROW_EXCEPTION(runtime_error("Hostcheck service refers to another host's service."));
return service;
return m_HostCheckService.lock();
}
set<Service::Ptr> Host::GetParentServices(void) const

View File

@ -71,12 +71,23 @@ protected:
void OnAttributeChanged(const String& name, const Value& oldValue);
private:
Attribute<String> m_DisplayName;
Attribute<Dictionary::Ptr> m_HostGroups;
Attribute<Dictionary::Ptr> m_Macros;
Attribute<Dictionary::Ptr> m_HostDependencies;
Attribute<Dictionary::Ptr> m_ServiceDependencies;
Attribute<String> m_HostCheck;
Dictionary::Ptr m_SlaveServices;
static boost::mutex m_Mutex;
static map<String, map<String, weak_ptr<Service> > > m_ServicesCache;
static bool m_ServicesCacheValid;
void UpdateSlaveServices(void);
static void UpdateSlaveServices(const Host::Ptr& self);
static void ValidateServicesCache(void);
weak_ptr<Service> m_HostCheckService;
};
}

View File

@ -29,26 +29,28 @@ REGISTER_TYPE(HostGroup, NULL);
HostGroup::HostGroup(const Dictionary::Ptr& properties)
: DynamicObject(properties)
{ }
{
RegisterAttribute("display_name", Attribute_Config, &m_DisplayName);
RegisterAttribute("notes_url", Attribute_Config, &m_NotesUrl);
RegisterAttribute("action_url", Attribute_Config, &m_ActionUrl);
}
String HostGroup::GetDisplayName(void) const
{
String value = Get("display_name");
if (!value.IsEmpty())
return value;
if (!m_DisplayName.IsEmpty())
return m_DisplayName;
else
return GetName();
}
String HostGroup::GetNotesUrl(void) const
{
return Get("notes_url");
return m_NotesUrl;
}
String HostGroup::GetActionUrl(void) const
{
return Get("action_url");
return m_ActionUrl;
}
/**

View File

@ -47,6 +47,10 @@ public:
static void InvalidateMembersCache(void);
private:
Attribute<String> m_DisplayName;
Attribute<String> m_NotesUrl;
Attribute<String> m_ActionUrl;
static boost::mutex m_Mutex;
static map<String, vector<weak_ptr<Host> > > m_MembersCache;
static bool m_MembersCacheValid;

View File

@ -30,7 +30,15 @@ REGISTER_TYPE(IcingaApplication, NULL);
IcingaApplication::IcingaApplication(const Dictionary::Ptr& serializedUpdate)
: Application(serializedUpdate)
{ }
{
RegisterAttribute("cert_path", Attribute_Config, &m_CertPath);
RegisterAttribute("ca_path", Attribute_Config, &m_CAPath);
RegisterAttribute("node", Attribute_Config, &m_Node);
RegisterAttribute("service", Attribute_Config, &m_Service);
RegisterAttribute("pid_path", Attribute_Config, &m_PidPath);
RegisterAttribute("state_path", Attribute_Config, &m_StatePath);
RegisterAttribute("macros", Attribute_Config, &m_Macros);
}
/**
* The entry point for the Icinga application.
@ -96,47 +104,43 @@ IcingaApplication::Ptr IcingaApplication::GetInstance(void)
String IcingaApplication::GetCertificateFile(void) const
{
return Get("cert_path");
return m_CertPath;
}
String IcingaApplication::GetCAFile(void) const
{
return Get("ca_path");
return m_CAPath;
}
String IcingaApplication::GetNode(void) const
{
return Get("node");
return m_Node;
}
String IcingaApplication::GetService(void) const
{
return Get("service");
return m_Service;
}
String IcingaApplication::GetPidPath(void) const
{
Value pidPath = Get("pid_path");
if (pidPath.IsEmpty())
pidPath = Application::GetLocalStateDir() + "/run/icinga2.pid";
return pidPath;
if (m_PidPath.IsEmpty())
return Application::GetLocalStateDir() + "/run/icinga2.pid";
else
return m_PidPath;
}
String IcingaApplication::GetStatePath(void) const
{
Value statePath = Get("state_path");
if (statePath.IsEmpty())
statePath = Application::GetLocalStateDir() + "/lib/icinga2/icinga2.state";
return statePath;
if (m_PidPath.IsEmpty())
return Application::GetLocalStateDir() + "/lib/icinga2/icinga2.state";
else
return m_PidPath;
}
Dictionary::Ptr IcingaApplication::GetMacros(void) const
{
return Get("macros");
return m_Macros;
}
double IcingaApplication::GetStartTime(void) const

View File

@ -54,6 +54,14 @@ public:
static Dictionary::Ptr CalculateDynamicMacros(const IcingaApplication::Ptr& self);
private:
Attribute<String> m_CertPath;
Attribute<String> m_CAPath;
Attribute<String> m_Node;
Attribute<String> m_Service;
Attribute<String> m_PidPath;
Attribute<String> m_StatePath;
Attribute<Dictionary::Ptr> m_Macros;
shared_ptr<SSL_CTX> m_SSLContext;
double m_StartTime;

View File

@ -26,6 +26,12 @@ REGISTER_TYPE(Notification, NULL);
Notification::Notification(const Dictionary::Ptr& properties)
: DynamicObject(properties)
{
RegisterAttribute("notification_command", Attribute_Config, &m_NotificationCommand);
RegisterAttribute("macros", Attribute_Config, &m_Macros);
RegisterAttribute("users", Attribute_Config, &m_Users);
RegisterAttribute("host_name", Attribute_Config, &m_HostName);
RegisterAttribute("service", Attribute_Config, &m_Service);
Service::InvalidateNotificationsCache();
}
@ -51,30 +57,29 @@ Notification::Ptr Notification::GetByName(const String& name)
Service::Ptr Notification::GetService(void) const
{
Host::Ptr host = Host::GetByName(Get("host_name"));
String service = Get("service");
Host::Ptr host = Host::GetByName(m_HostName);
if (service.IsEmpty())
if (m_Service.IsEmpty())
return host->GetHostCheckService();
else
return host->GetServiceByShortName(service);
return host->GetServiceByShortName(m_Service);
}
Value Notification::GetNotificationCommand(void) const
{
return Get("notification_command");
return m_NotificationCommand;
}
Dictionary::Ptr Notification::GetMacros(void) const
{
return Get("macros");
return m_Macros;
}
set<User::Ptr> Notification::GetUsers(void) const
{
set<User::Ptr> result;
Dictionary::Ptr users = Get("users");
Dictionary::Ptr users = m_Users;
if (users) {
String name;

View File

@ -71,6 +71,12 @@ protected:
void OnAttributeChanged(const String& name, const Value& oldValue);
private:
Attribute<Value> m_NotificationCommand;
Attribute<Dictionary::Ptr> m_Macros;
Attribute<Dictionary::Ptr> m_Users;
Attribute<String> m_HostName;
Attribute<String> m_Service;
set<ScriptTask::Ptr> m_Tasks;
void NotificationCompletedHandler(const ScriptTask::Ptr& task);

View File

@ -30,96 +30,64 @@ signals2::signal<void (const Service::Ptr&, const Value&)> Service::OnNextCheckC
Value Service::GetCheckCommand(void) const
{
return Get("check_command");
return m_CheckCommand;
}
long Service::GetMaxCheckAttempts(void) const
{
Value value = Get("max_check_attempts");
if (value.IsEmpty())
if (m_MaxCheckAttempts.IsEmpty())
return DefaultMaxCheckAttempts;
return value;
return m_MaxCheckAttempts;
}
double Service::GetCheckInterval(void) const
{
Value value = Get("check_interval");
if (value.IsEmpty())
if (m_CheckInterval.IsEmpty())
return DefaultCheckInterval;
return value;
return m_CheckInterval;
}
double Service::GetRetryInterval(void) const
{
Value value = Get("retry_interval");
if (value.IsEmpty())
if (m_RetryInterval.IsEmpty())
return GetCheckInterval() / CheckIntervalDivisor;
return value;
return m_RetryInterval;
}
Dictionary::Ptr Service::GetCheckers(void) const
{
return Get("checkers");
return m_Checkers;
}
void Service::SetSchedulingOffset(long offset)
{
Set("scheduling_offset", offset);
m_SchedulingOffset = offset;
}
long Service::GetSchedulingOffset(void)
{
Value value = Get("scheduling_offset");
if (value.IsEmpty()) {
value = rand();
SetSchedulingOffset(value);
}
return value;
return m_SchedulingOffset;
}
void Service::SetFirstCheck(bool first)
{
Set("first_check", first ? 1 : 0);
}
bool Service::GetFirstCheck(void) const
{
Value value = Get("first_check");
if (value.IsEmpty())
return true;
return static_cast<long>(value);
}
void Service::SetNextCheck(double nextCheck)
{
Set("next_check", nextCheck);
m_NextCheck = nextCheck;
Touch("next_check");
}
double Service::GetNextCheck(void)
{
Value value = Get("next_check");
if (value.IsEmpty()) {
if (m_NextCheck.IsEmpty()) {
UpdateNextCheck();
value = Get("next_check");
if (value.IsEmpty())
if (m_NextCheck.IsEmpty())
BOOST_THROW_EXCEPTION(runtime_error("Failed to schedule next check."));
}
return value;
return m_NextCheck;
}
void Service::UpdateNextCheck(void)
@ -140,146 +108,140 @@ void Service::UpdateNextCheck(void)
SetNextCheck(now - adj + interval);
}
void Service::SetChecker(const String& checker)
void Service::SetCurrentChecker(const String& checker)
{
Set("checker", checker);
m_CurrentChecker = checker;
Touch("current_checker");
}
String Service::GetChecker(void) const
String Service::GetCurrentChecker(void) const
{
return Get("checker");
return m_CurrentChecker;
}
void Service::SetCurrentCheckAttempt(long attempt)
{
Set("check_attempt", attempt);
m_CheckAttempt = attempt;
Touch("check_attempt");
}
long Service::GetCurrentCheckAttempt(void) const
{
Value value = Get("check_attempt");
if (value.IsEmpty())
if (m_CheckAttempt.IsEmpty())
return 1;
return value;
return m_CheckAttempt;
}
void Service::SetState(ServiceState state)
{
Set("state", static_cast<long>(state));
m_State = static_cast<long>(state);
Touch("state");
}
ServiceState Service::GetState(void) const
{
Value value = Get("state");
if (value.IsEmpty())
if (m_State.IsEmpty())
return StateUnknown;
int ivalue = static_cast<int>(value);
int ivalue = static_cast<int>(m_State);
return static_cast<ServiceState>(ivalue);
}
void Service::SetStateType(ServiceStateType type)
{
Set("state_type", static_cast<long>(type));
m_StateType = static_cast<long>(type);
Touch("state_type");
}
ServiceStateType Service::GetStateType(void) const
{
Value value = Get("state_type");
if (value.IsEmpty())
if (m_StateType.IsEmpty())
return StateTypeSoft;
int ivalue = static_cast<int>(value);
int ivalue = static_cast<int>(m_StateType);
return static_cast<ServiceStateType>(ivalue);
}
void Service::SetLastCheckResult(const Dictionary::Ptr& result)
{
Set("last_result", result);
m_LastResult = result;
Touch("last_result");
}
Dictionary::Ptr Service::GetLastCheckResult(void) const
{
return Get("last_result");
return m_LastResult;
}
void Service::SetLastStateChange(double ts)
{
Set("last_state_change", static_cast<long>(ts));
m_LastStateChange = ts;
Touch("last_state_change");
}
double Service::GetLastStateChange(void) const
{
Value value = Get("last_state_change");
if (value.IsEmpty())
if (m_LastStateChange.IsEmpty())
return IcingaApplication::GetInstance()->GetStartTime();
return value;
return m_LastStateChange;
}
void Service::SetLastHardStateChange(double ts)
{
Set("last_hard_state_change", ts);
m_LastHardStateChange = ts;
Touch("last_hard_state_change");
}
double Service::GetLastHardStateChange(void) const
{
Value value = Get("last_hard_state_change");
if (m_LastHardStateChange.IsEmpty())
return IcingaApplication::GetInstance()->GetStartTime();
if (value.IsEmpty())
value = IcingaApplication::GetInstance()->GetStartTime();
return value;
return m_LastHardStateChange;
}
bool Service::GetEnableActiveChecks(void) const
{
Value value = Get("enable_active_checks");
if (value.IsEmpty())
if (m_EnableActiveChecks.IsEmpty())
return true;
return static_cast<bool>(value);
return static_cast<bool>(m_EnableActiveChecks);
}
void Service::SetEnableActiveChecks(bool enabled)
{
Set("enable_active_checks", enabled ? 1 : 0);
m_EnableActiveChecks = enabled ? 1 : 0;
Touch("enable_active_checks");
}
bool Service::GetEnablePassiveChecks(void) const
{
Value value = Get("enable_passive_checks");
if (value.IsEmpty())
if (m_EnablePassiveChecks.IsEmpty())
return true;
return static_cast<bool>(value);
return static_cast<bool>(m_EnablePassiveChecks);
}
void Service::SetEnablePassiveChecks(bool enabled)
{
Set("enable_passive_checks", enabled ? 1 : 0);
m_EnablePassiveChecks = enabled ? 1 : 0;
Touch("enable_passive_checks");
}
bool Service::GetForceNextCheck(void) const
{
Value value = Get("force_next_check");
if (value.IsEmpty())
if (m_ForceNextCheck.IsEmpty())
return false;
return static_cast<bool>(value);
return static_cast<bool>(m_ForceNextCheck);
}
void Service::SetForceNextCheck(bool forced)
{
Set("force_next_check", forced ? 1 : 0);
m_ForceNextCheck = forced ? 1 : 0;
Touch("force_next_check");
}
void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
@ -429,7 +391,7 @@ void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (v
ObjectLock slock(self);
/* don't run another check if there is one pending */
if (!self->Get("current_task").IsEmpty()) {
if (self->m_CurrentTask) {
slock.Unlock();
/* we need to call the callback anyway */
@ -481,7 +443,7 @@ void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (v
{
ObjectLock olock(self);
task = self->MakeMethodTask("check", arguments);
self->Set("current_task", task);
self->m_CurrentTask = task;
}
task->Start(boost::bind(&Service::CheckCompletedHandler, self, checkInfo, _1, callback));
@ -537,11 +499,11 @@ void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
if (!result->Contains("active"))
result->Set("active", 1);
if (!result->Contains("checker")) {
if (!result->Contains("current_checker")) {
EndpointManager::Ptr em = EndpointManager::GetInstance();
ObjectLock olock(em);
result->Set("checker", em->GetIdentity());
result->Set("current_checker", em->GetIdentity());
}
}
@ -550,7 +512,7 @@ void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
if (result)
ProcessCheckResult(result);
Set("current_task", Empty);
m_CurrentTask.reset();
/* figure out when the next check is for this service; the call to
* ApplyCheckResult() should've already done this but lets do it again

View File

@ -34,9 +34,7 @@ int Service::GetNextCommentID(void)
Dictionary::Ptr Service::GetComments(void) const
{
Service::ValidateCommentsCache();
return Get("comments");
return m_Comments;
}
String Service::AddComment(CommentType entryType, const String& author,
@ -50,14 +48,16 @@ String Service::AddComment(CommentType entryType, const String& author,
comment->Set("expire_time", expireTime);
comment->Set("legacy_id", m_NextCommentID++);
Dictionary::Ptr comments = Get("comments");
Dictionary::Ptr comments = m_Comments;
if (!comments)
comments = boost::make_shared<Dictionary>();
String id = Utility::NewUUID();
comments->Set(id, comment);
Set("comments", comments);
m_Comments = comments;
Touch("comments");
return id;
}
@ -74,7 +74,7 @@ void Service::RemoveComment(const String& id)
if (!owner)
return;
Dictionary::Ptr comments = owner->Get("comments");
Dictionary::Ptr comments = owner->m_Comments;
if (comments) {
comments->Remove(id);
@ -106,7 +106,7 @@ Dictionary::Ptr Service::GetCommentByID(const String& id)
if (!owner)
return Dictionary::Ptr();
Dictionary::Ptr comments = owner->Get("comments");
Dictionary::Ptr comments = owner->m_Comments;
if (comments) {
Dictionary::Ptr comment = comments->Get(id);
@ -132,7 +132,7 @@ void Service::InvalidateCommentsCache(void)
void Service::AddCommentsToCache(void)
{
Dictionary::Ptr comments = Get("comments");
Dictionary::Ptr comments = m_Comments;
if (!comments)
return;
@ -184,7 +184,7 @@ void Service::ValidateCommentsCache(void)
void Service::RemoveExpiredComments(void)
{
Dictionary::Ptr comments = Get("comments");
Dictionary::Ptr comments = m_Comments;
if (!comments)
return;

View File

@ -34,9 +34,7 @@ int Service::GetNextDowntimeID(void)
Dictionary::Ptr Service::GetDowntimes(void) const
{
Service::ValidateDowntimesCache();
return Get("downtimes");
return m_Downtimes;
}
String Service::AddDowntime(const String& author, const String& comment,
@ -65,14 +63,16 @@ String Service::AddDowntime(const String& author, const String& comment,
otherOwner->Touch("downtimes");
}
Dictionary::Ptr downtimes = Get("downtimes");
Dictionary::Ptr downtimes = m_Downtimes;
if (!downtimes)
downtimes = boost::make_shared<Dictionary>();
String id = Utility::NewUUID();
downtimes->Set(id, downtime);
Set("downtimes", downtimes);
m_Downtimes = downtimes;
Touch("downtimes");
return id;
}
@ -84,7 +84,7 @@ void Service::RemoveDowntime(const String& id)
if (!owner)
return;
Dictionary::Ptr downtimes = owner->Get("downtimes");
Dictionary::Ptr downtimes = owner->m_Downtimes;
if (!downtimes)
return;
@ -95,7 +95,7 @@ void Service::RemoveDowntime(const String& id)
void Service::TriggerDowntimes(void)
{
Dictionary::Ptr downtimes = Get("downtimes");
Dictionary::Ptr downtimes = m_Downtimes;
if (!downtimes)
return;
@ -155,7 +155,7 @@ Dictionary::Ptr Service::GetDowntimeByID(const String& id)
if (!owner)
return Dictionary::Ptr();
Dictionary::Ptr downtimes = owner->Get("downtimes");
Dictionary::Ptr downtimes = owner->m_Downtimes;
if (downtimes) {
Dictionary::Ptr downtime = downtimes->Get(id);
@ -198,7 +198,7 @@ void Service::InvalidateDowntimesCache(void)
void Service::AddDowntimesToCache(void)
{
Dictionary::Ptr downtimes = Get("downtimes");
Dictionary::Ptr downtimes = m_Downtimes;
if (!downtimes)
return;
@ -249,7 +249,7 @@ void Service::ValidateDowntimesCache(void)
void Service::RemoveExpiredDowntimes(void)
{
Dictionary::Ptr downtimes = Get("downtimes");
Dictionary::Ptr downtimes = m_Downtimes;
if (!downtimes)
return;

View File

@ -123,38 +123,56 @@ static void CopyNotificationAttributes(TDict notificationDesc, const ConfigItemB
builder->AddExpression("notification_interval", OperatorSet, notificationInterval);*/
}
void Service::UpdateSlaveNotifications(void)
void Service::UpdateSlaveNotifications(const Service::Ptr& self)
{
ConfigItem::Ptr item = ConfigItem::GetObject("Service", GetName());
Dictionary::Ptr oldNotifications;
Host::Ptr host;
vector<Dictionary::Ptr> notificationDescsList;
String service_name;
ConfigItem::Ptr item;
/* Don't create slave notifications unless we own this object
* and it's not a template. */
if (!item || IsAbstract())
return;
{
ObjectLock olock(self);
Dictionary::Ptr oldNotifications = Get("slave_notifications");
item = ConfigItem::GetObject("Service", self->GetName());
/* Don't create slave notifications unless we own this object
* and it's not a template. */
if (!item || self->IsAbstract())
return;
service_name = self->GetName();
oldNotifications = self->m_SlaveNotifications;
host = self->GetHost();
notificationDescsList.push_back(self->Get("notifications"));
}
DebugInfo debug_info;
{
ObjectLock ilock(item);
debug_info = item->GetDebugInfo();
}
Dictionary::Ptr newNotifications;
newNotifications = boost::make_shared<Dictionary>();
vector<Dictionary::Ptr> notificationDescsList;
String host_name;
{
Host::Ptr host = GetHost();
ObjectLock olock(host);
notificationDescsList.push_back(host->Get("notifications"));
host_name = host->GetName();
}
notificationDescsList.push_back(Get("notifications"));
BOOST_FOREACH(const Dictionary::Ptr& notificationDescs, notificationDescsList) {
if (!notificationDescs)
continue;
ObjectLock olock(notificationDescs);
String nfcname;
Value nfcdesc;
BOOST_FOREACH(tie(nfcname, nfcdesc), notificationDescs) {
@ -162,21 +180,22 @@ void Service::UpdateSlaveNotifications(void)
nfcname = nfcdesc;
stringstream namebuf;
namebuf << GetName() << "-" << nfcname;
namebuf << service_name << "-" << nfcname;
String name = namebuf.str();
ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(item->GetDebugInfo());
ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(debug_info);
builder->SetType("Notification");
builder->SetName(name);
builder->AddExpression("host_name", OperatorSet, host_name);
builder->AddExpression("service", OperatorSet, GetName());
builder->AddExpression("service", OperatorSet, service_name);
CopyNotificationAttributes(this, builder);
CopyNotificationAttributes(self, builder);
if (nfcdesc.IsScalar()) {
builder->AddParent(nfcdesc);
} else if (nfcdesc.IsObjectType<Dictionary>()) {
Dictionary::Ptr notification = nfcdesc;
ObjectLock nlock(notification);
Dictionary::Ptr templates = notification->Get("templates");
@ -212,12 +231,15 @@ void Service::UpdateSlaveNotifications(void)
}
}
Set("slave_notifications", newNotifications);
{
ObjectLock olock(self);
self->m_SlaveNotifications = newNotifications;
}
}
double Service::GetLastNotification(void) const
{
Value value = Get("last_notification");
Value value = m_LastNotification;
if (value.IsEmpty())
value = 0;
@ -227,12 +249,13 @@ double Service::GetLastNotification(void) const
void Service::SetLastNotification(double time)
{
Set("last_notification", time);
m_LastNotification = time;
Touch("last_notification");
}
double Service::GetNextNotification(void) const
{
Value value = Get("next_notification");
Value value = m_NextNotification;
if (value.IsEmpty())
value = 0;
@ -242,5 +265,6 @@ double Service::GetNextNotification(void) const
void Service::SetNextNotification(double time)
{
Set("next_notification", time);
m_NextNotification = time;
Touch("next_notification");
}

View File

@ -21,33 +21,51 @@
using namespace icinga;
static AttributeDescription serviceAttributes[] = {
{ "scheduling_offset", Attribute_Transient },
{ "first_check", Attribute_Transient },
{ "next_check", Attribute_Replicated },
{ "checker", Attribute_Replicated },
{ "check_attempt", Attribute_Replicated },
{ "state", Attribute_Replicated },
{ "state_type", Attribute_Replicated },
{ "last_result", Attribute_Replicated },
{ "last_state_change", Attribute_Replicated },
{ "last_hard_state_change", Attribute_Replicated },
{ "enable_active_checks", Attribute_Replicated },
{ "enable_passive_checks", Attribute_Replicated },
{ "force_next_check", Attribute_Replicated },
{ "acknowledgement", Attribute_Replicated },
{ "acknowledgement_expiry", Attribute_Replicated },
{ "downtimes", Attribute_Replicated },
{ "comments", Attribute_Replicated },
{ "last_notification", Attribute_Replicated },
{ "next_notification", Attribute_Replicated }
};
REGISTER_TYPE(Service, serviceAttributes);
REGISTER_TYPE(Service, NULL);
Service::Service(const Dictionary::Ptr& serializedObject)
: DynamicObject(serializedObject)
{ }
{
RegisterAttribute("display_name", Attribute_Config, &m_DisplayName);
RegisterAttribute("macros", Attribute_Config, &m_Macros);
RegisterAttribute("hostdependencies", Attribute_Config, &m_HostDependencies);
RegisterAttribute("servicedependencies", Attribute_Config, &m_ServiceDependencies);
RegisterAttribute("servicegroups", Attribute_Config, &m_ServiceGroups);
RegisterAttribute("check_command", Attribute_Config, &m_CheckCommand);
RegisterAttribute("max_check_attempts", Attribute_Config, &m_MaxCheckAttempts);
RegisterAttribute("check_interval", Attribute_Config, &m_CheckInterval);
RegisterAttribute("retry_interval", Attribute_Config, &m_RetryInterval);
RegisterAttribute("checkers", Attribute_Config, &m_Checkers);
RegisterAttribute("next_check", Attribute_Replicated, &m_NextCheck);
RegisterAttribute("current_checker", Attribute_Replicated, &m_CurrentChecker);
RegisterAttribute("check_attempt", Attribute_Replicated, &m_CheckAttempt);
RegisterAttribute("state", Attribute_Replicated, &m_State);
RegisterAttribute("state_type", Attribute_Replicated, &m_StateType);
RegisterAttribute("last_result", Attribute_Replicated, &m_LastResult);
RegisterAttribute("last_state_change", Attribute_Replicated, &m_LastStateChange);
RegisterAttribute("last_hard_state_change", Attribute_Replicated, &m_LastHardStateChange);
RegisterAttribute("enable_active_checks", Attribute_Replicated, &m_EnableActiveChecks);
RegisterAttribute("enable_passive_checks", Attribute_Replicated, &m_EnablePassiveChecks);
RegisterAttribute("force_next_check", Attribute_Replicated, &m_ForceNextCheck);
RegisterAttribute("short_name", Attribute_Config, &m_ShortName);
RegisterAttribute("host_name", Attribute_Config, &m_HostName);
RegisterAttribute("acknowledgement", Attribute_Replicated, &m_Acknowledgement);
RegisterAttribute("acknowledgement_expiry", Attribute_Replicated, &m_AcknowledgementExpiry);
RegisterAttribute("comments", Attribute_Replicated, &m_Comments);
RegisterAttribute("downtimes", Attribute_Replicated, &m_Downtimes);
RegisterAttribute("last_notification", Attribute_Replicated, &m_LastNotification);
RegisterAttribute("next_notification", Attribute_Replicated, &m_NextNotification);
SetSchedulingOffset(rand());
}
void Service::OnRegistrationCompleted(void)
{
@ -60,7 +78,7 @@ void Service::OnRegistrationCompleted(void)
{
ObjectLock olock(this);
UpdateSlaveNotifications();
m_Host = Host::GetByName(GetHostName());
}
}
@ -74,12 +92,10 @@ Service::~Service(void)
String Service::GetDisplayName(void) const
{
String value = Get("display_name");
if (value.IsEmpty())
if (m_DisplayName.IsEmpty())
return GetShortName();
return value;
else
return m_DisplayName;
}
/**
@ -119,42 +135,40 @@ Service::Ptr Service::GetByNamePair(const String& hostName, const String& servic
Host::Ptr Service::GetHost(void) const
{
String hostname = Get("host_name");
if (hostname.IsEmpty())
BOOST_THROW_EXCEPTION(runtime_error("Service object is missing the 'host_name' property."));
return Host::GetByName(hostname);
return m_Host;
}
Dictionary::Ptr Service::GetMacros(void) const
{
return Get("macros");
return m_Macros;
}
Dictionary::Ptr Service::GetHostDependencies(void) const
{
return Get("hostdependencies");
return m_HostDependencies;
}
Dictionary::Ptr Service::GetServiceDependencies(void) const
{
return Get("servicedependencies");
return m_ServiceDependencies;
}
Dictionary::Ptr Service::GetGroups(void) const
{
return Get("servicegroups");
return m_ServiceGroups;
}
String Service::GetHostName(void) const
{
return m_HostName;
}
String Service::GetShortName(void) const
{
Value value = Get("short_name");
if (value.IsEmpty())
if (m_ShortName.IsEmpty())
return GetName();
return value;
else
return m_ShortName;
}
bool Service::IsReachable(const Service::Ptr& self)
@ -212,12 +226,10 @@ bool Service::IsReachable(const Service::Ptr& self)
AcknowledgementType Service::GetAcknowledgement(void)
{
Value value = Get("acknowledgement");
if (value.IsEmpty())
if (m_Acknowledgement.IsEmpty())
return AcknowledgementNone;
int ivalue = static_cast<int>(value);
int ivalue = static_cast<int>(m_Acknowledgement);
AcknowledgementType avalue = static_cast<AcknowledgementType>(ivalue);
if (avalue != AcknowledgementNone) {
@ -235,7 +247,8 @@ AcknowledgementType Service::GetAcknowledgement(void)
void Service::SetAcknowledgement(AcknowledgementType acknowledgement)
{
Set("acknowledgement", static_cast<long>(acknowledgement));
m_Acknowledgement = acknowledgement;
Touch("acknowledgement");
}
bool Service::IsAcknowledged(void)
@ -245,17 +258,16 @@ bool Service::IsAcknowledged(void)
double Service::GetAcknowledgementExpiry(void) const
{
Value value = Get("acknowledgement_expiry");
if (value.IsEmpty())
if (m_AcknowledgementExpiry.IsEmpty())
return 0;
return static_cast<double>(value);
return static_cast<double>(m_AcknowledgementExpiry);
}
void Service::SetAcknowledgementExpiry(double timestamp)
{
Set("acknowledgement_expiry", timestamp);
m_AcknowledgementExpiry = timestamp;
Touch("acknowledgement_expiry");
}
void Service::AcknowledgeProblem(AcknowledgementType type, double expiry)
@ -274,7 +286,7 @@ void Service::ClearAcknowledgement(void)
void Service::OnAttributeChanged(const String& name, const Value& oldValue)
{
if (name == "checker")
if (name == "current_checker")
OnCheckerChanged(GetSelf(), oldValue);
else if (name == "next_check")
OnNextCheckChanged(GetSelf(), oldValue);
@ -283,16 +295,16 @@ void Service::OnAttributeChanged(const String& name, const Value& oldValue)
else if (name == "host_name" || name == "short_name") {
Host::InvalidateServicesCache();
{
ObjectLock olock(this);
UpdateSlaveNotifications();
}
UpdateSlaveNotifications(GetSelf());
if (name == "host_name")
m_Host = Host::GetByName(GetHostName());
} else if (name == "downtimes")
Service::InvalidateDowntimesCache();
else if (name == "comments")
Service::InvalidateCommentsCache();
else if (name == "notifications")
UpdateSlaveNotifications();
UpdateSlaveNotifications(GetSelf());
else if (name == "check_interval") {
ObjectLock(this);
ConfigItem::Ptr item = ConfigItem::GetObject("Service", GetName());

View File

@ -104,6 +104,7 @@ public:
Dictionary::Ptr GetHostDependencies(void) const;
Dictionary::Ptr GetServiceDependencies(void) const;
Dictionary::Ptr GetGroups(void) const;
String GetHostName(void) const;
String GetShortName(void) const;
static Dictionary::Ptr CalculateDynamicMacros(const Service::Ptr& self);
@ -126,15 +127,12 @@ public:
long GetSchedulingOffset(void);
void SetSchedulingOffset(long offset);
void SetFirstCheck(bool first);
bool GetFirstCheck(void) const;
void SetNextCheck(double nextCheck);
double GetNextCheck(void);
void UpdateNextCheck(void);
void SetChecker(const String& checker);
String GetChecker(void) const;
void SetCurrentChecker(const String& checker);
String GetCurrentChecker(void) const;
bool IsAllowedChecker(const String& checker) const;
@ -245,7 +243,7 @@ public:
set<Notification::Ptr> GetNotifications(void) const;
void UpdateSlaveNotifications(void);
static void UpdateSlaveNotifications(const Service::Ptr& self);
double GetLastNotification(void) const;
void SetLastNotification(double time);
@ -258,10 +256,46 @@ protected:
virtual void OnAttributeChanged(const String& name, const Value& oldValue);
private:
Host::Ptr m_Host;
Dictionary::Ptr m_SlaveNotifications;
Attribute<String> m_DisplayName;
Attribute<Dictionary::Ptr> m_Macros;
Attribute<Dictionary::Ptr> m_HostDependencies;
Attribute<Dictionary::Ptr> m_ServiceDependencies;
Attribute<Dictionary::Ptr> m_ServiceGroups;
Attribute<String> m_ShortName;
Attribute<long> m_Acknowledgement;
Attribute<double> m_AcknowledgementExpiry;
Attribute<String> m_HostName;
/* Checks */
Attribute<Value> m_CheckCommand;
Attribute<long> m_MaxCheckAttempts;
Attribute<double> m_CheckInterval;
Attribute<double> m_RetryInterval;
Attribute<double> m_NextCheck;
Attribute<Dictionary::Ptr> m_Checkers;
Attribute<String> m_CurrentChecker;
Attribute<long> m_CheckAttempt;
Attribute<long> m_State;
Attribute<long> m_StateType;
Attribute<Dictionary::Ptr> m_LastResult;
Attribute<double> m_LastStateChange;
Attribute<double> m_LastHardStateChange;
Attribute<bool> m_EnableActiveChecks;
Attribute<bool> m_EnablePassiveChecks;
Attribute<bool> m_ForceNextCheck;
ScriptTask::Ptr m_CurrentTask;
long m_SchedulingOffset;
void CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
const ScriptTask::Ptr& task, const function<void (void)>& callback);
/* Downtimes */
Attribute<Dictionary::Ptr> m_Downtimes;
static int m_NextDowntimeID;
static map<int, String> m_LegacyDowntimesCache;
@ -275,6 +309,8 @@ private:
void RemoveExpiredDowntimes(void);
/* Comments */
Attribute<Dictionary::Ptr> m_Comments;
static int m_NextCommentID;
static map<int, String> m_LegacyCommentsCache;
@ -288,6 +324,9 @@ private:
void RemoveExpiredComments(void);
/* Notifications */
Attribute<double> m_LastNotification;
Attribute<double> m_NextNotification;
static map<String, set<Notification::WeakPtr> > m_NotificationsCache;
static bool m_NotificationsCacheValid;
};

View File

@ -29,26 +29,28 @@ REGISTER_TYPE(ServiceGroup, NULL);
ServiceGroup::ServiceGroup(const Dictionary::Ptr& properties)
: DynamicObject(properties)
{ }
{
RegisterAttribute("display_name", Attribute_Config, &m_DisplayName);
RegisterAttribute("notes_url", Attribute_Config, &m_NotesUrl);
RegisterAttribute("action_url", Attribute_Config, &m_ActionUrl);
}
String ServiceGroup::GetDisplayName(void) const
{
String value = Get("display_name");
if (!value.IsEmpty())
return value;
if (!m_DisplayName.Get().IsEmpty())
return m_DisplayName;
else
return GetName();
}
String ServiceGroup::GetNotesUrl(void) const
{
return Get("notes_url");
return m_NotesUrl;
}
String ServiceGroup::GetActionUrl(void) const
{
return Get("action_url");
return m_ActionUrl;
}
/**

View File

@ -47,6 +47,10 @@ public:
static void InvalidateMembersCache(void);
private:
Attribute<String> m_DisplayName;
Attribute<String> m_NotesUrl;
Attribute<String> m_ActionUrl;
static boost::mutex m_Mutex;
static map<String, vector<weak_ptr<Service> > > m_MembersCache;
static bool m_MembersCacheValid;

View File

@ -25,7 +25,9 @@ REGISTER_TYPE(User, NULL);
User::User(const Dictionary::Ptr& properties)
: DynamicObject(properties)
{ }
{
RegisterAttribute("macros", Attribute_Config, &m_Macros);
}
bool User::Exists(const String& name)
{
@ -44,7 +46,7 @@ User::Ptr User::GetByName(const String& name)
Dictionary::Ptr User::GetMacros(void) const
{
return Get("macros");
return m_Macros;
}
Dictionary::Ptr User::CalculateDynamicMacros(const User::Ptr& self)

View File

@ -41,6 +41,9 @@ public:
Dictionary::Ptr GetMacros(void) const;
static Dictionary::Ptr CalculateDynamicMacros(const User::Ptr& self);
private:
Attribute<Dictionary::Ptr> m_Macros;
};
}

View File

@ -21,14 +21,7 @@
using namespace icinga;
static AttributeDescription endpointAttributes[] = {
{ "node", Attribute_Replicated },
{ "service", Attribute_Replicated },
{ "subscriptions", Attribute_Replicated },
{ "client", Attribute_Transient }
};
REGISTER_TYPE(Endpoint, endpointAttributes);
REGISTER_TYPE(Endpoint, NULL);
signals2::signal<void (const Endpoint::Ptr&)> Endpoint::OnConnected;
signals2::signal<void (const Endpoint::Ptr&)> Endpoint::OnDisconnected;
@ -42,7 +35,13 @@ signals2::signal<void (const Endpoint::Ptr&, const String& topic)> Endpoint::OnS
*/
Endpoint::Endpoint(const Dictionary::Ptr& serializedUpdate)
: DynamicObject(serializedUpdate)
{ }
{
RegisterAttribute("local", Attribute_Config, &m_Local);
RegisterAttribute("node", Attribute_Replicated, &m_Node);
RegisterAttribute("service", Attribute_Replicated, &m_Service);
RegisterAttribute("subscriptions", Attribute_Replicated, &m_Subscriptions);
}
/**
* Checks whether an endpoint with the specified name exists.
@ -98,9 +97,7 @@ Endpoint::Ptr Endpoint::MakeEndpoint(const String& name, bool replicated, bool l
*/
bool Endpoint::IsLocalEndpoint(void) const
{
Value value = Get("local");
return (!value.IsEmpty() && value);
return m_Local;
}
/**
@ -121,12 +118,12 @@ bool Endpoint::IsConnected(void) const
JsonRpcConnection::Ptr Endpoint::GetClient(void) const
{
return Get("client");
return m_Client;
}
void Endpoint::SetClient(const JsonRpcConnection::Ptr& client)
{
Set("client", client);
m_Client = client;
client->OnNewMessage.connect(boost::bind(&Endpoint::NewMessageHandler, this, _2));
client->OnClosed.connect(boost::bind(&Endpoint::ClientClosedHandler, this));
@ -186,17 +183,19 @@ bool Endpoint::HasSubscription(const String& topic) const
*/
void Endpoint::ClearSubscriptions(void)
{
Set("subscriptions", Empty);
m_Subscriptions = Empty;
Touch("subscriptions");
}
Dictionary::Ptr Endpoint::GetSubscriptions(void) const
{
return Get("subscriptions");
return m_Subscriptions;
}
void Endpoint::SetSubscriptions(const Dictionary::Ptr& subscriptions)
{
Set("subscriptions", subscriptions);
m_Subscriptions = subscriptions;
Touch("subscriptions");
}
void Endpoint::RegisterTopicHandler(const String& topic, const function<Endpoint::Callback>& callback)
@ -336,7 +335,7 @@ void Endpoint::ClientClosedHandler(void)
// timer for that, once we have a TTL property for the topics)
ClearSubscriptions();
Set("client", Empty);
m_Client.reset();
OnDisconnected(GetSelf());
}
@ -348,7 +347,7 @@ void Endpoint::ClientClosedHandler(void)
*/
String Endpoint::GetNode(void) const
{
return Get("node");
return m_Node;
}
/**
@ -358,5 +357,5 @@ String Endpoint::GetNode(void) const
*/
String Endpoint::GetService(void) const
{
return Get("service");
return m_Service;
}

View File

@ -78,6 +78,13 @@ public:
static signals2::signal<void (const Endpoint::Ptr&, const String& topic)> OnSubscriptionUnregistered;
private:
Attribute<bool> m_Local;
Attribute<Dictionary::Ptr> m_Subscriptions;
Attribute<String> m_Node;
Attribute<String> m_Service;
JsonRpcConnection::Ptr m_Client;
bool m_ReceivedWelcome; /**< Have we received a welcome message
from this endpoint? */
bool m_SentWelcome; /**< Have we sent a welcome message to this