Make the services/notifications caches thread safe.

Send notifications based on the notification_interval setting.
This commit is contained in:
Gunnar Beutner 2013-02-27 12:44:51 +01:00
parent 3a74316aab
commit e9648f35bc
26 changed files with 499 additions and 469 deletions

View File

@ -129,7 +129,7 @@ void CheckerComponent::CheckThreadProc(void)
try {
olock.Unlock();
Service::BeginExecuteCheck(service, boost::bind(&CheckerComponent::CheckCompletedHandler, this, service));
Service::BeginExecuteCheck(service, boost::bind(&CheckerComponent::CheckCompletedHandler, static_cast<CheckerComponent::Ptr>(GetSelf()), service));
} catch (const exception& ex) {
olock.Lock();
Logger::Write(LogCritical, "checker", "Exception occured while checking service '" + service->GetName() + "': " + diagnostic_information(ex));

View File

@ -257,11 +257,8 @@ void CompatComponent::DumpDowntimes(ostream& fp, const Service::Ptr& owner, Comp
void CompatComponent::DumpHostStatus(ostream& fp, const Host::Ptr& host)
{
Service::Ptr hc;
{
ObjectLock olock(host);
hc = host->GetHostCheckService();
fp << "hoststatus {" << "\n"
<< "\t" << "host_name=" << host->GetName() << "\n";
@ -269,6 +266,7 @@ void CompatComponent::DumpHostStatus(ostream& fp, const Host::Ptr& host)
ServiceState hcState = StateOK;
Service::Ptr hc = Host::GetHostCheckService(host);
if (hc) {
ObjectLock olock(hc);
hcState = hc->GetState();
@ -296,26 +294,23 @@ void CompatComponent::DumpHostStatus(ostream& fp, const Host::Ptr& host)
void CompatComponent::DumpHostObject(ostream& fp, const Host::Ptr& host)
{
Service::Ptr hc;
{
ObjectLock olock(host);
fp << "define host {" << "\n"
<< "\t" << "host_name" << "\t" << host->GetName() << "\n"
<< "\t" << "display_name" << "\t" << host->GetDisplayName() << "\n";
set<Host::Ptr> parents = host->GetParentHosts();
if (!parents.empty()) {
fp << "\t" << "parents" << "\t";
DumpNameList(fp, parents);
fp << "\n";
}
hc = host->GetHostCheckService();
}
set<Host::Ptr> parents = Host::GetParentHosts(host);
if (!parents.empty()) {
fp << "\t" << "parents" << "\t";
DumpNameList(fp, parents);
fp << "\n";
}
Service::Ptr hc = Host::GetHostCheckService(host);
if (hc) {
ObjectLock olock(hc);
@ -326,7 +321,7 @@ void CompatComponent::DumpHostObject(ostream& fp, const Host::Ptr& host)
<< "\t" << "passive_checks_enabled" << "\t" << (hc->GetEnablePassiveChecks() ? 1 : 0) << "\n"
<< "\t" << "notifications_enabled" << "\t" << (hc->GetEnableNotifications() ? 1 : 0) << "\n"
<< "\t" << "notification_options" << "\t" << "d,u,r" << "\n"
<< "\t" << "notification_interval" << "\t" << "60" << "\n"
<< "\t" << "notification_interval" << "\t" << hc->GetNotificationInterval() << "\n"
<< "\t" << "notification_period" << "\t" << "24x7" << "\n";
}
@ -434,13 +429,11 @@ void CompatComponent::DumpServiceStatus(ostream& fp, const Service::Ptr& service
void CompatComponent::DumpServiceObject(ostream& fp, const Service::Ptr& service)
{
set<Service::Ptr> parentServices;
Host::Ptr host;
String host_name, short_name;
{
ObjectLock olock(service);
parentServices = service->GetParentServices();
host = service->GetHost();
short_name = service->GetShortName();
}
@ -465,13 +458,13 @@ void CompatComponent::DumpServiceObject(ostream& fp, const Service::Ptr& service
<< "\t" << "passive_checks_enabled" << "\t" << (service->GetEnablePassiveChecks() ? 1 : 0) << "\n"
<< "\t" << "notifications_enabled" << "\t" << (service->GetEnableNotifications() ? 1 : 0) << "\n"
<< "\t" << "notification_options" << "\t" << "u,w,c,r" << "\n"
<< "\t" << "notification_interval" << "\t" << "60" << "\n"
<< "\t" << "notification_interval" << "\t" << service->GetNotificationInterval() << "\n"
<< "\t" << "notification_period" << "\t" << "24x7" << "\n"
<< "\t" << "}" << "\n"
<< "\n";
}
BOOST_FOREACH(const Service::Ptr& parent, parentServices) {
BOOST_FOREACH(const Service::Ptr& parent, Service::GetParentServices(service)) {
ObjectLock plock(parent);
fp << "define servicedependency {" << "\n"

View File

@ -440,7 +440,7 @@ void CompatIdoComponent::DumpHostStatus(const Host::Ptr& host)
int state;
if (!Host::IsReachable(host))
state = 2; /* unreachable */
else if (host->GetHostCheckService()->GetState() != StateOK)
else if (Host::GetHostCheckService(host)->GetState() != StateOK)
state = 1; /* down */
else
state = 0; /* up */

View File

@ -55,9 +55,24 @@ void NotificationComponent::Stop(void)
*/
void NotificationComponent::NotificationTimerHandler(void)
{
// TODO: implement
}
double now = Utility::GetTime();
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
ObjectLock olock(service);
if (service->GetStateType() == StateTypeSoft)
continue;
if (service->GetState() == StateOK)
continue;
if (service->GetLastNotification() > now - service->GetNotificationInterval())
continue;
service->RequestNotifications(NotificationProblem);
}
}
/**
* Processes icinga::SendNotifications messages.
@ -79,6 +94,5 @@ void NotificationComponent::SendNotificationsRequestHandler(const Endpoint::Ptr&
Service::Ptr service = Service::GetByName(svc);
ObjectLock olock(service);
service->SendNotifications(static_cast<NotificationType>(type));
Service::SendNotifications(service, static_cast<NotificationType>(type));
}

View File

@ -32,8 +32,8 @@ void ReplicationComponent::Start(void)
DynamicObject::OnRegistered.connect(boost::bind(&ReplicationComponent::LocalObjectRegisteredHandler, this, _1));
DynamicObject::OnUnregistered.connect(boost::bind(&ReplicationComponent::LocalObjectUnregisteredHandler, this, _1));
DynamicObject::OnTransactionClosing.connect(boost::bind(&ReplicationComponent::TransactionClosingHandler, this, _2));
DynamicObject::OnFlushObject.connect(boost::bind(&ReplicationComponent::FlushObjectHandler, this, _1));
DynamicObject::OnTransactionClosing.connect(boost::bind(&ReplicationComponent::TransactionClosingHandler, this, _1, _2));
DynamicObject::OnFlushObject.connect(boost::bind(&ReplicationComponent::FlushObjectHandler, this, _1, _2));
Endpoint::OnConnected.connect(boost::bind(&ReplicationComponent::EndpointConnectedHandler, this, _1));
@ -161,7 +161,7 @@ void ReplicationComponent::LocalObjectUnregisteredHandler(const DynamicObject::P
MakeObjectMessage(object, "config::ObjectRemoved", 0, false));
}
void ReplicationComponent::TransactionClosingHandler(const set<DynamicObject::WeakPtr>& modifiedObjects)
void ReplicationComponent::TransactionClosingHandler(double tx, const set<DynamicObject::WeakPtr>& modifiedObjects)
{
if (modifiedObjects.empty())
return;
@ -176,16 +176,16 @@ void ReplicationComponent::TransactionClosingHandler(const set<DynamicObject::We
if (!object)
continue;
FlushObjectHandler(object);
FlushObjectHandler(tx, object);
}
}
void ReplicationComponent::FlushObjectHandler(const DynamicObject::Ptr& object)
void ReplicationComponent::FlushObjectHandler(double tx, const DynamicObject::Ptr& object)
{
if (!ShouldReplicateObject(object))
return;
RequestMessage request = MakeObjectMessage(object, "config::ObjectUpdate", DynamicObject::GetCurrentTx(), true);
RequestMessage request = MakeObjectMessage(object, "config::ObjectUpdate", tx, true);
EndpointManager::Ptr em = EndpointManager::GetInstance();
{

View File

@ -41,8 +41,8 @@ private:
void LocalObjectRegisteredHandler(const DynamicObject::Ptr& object);
void LocalObjectUnregisteredHandler(const DynamicObject::Ptr& object);
void TransactionClosingHandler(const set<DynamicObject::WeakPtr>& modifiedObjects);
void FlushObjectHandler(const DynamicObject::Ptr& object);
void TransactionClosingHandler(double tx, const set<DynamicObject::WeakPtr>& modifiedObjects);
void FlushObjectHandler(double tx, const DynamicObject::Ptr& object);
void RemoteObjectUpdateHandler(const RequestMessage& request);
void RemoteObjectRemovedHandler(const RequestMessage& request);

View File

@ -210,7 +210,9 @@ type Service {
%attribute string "*"
}
}
}
},
%attribute number "notification_interval"
}
type ServiceGroup {

View File

@ -30,7 +30,7 @@ Timer::Ptr DynamicObject::m_TransactionTimer;
signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnRegistered;
signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnUnregistered;
signals2::signal<void (double, const set<DynamicObject::WeakPtr>&)> DynamicObject::OnTransactionClosing;
signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnFlushObject;
signals2::signal<void (double, const DynamicObject::Ptr&)> DynamicObject::OnFlushObject;
DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject)
: m_EventSafe(false), m_ConfigTx(0), m_Registered(false)
@ -75,26 +75,6 @@ void DynamicObject::Initialize(void)
m_TransactionTimer->Start();
}
/**
* @threadsafety Always.
*/
void DynamicObject::SendLocalUpdateEvents(void)
{
map<String, Value, string_iless> attrs;
{
ObjectLock olock(this);
attrs.swap(m_ModifiedAttributes);
}
/* Check if it's safe to send events. */
if (GetEventSafe()) {
map<String, Value, string_iless>::iterator it;
for (it = attrs.begin(); it != attrs.end(); it++)
OnAttributeChanged(it->first, it->second);
}
}
Dictionary::Ptr DynamicObject::BuildUpdate(double sinceTx, int attributeTypes) const
{
DynamicObject::AttributeConstIterator it;
@ -244,7 +224,7 @@ void DynamicObject::InternalSetAttribute(const String& name, const Value& data,
if (GetEventSafe()) {
/* We can't call GetSelf() in the constructor or destructor.
* The OnConstructionCompleted() function will take care of adding this
* The Register() function will take care of adding this
* object to the list of modified objects later on if we can't
* do it here. */
@ -327,6 +307,17 @@ String DynamicObject::GetSource(void) const
void DynamicObject::Register(void)
{
/* It's now safe to send us attribute events. */
SetEventSafe(true);
/* Add this new object to the list of modified objects.
* We're doing this here because we can't construct
* a while WeakPtr from within the object's constructor. */
{
boost::mutex::scoped_lock lock(m_TransactionMutex);
m_ModifiedObjects.insert(GetSelf());
}
{
DynamicType::Ptr dtype = GetType();
ObjectLock olock(dtype);
@ -339,10 +330,24 @@ void DynamicObject::Register(void)
if (!dobj)
dtype->RegisterObject(self);
}
}
OnRegistered(GetSelf());
void DynamicObject::OnRegistrationCompleted(void)
{
DynamicObject::Ptr object;
Start();
{
ObjectLock olock(this);
m_Registered = true;
Start();
Flush();
object = GetSelf();
}
OnRegistered(object);
}
void DynamicObject::Start(void)
@ -532,8 +537,7 @@ double DynamicObject::GetCurrentTx(void)
void DynamicObject::Flush(void)
{
SendLocalUpdateEvents();
OnFlushObject(GetSelf());
OnFlushObject(GetCurrentTx(), GetSelf());
}
/*
@ -558,30 +562,24 @@ void DynamicObject::NewTx(void)
if (!object)
continue;
object->SendLocalUpdateEvents();
map<String, Value, string_iless> attrs;
{
ObjectLock olock(object);
attrs.swap(object->m_ModifiedAttributes);
}
/* Check if it's safe to send events. */
if (object->GetEventSafe()) {
map<String, Value, string_iless>::iterator it;
for (it = attrs.begin(); it != attrs.end(); it++)
object->OnAttributeChanged(it->first, it->second);
}
}
OnTransactionClosing(tx, objects);
}
void DynamicObject::OnConstructionCompleted(void)
{
/* It's now safe to send us attribute events. */
SetEventSafe(true);
/* Add this new object to the list of modified objects.
* We're doing this here because we can't construct
* a while WeakPtr from within the object's constructor. */
boost::mutex::scoped_lock lock(m_TransactionMutex);
m_ModifiedObjects.insert(GetSelf());
}
void DynamicObject::OnRegistrationCompleted(void)
{
ObjectLock olock(this);
m_Registered = true;
}
void DynamicObject::OnAttributeChanged(const String&, const Value&)
{ }

View File

@ -228,7 +228,7 @@ public:
static signals2::signal<void (const DynamicObject::Ptr&)> OnRegistered;
static signals2::signal<void (const DynamicObject::Ptr&)> OnUnregistered;
static signals2::signal<void (double, const set<DynamicObject::WeakPtr>&)> OnTransactionClosing;
static signals2::signal<void (const DynamicObject::Ptr&)> OnFlushObject;
static signals2::signal<void (double, const DynamicObject::Ptr&)> OnFlushObject;
ScriptTask::Ptr MakeMethodTask(const String& method,
const vector<Value>& arguments);
@ -243,9 +243,6 @@ public:
void SetSource(const String& value);
String GetSource(void) const;
void SetTx(double tx);
double GetTx(void) const;
void Flush(void);
void Register(void);
@ -267,7 +264,6 @@ public:
static double GetCurrentTx(void);
protected:
virtual void OnConstructionCompleted(void);
virtual void OnRegistrationCompleted(void);
virtual void OnAttributeChanged(const String& name, const Value& oldValue);
@ -301,7 +297,7 @@ private:
static boost::once_flag m_TransactionOnce;
static Timer::Ptr m_TransactionTimer;
friend class DynamicType; /* for OnInitCompleted. */
friend class DynamicType; /* for OnRegistrationCompleted. */
};
}

View File

@ -99,14 +99,7 @@ void DynamicType::RegisterObject(const DynamicObject::Ptr& object)
m_ObjectMap[name] = object;
m_ObjectSet.insert(object);
/* notify the object that it's been registered */
object->OnRegistrationCompleted();
{
ObjectLock olock(object);
object->Flush();
}
}
void DynamicType::UnregisterObject(const DynamicObject::Ptr& object)
@ -162,8 +155,6 @@ DynamicObject::Ptr DynamicType::CreateObject(const Dictionary::Ptr& serializedUp
object->ApplyUpdate(serializedUpdate, Attribute_All & ~Attribute_Config);
}
object->OnConstructionCompleted();
return object;
}

View File

@ -35,10 +35,8 @@ Script::Script(const Dictionary::Ptr& properties)
RegisterAttribute("code", Attribute_Config, &m_Code);
}
void Script::OnRegistrationCompleted(void)
void Script::Start(void)
{
DynamicObject::OnRegistrationCompleted();
SpawnInterpreter();
}

View File

@ -38,11 +38,12 @@ public:
Script(const Dictionary::Ptr& properties);
virtual void Start(void);
String GetLanguage(void) const;
String GetCode(void) const;
protected:
virtual void OnRegistrationCompleted(void);
virtual void OnAttributeUpdate(const String& name, const Value& oldValue);
private:

View File

@ -162,7 +162,7 @@ void ExternalCommandProcessor::ProcessHostCheckResult(double time, const vector<
Host::Ptr host = Host::GetByName(arguments[0]);
Service::Ptr hc = host->GetHostCheckService();
Service::Ptr hc = Host::GetHostCheckService(host);
if (!hc->GetEnablePassiveChecks())
BOOST_THROW_EXCEPTION(invalid_argument("Got passive check result for host '" + arguments[0] + "' which has passive checks disabled."));
@ -222,7 +222,7 @@ void ExternalCommandProcessor::ScheduleHostCheck(double, const vector<String>& a
Host::Ptr host = Host::GetByName(arguments[0]);
Service::Ptr hc = host->GetHostCheckService();
Service::Ptr hc = Host::GetHostCheckService(host);
double planned_check = Convert::ToDouble(arguments[1]);
@ -243,7 +243,7 @@ void ExternalCommandProcessor::ScheduleForcedHostCheck(double, const vector<Stri
Host::Ptr host = Host::GetByName(arguments[0]);
Service::Ptr hc = host->GetHostCheckService();
Service::Ptr hc = Host::GetHostCheckService(host);
Logger::Write(LogInformation, "icinga", "Rescheduling next check for host '" + arguments[0] + "'");
hc->SetForceNextCheck(true);
@ -289,7 +289,7 @@ void ExternalCommandProcessor::EnableHostCheck(double, const vector<String>& arg
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Enabling active checks for host '" + arguments[0] + "'");
Service::Ptr hc = host->GetHostCheckService();
Service::Ptr hc = Host::GetHostCheckService(host);
if (hc)
hc->SetEnableActiveChecks(true);
@ -303,7 +303,7 @@ void ExternalCommandProcessor::DisableHostCheck(double, const vector<String>& ar
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Disabling active checks for host '" + arguments[0] + "'");
Service::Ptr hc = host->GetHostCheckService();
Service::Ptr hc = Host::GetHostCheckService(host);
if (hc)
hc->SetEnableActiveChecks(false);
@ -454,7 +454,7 @@ void ExternalCommandProcessor::AcknowledgeHostProblem(double, const vector<Strin
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Setting acknowledgement for host '" + host->GetName() + "'");
Service::Ptr service = host->GetHostCheckService();
Service::Ptr service = Host::GetHostCheckService(host);
if (service) {
if (service->GetState() == StateOK)
BOOST_THROW_EXCEPTION(invalid_argument("The host '" + arguments[0] + "' is OK."));
@ -474,7 +474,7 @@ void ExternalCommandProcessor::AcknowledgeHostProblemExpire(double, const vector
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Setting timed acknowledgement for host '" + host->GetName() + "'");
Service::Ptr service = host->GetHostCheckService();
Service::Ptr service = Host::GetHostCheckService(host);
if (service) {
if (service->GetState() == StateOK)
BOOST_THROW_EXCEPTION(invalid_argument("The host '" + arguments[0] + "' is OK."));
@ -491,7 +491,7 @@ void ExternalCommandProcessor::RemoveHostAcknowledgement(double, const vector<St
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Removing acknowledgement for host '" + host->GetName() + "'");
Service::Ptr service = host->GetHostCheckService();
Service::Ptr service = Host::GetHostCheckService(host);
if (service) {
service->ClearAcknowledgement();
}
@ -561,7 +561,7 @@ void ExternalCommandProcessor::EnablePassiveHostChecks(double, const vector<Stri
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Enabling passive checks for host '" + arguments[0] + "'");
Service::Ptr hc = host->GetHostCheckService();
Service::Ptr hc = Host::GetHostCheckService(host);
if (hc)
hc->SetEnablePassiveChecks(true);
@ -575,7 +575,7 @@ void ExternalCommandProcessor::DisablePassiveHostChecks(double, const vector<Str
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Disabling passive checks for host '" + arguments[0] + "'");
Service::Ptr hc = host->GetHostCheckService();
Service::Ptr hc = Host::GetHostCheckService(host);
if (hc)
hc->SetEnablePassiveChecks(false);
@ -735,7 +735,7 @@ void ExternalCommandProcessor::ScheduleHostDowntime(double, const vector<String>
triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy);
Logger::Write(LogInformation, "icinga", "Creating downtime for host " + host->GetName());
Service::Ptr service = host->GetHostCheckService();
Service::Ptr service = Host::GetHostCheckService(host);
if (service) {
(void) service->AddDowntime(arguments[6], arguments[7],
Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]),
@ -788,7 +788,7 @@ void ExternalCommandProcessor::ScheduleHostgroupHostDowntime(double, const vecto
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
Logger::Write(LogInformation, "icinga", "Creating downtime for host " + host->GetName());
Service::Ptr service = host->GetHostCheckService();
Service::Ptr service = Host::GetHostCheckService(host);
if (service) {
(void) service->AddDowntime(arguments[6], arguments[7],
Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]),
@ -849,7 +849,7 @@ void ExternalCommandProcessor::ScheduleServicegroupHostDowntime(double, const ve
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
Host::Ptr host = service->GetHost();
Service::Ptr hcService = host->GetHostCheckService();
Service::Ptr hcService = Host::GetHostCheckService(host);
if (hcService)
services.insert(hcService);
}
@ -890,7 +890,7 @@ void ExternalCommandProcessor::AddHostComment(double, const vector<String>& argu
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Creating comment for host " + host->GetName());
Service::Ptr service = host->GetHostCheckService();
Service::Ptr service = Host::GetHostCheckService(host);
if (service)
(void) service->AddComment(CommentUser, arguments[2], arguments[3], 0);
}
@ -937,7 +937,7 @@ void ExternalCommandProcessor::DelAllHostComments(double, const vector<String>&
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Removing all comments for host " + host->GetName());
Service::Ptr service = host->GetHostCheckService();
Service::Ptr service = Host::GetHostCheckService(host);
if (service)
service->RemoveAllComments();
}
@ -961,7 +961,7 @@ void ExternalCommandProcessor::SendCustomHostNotification(double time, const vec
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Sending custom notification for host " + host->GetName());
Service::Ptr service = host->GetHostCheckService();
Service::Ptr service = Host::GetHostCheckService(host);
if (service) {
service->RequestNotifications(NotificationCustom);
}
@ -986,7 +986,7 @@ void ExternalCommandProcessor::DelayHostNotification(double time, const vector<S
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Delaying notifications for host " + host->GetName());
Service::Ptr service = host->GetHostCheckService();
Service::Ptr service = Host::GetHostCheckService(host);
if (service) {
service->SetLastNotification(Convert::ToDouble(arguments[1]));
}
@ -1011,7 +1011,7 @@ void ExternalCommandProcessor::EnableHostNotifications(double, const vector<Stri
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Enabling notifications for host '" + arguments[0] + "'");
Service::Ptr hc = host->GetHostCheckService();
Service::Ptr hc = Host::GetHostCheckService(host);
if (hc)
hc->SetEnableNotifications(true);
@ -1025,7 +1025,7 @@ void ExternalCommandProcessor::DisableHostNotifications(double, const vector<Str
Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Disabling notifications for host '" + arguments[0] + "'");
Service::Ptr hc = host->GetHostCheckService();
Service::Ptr hc = Host::GetHostCheckService(host);
if (hc)
hc->SetEnableNotifications(false);

View File

@ -21,9 +21,8 @@
using namespace icinga;
boost::mutex Host::m_Mutex;
boost::mutex Host::m_ServiceMutex;
map<String, map<String, weak_ptr<Service> > > Host::m_ServicesCache;
bool Host::m_ServicesCacheValid = true;
REGISTER_SCRIPTFUNCTION("ValidateServiceDictionary", &Host::ValidateServiceDictionary);
@ -41,17 +40,9 @@ Host::Host(const Dictionary::Ptr& properties)
}
void Host::OnRegistrationCompleted(void)
{
DynamicObject::OnRegistrationCompleted();
HostGroup::InvalidateMembersCache();
Host::UpdateSlaveServices(GetSelf());
}
Host::~Host(void)
{
HostGroup::InvalidateMembersCache();
HostGroup::RefreshMembersCache();
if (m_SlaveServices) {
ConfigItem::Ptr service;
@ -61,6 +52,14 @@ Host::~Host(void)
}
}
void Host::OnRegistrationCompleted(void)
{
DynamicObject::OnRegistrationCompleted();
HostGroup::RefreshMembersCache();
Host::UpdateSlaveServices(GetSelf());
}
String Host::GetDisplayName(void) const
{
if (!m_DisplayName.IsEmpty())
@ -117,12 +116,7 @@ String Host::GetHostCheck(void) const
bool Host::IsReachable(const Host::Ptr& self)
{
set<Service::Ptr> parentServices;
{
ObjectLock olock(self);
parentServices = self->GetParentServices();
}
set<Service::Ptr> parentServices = Host::GetParentServices(self);
BOOST_FOREACH(const Service::Ptr& service, parentServices) {
ObjectLock olock(service);
@ -143,21 +137,10 @@ bool Host::IsReachable(const Host::Ptr& self)
return false;
}
set<Host::Ptr> parentHosts;
{
ObjectLock olock(self);
parentHosts = self->GetParentHosts();
}
set<Host::Ptr> parentHosts = Host::GetParentHosts(self);
BOOST_FOREACH(const Host::Ptr& host, parentHosts) {
Service::Ptr hc;
{
ObjectLock olock(host);
hc = host->GetHostCheckService();
}
Service::Ptr hc = Host::GetHostCheckService(host);
ObjectLock olock(hc);
/* ignore hosts that are up */
@ -309,7 +292,7 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
void Host::OnAttributeChanged(const String& name, const Value&)
{
if (name == "hostgroups")
HostGroup::InvalidateMembersCache();
HostGroup::RefreshMembersCache();
else if (name == "services") {
UpdateSlaveServices(GetSelf());
} else if (name == "notifications") {
@ -323,9 +306,6 @@ void Host::OnAttributeChanged(const String& name, const Value&)
BOOST_FOREACH(const Service::Ptr& service, services) {
Service::UpdateSlaveNotifications(service);
}
} else if (name == "hostcheck") {
ObjectLock olock(this);
m_HostCheckService = GetServiceByShortName(GetHostCheck());
}
}
@ -333,9 +313,7 @@ set<Service::Ptr> Host::GetServices(void) const
{
set<Service::Ptr> services;
boost::mutex::scoped_lock lock(m_Mutex);
ValidateServicesCache();
boost::mutex::scoped_lock lock(m_ServiceMutex);
Service::WeakPtr wservice;
BOOST_FOREACH(tie(tuples::ignore, wservice), m_ServicesCache[GetName()]) {
@ -350,22 +328,9 @@ set<Service::Ptr> Host::GetServices(void) const
return services;
}
void Host::InvalidateServicesCache(void)
void Host::RefreshServicesCache(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)
return;
m_ServicesCache.clear();
map<String, map<String, weak_ptr<Service> > > newServicesCache;
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
const Service::Ptr& service = static_pointer_cast<Service>(object);
@ -388,10 +353,11 @@ void Host::ValidateServicesCache(void)
// TODO: assert for duplicate short_names
m_ServicesCache[host_name][short_name] = service;
newServicesCache[host_name][short_name] = service;
}
m_ServicesCacheValid = true;
boost::mutex::scoped_lock lock(m_ServiceMutex);
m_ServicesCache.swap(newServicesCache);
}
void Host::ValidateServiceDictionary(const ScriptTask::Ptr& task, const vector<Value>& arguments)
@ -444,16 +410,20 @@ void Host::ValidateServiceDictionary(const ScriptTask::Ptr& task, const vector<V
task->FinishResult(Empty);
}
Service::Ptr Host::GetServiceByShortName(const Value& name) const
Service::Ptr Host::GetServiceByShortName(const Host::Ptr& self, const Value& name)
{
String host_name;
{
ObjectLock olock(self);
host_name = self->GetName();
}
if (name.IsScalar()) {
{
boost::mutex::scoped_lock lock(m_Mutex);
boost::mutex::scoped_lock lock(m_ServiceMutex);
ValidateServicesCache();
map<String, weak_ptr<Service> >& services = m_ServicesCache[GetName()];
map<String, weak_ptr<Service> >& services = m_ServicesCache[host_name];
map<String, weak_ptr<Service> >::iterator it = services.find(name);
if (it != services.end()) {
@ -466,22 +436,29 @@ Service::Ptr Host::GetServiceByShortName(const Value& name) const
return Service::GetByName(name);
} else if (name.IsObjectType<Dictionary>()) {
Dictionary::Ptr dict = name;
return GetByName(dict->Get("host"))->GetServiceByShortName(dict->Get("service"));
return GetServiceByShortName(GetByName(dict->Get("host")), dict->Get("service"));
} else {
BOOST_THROW_EXCEPTION(invalid_argument("Host/Service name pair is invalid."));
}
}
set<Host::Ptr> Host::GetParentHosts(void) const
set<Host::Ptr> Host::GetParentHosts(const Host::Ptr& self)
{
set<Host::Ptr> parents;
Dictionary::Ptr dependencies = GetHostDependencies();
Dictionary::Ptr dependencies;
String host_name;
{
ObjectLock olock(self);
dependencies = self->GetHostDependencies();
host_name = self->GetName();
}
if (dependencies) {
Value value;
BOOST_FOREACH(tie(tuples::ignore, value), dependencies) {
if (value == GetName())
if (value == host_name)
continue;
parents.insert(Host::GetByName(value));
@ -491,21 +468,33 @@ set<Host::Ptr> Host::GetParentHosts(void) const
return parents;
}
Service::Ptr Host::GetHostCheckService(void) const
Service::Ptr Host::GetHostCheckService(const Host::Ptr& self)
{
return m_HostCheckService.lock();
String host_check;
{
ObjectLock olock(self);
host_check = self->GetHostCheck();
}
return GetServiceByShortName(self, host_check);
}
set<Service::Ptr> Host::GetParentServices(void) const
set<Service::Ptr> Host::GetParentServices(const Host::Ptr& self)
{
set<Service::Ptr> parents;
Dictionary::Ptr dependencies = GetServiceDependencies();
Dictionary::Ptr dependencies;
{
ObjectLock olock(self);
dependencies = self->GetServiceDependencies();
}
if (dependencies) {
Value value;
BOOST_FOREACH(tie(tuples::ignore, value), dependencies) {
parents.insert(GetServiceByShortName(value));
parents.insert(GetServiceByShortName(self, value));
}
}
@ -516,22 +505,20 @@ Dictionary::Ptr Host::CalculateDynamicMacros(const Host::Ptr& self)
{
Dictionary::Ptr macros = boost::make_shared<Dictionary>();
Service::Ptr hc;
{
ObjectLock olock(self);
macros->Set("HOSTNAME", self->GetName());
macros->Set("HOSTDISPLAYNAME", self->GetDisplayName());
macros->Set("HOSTALIAS", self->GetName());
hc = self->GetHostCheckService();
}
bool reachable = Host::IsReachable(self);
Dictionary::Ptr cr;
Service::Ptr hc = Host::GetHostCheckService(self);
if (hc) {
ObjectLock olock(hc);

View File

@ -52,23 +52,23 @@ public:
static Dictionary::Ptr CalculateDynamicMacros(const Host::Ptr& self);
shared_ptr<Service> GetHostCheckService(void) const;
set<Host::Ptr> GetParentHosts(void) const;
set<shared_ptr<Service> > GetParentServices(void) const;
static shared_ptr<Service> GetHostCheckService(const Host::Ptr& self);
static set<Host::Ptr> GetParentHosts(const Host::Ptr& self);
static set<shared_ptr<Service> > GetParentServices(const Host::Ptr& self);
static bool IsReachable(const Host::Ptr& self);
shared_ptr<Service> GetServiceByShortName(const Value& name) const;
static shared_ptr<Service> GetServiceByShortName(const Host::Ptr& self, const Value& name);
set<shared_ptr<Service> > GetServices(void) const;
static void InvalidateServicesCache(void);
static void RefreshServicesCache(void);
static void ValidateServiceDictionary(const ScriptTask::Ptr& task,
const std::vector<icinga::Value>& arguments);
protected:
void OnRegistrationCompleted(void);
void OnAttributeChanged(const String& name, const Value& oldValue);
virtual void OnRegistrationCompleted(void);
virtual void OnAttributeChanged(const String& name, const Value& oldValue);
private:
Attribute<String> m_DisplayName;
@ -79,15 +79,12 @@ private:
Attribute<String> m_HostCheck;
Dictionary::Ptr m_SlaveServices;
static boost::mutex m_Mutex;
static boost::mutex m_ServiceMutex;
static map<String, map<String, weak_ptr<Service> > > m_ServicesCache;
static bool m_ServicesCacheValid;
static void UpdateSlaveServices(const Host::Ptr& self);
static void ValidateServicesCache(void);
weak_ptr<Service> m_HostCheckService;
};
}

View File

@ -23,7 +23,6 @@ using namespace icinga;
boost::mutex HostGroup::m_Mutex;
map<String, vector<Host::WeakPtr> > HostGroup::m_MembersCache;
bool HostGroup::m_MembersCacheValid = true;
REGISTER_TYPE(HostGroup, NULL);
@ -35,6 +34,16 @@ HostGroup::HostGroup(const Dictionary::Ptr& properties)
RegisterAttribute("action_url", Attribute_Config, &m_ActionUrl);
}
HostGroup::~HostGroup(void)
{
RefreshMembersCache();
}
void HostGroup::OnRegistrationCompleted(void)
{
RefreshMembersCache();
}
String HostGroup::GetDisplayName(void) const
{
if (!m_DisplayName.IsEmpty())
@ -88,10 +97,8 @@ set<Host::Ptr> HostGroup::GetMembers(const HostGroup::Ptr& self)
{
boost::mutex::scoped_lock lock(m_Mutex);
ValidateMembersCache();
BOOST_FOREACH(const Host::WeakPtr& hst, m_MembersCache[name]) {
Host::Ptr host = hst.lock();
BOOST_FOREACH(const Host::WeakPtr& whost, m_MembersCache[name]) {
Host::Ptr host = whost.lock();
if (!host)
continue;
@ -103,22 +110,9 @@ set<Host::Ptr> HostGroup::GetMembers(const HostGroup::Ptr& self)
return hosts;
}
void HostGroup::InvalidateMembersCache(void)
void HostGroup::RefreshMembersCache(void)
{
boost::mutex::scoped_lock lock(m_Mutex);
m_MembersCacheValid = false;
m_MembersCache.clear();
}
/**
* @threadsafety Caller must hold m_Mutex.
*/
void HostGroup::ValidateMembersCache(void)
{
if (m_MembersCacheValid)
return;
m_MembersCache.clear();
map<String, vector<weak_ptr<Host> > > newMembersCache;
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Host")) {
const Host::Ptr& host = static_pointer_cast<Host>(object);
@ -132,12 +126,13 @@ void HostGroup::ValidateMembersCache(void)
Value hostgroup;
BOOST_FOREACH(tie(tuples::ignore, hostgroup), dict) {
if (!HostGroup::Exists(hostgroup))
Logger::Write(LogWarning, "icinga", "Host group '" + static_cast<String>(hostgroup) + "' used but not defined.");
continue;
m_MembersCache[hostgroup].push_back(host);
newMembersCache[hostgroup].push_back(host);
}
}
}
m_MembersCacheValid = true;
boost::mutex::scoped_lock lock(m_Mutex);
m_MembersCache.swap(newMembersCache);
}

View File

@ -34,7 +34,8 @@ public:
typedef shared_ptr<HostGroup> Ptr;
typedef weak_ptr<HostGroup> WeakPtr;
HostGroup(const Dictionary::Ptr& properties);;
HostGroup(const Dictionary::Ptr& properties);
~HostGroup(void);
static bool Exists(const String& name);
static HostGroup::Ptr GetByName(const String& name);
@ -44,7 +45,11 @@ public:
String GetActionUrl(void) const;
static set<Host::Ptr> GetMembers(const HostGroup::Ptr& self);
static void InvalidateMembersCache(void);
static void RefreshMembersCache(void);
protected:
virtual void OnRegistrationCompleted(void);
private:
Attribute<String> m_DisplayName;
@ -53,9 +58,6 @@ private:
static boost::mutex m_Mutex;
static map<String, vector<weak_ptr<Host> > > m_MembersCache;
static bool m_MembersCacheValid;
static void ValidateMembersCache(void);
};
}

View File

@ -32,12 +32,12 @@ Notification::Notification(const Dictionary::Ptr& properties)
RegisterAttribute("host_name", Attribute_Config, &m_HostName);
RegisterAttribute("service", Attribute_Config, &m_Service);
Service::InvalidateNotificationsCache();
Service::RefreshNotificationsCache();
}
Notification::~Notification(void)
{
Service::InvalidateNotificationsCache();
Service::RefreshNotificationsCache();
}
bool Notification::Exists(const String& name)
@ -60,9 +60,9 @@ Service::Ptr Notification::GetService(void) const
Host::Ptr host = Host::GetByName(m_HostName);
if (m_Service.IsEmpty())
return host->GetHostCheckService();
return Host::GetHostCheckService(host);
else
return host->GetServiceByShortName(m_Service);
return Host::GetServiceByShortName(host, m_Service);
}
Value Notification::GetNotificationCommand(void) const
@ -239,5 +239,5 @@ void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task)
void Notification::OnAttributeChanged(const String& name, const Value& oldValue)
{
if (name == "host_name" || name == "service")
Service::InvalidateNotificationsCache();
Service::RefreshNotificationsCache();
}

View File

@ -254,10 +254,11 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
long attempt = GetCurrentCheckAttempt();
if (cr->Get("state") == StateOK) {
if (old_state == StateOK && old_stateType == StateTypeSoft) {
if (old_state == StateOK && old_stateType == StateTypeSoft)
hardChange = true; // hard recovery
if (old_state == StateOK || old_stateType == StateTypeSoft)
SetStateType(StateTypeHard);
}
attempt = 1;
recovery = true;
@ -294,16 +295,18 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
}
/* reschedule service dependencies */
BOOST_FOREACH(const Service::Ptr& parent, GetParentServices()) {
BOOST_FOREACH(const Service::Ptr& parent, Service::GetParentServices(GetSelf())) {
parent->SetNextCheck(Utility::GetTime());
}
/* reschedule host dependencies */
BOOST_FOREACH(const Host::Ptr& parent, GetParentHosts()) {
Service::Ptr service = parent->GetHostCheckService();
BOOST_FOREACH(const Host::Ptr& parent, Service::GetParentHosts(GetSelf())) {
Service::Ptr service = Host::GetHostCheckService(parent);
if (service)
if (service) {
ObjectLock olock(service);
service->SetNextCheck(Utility::GetTime());
}
}
}

View File

@ -22,9 +22,9 @@
using namespace icinga;
int Service::m_NextCommentID = 1;
boost::mutex Service::m_CommentMutex;
map<int, String> Service::m_LegacyCommentsCache;
map<String, Service::WeakPtr> Service::m_CommentsCache;
bool Service::m_CommentsCacheValid;
Timer::Ptr Service::m_CommentsExpireTimer;
int Service::GetNextCommentID(void)
@ -46,7 +46,15 @@ String Service::AddComment(CommentType entryType, const String& author,
comment->Set("author", author);
comment->Set("text", text);
comment->Set("expire_time", expireTime);
comment->Set("legacy_id", m_NextCommentID++);
int legacy_id;
{
boost::mutex::scoped_lock lock(m_CommentMutex);
legacy_id = m_NextCommentID++;
}
comment->Set("legacy_id", legacy_id);
Dictionary::Ptr comments = m_Comments;
@ -64,7 +72,8 @@ String Service::AddComment(CommentType entryType, const String& author,
void Service::RemoveAllComments(void)
{
Set("comments", Empty);
m_Comments = Empty;
Touch("comments");
}
void Service::RemoveComment(const String& id)
@ -84,6 +93,8 @@ void Service::RemoveComment(const String& id)
String Service::GetCommentIDFromLegacyID(int id)
{
boost::mutex::scoped_lock lock(m_CommentMutex);
map<int, String>::iterator it = m_LegacyCommentsCache.find(id);
if (it == m_LegacyCommentsCache.end())
@ -94,7 +105,7 @@ String Service::GetCommentIDFromLegacyID(int id)
Service::Ptr Service::GetOwnerByCommentID(const String& id)
{
ValidateCommentsCache();
boost::mutex::scoped_lock lock(m_CommentMutex);
return m_CommentsCache[id].lock();
}
@ -118,61 +129,60 @@ Dictionary::Ptr Service::GetCommentByID(const String& id)
bool Service::IsCommentExpired(const Dictionary::Ptr& comment)
{
ObjectLock olock(comment);
double expire_time = comment->Get("expire_time");
return (expire_time != 0 && expire_time < Utility::GetTime());
}
void Service::InvalidateCommentsCache(void)
void Service::RefreshCommentsCache(void)
{
m_CommentsCacheValid = false;
m_CommentsCache.clear();
m_LegacyCommentsCache.clear();
}
void Service::AddCommentsToCache(void)
{
Dictionary::Ptr comments = m_Comments;
if (!comments)
return;
String id;
Dictionary::Ptr comment;
BOOST_FOREACH(tie(id, comment), comments) {
int legacy_id = comment->Get("legacy_id");
if (legacy_id >= m_NextCommentID)
m_NextCommentID = legacy_id + 1;
if (m_LegacyCommentsCache.find(legacy_id) != m_LegacyCommentsCache.end()) {
/* The legacy_id is already in use by another comment;
* this shouldn't usually happen - assign it a new ID */
legacy_id = m_NextCommentID++;
comment->Set("legacy_id", legacy_id);
Touch("comments");
}
m_LegacyCommentsCache[legacy_id] = id;
m_CommentsCache[id] = GetSelf();
}
}
void Service::ValidateCommentsCache(void)
{
if (m_CommentsCacheValid)
return;
m_CommentsCache.clear();
m_LegacyCommentsCache.clear();
map<int, String> newLegacyCommentsCache;
map<String, Service::WeakPtr> newCommentsCache;
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
service->AddCommentsToCache();
Dictionary::Ptr comments;
{
ObjectLock olock(service);
comments = service->GetComments();
}
if (!comments)
continue;
ObjectLock olock(comments);
String id;
Dictionary::Ptr comment;
BOOST_FOREACH(tie(id, comment), comments) {
ObjectLock clock(comment);
int legacy_id = comment->Get("legacy_id");
if (legacy_id >= m_NextCommentID)
m_NextCommentID = legacy_id + 1;
if (newLegacyCommentsCache.find(legacy_id) != newLegacyCommentsCache.end()) {
/* The legacy_id is already in use by another comment;
* this shouldn't usually happen - assign it a new ID */
legacy_id = m_NextCommentID++;
comment->Set("legacy_id", legacy_id);
service->Touch("comments");
}
newLegacyCommentsCache[legacy_id] = id;
newCommentsCache[id] = service;
}
}
m_CommentsCacheValid = true;
boost::mutex::scoped_lock lock(m_CommentMutex);
m_CommentsCache.swap(newCommentsCache);
m_LegacyCommentsCache.swap(newLegacyCommentsCache);
if (!m_CommentsExpireTimer) {
m_CommentsExpireTimer = boost::make_shared<Timer>();
@ -191,6 +201,8 @@ void Service::RemoveExpiredComments(void)
vector<String> expiredComments;
ObjectLock olock(comments);
String id;
Dictionary::Ptr comment;
BOOST_FOREACH(tie(id, comment), comments) {

View File

@ -22,9 +22,9 @@
using namespace icinga;
int Service::m_NextDowntimeID = 1;
boost::mutex Service::m_DowntimeMutex;
map<int, String> Service::m_LegacyDowntimesCache;
map<String, Service::WeakPtr> Service::m_DowntimesCache;
bool Service::m_DowntimesCacheValid;
Timer::Ptr Service::m_DowntimesExpireTimer;
int Service::GetNextDowntimeID(void)
@ -52,7 +52,15 @@ String Service::AddDowntime(const String& author, const String& comment,
downtime->Set("triggered_by", triggeredBy);
downtime->Set("triggers", boost::make_shared<Dictionary>());
downtime->Set("trigger_time", 0);
downtime->Set("legacy_id", m_NextDowntimeID++);
int legacy_id;
{
boost::mutex::scoped_lock lock(m_DowntimeMutex);
legacy_id = m_NextDowntimeID++;
}
downtime->Set("legacy_id", legacy_id);
if (!triggeredBy.IsEmpty()) {
Service::Ptr otherOwner = GetOwnerByDowntimeID(triggeredBy);
@ -89,7 +97,11 @@ void Service::RemoveDowntime(const String& id)
if (!downtimes)
return;
downtimes->Remove(id);
{
ObjectLock olock(downtimes);
downtimes->Remove(id);
}
owner->Touch("downtimes");
}
@ -100,6 +112,8 @@ void Service::TriggerDowntimes(void)
if (!downtimes)
return;
ObjectLock olock(downtimes);
String id;
BOOST_FOREACH(tie(id, tuples::ignore), downtimes) {
TriggerDowntime(id);
@ -111,8 +125,13 @@ void Service::TriggerDowntime(const String& id)
Service::Ptr owner = GetOwnerByDowntimeID(id);
Dictionary::Ptr downtime = GetDowntimeByID(id);
if (!downtime)
return;
double now = Utility::GetTime();
ObjectLock olock(downtime);
if (now < downtime->Get("start_time") ||
now > downtime->Get("end_time"))
return;
@ -121,6 +140,7 @@ void Service::TriggerDowntime(const String& id)
downtime->Set("trigger_time", now);
Dictionary::Ptr triggers = downtime->Get("triggers");
ObjectLock tlock(triggers);
String tid;
BOOST_FOREACH(tie(tid, tuples::ignore), triggers) {
TriggerDowntime(tid);
@ -131,7 +151,7 @@ void Service::TriggerDowntime(const String& id)
String Service::GetDowntimeIDFromLegacyID(int id)
{
ValidateDowntimesCache();
boost::mutex::scoped_lock lock(m_DowntimeMutex);
map<int, String>::iterator it = m_LegacyDowntimesCache.find(id);
@ -143,8 +163,7 @@ String Service::GetDowntimeIDFromLegacyID(int id)
Service::Ptr Service::GetOwnerByDowntimeID(const String& id)
{
ValidateDowntimesCache();
boost::mutex::scoped_lock lock(m_DowntimeMutex);
return m_DowntimesCache[id].lock();
}
@ -158,6 +177,7 @@ Dictionary::Ptr Service::GetDowntimeByID(const String& id)
Dictionary::Ptr downtimes = owner->m_Downtimes;
if (downtimes) {
ObjectLock olock(downtimes);
Dictionary::Ptr downtime = downtimes->Get(id);
return downtime;
}
@ -169,6 +189,8 @@ bool Service::IsDowntimeActive(const Dictionary::Ptr& downtime)
{
double now = Utility::GetTime();
ObjectLock olock(downtime);
if (now < downtime->Get("start_time") ||
now > downtime->Get("end_time"))
return false;
@ -186,58 +208,56 @@ bool Service::IsDowntimeActive(const Dictionary::Ptr& downtime)
bool Service::IsDowntimeExpired(const Dictionary::Ptr& downtime)
{
ObjectLock olock(downtime);
return (downtime->Get("end_time") < Utility::GetTime());
}
void Service::InvalidateDowntimesCache(void)
void Service::RefreshDowntimesCache(void)
{
m_DowntimesCacheValid = false;
m_DowntimesCache.clear();
m_LegacyDowntimesCache.clear();
}
void Service::AddDowntimesToCache(void)
{
Dictionary::Ptr downtimes = m_Downtimes;
if (!downtimes)
return;
String id;
Dictionary::Ptr downtime;
BOOST_FOREACH(tie(id, downtime), downtimes) {
int legacy_id = downtime->Get("legacy_id");
if (legacy_id >= m_NextDowntimeID)
m_NextDowntimeID = legacy_id + 1;
if (m_LegacyDowntimesCache.find(legacy_id) != m_LegacyDowntimesCache.end()) {
/* The legacy_id is already in use by another downtime;
* this shouldn't usually happen - assign it a new ID. */
legacy_id = m_NextDowntimeID++;
downtime->Set("legacy_id", legacy_id);
Touch("downtimes");
}
m_LegacyDowntimesCache[legacy_id] = id;
m_DowntimesCache[id] = GetSelf();
}
}
void Service::ValidateDowntimesCache(void)
{
if (m_DowntimesCacheValid)
return;
m_DowntimesCache.clear();
m_LegacyDowntimesCache.clear();
map<int, String> newLegacyDowntimesCache;
map<String, Service::WeakPtr> newDowntimesCache;
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
service->AddDowntimesToCache();
Dictionary::Ptr downtimes;
{
ObjectLock olock(service);
downtimes = service->GetDowntimes();
}
if (!downtimes)
continue;
ObjectLock olock(downtimes);
String id;
Dictionary::Ptr downtime;
BOOST_FOREACH(tie(id, downtime), downtimes) {
ObjectLock dlock(downtime);
int legacy_id = downtime->Get("legacy_id");
if (legacy_id >= m_NextDowntimeID)
m_NextDowntimeID = legacy_id + 1;
if (newLegacyDowntimesCache.find(legacy_id) != newLegacyDowntimesCache.end()) {
/* The legacy_id is already in use by another downtime;
* this shouldn't usually happen - assign it a new ID. */
legacy_id = m_NextDowntimeID++;
downtime->Set("legacy_id", legacy_id);
service->Touch("downtimes");
}
newLegacyDowntimesCache[legacy_id] = id;
newDowntimesCache[id] = service;
}
}
m_DowntimesCacheValid = true;
boost::mutex::scoped_lock lock(m_DowntimeMutex);
m_DowntimesCache.swap(newDowntimesCache);
m_LegacyDowntimesCache.swap(newLegacyDowntimesCache);
if (!m_DowntimesExpireTimer) {
m_DowntimesExpireTimer = boost::make_shared<Timer>();
@ -256,6 +276,8 @@ void Service::RemoveExpiredDowntimes(void)
vector<String> expiredDowntimes;
ObjectLock olock(downtimes);
String id;
Dictionary::Ptr downtime;
BOOST_FOREACH(tie(id, downtime), downtimes) {
@ -288,6 +310,8 @@ bool Service::IsInDowntime(void) const
if (!downtimes)
return false;
ObjectLock olock(downtimes);
Dictionary::Ptr downtime;
BOOST_FOREACH(tie(tuples::ignore, downtime), downtimes) {
if (Service::IsDowntimeActive(downtime))

View File

@ -21,10 +21,10 @@
using namespace icinga;
boost::mutex Service::m_NotificationMutex;
map<String, set<Notification::WeakPtr> > Service::m_NotificationsCache;
bool Service::m_NotificationsCacheValid;
void Service::RequestNotifications(NotificationType type) const
void Service::RequestNotifications(NotificationType type)
{
RequestMessage msg;
msg.SetMethod("icinga::SendNotifications");
@ -37,21 +37,32 @@ void Service::RequestNotifications(NotificationType type) const
Logger::Write(LogDebug, "icinga", "Sending notification anycast request for service '" + GetName() + "'");
EndpointManager::GetInstance()->SendAnycastMessage(Endpoint::Ptr(), msg);
SetLastNotification(Utility::GetTime());
}
void Service::SendNotifications(NotificationType type)
void Service::SendNotifications(const Service::Ptr& self, NotificationType type)
{
if (!GetEnableNotifications()) {
Logger::Write(LogInformation, "icinga", "Notifications are disabled for service '" + GetName() + "'.");
String service_name;
bool enable_notifications;
{
ObjectLock olock(self);
service_name = self->GetName();
enable_notifications = self->GetEnableNotifications();
}
if (!enable_notifications) {
Logger::Write(LogInformation, "icinga", "Notifications are disabled for service '" + service_name + "'.");
return;
}
Logger::Write(LogInformation, "icinga", "Sending notifications for service '" + GetName() + "'");
Logger::Write(LogInformation, "icinga", "Sending notifications for service '" + service_name + "'");
set<Notification::Ptr> notifications = GetNotifications();
set<Notification::Ptr> notifications = GetNotifications(self);
if (notifications.size() == 0)
Logger::Write(LogInformation, "icinga", "Service '" + GetName() + "' does not have any notifications.");
Logger::Write(LogInformation, "icinga", "Service '" + service_name + "' does not have any notifications.");
BOOST_FOREACH(const Notification::Ptr& notification, notifications) {
try {
@ -59,51 +70,64 @@ void Service::SendNotifications(NotificationType type)
} catch (const exception& ex) {
stringstream msgbuf;
msgbuf << "Exception occured during notification for service '"
<< GetName() << "': " << diagnostic_information(ex);
<< service_name << "': " << diagnostic_information(ex);
String message = msgbuf.str();
Logger::Write(LogWarning, "icinga", message);
}
}
SetLastNotification(Utility::GetTime());
}
void Service::InvalidateNotificationsCache(void)
void Service::RefreshNotificationsCache(void)
{
m_NotificationsCacheValid = false;
m_NotificationsCache.clear();
}
void Service::ValidateNotificationsCache(void)
{
if (m_NotificationsCacheValid)
return;
m_NotificationsCache.clear();
map<String, set<Notification::WeakPtr> > newNotificationsCache;
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Notification")) {
const Notification::Ptr& notification = static_pointer_cast<Notification>(object);
m_NotificationsCache[notification->GetService()->GetName()].insert(notification);
Service::Ptr service;
{
ObjectLock olock(notification);
service = notification->GetService();
}
String service_name;
{
ObjectLock olock(service);
service_name = service->GetName();
}
newNotificationsCache[service_name].insert(notification);
}
m_NotificationsCacheValid = true;
boost::mutex::scoped_lock lock(m_NotificationMutex);
m_NotificationsCache.swap(newNotificationsCache);
}
set<Notification::Ptr> Service::GetNotifications(void) const
set<Notification::Ptr> Service::GetNotifications(const Service::Ptr& self)
{
String name;
{
ObjectLock olock(self);
name = self->GetName();
}
set<Notification::Ptr> notifications;
ValidateNotificationsCache();
{
boost::mutex::scoped_lock lock(m_NotificationMutex);
BOOST_FOREACH(const Notification::WeakPtr& wservice, m_NotificationsCache[GetName()]) {
Notification::Ptr notification = wservice.lock();
BOOST_FOREACH(const Notification::WeakPtr& wservice, m_NotificationsCache[name]) {
Notification::Ptr notification = wservice.lock();
if (!notification)
continue;
if (!notification)
continue;
notifications.insert(notification);
notifications.insert(notification);
}
}
return notifications;
@ -269,3 +293,11 @@ void Service::SetEnableNotifications(bool enabled)
m_EnableNotifications = enabled;
Touch("enable_notifications");
}
double Service::GetNotificationInterval(void) const
{
if (m_NotificationInterval.IsEmpty())
return 300;
else
return m_NotificationInterval;
}

View File

@ -63,31 +63,25 @@ Service::Service(const Dictionary::Ptr& serializedObject)
RegisterAttribute("enable_notifications", Attribute_Replicated, &m_EnableNotifications);
RegisterAttribute("last_notification", Attribute_Replicated, &m_LastNotification);
RegisterAttribute("notification_interval", Attribute_Config, &m_NotificationInterval);
SetSchedulingOffset(rand());
}
Service::~Service(void)
{
ServiceGroup::RefreshMembersCache();
Host::RefreshServicesCache();
Service::RefreshDowntimesCache();
Service::RefreshCommentsCache();
}
void Service::OnRegistrationCompleted(void)
{
DynamicObject::OnRegistrationCompleted();
ServiceGroup::InvalidateMembersCache();
Host::InvalidateServicesCache();
Service::InvalidateDowntimesCache();
Service::InvalidateCommentsCache();
{
ObjectLock olock(this);
m_Host = Host::GetByName(GetHostName());
}
}
Service::~Service(void)
{
ServiceGroup::InvalidateMembersCache();
Host::InvalidateServicesCache();
Service::InvalidateDowntimesCache();
Service::InvalidateCommentsCache();
ServiceGroup::RefreshMembersCache();
Host::RefreshServicesCache();
}
String Service::GetDisplayName(void) const
@ -126,8 +120,7 @@ Service::Ptr Service::GetByNamePair(const String& hostName, const String& servic
{
if (!hostName.IsEmpty()) {
Host::Ptr host = Host::GetByName(hostName);
ObjectLock olock(host);
return host->GetServiceByShortName(serviceName);
return Host::GetServiceByShortName(host, serviceName);
} else {
return Service::GetByName(serviceName);
}
@ -135,7 +128,7 @@ Service::Ptr Service::GetByNamePair(const String& hostName, const String& servic
Host::Ptr Service::GetHost(void) const
{
return m_Host;
return Host::GetByName(m_HostName);
}
Dictionary::Ptr Service::GetMacros(void) const
@ -173,14 +166,7 @@ String Service::GetShortName(void) const
bool Service::IsReachable(const Service::Ptr& self)
{
set<Service::Ptr> parentServices;
{
ObjectLock olock(self);
parentServices = self->GetParentServices();
}
BOOST_FOREACH(const Service::Ptr& service, parentServices) {
BOOST_FOREACH(const Service::Ptr& service, Service::GetParentServices(self)) {
ObjectLock olock(service);
/* ignore pending services */
@ -199,20 +185,9 @@ bool Service::IsReachable(const Service::Ptr& self)
return false;
}
set<Host::Ptr> parentHosts;
{
ObjectLock olock(self);
parentHosts = self->GetParentHosts();
}
BOOST_FOREACH(const Host::Ptr& host, parentHosts) {
Service::Ptr hc;
{
ObjectLock olock(host);
hc = host->GetHostCheckService();
}
BOOST_FOREACH(const Host::Ptr& host, Service::GetParentHosts(self)) {
Service::Ptr hc = Host::GetHostCheckService(host);
ObjectLock olock(hc);
/* ignore hosts that are up */
if (hc && hc->GetState() == StateOK)
@ -291,18 +266,15 @@ void Service::OnAttributeChanged(const String& name, const Value& oldValue)
else if (name == "next_check")
OnNextCheckChanged(GetSelf(), oldValue);
else if (name == "servicegroups")
ServiceGroup::InvalidateMembersCache();
ServiceGroup::RefreshMembersCache();
else if (name == "host_name" || name == "short_name") {
Host::InvalidateServicesCache();
Host::RefreshServicesCache();
UpdateSlaveNotifications(GetSelf());
if (name == "host_name")
m_Host = Host::GetByName(GetHostName());
} else if (name == "downtimes")
Service::InvalidateDowntimesCache();
Service::RefreshDowntimesCache();
else if (name == "comments")
Service::InvalidateCommentsCache();
Service::RefreshCommentsCache();
else if (name == "notifications")
UpdateSlaveNotifications(GetSelf());
else if (name == "check_interval") {
@ -315,14 +287,21 @@ void Service::OnAttributeChanged(const String& name, const Value& oldValue)
}
}
set<Host::Ptr> Service::GetParentHosts(void) const
set<Host::Ptr> Service::GetParentHosts(const Service::Ptr& self)
{
set<Host::Ptr> parents;
/* The service's host is implicitly a parent. */
parents.insert(GetHost());
Dictionary::Ptr dependencies;
{
ObjectLock olock(self);
/* The service's host is implicitly a parent. */
parents.insert(self->GetHost());
dependencies = self->GetHostDependencies();
}
Dictionary::Ptr dependencies = GetHostDependencies();
if (dependencies) {
String key;
@ -334,19 +313,29 @@ set<Host::Ptr> Service::GetParentHosts(void) const
return parents;
}
set<Service::Ptr> Service::GetParentServices(void) const
set<Service::Ptr> Service::GetParentServices(const Service::Ptr& self)
{
set<Service::Ptr> parents;
Dictionary::Ptr dependencies = GetServiceDependencies();
Dictionary::Ptr dependencies;
Host::Ptr host;
String service_name;
{
ObjectLock olock(self);
dependencies = self->GetServiceDependencies();
host = self->GetHost();
service_name = self->GetName();
}
if (dependencies) {
String key;
Value value;
BOOST_FOREACH(tie(key, value), dependencies) {
Service::Ptr service = GetHost()->GetServiceByShortName(value);
Service::Ptr service = Host::GetServiceByShortName(host, value);
ObjectLock olock(service);
if (service->GetName() == GetName())
if (service->GetName() == service_name)
continue;
parents.insert(service);

View File

@ -109,8 +109,8 @@ public:
static Dictionary::Ptr CalculateDynamicMacros(const Service::Ptr& self);
set<Host::Ptr> GetParentHosts(void) const;
set<Service::Ptr> GetParentServices(void) const;
static set<Host::Ptr> GetParentHosts(const Service::Ptr& self);
static set<Service::Ptr> GetParentServices(const Service::Ptr& self);
bool IsReachable(const Service::Ptr& self);
@ -208,8 +208,7 @@ public:
static bool IsDowntimeActive(const Dictionary::Ptr& downtime);
static bool IsDowntimeExpired(const Dictionary::Ptr& downtime);
static void InvalidateDowntimesCache(void);
static void ValidateDowntimesCache(void);
static void RefreshDowntimesCache(void);
bool IsInDowntime(void) const;
bool IsAcknowledged(void);
@ -231,20 +230,20 @@ public:
static bool IsCommentExpired(const Dictionary::Ptr& comment);
static void InvalidateCommentsCache(void);
static void ValidateCommentsCache(void);
static void RefreshCommentsCache(void);
/* Notifications */
bool GetEnableNotifications(void) const;
void SetEnableNotifications(bool enabled);
void RequestNotifications(NotificationType type) const;
void SendNotifications(NotificationType type);
double GetNotificationInterval(void) const;
static void InvalidateNotificationsCache(void);
static void ValidateNotificationsCache(void);
void RequestNotifications(NotificationType type);
static void SendNotifications(const Service::Ptr& self, NotificationType type);
set<Notification::Ptr> GetNotifications(void) const;
static set<Notification::Ptr> GetNotifications(const Service::Ptr& self);
static void RefreshNotificationsCache(void);
static void UpdateSlaveNotifications(const Service::Ptr& self);
@ -256,7 +255,6 @@ protected:
virtual void OnAttributeChanged(const String& name, const Value& oldValue);
private:
Host::Ptr m_Host;
Dictionary::Ptr m_SlaveNotifications;
Attribute<String> m_DisplayName;
@ -298,14 +296,13 @@ private:
static int m_NextDowntimeID;
static boost::mutex m_DowntimeMutex;
static map<int, String> m_LegacyDowntimesCache;
static map<String, Service::WeakPtr> m_DowntimesCache;
static bool m_DowntimesCacheValid;
static Timer::Ptr m_DowntimesExpireTimer;
static void DowntimesExpireTimerHandler(void);
void AddDowntimesToCache(void);
void RemoveExpiredDowntimes(void);
/* Comments */
@ -313,9 +310,9 @@ private:
static int m_NextCommentID;
static boost::mutex m_CommentMutex;
static map<int, String> m_LegacyCommentsCache;
static map<String, Service::WeakPtr> m_CommentsCache;
static bool m_CommentsCacheValid;
static Timer::Ptr m_CommentsExpireTimer;
static void CommentsExpireTimerHandler(void);
@ -326,9 +323,10 @@ private:
/* Notifications */
Attribute<bool> m_EnableNotifications;
Attribute<double> m_LastNotification;
Attribute<double> m_NotificationInterval;
static boost::mutex m_NotificationMutex;
static map<String, set<Notification::WeakPtr> > m_NotificationsCache;
static bool m_NotificationsCacheValid;
};
}

View File

@ -23,7 +23,6 @@ using namespace icinga;
boost::mutex ServiceGroup::m_Mutex;
map<String, vector<Service::WeakPtr> > ServiceGroup::m_MembersCache;
bool ServiceGroup::m_MembersCacheValid;
REGISTER_TYPE(ServiceGroup, NULL);
@ -35,6 +34,16 @@ ServiceGroup::ServiceGroup(const Dictionary::Ptr& properties)
RegisterAttribute("action_url", Attribute_Config, &m_ActionUrl);
}
ServiceGroup::~ServiceGroup(void)
{
RefreshMembersCache();
}
void ServiceGroup::OnRegistrationCompleted(void)
{
RefreshMembersCache();
}
String ServiceGroup::GetDisplayName(void) const
{
if (!m_DisplayName.Get().IsEmpty())
@ -88,10 +97,8 @@ set<Service::Ptr> ServiceGroup::GetMembers(const ServiceGroup::Ptr& self)
{
boost::mutex::scoped_lock lock(m_Mutex);
ValidateMembersCache();
BOOST_FOREACH(const Service::WeakPtr& svc, m_MembersCache[name]) {
Service::Ptr service = svc.lock();
BOOST_FOREACH(const Service::WeakPtr& wservice, m_MembersCache[name]) {
Service::Ptr service = wservice.lock();
if (!service)
continue;
@ -103,22 +110,9 @@ set<Service::Ptr> ServiceGroup::GetMembers(const ServiceGroup::Ptr& self)
return services;
}
void ServiceGroup::InvalidateMembersCache(void)
void ServiceGroup::RefreshMembersCache(void)
{
boost::mutex::scoped_lock lock(m_Mutex);
m_MembersCacheValid = false;
m_MembersCache.clear();
}
/**
* @threadsafety Caller must hold m_Mutex.
*/
void ServiceGroup::ValidateMembersCache(void)
{
if (m_MembersCacheValid)
return;
m_MembersCache.clear();
map<String, vector<weak_ptr<Service> > > newMembersCache;
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
const Service::Ptr& service = static_pointer_cast<Service>(object);
@ -132,12 +126,14 @@ void ServiceGroup::ValidateMembersCache(void)
Value servicegroup;
BOOST_FOREACH(tie(tuples::ignore, servicegroup), dict) {
if (!ServiceGroup::Exists(servicegroup))
Logger::Write(LogWarning, "icinga", "Service group '" + static_cast<String>(servicegroup) + "' used but not defined.");
continue;
m_MembersCache[servicegroup].push_back(service);
newMembersCache[servicegroup].push_back(service);
}
}
}
m_MembersCacheValid = true;
boost::mutex::scoped_lock lock(m_Mutex);
m_MembersCache.swap(newMembersCache);
}

View File

@ -35,6 +35,7 @@ public:
typedef weak_ptr<ServiceGroup> WeakPtr;
ServiceGroup(const Dictionary::Ptr& properties);
~ServiceGroup(void);
static bool Exists(const String& name);
static ServiceGroup::Ptr GetByName(const String& name);
@ -44,7 +45,11 @@ public:
String GetActionUrl(void) const;
static set<Service::Ptr> GetMembers(const ServiceGroup::Ptr& self);
static void InvalidateMembersCache(void);
static void RefreshMembersCache(void);
protected:
virtual void OnRegistrationCompleted(void);
private:
Attribute<String> m_DisplayName;
@ -53,9 +58,6 @@ private:
static boost::mutex m_Mutex;
static map<String, vector<weak_ptr<Service> > > m_MembersCache;
static bool m_MembersCacheValid;
static void ValidateMembersCache(void);
};
}