Fine-grained locks (WIP, Part 7).

This commit is contained in:
Gunnar Beutner 2013-02-20 19:52:25 +01:00
parent 997ca3a77a
commit 5e91f6c54d
28 changed files with 241 additions and 146 deletions

View File

@ -60,6 +60,7 @@ void CheckerComponent::Stop(void)
void CheckerComponent::CheckThreadProc(void) void CheckerComponent::CheckThreadProc(void)
{ {
for (;;) { for (;;) {
vector<Service::Ptr> services;
Service::Ptr service; Service::Ptr service;
{ {
@ -142,6 +143,11 @@ void CheckerComponent::CheckThreadProc(void)
m_PendingServices.insert(service); m_PendingServices.insert(service);
} }
double rwait = service->GetNextCheck() - Utility::GetTime();
if (abs(rwait - wait) > 5)
Logger::Write(LogWarning, "checker", "Check delayed: " + Convert::ToString(-rwait) + ",planned wait: " + Convert::ToString(-wait));
try { try {
service->BeginExecuteCheck(boost::bind(&CheckerComponent::CheckCompletedHandler, this, service)); service->BeginExecuteCheck(boost::bind(&CheckerComponent::CheckCompletedHandler, this, service));
} catch (const exception& ex) { } catch (const exception& ex) {

View File

@ -91,7 +91,7 @@ String CompatComponent::GetCommandPath(void) const
void CompatComponent::Start(void) void CompatComponent::Start(void)
{ {
m_StatusTimer = boost::make_shared<Timer>(); m_StatusTimer = boost::make_shared<Timer>();
m_StatusTimer->SetInterval(5); m_StatusTimer->SetInterval(30);
m_StatusTimer->OnTimerExpired.connect(boost::bind(&CompatComponent::StatusTimerHandler, this)); m_StatusTimer->OnTimerExpired.connect(boost::bind(&CompatComponent::StatusTimerHandler, this));
m_StatusTimer->Start(); m_StatusTimer->Start();
m_StatusTimer->Reschedule(0); m_StatusTimer->Reschedule(0);
@ -544,22 +544,19 @@ void CompatComponent::StatusTimerHandler(void)
} }
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("HostGroup")) { BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("HostGroup")) {
set<Host::Ptr> members; HostGroup::Ptr hg = static_pointer_cast<HostGroup>(object);
{ {
HostGroup::Ptr hg = static_pointer_cast<HostGroup>(object);
ObjectLock olock(hg); ObjectLock olock(hg);
objectfp << "define hostgroup {" << "\n" objectfp << "define hostgroup {" << "\n"
<< "\t" << "hostgroup_name" << "\t" << hg->GetName() << "\n" << "\t" << "hostgroup_name" << "\t" << hg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << hg->GetNotesUrl() << "\n" << "\t" << "notes_url" << "\t" << hg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << hg->GetActionUrl() << "\n"; << "\t" << "action_url" << "\t" << hg->GetActionUrl() << "\n";
members = hg->GetMembers();
} }
objectfp << "\t" << "members" << "\t"; objectfp << "\t" << "members" << "\t";
DumpNameList(objectfp, members); DumpNameList(objectfp, HostGroup::GetMembers(hg));
objectfp << "\n" objectfp << "\n"
<< "}" << "\n"; << "}" << "\n";
} }
@ -572,24 +569,21 @@ void CompatComponent::StatusTimerHandler(void)
} }
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("ServiceGroup")) { BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("ServiceGroup")) {
set<Service::Ptr> members; ServiceGroup::Ptr sg = static_pointer_cast<ServiceGroup>(object);
{ {
ServiceGroup::Ptr sg = static_pointer_cast<ServiceGroup>(object);
ObjectLock olock(sg); ObjectLock olock(sg);
objectfp << "define servicegroup {" << "\n" objectfp << "define servicegroup {" << "\n"
<< "\t" << "servicegroup_name" << "\t" << sg->GetName() << "\n" << "\t" << "servicegroup_name" << "\t" << sg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << sg->GetNotesUrl() << "\n" << "\t" << "notes_url" << "\t" << sg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << sg->GetActionUrl() << "\n"; << "\t" << "action_url" << "\t" << sg->GetActionUrl() << "\n";
members = sg->GetMembers();
} }
objectfp << "\t" << "members" << "\t"; objectfp << "\t" << "members" << "\t";
vector<String> sglist; vector<String> sglist;
BOOST_FOREACH(const Service::Ptr& service, members) { BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
Host::Ptr host; Host::Ptr host;
String host_name, short_name; String host_name, short_name;

View File

@ -759,7 +759,7 @@ void CompatIdoComponent::DumpConfigObjects(void)
vector<String> hglist; vector<String> hglist;
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) { BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
hglist.push_back(host->GetName()); hglist.push_back(host->GetName());
} }
@ -793,7 +793,7 @@ void CompatIdoComponent::DumpConfigObjects(void)
vector<String> sglist; vector<String> sglist;
vector<Service::Ptr>::iterator vt; vector<Service::Ptr>::iterator vt;
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) { BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
sglist.push_back(service->GetHost()->GetName()); sglist.push_back(service->GetHost()->GetName());
sglist.push_back(service->GetShortName()); sglist.push_back(service->GetShortName());
} }

View File

@ -33,7 +33,7 @@ signals2::signal<void (double, const set<DynamicObject::WeakPtr>&)> DynamicObjec
signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnFlushObject; signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnFlushObject;
DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject) DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject)
: m_Events(false), m_ConfigTx(0) : m_EventSafe(false), m_ConfigTx(0)
{ {
RegisterAttribute("__name", Attribute_Config); RegisterAttribute("__name", Attribute_Config);
RegisterAttribute("__type", Attribute_Config); RegisterAttribute("__type", Attribute_Config);
@ -88,7 +88,7 @@ void DynamicObject::SendLocalUpdateEvents(void)
} }
/* Check if it's safe to send events. */ /* Check if it's safe to send events. */
if (GetEvents()) { if (GetEventSafe()) {
map<String, Value, string_iless>::iterator it; map<String, Value, string_iless>::iterator it;
for (it = attrs.begin(); it != attrs.end(); it++) for (it = attrs.begin(); it != attrs.end(); it++)
OnAttributeChanged(it->first, it->second); OnAttributeChanged(it->first, it->second);
@ -237,19 +237,14 @@ void DynamicObject::InternalSetAttribute(const String& name, const Value& data,
if (tt.first->second.Type & Attribute_Config) if (tt.first->second.Type & Attribute_Config)
m_ConfigTx = tx; m_ConfigTx = tx;
DynamicObject::Ptr self; if (GetEventSafe()) {
try { /* We can't call GetSelf() in the constructor or destructor.
self = GetSelf(); * The OnConstructionCompleted() function will take care of adding this
} catch (const boost::bad_weak_ptr& ex) { * object to the list of modified objects later on if we can't
/* We're being called from the constructor. Ignore * do it here. */
* the exception. The OnInitCompleted() function
* will take care of adding this object to the list
* of modified objects. */
}
if (self) {
boost::mutex::scoped_lock lock(m_TransactionMutex); boost::mutex::scoped_lock lock(m_TransactionMutex);
m_ModifiedObjects.insert(self); m_ModifiedObjects.insert(GetSelf());
} }
/* Use insert() rather than [] so we don't overwrite /* Use insert() rather than [] so we don't overwrite
@ -570,8 +565,11 @@ void DynamicObject::NewTx(void)
OnTransactionClosing(tx, objects); OnTransactionClosing(tx, objects);
} }
void DynamicObject::OnInitCompleted(void) 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. /* Add this new object to the list of modified objects.
* We're doing this here because we can't construct * We're doing this here because we can't construct
* a while WeakPtr from within the object's constructor. */ * a while WeakPtr from within the object's constructor. */
@ -579,6 +577,9 @@ void DynamicObject::OnInitCompleted(void)
m_ModifiedObjects.insert(GetSelf()); m_ModifiedObjects.insert(GetSelf());
} }
void DynamicObject::OnRegistrationCompleted(void)
{ }
void DynamicObject::OnAttributeChanged(const String&, const Value&) void DynamicObject::OnAttributeChanged(const String&, const Value&)
{ } { }
@ -600,12 +601,12 @@ const DynamicObject::AttributeMap& DynamicObject::GetAttributes(void) const
return m_Attributes; return m_Attributes;
} }
void DynamicObject::SetEvents(bool events) void DynamicObject::SetEventSafe(bool safe)
{ {
m_Events = events; m_EventSafe = safe;
} }
bool DynamicObject::GetEvents(void) const bool DynamicObject::GetEventSafe(void) const
{ {
return m_Events; return m_EventSafe;
} }

View File

@ -125,8 +125,8 @@ public:
const AttributeMap& GetAttributes(void) const; const AttributeMap& GetAttributes(void) const;
void SetEvents(bool events); void SetEventSafe(bool initialized);
bool GetEvents(void) const; bool GetEventSafe(void) const;
static DynamicObject::Ptr GetObject(const String& type, const String& name); static DynamicObject::Ptr GetObject(const String& type, const String& name);
@ -137,7 +137,8 @@ public:
static double GetCurrentTx(void); static double GetCurrentTx(void);
protected: protected:
virtual void OnInitCompleted(void); virtual void OnConstructionCompleted(void);
virtual void OnRegistrationCompleted(void);
virtual void OnAttributeChanged(const String& name, const Value& oldValue); virtual void OnAttributeChanged(const String& name, const Value& oldValue);
private: private:
@ -149,7 +150,7 @@ private:
map<String, Value, string_iless> m_ModifiedAttributes; map<String, Value, string_iless> m_ModifiedAttributes;
double m_ConfigTx; double m_ConfigTx;
bool m_Events; bool m_EventSafe;
static double m_CurrentTx; static double m_CurrentTx;

View File

@ -80,29 +80,33 @@ String DynamicType::GetName(void) const
void DynamicType::RegisterObject(const DynamicObject::Ptr& object) void DynamicType::RegisterObject(const DynamicObject::Ptr& object)
{ {
ObjectLock olock(object); String name;
object->SetEvents(true);
ObjectMap::iterator it = m_ObjectMap.find(object->GetName()); {
ObjectLock olock(object);
name = object->GetName();
}
ObjectMap::iterator it = m_ObjectMap.find(name);
if (it != m_ObjectMap.end()) { if (it != m_ObjectMap.end()) {
if (it->second == object) if (it->second == object)
return; return;
BOOST_THROW_EXCEPTION(runtime_error("RegisterObject() found existing object with the same name: " + object->GetName())); BOOST_THROW_EXCEPTION(runtime_error("RegisterObject() found existing object with the same name: " + name));
} }
m_ObjectMap[object->GetName()] = object; m_ObjectMap[name] = object;
m_ObjectSet.insert(object); m_ObjectSet.insert(object);
/* notify the object that it's been fully initialized */ /* notify the object that it's been registered */
object->OnInitCompleted(); object->OnRegistrationCompleted();
} }
void DynamicType::UnregisterObject(const DynamicObject::Ptr& object) void DynamicType::UnregisterObject(const DynamicObject::Ptr& object)
{ {
ObjectLock olock(object); ObjectLock olock(object);
object->SetEvents(false); object->SetEventSafe(false);
m_ObjectMap.erase(object->GetName()); m_ObjectMap.erase(object->GetName());
m_ObjectSet.erase(object); m_ObjectSet.erase(object);
@ -138,16 +142,21 @@ void DynamicType::RegisterType(const DynamicType::Ptr& type)
DynamicObject::Ptr DynamicType::CreateObject(const Dictionary::Ptr& serializedUpdate) const DynamicObject::Ptr DynamicType::CreateObject(const Dictionary::Ptr& serializedUpdate) const
{ {
DynamicObject::Ptr object = m_ObjectFactory(serializedUpdate); DynamicObject::Ptr object = m_ObjectFactory(serializedUpdate);
ObjectLock olock(object);
/* register attributes */ {
String name; ObjectLock olock(object);
DynamicAttributeType type;
BOOST_FOREACH(tuples::tie(name, type), m_Attributes)
object->RegisterAttribute(name, type);
/* apply the object's non-config attributes */ /* register attributes */
object->ApplyUpdate(serializedUpdate, Attribute_All & ~Attribute_Config); String name;
DynamicAttributeType type;
BOOST_FOREACH(tuples::tie(name, type), m_Attributes)
object->RegisterAttribute(name, type);
/* apply the object's non-config attributes */
object->ApplyUpdate(serializedUpdate, Attribute_All & ~Attribute_Config);
}
object->OnConstructionCompleted();
return object; return object;
} }

View File

@ -25,15 +25,13 @@ using namespace icinga;
* @threadsafety Always. * @threadsafety Always.
*/ */
EventQueue::EventQueue(void) EventQueue::EventQueue(void)
: m_Stopped(false) : m_Stopped(false), m_LastReport(0)
{ {
int thread_count = thread::hardware_concurrency(); int thread_count = thread::hardware_concurrency();
if (thread_count < 4) if (thread_count < 4)
thread_count = 4; thread_count = 4;
thread_count *= 4;
for (int i = 0; i < thread_count; i++) for (int i = 0; i < thread_count; i++)
m_Threads.create_thread(boost::bind(&EventQueue::QueueThreadProc, this)); m_Threads.create_thread(boost::bind(&EventQueue::QueueThreadProc, this));
} }
@ -116,4 +114,11 @@ void EventQueue::Post(const EventQueue::Callback& callback)
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
m_Events.push_back(callback); m_Events.push_back(callback);
m_CV.notify_one(); m_CV.notify_one();
int pending = m_Events.size();
double now = Utility::GetTime();
if (pending > 1000 && now - m_LastReport > 5) {
Logger::Write(LogWarning, "base", "More than 1000 pending events: " + Convert::ToString(pending));
m_LastReport = now;
}
} }

View File

@ -47,6 +47,7 @@ private:
boost::mutex m_Mutex; boost::mutex m_Mutex;
condition_variable m_CV; condition_variable m_CV;
double m_LastReport;
bool m_Stopped; bool m_Stopped;
vector<Callback> m_Events; vector<Callback> m_Events;

View File

@ -24,6 +24,7 @@ using namespace icinga;
boost::once_flag Process::m_ThreadOnce; boost::once_flag Process::m_ThreadOnce;
boost::mutex Process::m_Mutex; boost::mutex Process::m_Mutex;
deque<Process::Ptr> Process::m_Tasks; deque<Process::Ptr> Process::m_Tasks;
double Process::m_LastReport = 0;
Process::Process(const vector<String>& arguments, const Dictionary::Ptr& extraEnvironment) Process::Process(const vector<String>& arguments, const Dictionary::Ptr& extraEnvironment)
: AsyncTask<Process, ProcessResult>(), m_Arguments(arguments), m_ExtraEnvironment(extraEnvironment) : AsyncTask<Process, ProcessResult>(), m_Arguments(arguments), m_ExtraEnvironment(extraEnvironment)
@ -65,9 +66,18 @@ vector<String> Process::SplitCommand(const Value& command)
void Process::Run(void) void Process::Run(void)
{ {
int count;
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
m_Tasks.push_back(GetSelf()); m_Tasks.push_back(GetSelf());
count = m_Tasks.size();
}
if (count > 50 && Utility::GetTime() - m_LastReport > 5) {
Logger::Write(LogInformation, "base", "More than 50 pending Process tasks: " +
Convert::ToString(count));
m_LastReport = Utility::GetTime();
} }
NotifyWorker(); NotifyWorker();

View File

@ -48,7 +48,7 @@ public:
typedef shared_ptr<Process> Ptr; typedef shared_ptr<Process> Ptr;
typedef weak_ptr<Process> WeakPtr; typedef weak_ptr<Process> WeakPtr;
static const deque<Process::Ptr>::size_type MaxTasksPerThread = 512; static const deque<Process::Ptr>::size_type MaxTasksPerThread = 128;
Process(const vector<String>& arguments, const Dictionary::Ptr& extraEnvironment = Dictionary::Ptr()); Process(const vector<String>& arguments, const Dictionary::Ptr& extraEnvironment = Dictionary::Ptr());
@ -69,6 +69,7 @@ private:
virtual void Run(void); virtual void Run(void);
static boost::mutex m_Mutex; static boost::mutex m_Mutex;
static double m_LastReport;
static deque<Process::Ptr> m_Tasks; static deque<Process::Ptr> m_Tasks;
#ifndef _WIN32 #ifndef _WIN32
static int m_TaskFd; static int m_TaskFd;

View File

@ -32,9 +32,9 @@ Script::Script(const Dictionary::Ptr& properties)
: DynamicObject(properties) : DynamicObject(properties)
{ } { }
void Script::OnInitCompleted(void) void Script::OnRegistrationCompleted(void)
{ {
DynamicObject::OnInitCompleted(); DynamicObject::OnRegistrationCompleted();
SpawnInterpreter(); SpawnInterpreter();
} }

View File

@ -42,7 +42,7 @@ public:
String GetCode(void) const; String GetCode(void) const;
protected: protected:
virtual void OnInitCompleted(void); virtual void OnRegistrationCompleted(void);
virtual void OnAttributeUpdate(const String& name, const Value& oldValue); virtual void OnAttributeUpdate(const String& name, const Value& oldValue);
private: private:

View File

@ -79,7 +79,10 @@ void StreamLogger::ProcessLogEntry(ostream& stream, bool tty, const LogEntry& en
char timestamp[100]; char timestamp[100];
time_t ts = entry.Timestamp; time_t ts = entry.Timestamp;
tm tmnow = *localtime(&ts); tm tmnow;
if (localtime_r(&ts, &tmnow) == NULL)
BOOST_THROW_EXCEPTION(PosixException("localtime_r() failed.", errno));
strftime(timestamp, sizeof(timestamp), "%Y/%m/%d %H:%M:%S %z", &tmnow); strftime(timestamp, sizeof(timestamp), "%Y/%m/%d %H:%M:%S %z", &tmnow);
@ -98,7 +101,7 @@ void StreamLogger::ProcessLogEntry(ostream& stream, bool tty, const LogEntry& en
} }
} }
stream << "[" << timestamp << "] " stream << "[" << timestamp << "] <" << boost::this_thread::get_id() << "> "
<< Logger::SeverityToString(entry.Severity) << "/" << entry.Facility << ": " << Logger::SeverityToString(entry.Severity) << "/" << entry.Facility << ": "
<< entry.Message; << entry.Message;

View File

@ -137,7 +137,6 @@ void ConfigCompilerContext::ActivateItems(void)
Logger::Write(LogInformation, "config", "Activating config items in compilation unit '" + m_Unit + "'"); Logger::Write(LogInformation, "config", "Activating config items in compilation unit '" + m_Unit + "'");
BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) { BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) {
ObjectLock olock(item); ConfigItem::Commit(item);
item->Commit();
} }
} }

View File

@ -103,6 +103,11 @@ vector<String> ConfigItem::GetParents(void) const
return m_Parents; return m_Parents;
} }
set<ConfigItem::WeakPtr> ConfigItem::GetChildren(void) const
{
return m_ChildObjects;
}
Dictionary::Ptr ConfigItem::Link(void) const Dictionary::Ptr ConfigItem::Link(void) const
{ {
Dictionary::Ptr attrs = boost::make_shared<Dictionary>(); Dictionary::Ptr attrs = boost::make_shared<Dictionary>();
@ -151,42 +156,70 @@ void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
* *
* @returns The DynamicObject that was created/updated. * @returns The DynamicObject that was created/updated.
*/ */
DynamicObject::Ptr ConfigItem::Commit(void) DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
{ {
Logger::Write(LogDebug, "base", "Commit called for ConfigItem Type=" + GetType() + ", Name=" + GetName()); String type, name;
DynamicObject::Ptr dobj;
vector<String> parents;
Dictionary::Ptr properties;
{
ObjectLock olock(self);
type = self->GetType();
name = self->GetName();
dobj = self->GetDynamicObject();
parents = self->GetParents();
properties = self->Link();
}
Logger::Write(LogDebug, "base", "Commit called for ConfigItem Type=" + type + ", Name=" + name);
/* Make sure the type is valid. */ /* Make sure the type is valid. */
DynamicType::Ptr dtype = DynamicType::GetByName(GetType()); DynamicType::Ptr dtype = DynamicType::GetByName(type);
if (!dtype) if (!dtype)
BOOST_THROW_EXCEPTION(runtime_error("Type '" + GetType() + "' does not exist.")); BOOST_THROW_EXCEPTION(runtime_error("Type '" + type + "' does not exist."));
/* Try to find an existing item with the same type and name. */ {
pair<String, String> ikey = make_pair(GetType(), GetName()); boost::mutex::scoped_lock lock(m_Mutex);
ItemMap::iterator it = m_Items.find(ikey);
if (it != m_Items.end()) { /* Try to find an existing item with the same type and name. */
/* Unregister the old item from its parents. */ pair<String, String> ikey = make_pair(type, name);
ConfigItem::Ptr oldItem = it->second; ItemMap::iterator it = m_Items.find(ikey);
ObjectLock olock(oldItem);
oldItem->UnregisterFromParents();
/* Steal the old item's children. */ set<ConfigItem::WeakPtr> children;
m_ChildObjects = oldItem->m_ChildObjects;
if (it != m_Items.end()) {
/* Unregister the old item from its parents. */
ConfigItem::Ptr oldItem = it->second;
ObjectLock olock(oldItem);
oldItem->UnregisterFromParents();
/* Steal the old item's children. */
children = oldItem->GetChildren();
}
{
ObjectLock olock(self);
self->m_ChildObjects = children;
}
/* Register this item. */
m_Items[ikey] = self;
}
if (!dobj) {
ObjectLock olock(dtype);
dobj = dtype->GetObject(name);
} }
/* Register this item with its parents. */ /* Register this item with its parents. */
BOOST_FOREACH(const String& parentName, m_Parents) { BOOST_FOREACH(const String& parentName, parents) {
ConfigItem::Ptr parent = GetObject(GetType(), parentName); ConfigItem::Ptr parent = GetObject(type, parentName);
ObjectLock olock(parent); ObjectLock olock(parent);
parent->RegisterChild(GetSelf()); parent->RegisterChild(self);
} }
/* Register this item. */
m_Items[ikey] = GetSelf();
Dictionary::Ptr properties = Link();
/* Create a fake update in the format that /* Create a fake update in the format that
* DynamicObject::ApplyUpdate expects. */ * DynamicObject::ApplyUpdate expects. */
Dictionary::Ptr attrs = boost::make_shared<Dictionary>(); Dictionary::Ptr attrs = boost::make_shared<Dictionary>();
@ -206,13 +239,6 @@ DynamicObject::Ptr ConfigItem::Commit(void)
update->Set("configTx", DynamicObject::GetCurrentTx()); update->Set("configTx", DynamicObject::GetCurrentTx());
/* Update or create the object and apply the configuration settings. */ /* Update or create the object and apply the configuration settings. */
DynamicObject::Ptr dobj = m_DynamicObject.lock();
if (!dobj) {
ObjectLock dlock(dtype);
dobj = dtype->GetObject(GetName());
}
bool was_null = false; bool was_null = false;
if (!dobj) { if (!dobj) {
@ -227,7 +253,7 @@ DynamicObject::Ptr ConfigItem::Commit(void)
if (!was_null) if (!was_null)
dobj->ApplyUpdate(update, Attribute_Config); dobj->ApplyUpdate(update, Attribute_Config);
m_DynamicObject = dobj; self->m_DynamicObject = dobj;
if (dobj->IsAbstract()) if (dobj->IsAbstract())
dobj->Unregister(); dobj->Unregister();
@ -237,7 +263,12 @@ DynamicObject::Ptr ConfigItem::Commit(void)
/* We need to make a copy of the child objects because the /* We need to make a copy of the child objects because the
* OnParentCommitted() handler is going to update the list. */ * OnParentCommitted() handler is going to update the list. */
set<ConfigItem::WeakPtr> children = m_ChildObjects; set<ConfigItem::WeakPtr> children;
{
ObjectLock olock(self);
children = self->m_ChildObjects;
}
/* notify our children of the update */ /* notify our children of the update */
BOOST_FOREACH(const ConfigItem::WeakPtr wchild, children) { BOOST_FOREACH(const ConfigItem::WeakPtr wchild, children) {
@ -246,11 +277,10 @@ DynamicObject::Ptr ConfigItem::Commit(void)
if (!child) if (!child)
continue; continue;
ObjectLock olock(child);
child->OnParentCommitted(); child->OnParentCommitted();
} }
OnCommitted(GetSelf()); OnCommitted(self);
return dobj; return dobj;
} }
@ -305,8 +335,17 @@ void ConfigItem::UnregisterFromParents(void)
*/ */
void ConfigItem::OnParentCommitted(void) void ConfigItem::OnParentCommitted(void)
{ {
if (GetObject(GetType(), GetName()) == static_cast<ConfigItem::Ptr>(GetSelf())) ConfigItem::Ptr self;
Commit();
{
ObjectLock olock(this);
self = GetSelf();
if (GetObject(self->GetType(), self->GetName()) != self)
return;
}
Commit(self);
} }
/** /**

View File

@ -43,10 +43,11 @@ public:
String GetUnit(void) const; String GetUnit(void) const;
vector<String> GetParents(void) const; vector<String> GetParents(void) const;
set<ConfigItem::WeakPtr> GetChildren(void) const;
ExpressionList::Ptr GetExpressionList(void) const; ExpressionList::Ptr GetExpressionList(void) const;
DynamicObject::Ptr Commit(void); static DynamicObject::Ptr Commit(const ConfigItem::Ptr& self);
void Unregister(void); void Unregister(void);
void Dump(ostream& fp) const; void Dump(ostream& fp) const;

View File

@ -403,7 +403,7 @@ void ExternalCommandProcessor::EnableHostgroupSvcChecks(double, const vector<Str
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) { BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) { BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Enabling active checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Enabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(true); service->SetEnableActiveChecks(true);
@ -418,7 +418,7 @@ void ExternalCommandProcessor::DisableHostgroupSvcChecks(double, const vector<St
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) { BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) { BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Disabling active checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Disabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(false); service->SetEnableActiveChecks(false);
@ -433,7 +433,7 @@ void ExternalCommandProcessor::EnableServicegroupSvcChecks(double, const vector<
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) { BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
Logger::Write(LogInformation, "icinga", "Enabling active checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Enabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(true); service->SetEnableActiveChecks(true);
} }
@ -446,7 +446,7 @@ void ExternalCommandProcessor::DisableServicegroupSvcChecks(double, const vector
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) { BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
Logger::Write(LogInformation, "icinga", "Disabling active checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Disabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(false); service->SetEnableActiveChecks(false);
} }
@ -481,7 +481,7 @@ void ExternalCommandProcessor::EnableServicegroupPassiveSvcChecks(double, const
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) { BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
Logger::Write(LogInformation, "icinga", "Enabling passive checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Enabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(true); service->SetEnablePassiveChecks(true);
} }
@ -494,7 +494,7 @@ void ExternalCommandProcessor::DisableServicegroupPassiveSvcChecks(double, const
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) { BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
Logger::Write(LogInformation, "icinga", "Disabling passive checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Disabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(true); service->SetEnablePassiveChecks(true);
} }
@ -507,7 +507,7 @@ void ExternalCommandProcessor::EnableHostgroupPassiveSvcChecks(double, const vec
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) { BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) { BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Enabling passive checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Enabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(true); service->SetEnablePassiveChecks(true);
@ -522,7 +522,7 @@ void ExternalCommandProcessor::DisableHostgroupPassiveSvcChecks(double, const ve
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) { BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) { BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Disabling passive checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Disabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(false); service->SetEnablePassiveChecks(false);
@ -657,7 +657,7 @@ void ExternalCommandProcessor::ScheduleHostgroupHostDowntime(double, const vecto
if (triggeredByLegacy != 0) if (triggeredByLegacy != 0)
triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy); triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy);
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) { BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
Logger::Write(LogInformation, "icinga", "Creating downtime for host " + host->GetName()); Logger::Write(LogInformation, "icinga", "Creating downtime for host " + host->GetName());
Service::Ptr service = host->GetHostCheckService(); Service::Ptr service = host->GetHostCheckService();
if (service) { if (service) {
@ -686,7 +686,7 @@ void ExternalCommandProcessor::ScheduleHostgroupSvcDowntime(double, const vector
set<Service::Ptr> services; set<Service::Ptr> services;
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) { BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) { BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
services.insert(service); services.insert(service);
} }
@ -718,7 +718,7 @@ void ExternalCommandProcessor::ScheduleServicegroupHostDowntime(double, const ve
set<Service::Ptr> services; set<Service::Ptr> services;
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) { BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
Host::Ptr host = service->GetHost(); Host::Ptr host = service->GetHost();
Service::Ptr hcService = host->GetHostCheckService(); Service::Ptr hcService = host->GetHostCheckService();
if (hcService) if (hcService)
@ -745,7 +745,7 @@ void ExternalCommandProcessor::ScheduleServicegroupSvcDowntime(double, const vec
if (triggeredByLegacy != 0) if (triggeredByLegacy != 0)
triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy); triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy);
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) { BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
Logger::Write(LogInformation, "icinga", "Creating downtime for service " + service->GetName()); Logger::Write(LogInformation, "icinga", "Creating downtime for service " + service->GetName());
(void) service->AddDowntime(arguments[6], arguments[7], (void) service->AddDowntime(arguments[6], arguments[7],
Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]),

View File

@ -34,13 +34,18 @@ REGISTER_TYPE(Host, hostAttributes);
Host::Host(const Dictionary::Ptr& properties) Host::Host(const Dictionary::Ptr& properties)
: DynamicObject(properties) : DynamicObject(properties)
{ { }
HostGroup::InvalidateMembersCache();
}
void Host::OnInitCompleted(void) void Host::OnRegistrationCompleted(void)
{ {
UpdateSlaveServices(); DynamicObject::OnRegistrationCompleted();
HostGroup::InvalidateMembersCache();
{
ObjectLock olock(this);
UpdateSlaveServices();
}
} }
Host::~Host(void) Host::~Host(void)
@ -264,7 +269,7 @@ void Host::UpdateSlaveServices(void)
} }
ConfigItem::Ptr serviceItem = builder->Compile(); ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Commit(); ConfigItem::Commit(serviceItem);
newServices->Set(name, serviceItem); newServices->Set(name, serviceItem);
} }

View File

@ -67,7 +67,7 @@ public:
const std::vector<icinga::Value>& arguments); const std::vector<icinga::Value>& arguments);
protected: protected:
void OnInitCompleted(void); void OnRegistrationCompleted(void);
void OnAttributeChanged(const String& name, const Value& oldValue); void OnAttributeChanged(const String& name, const Value& oldValue);
private: private:

View File

@ -72,15 +72,23 @@ HostGroup::Ptr HostGroup::GetByName(const String& name)
return dynamic_pointer_cast<HostGroup>(configObject); return dynamic_pointer_cast<HostGroup>(configObject);
} }
set<Host::Ptr> HostGroup::GetMembers(void) const set<Host::Ptr> HostGroup::GetMembers(const HostGroup::Ptr& self)
{ {
set<Host::Ptr> hosts; String name;
ValidateMembersCache(); {
ObjectLock olock(self);
name = self->GetName();
}
set<Host::Ptr> hosts;
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const Host::WeakPtr& hst, m_MembersCache[GetName()]) {
ValidateMembersCache();
BOOST_FOREACH(const Host::WeakPtr& hst, m_MembersCache[name]) {
Host::Ptr host = hst.lock(); Host::Ptr host = hst.lock();
if (!host) if (!host)
@ -100,10 +108,11 @@ void HostGroup::InvalidateMembersCache(void)
m_MembersCache.clear(); m_MembersCache.clear();
} }
/**
* @threadsafety Caller must hold m_Mutex.
*/
void HostGroup::ValidateMembersCache(void) void HostGroup::ValidateMembersCache(void)
{ {
boost::mutex::scoped_lock lock(m_Mutex);
if (m_MembersCacheValid) if (m_MembersCacheValid)
return; return;

View File

@ -43,7 +43,7 @@ public:
String GetNotesUrl(void) const; String GetNotesUrl(void) const;
String GetActionUrl(void) const; String GetActionUrl(void) const;
set<Host::Ptr> GetMembers(void) const; static set<Host::Ptr> GetMembers(const HostGroup::Ptr& self);
static void InvalidateMembersCache(void); static void InvalidateMembersCache(void);
private: private:

View File

@ -77,12 +77,11 @@ void PluginCheckTask::ProcessFinishedHandler(PluginCheckTask ct)
ProcessResult pr; ProcessResult pr;
try { try {
ObjectLock olock(ct.m_Process);
pr = ct.m_Process->GetResult(); pr = ct.m_Process->GetResult();
} catch (...) { } catch (...) {
{ ObjectLock olock(ct.m_Task);
ObjectLock olock(ct.m_Task); ct.m_Task->FinishException(boost::current_exception());
ct.m_Task->FinishException(boost::current_exception());
}
return; return;
} }
@ -94,10 +93,8 @@ void PluginCheckTask::ProcessFinishedHandler(PluginCheckTask ct)
result->Set("execution_start", pr.ExecutionStart); result->Set("execution_start", pr.ExecutionStart);
result->Set("execution_end", pr.ExecutionEnd); result->Set("execution_end", pr.ExecutionEnd);
{ ObjectLock olock(ct.m_Task);
ObjectLock olock(ct.m_Task); ct.m_Task->FinishResult(result);
ct.m_Task->FinishResult(result);
}
} }
ServiceState PluginCheckTask::ExitStatusToState(int exitStatus) ServiceState PluginCheckTask::ExitStatusToState(int exitStatus)

View File

@ -182,7 +182,7 @@ void Service::UpdateSlaveNotifications(void)
} }
ConfigItem::Ptr notificationItem = builder->Compile(); ConfigItem::Ptr notificationItem = builder->Compile();
notificationItem->Commit(); ConfigItem::Commit(notificationItem);
newNotifications->Set(name, notificationItem); newNotifications->Set(name, notificationItem);
} }

View File

@ -47,16 +47,21 @@ REGISTER_TYPE(Service, serviceAttributes);
Service::Service(const Dictionary::Ptr& serializedObject) Service::Service(const Dictionary::Ptr& serializedObject)
: DynamicObject(serializedObject) : DynamicObject(serializedObject)
{ }
void Service::OnRegistrationCompleted(void)
{ {
DynamicObject::OnRegistrationCompleted();
ServiceGroup::InvalidateMembersCache(); ServiceGroup::InvalidateMembersCache();
Host::InvalidateServicesCache(); Host::InvalidateServicesCache();
Service::InvalidateDowntimesCache(); Service::InvalidateDowntimesCache();
Service::InvalidateCommentsCache(); Service::InvalidateCommentsCache();
}
void Service::OnInitCompleted(void) {
{ ObjectLock olock(this);
UpdateSlaveNotifications(); UpdateSlaveNotifications();
}
} }
Service::~Service(void) Service::~Service(void)

View File

@ -248,7 +248,7 @@ public:
void SetNextNotification(double time); void SetNextNotification(double time);
protected: protected:
virtual void OnInitCompleted(void); virtual void OnRegistrationCompleted(void);
virtual void OnAttributeChanged(const String& name, const Value& oldValue); virtual void OnAttributeChanged(const String& name, const Value& oldValue);
private: private:

View File

@ -72,15 +72,23 @@ ServiceGroup::Ptr ServiceGroup::GetByName(const String& name)
return dynamic_pointer_cast<ServiceGroup>(configObject); return dynamic_pointer_cast<ServiceGroup>(configObject);
} }
set<Service::Ptr> ServiceGroup::GetMembers(void) const set<Service::Ptr> ServiceGroup::GetMembers(const ServiceGroup::Ptr& self)
{ {
set<Service::Ptr> services; String name;
ValidateMembersCache(); {
ObjectLock olock(self);
name = self->GetName();
}
set<Service::Ptr> services;
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const Service::WeakPtr& svc, m_MembersCache[GetName()]) {
ValidateMembersCache();
BOOST_FOREACH(const Service::WeakPtr& svc, m_MembersCache[name]) {
Service::Ptr service = svc.lock(); Service::Ptr service = svc.lock();
if (!service) if (!service)
@ -100,10 +108,11 @@ void ServiceGroup::InvalidateMembersCache(void)
m_MembersCache.clear(); m_MembersCache.clear();
} }
/**
* @threadsafety Caller must hold m_Mutex.
*/
void ServiceGroup::ValidateMembersCache(void) void ServiceGroup::ValidateMembersCache(void)
{ {
boost::mutex::scoped_lock lock(m_Mutex);
if (m_MembersCacheValid) if (m_MembersCacheValid)
return; return;

View File

@ -43,7 +43,7 @@ public:
String GetNotesUrl(void) const; String GetNotesUrl(void) const;
String GetActionUrl(void) const; String GetActionUrl(void) const;
set<Service::Ptr> GetMembers(void) const; static set<Service::Ptr> GetMembers(const ServiceGroup::Ptr& self);
static void InvalidateMembersCache(void); static void InvalidateMembersCache(void);
private: private:

View File

@ -87,7 +87,7 @@ Endpoint::Ptr Endpoint::MakeEndpoint(const String& name, bool replicated, bool l
endpointConfig->SetLocal(!replicated); endpointConfig->SetLocal(!replicated);
endpointConfig->AddExpression("local", OperatorSet, local); endpointConfig->AddExpression("local", OperatorSet, local);
DynamicObject::Ptr object = endpointConfig->Compile()->Commit(); DynamicObject::Ptr object = ConfigItem::Commit(endpointConfig->Compile());
return dynamic_pointer_cast<Endpoint>(object); return dynamic_pointer_cast<Endpoint>(object);
} }