More lock refactoring. Yay.

This commit is contained in:
Gunnar Beutner 2013-03-02 09:07:47 +01:00
parent 572a477da3
commit 48485c5f26
67 changed files with 1741 additions and 1041 deletions

View File

@ -27,13 +27,9 @@ void CheckerComponent::Start(void)
{
m_Endpoint = Endpoint::MakeEndpoint("checker", false);
{
ObjectLock olock(m_Endpoint);
/* dummy registration so the delegation module knows this is a checker
TODO: figure out a better way for this */
m_Endpoint->RegisterSubscription("checker");
}
/* dummy registration so the delegation module knows this is a checker
TODO: figure out a better way for this */
m_Endpoint->RegisterSubscription("checker");
Service::OnCheckerChanged.connect(bind(&CheckerComponent::CheckerChangedHandler, this, _1));
Service::OnNextCheckChanged.connect(bind(&CheckerComponent::NextCheckChangedHandler, this, _1));
@ -50,10 +46,7 @@ void CheckerComponent::Start(void)
void CheckerComponent::Stop(void)
{
{
ObjectLock olock(m_Endpoint);
m_Endpoint->Unregister();
}
m_Endpoint->Unregister();
{
boost::mutex::scoped_lock lock(m_Mutex);
@ -81,24 +74,14 @@ void CheckerComponent::CheckThreadProc(void)
CheckTimeView::iterator it = idx.begin();
Service::Ptr service = *it;
ObjectLock olock(service); /* also required for the key extractor. */
if (!service->IsRegistered()) {
idx.erase(it);
continue;
}
double wait;
{
ObjectLock olock(service);
wait = service->GetNextCheck() - Utility::GetTime();
}
double wait = service->GetNextCheck() - Utility::GetTime();
if (wait > 0) {
/* Release the object lock. */
olock.Unlock();
/* Make sure the service we just examined can be destroyed while we're waiting. */
service.reset();
@ -113,19 +96,17 @@ void CheckerComponent::CheckThreadProc(void)
/* reschedule the service if checks are currently disabled
* for it and this is not a forced check */
if (!service->GetEnableActiveChecks()) {
if (!service->GetForceNextCheck()) {
Logger::Write(LogDebug, "checker", "Ignoring service check for disabled service: " + service->GetName());
if (!service->GetEnableActiveChecks() && !service->GetForceNextCheck()) {
Logger::Write(LogDebug, "checker", "Ignoring service check for disabled service: " + service->GetName());
service->UpdateNextCheck();
service->UpdateNextCheck();
typedef nth_index<ServiceSet, 1>::type CheckTimeView;
CheckTimeView& idx = boost::get<1>(m_IdleServices);
typedef nth_index<ServiceSet, 1>::type CheckTimeView;
CheckTimeView& idx = boost::get<1>(m_IdleServices);
idx.insert(service);
idx.insert(service);
continue;
}
continue;
}
service->SetForceNextCheck(false);
@ -136,18 +117,9 @@ void CheckerComponent::CheckThreadProc(void)
m_PendingServices.insert(service);
try {
olock.Unlock();
CheckerComponent::Ptr self;
{
ObjectLock olock(this);
self = GetSelf();
}
Service::BeginExecuteCheck(service, boost::bind(&CheckerComponent::CheckCompletedHandler, static_cast<CheckerComponent::Ptr>(self), service));
CheckerComponent::Ptr self = GetSelf();
Service::BeginExecuteCheck(service, boost::bind(&CheckerComponent::CheckCompletedHandler, self, service));
} catch (const exception& ex) {
olock.Lock();
Logger::Write(LogCritical, "checker", "Exception occured while checking service '" + service->GetName() + "': " + diagnostic_information(ex));
}
}
@ -156,7 +128,6 @@ void CheckerComponent::CheckThreadProc(void)
void CheckerComponent::CheckCompletedHandler(const Service::Ptr& service)
{
boost::mutex::scoped_lock lock(m_Mutex);
ObjectLock olock(service); /* required for the key extractor */
/* remove the service from the list of pending services; if it's not in the
* list this was a manual (i.e. forced) check and we must not re-add the
@ -191,19 +162,9 @@ void CheckerComponent::CheckerChangedHandler(const Service::Ptr& service)
{
boost::mutex::scoped_lock lock(m_Mutex);
ObjectLock olock(service); /* also required for the key extractor */
String checker = service->GetCurrentChecker();
EndpointManager::Ptr em = EndpointManager::GetInstance();
String identity;
{
ObjectLock elock(em);
identity = em->GetIdentity();
}
if (checker == identity || Endpoint::GetByName(checker) == m_Endpoint) {
if (checker == EndpointManager::GetInstance()->GetIdentity() || Endpoint::GetByName(checker) == m_Endpoint) {
if (m_PendingServices.find(service) != m_PendingServices.end())
return;
@ -220,8 +181,6 @@ void CheckerComponent::NextCheckChangedHandler(const Service::Ptr& service)
{
boost::mutex::scoped_lock lock(m_Mutex);
ObjectLock olock(service); /* required for the key extractor */
/* remove and re-insert the service from the set in order to force an index update */
typedef nth_index<ServiceSet, 0>::type ServiceView;
ServiceView& idx = boost::get<0>(m_IdleServices);

View File

@ -31,7 +31,7 @@ struct ServiceNextCheckExtractor
typedef double result_type;
/**
* @threadsafety Caller must hold the mutex for the service.
* @threadsafety Always.
*/
double operator()(const Service::Ptr& service)
{

View File

@ -38,8 +38,6 @@ String CompatComponent::GetStatusPath(void) const
{
DynamicObject::Ptr config = GetConfig();
ObjectLock olock(config);
Value statusPath = config->Get("status_path");
if (statusPath.IsEmpty())
return Application::GetLocalStateDir() + "/cache/icinga2/status.dat";
@ -56,8 +54,6 @@ String CompatComponent::GetObjectsPath(void) const
{
DynamicObject::Ptr config = GetConfig();
ObjectLock olock(config);
Value objectsPath = config->Get("objects_path");
if (objectsPath.IsEmpty())
return Application::GetLocalStateDir() + "/cache/icinga2/objects.cache";
@ -74,8 +70,6 @@ String CompatComponent::GetLogPath(void) const
{
DynamicObject::Ptr config = GetConfig();
ObjectLock olock(config);
Value logPath = config->Get("log_path");
if (logPath.IsEmpty())
return Application::GetLocalStateDir() + "/log/icinga2/compat";
@ -92,8 +86,6 @@ String CompatComponent::GetCommandPath(void) const
{
DynamicObject::Ptr config = GetConfig();
ObjectLock olock(config);
Value commandPath = config->Get("command_path");
if (commandPath.IsEmpty())
return Application::GetLocalStateDir() + "/run/icinga.cmd";
@ -107,7 +99,7 @@ String CompatComponent::GetCommandPath(void) const
void CompatComponent::Start(void)
{
m_StatusTimer = boost::make_shared<Timer>();
m_StatusTimer->SetInterval(5);
m_StatusTimer->SetInterval(15);
m_StatusTimer->OnTimerExpired.connect(boost::bind(&CompatComponent::StatusTimerHandler, this));
m_StatusTimer->Start();
m_StatusTimer->Reschedule(0);
@ -170,31 +162,24 @@ void CompatComponent::CommandPipeThread(const String& commandPath)
String command = line;
ProcessCommand(command);
try {
Logger::Write(LogInformation, "compat", "Executing external command: " + command);
ExternalCommandProcessor::Execute(command);
} catch (const exception& ex) {
stringstream msgbuf;
msgbuf << "External command failed: " << diagnostic_information(ex);
Logger::Write(LogWarning, "compat", msgbuf.str());
}
}
fclose(fp);
}
}
void CompatComponent::ProcessCommand(const String& command)
{
try {
Logger::Write(LogInformation, "compat", "Executing external command: " + command);
ExternalCommandProcessor::Execute(command);
} catch (const exception& ex) {
stringstream msgbuf;
msgbuf << "External command failed: " << diagnostic_information(ex);
Logger::Write(LogWarning, "compat", msgbuf.str());
}
}
#endif /* _WIN32 */
void CompatComponent::DumpComments(ostream& fp, const Service::Ptr& owner, CompatObjectType type)
{
ObjectLock olock(owner);
Service::Ptr service;
Host::Ptr host;
Dictionary::Ptr comments = owner->GetComments();
@ -202,6 +187,8 @@ void CompatComponent::DumpComments(ostream& fp, const Service::Ptr& owner, Compa
if (!comments)
return;
ObjectLock olock(comments);
String id;
Dictionary::Ptr comment;
BOOST_FOREACH(tie(id, comment), comments) {
@ -230,27 +217,17 @@ void CompatComponent::DumpComments(ostream& fp, const Service::Ptr& owner, Compa
void CompatComponent::DumpDowntimes(ostream& fp, const Service::Ptr& owner, CompatObjectType type)
{
Dictionary::Ptr downtimes;
String short_name, host_name;
Host::Ptr host;
Host::Ptr host = owner->GetHost();
{
ObjectLock olock(owner);
if (!host)
return;
downtimes = owner->GetDowntimes();
short_name = owner->GetShortName();
host = owner->GetHost();
}
{
ObjectLock olock(host);
host_name = host->GetName();
}
Dictionary::Ptr downtimes = owner->GetDowntimes();
if (!downtimes)
return;
ObjectLock dlock(downtimes);
ObjectLock olock(downtimes);
String id;
Dictionary::Ptr downtime;
@ -264,14 +241,14 @@ void CompatComponent::DumpDowntimes(ostream& fp, const Service::Ptr& owner, Comp
fp << "hostdowntime {" << "\n";
else
fp << "servicedowntime {" << "\n"
<< "\t" << "service_description=" << short_name << "\n";
<< "\t" << "service_description=" << owner->GetShortName() << "\n";
Dictionary::Ptr triggeredByObj = Service::GetDowntimeByID(downtime->Get("triggered_by"));
int triggeredByLegacy = 0;
if (triggeredByObj)
triggeredByLegacy = triggeredByObj->Get("legacy_id");
fp << "\t" << "host_name=" << host_name << "\n"
fp << "\t" << "host_name=" << host->GetName() << "\n"
<< "\t" << "downtime_id=" << static_cast<String>(downtime->Get("legacy_id")) << "\n"
<< "\t" << "entry_time=" << static_cast<double>(downtime->Get("entry_time")) << "\n"
<< "\t" << "start_time=" << static_cast<double>(downtime->Get("start_time")) << "\n"
@ -290,23 +267,19 @@ void CompatComponent::DumpDowntimes(ostream& fp, const Service::Ptr& owner, Comp
void CompatComponent::DumpHostStatus(ostream& fp, const Host::Ptr& host)
{
{
ObjectLock olock(host);
fp << "hoststatus {" << "\n"
<< "\t" << "host_name=" << host->GetName() << "\n";
}
fp << "hoststatus {" << "\n"
<< "\t" << "host_name=" << host->GetName() << "\n";
ServiceState hcState = StateOK;
Service::Ptr hc = Host::GetHostCheckService(host);
if (hc) {
ObjectLock olock(hc);
Service::Ptr hc = host->GetHostCheckService();
ObjectLock olock(hc);
if (hc)
hcState = hc->GetState();
}
int state;
if (!Host::IsReachable(host))
if (!host->IsReachable())
state = 2; /* unreachable */
else if (hcState != StateOK)
state = 1; /* down */
@ -327,15 +300,11 @@ void CompatComponent::DumpHostStatus(ostream& fp, const Host::Ptr& host)
void CompatComponent::DumpHostObject(ostream& fp, const Host::Ptr& host)
{
{
ObjectLock olock(host);
fp << "define host {" << "\n"
<< "\t" << "host_name" << "\t" << host->GetName() << "\n"
<< "\t" << "display_name" << "\t" << host->GetDisplayName() << "\n";
fp << "define host {" << "\n"
<< "\t" << "host_name" << "\t" << host->GetName() << "\n"
<< "\t" << "display_name" << "\t" << host->GetDisplayName() << "\n";
}
set<Host::Ptr> parents = Host::GetParentHosts(host);
set<Host::Ptr> parents = host->GetParentHosts();
if (!parents.empty()) {
fp << "\t" << "parents" << "\t";
@ -343,7 +312,7 @@ void CompatComponent::DumpHostObject(ostream& fp, const Host::Ptr& host)
fp << "\n";
}
Service::Ptr hc = Host::GetHostCheckService(host);
Service::Ptr hc = host->GetHostCheckService();
if (hc) {
ObjectLock olock(hc);
@ -372,94 +341,77 @@ void CompatComponent::DumpHostObject(ostream& fp, const Host::Ptr& host)
void CompatComponent::DumpServiceStatusAttrs(ostream& fp, const Service::Ptr& service, CompatObjectType type)
{
ObjectLock olock(service);
String output;
String perfdata;
double schedule_end = -1;
Dictionary::Ptr cr;
int state, state_type;
Host::Ptr host;
{
ObjectLock olock(service);
cr = service->GetLastCheckResult();
state = service->GetState();
state_type = service->GetStateType();
host = service->GetHost();
}
Dictionary::Ptr cr = service->GetLastCheckResult();
if (cr) {
ObjectLock olock(cr);
output = cr->Get("output");
schedule_end = cr->Get("schedule_end");
perfdata = cr->Get("performance_data_raw");
}
int state = service->GetState();
if (state > StateUnknown)
state = StateUnknown;
if (type == CompatTypeHost) {
if (state == StateOK || state == StateWarning)
state = 0;
state = 0; /* UP */
else
state = 1;
state = 1; /* DOWN */
if (!Host::IsReachable(host))
state = 2;
Host::Ptr host = service->GetHost();
if (!host)
return;
if (!host->IsReachable())
state = 2; /* UNREACHABLE */
}
{
ObjectLock olock(service);
fp << "\t" << "check_interval=" << service->GetCheckInterval() / 60.0 << "\n"
<< "\t" << "retry_interval=" << service->GetRetryInterval() / 60.0 << "\n"
<< "\t" << "has_been_checked=" << (service->GetLastCheckResult() ? 1 : 0) << "\n"
<< "\t" << "should_be_scheduled=1" << "\n"
<< "\t" << "check_execution_time=" << Service::CalculateExecutionTime(cr) << "\n"
<< "\t" << "check_latency=" << Service::CalculateLatency(cr) << "\n"
<< "\t" << "current_state=" << state << "\n"
<< "\t" << "state_type=" << state_type << "\n"
<< "\t" << "plugin_output=" << output << "\n"
<< "\t" << "performance_data=" << perfdata << "\n"
<< "\t" << "last_check=" << schedule_end << "\n"
<< "\t" << "next_check=" << service->GetNextCheck() << "\n"
<< "\t" << "current_attempt=" << service->GetCurrentCheckAttempt() << "\n"
<< "\t" << "max_attempts=" << service->GetMaxCheckAttempts() << "\n"
<< "\t" << "last_state_change=" << service->GetLastStateChange() << "\n"
<< "\t" << "last_hard_state_change=" << service->GetLastHardStateChange() << "\n"
<< "\t" << "last_update=" << time(NULL) << "\n"
<< "\t" << "notifications_enabled=" << (service->GetEnableNotifications() ? 1 : 0) << "\n"
<< "\t" << "active_checks_enabled=" << (service->GetEnableActiveChecks() ? 1 : 0) <<"\n"
<< "\t" << "passive_checks_enabled=" << (service->GetEnablePassiveChecks() ? 1 : 0) << "\n"
<< "\t" << "problem_has_been_acknowledged=" << (service->GetAcknowledgement() != AcknowledgementNone ? 1 : 0) << "\n"
<< "\t" << "acknowledgement_type=" << static_cast<int>(service->GetAcknowledgement()) << "\n"
<< "\t" << "acknowledgement_end_time=" << service->GetAcknowledgementExpiry() << "\n"
<< "\t" << "scheduled_downtime_depth=" << (service->IsInDowntime() ? 1 : 0) << "\n"
<< "\t" << "last_notification=" << service->GetLastNotification() << "\n";
}
fp << "\t" << "check_interval=" << service->GetCheckInterval() / 60.0 << "\n"
<< "\t" << "retry_interval=" << service->GetRetryInterval() / 60.0 << "\n"
<< "\t" << "has_been_checked=" << (service->GetLastCheckResult() ? 1 : 0) << "\n"
<< "\t" << "should_be_scheduled=1" << "\n"
<< "\t" << "check_execution_time=" << Service::CalculateExecutionTime(cr) << "\n"
<< "\t" << "check_latency=" << Service::CalculateLatency(cr) << "\n"
<< "\t" << "current_state=" << state << "\n"
<< "\t" << "state_type=" << service->GetStateType() << "\n"
<< "\t" << "plugin_output=" << output << "\n"
<< "\t" << "performance_data=" << perfdata << "\n"
<< "\t" << "last_check=" << schedule_end << "\n"
<< "\t" << "next_check=" << service->GetNextCheck() << "\n"
<< "\t" << "current_attempt=" << service->GetCurrentCheckAttempt() << "\n"
<< "\t" << "max_attempts=" << service->GetMaxCheckAttempts() << "\n"
<< "\t" << "last_state_change=" << service->GetLastStateChange() << "\n"
<< "\t" << "last_hard_state_change=" << service->GetLastHardStateChange() << "\n"
<< "\t" << "last_update=" << time(NULL) << "\n"
<< "\t" << "notifications_enabled=" << (service->GetEnableNotifications() ? 1 : 0) << "\n"
<< "\t" << "active_checks_enabled=" << (service->GetEnableActiveChecks() ? 1 : 0) <<"\n"
<< "\t" << "passive_checks_enabled=" << (service->GetEnablePassiveChecks() ? 1 : 0) << "\n"
<< "\t" << "problem_has_been_acknowledged=" << (service->GetAcknowledgement() != AcknowledgementNone ? 1 : 0) << "\n"
<< "\t" << "acknowledgement_type=" << static_cast<int>(service->GetAcknowledgement()) << "\n"
<< "\t" << "acknowledgement_end_time=" << service->GetAcknowledgementExpiry() << "\n"
<< "\t" << "scheduled_downtime_depth=" << (service->IsInDowntime() ? 1 : 0) << "\n"
<< "\t" << "last_notification=" << service->GetLastNotification() << "\n";
}
void CompatComponent::DumpServiceStatus(ostream& fp, const Service::Ptr& service)
{
String host_name, short_name;
Host::Ptr host;
Host::Ptr host = service->GetHost();
{
ObjectLock olock(service);
short_name = service->GetShortName();
host = service->GetHost();
}
{
ObjectLock olock(host);
host_name = host->GetName();
}
if (!host)
return;
fp << "servicestatus {" << "\n"
<< "\t" << "host_name=" << host_name << "\n"
<< "\t" << "service_description=" << short_name << "\n";
<< "\t" << "host_name=" << host->GetName() << "\n"
<< "\t" << "service_description=" << service->GetShortName() << "\n";
DumpServiceStatusAttrs(fp, service, CompatTypeService);
@ -472,29 +424,17 @@ void CompatComponent::DumpServiceStatus(ostream& fp, const Service::Ptr& service
void CompatComponent::DumpServiceObject(ostream& fp, const Service::Ptr& service)
{
Host::Ptr host;
String host_name, short_name;
{
ObjectLock olock(service);
host = service->GetHost();
short_name = service->GetShortName();
}
Host::Ptr host = service->GetHost();
if (!host)
return;
{
ObjectLock olock(host);
host_name = host->GetName();
}
{
ObjectLock olock(service);
fp << "define service {" << "\n"
<< "\t" << "host_name" << "\t" << host_name << "\n"
<< "\t" << "service_description" << "\t" << short_name << "\n"
<< "\t" << "host_name" << "\t" << host->GetName() << "\n"
<< "\t" << "service_description" << "\t" << service->GetShortName() << "\n"
<< "\t" << "display_name" << "\t" << service->GetDisplayName() << "\n"
<< "\t" << "check_command" << "\t" << "check_i2" << "\n"
<< "\t" << "check_interval" << "\t" << service->GetCheckInterval() / 60.0 << "\n"
@ -510,14 +450,22 @@ void CompatComponent::DumpServiceObject(ostream& fp, const Service::Ptr& service
<< "\n";
}
BOOST_FOREACH(const Service::Ptr& parent, Service::GetParentServices(service)) {
ObjectLock plock(parent);
BOOST_FOREACH(const Service::Ptr& parent, service->GetParentServices()) {
Host::Ptr host = service->GetHost();
if (!host)
continue;
Host::Ptr parent_host = parent->GetHost();
if (!parent_host)
continue;
fp << "define servicedependency {" << "\n"
<< "\t" << "dependent_host_name" << "\t" << host_name << "\n"
<< "\t" << "dependent_host_name" << "\t" << host->GetName() << "\n"
<< "\t" << "dependent_service_description" << "\t" << service->GetShortName() << "\n"
<< "\t" << "host_name" << "\t" << parent->GetHost()->GetName() << "\n"
<< "\t" << "service_description" << "\t" << short_name << "\n"
<< "\t" << "host_name" << "\t" << parent_host->GetName() << "\n"
<< "\t" << "service_description" << "\t" << service->GetShortName() << "\n"
<< "\t" << "execution_failure_criteria" << "\t" << "n" << "\n"
<< "\t" << "notification_failure_criteria" << "\t" << "w,u,c" << "\n"
<< "\t" << "}" << "\n"
@ -552,18 +500,10 @@ void CompatComponent::StatusTimerHandler(void)
<< "\t" << "}" << "\n"
<< "\n";
double startTime;
{
IcingaApplication::Ptr app = IcingaApplication::GetInstance();
ObjectLock olock(app);
startTime = app->GetStartTime();
}
statusfp << "programstatus {" << "\n"
<< "icinga_pid=" << Utility::GetPid() << "\n"
<< "\t" << "daemon_mode=1" << "\n"
<< "\t" << "program_start=" << startTime << "\n"
<< "\t" << "program_start=" << IcingaApplication::GetInstance()->GetStartTime() << "\n"
<< "\t" << "active_service_checks_enabled=1" << "\n"
<< "\t" << "passive_service_checks_enabled=1" << "\n"
<< "\t" << "active_host_checks_enabled=1" << "\n"
@ -622,17 +562,13 @@ void CompatComponent::StatusTimerHandler(void)
stringstream tempobjectfp;
tempobjectfp << std::fixed;
{
ObjectLock olock(hg);
tempobjectfp << "define hostgroup {" << "\n"
<< "\t" << "hostgroup_name" << "\t" << hg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << hg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << hg->GetActionUrl() << "\n";
}
tempobjectfp << "define hostgroup {" << "\n"
<< "\t" << "hostgroup_name" << "\t" << hg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << hg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << hg->GetActionUrl() << "\n";
tempobjectfp << "\t" << "members" << "\t";
DumpNameList(tempobjectfp, HostGroup::GetMembers(hg));
DumpNameList(tempobjectfp, hg->GetMembers());
tempobjectfp << "\n"
<< "\t" << "}" << "\n";
@ -659,35 +595,22 @@ void CompatComponent::StatusTimerHandler(void)
stringstream tempobjectfp;
tempobjectfp << std::fixed;
{
ObjectLock olock(sg);
tempobjectfp << "define servicegroup {" << "\n"
<< "\t" << "servicegroup_name" << "\t" << sg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << sg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << sg->GetActionUrl() << "\n";
}
tempobjectfp << "define servicegroup {" << "\n"
<< "\t" << "servicegroup_name" << "\t" << sg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << sg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << sg->GetActionUrl() << "\n";
tempobjectfp << "\t" << "members" << "\t";
vector<String> sglist;
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
Host::Ptr host;
String host_name, short_name;
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Host::Ptr host = service->GetHost();
{
ObjectLock olock(service);
host = service->GetHost();
short_name = service->GetShortName();
}
if (!host)
continue;
{
ObjectLock olock(host);
host_name = host->GetName();
}
sglist.push_back(host_name);
sglist.push_back(short_name);
sglist.push_back(host->GetName());
sglist.push_back(service->GetShortName());
}
DumpStringList(tempobjectfp, sglist);
@ -704,19 +627,15 @@ void CompatComponent::StatusTimerHandler(void)
stringstream tempobjectfp;
tempobjectfp << std::fixed;
{
ObjectLock olock(user);
tempobjectfp << "define contact {" << "\n"
<< "\t" << "contact_name" << "\t" << user->GetName() << "\n"
<< "\t" << "alias" << "\t" << user->GetDisplayName() << "\n"
<< "\t" << "service_notification_options" << "\t" << "w,u,c,r,f,s" << "\n"
<< "\t" << "host_notification_options" << "\t" << "d,u,r,f,s" << "\n"
<< "\t" << "host_notifications_enabled" << "\t" << 1 << "\n"
<< "\t" << "service_notifications_enabled" << "\t" << 1 << "\n"
<< "\t" << "}" << "\n"
<< "\n";
}
tempobjectfp << "define contact {" << "\n"
<< "\t" << "contact_name" << "\t" << user->GetName() << "\n"
<< "\t" << "alias" << "\t" << user->GetDisplayName() << "\n"
<< "\t" << "service_notification_options" << "\t" << "w,u,c,r,f,s" << "\n"
<< "\t" << "host_notification_options" << "\t" << "d,u,r,f,s" << "\n"
<< "\t" << "host_notifications_enabled" << "\t" << 1 << "\n"
<< "\t" << "service_notifications_enabled" << "\t" << 1 << "\n"
<< "\t" << "}" << "\n"
<< "\n";
objectfp << tempobjectfp.str();
}
@ -727,16 +646,12 @@ void CompatComponent::StatusTimerHandler(void)
stringstream tempobjectfp;
tempobjectfp << std::fixed;
{
ObjectLock olock(ug);
tempobjectfp << "define contactgroup {" << "\n"
<< "\t" << "contactgroup_name" << "\t" << ug->GetName() << "\n"
<< "\t" << "alias" << "\t" << ug->GetDisplayName() << "\n";
}
tempobjectfp << "define contactgroup {" << "\n"
<< "\t" << "contactgroup_name" << "\t" << ug->GetName() << "\n"
<< "\t" << "alias" << "\t" << ug->GetDisplayName() << "\n";
tempobjectfp << "\t" << "members" << "\t";
DumpNameList(tempobjectfp, UserGroup::GetMembers(ug));
DumpNameList(tempobjectfp, ug->GetMembers());
tempobjectfp << "\n"
<< "\t" << "}" << "\n";

View File

@ -43,7 +43,6 @@ private:
thread m_CommandThread;
void CommandPipeThread(const String& commandPath);
void ProcessCommand(const String& command);
#endif /* _WIN32 */
Timer::Ptr m_StatusTimer;

View File

@ -46,8 +46,6 @@ set<Endpoint::Ptr> DelegationComponent::GetCheckerCandidates(const Service::Ptr&
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Endpoint")) {
Endpoint::Ptr endpoint = dynamic_pointer_cast<Endpoint>(object);
ObjectLock olock(endpoint);
String myIdentity = EndpointManager::GetInstance()->GetIdentity();
/* ignore local-only endpoints (unless this is a local-only instance) */
@ -93,8 +91,8 @@ void DelegationComponent::DelegationTimerHandler(void)
services.push_back(service);
ObjectLock olock(service);
String checker = service->GetCurrentChecker();
if (checker.IsEmpty())
continue;
@ -112,8 +110,6 @@ void DelegationComponent::DelegationTimerHandler(void)
/* re-assign services */
BOOST_FOREACH(const Service::Ptr& service, services) {
ObjectLock olock(service);
String checker = service->GetCurrentChecker();
Endpoint::Ptr oldEndpoint = Endpoint::GetByName(checker);
@ -141,8 +137,6 @@ void DelegationComponent::DelegationTimerHandler(void)
/* don't re-assign service if the checker is still valid
* and doesn't have too many services */
ObjectLock elock(oldEndpoint);
if (oldEndpoint && oldEndpoint->IsConnected() &&
candidates.find(oldEndpoint) != candidates.end() &&
histogram[oldEndpoint] <= avg_services + overflow_tolerance)
@ -162,7 +156,6 @@ void DelegationComponent::DelegationTimerHandler(void)
if (histogram[candidate] > avg_services)
continue;
ObjectLock clock(candidate);
service->SetCurrentChecker(candidate->GetName());
histogram[candidate]++;
@ -189,6 +182,8 @@ void DelegationComponent::DelegationTimerHandler(void)
cr->Set("state", StateUncheckable);
cr->Set("output", "No checker is available for this service.");
cr->Seal();
service->ProcessCheckResult(cr);
Logger::Write(LogWarning, "delegation", "Can't delegate service: " + service->GetName());
@ -203,8 +198,6 @@ void DelegationComponent::DelegationTimerHandler(void)
Endpoint::Ptr endpoint;
int count;
BOOST_FOREACH(tie(endpoint, count), histogram) {
ObjectLock olock(endpoint);
stringstream msgbuf;
msgbuf << "histogram: " << endpoint->GetName() << " - " << count;
Logger::Write(LogInformation, "delegation", msgbuf.str());

View File

@ -54,16 +54,12 @@ void DemoComponent::Stop(void)
*/
void DemoComponent::DemoTimerHandler(void)
{
Logger::Write(LogInformation, "demo", "Sending multicast 'hello"
" world' message.");
Logger::Write(LogInformation, "demo", "Sending multicast 'hello world' message.");
RequestMessage request;
request.SetMethod("demo::HelloWorld");
EndpointManager::Ptr em = EndpointManager::GetInstance();
ObjectLock olock(em);
em->SendMulticastMessage(m_Endpoint, request);
EndpointManager::GetInstance()->SendMulticastMessage(m_Endpoint, request);
}
/**

View File

@ -29,13 +29,9 @@ REGISTER_COMPONENT("notification", NotificationComponent);
void NotificationComponent::Start(void)
{
m_Endpoint = Endpoint::MakeEndpoint("notification", false);
{
ObjectLock olock(m_Endpoint);
m_Endpoint->RegisterTopicHandler("icinga::SendNotifications",
boost::bind(&NotificationComponent::SendNotificationsRequestHandler, this, _2,
_3));
}
m_Endpoint->RegisterTopicHandler("icinga::SendNotifications",
boost::bind(&NotificationComponent::SendNotificationsRequestHandler, this, _2,
_3));
m_NotificationTimer = boost::make_shared<Timer>();
m_NotificationTimer->SetInterval(5);
@ -48,6 +44,7 @@ void NotificationComponent::Start(void)
*/
void NotificationComponent::Stop(void)
{
m_Endpoint->Unregister();
}
/**
@ -61,6 +58,8 @@ void NotificationComponent::NotificationTimerHandler(void)
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
bool reachable = service->IsReachable();
ObjectLock olock(service);
if (service->GetStateType() == StateTypeSoft)
@ -75,7 +74,7 @@ void NotificationComponent::NotificationTimerHandler(void)
if (service->GetLastNotification() > now - service->GetNotificationInterval())
continue;
if (Service::IsReachable(service) && !service->IsInDowntime() && !service->IsAcknowledged())
if (reachable && !service->IsInDowntime() && !service->IsAcknowledged())
service->RequestNotifications(NotificationProblem);
}
}
@ -100,5 +99,5 @@ void NotificationComponent::SendNotificationsRequestHandler(const Endpoint::Ptr&
Service::Ptr service = Service::GetByName(svc);
Service::SendNotifications(service, static_cast<NotificationType>(type));
service->SendNotifications(static_cast<NotificationType>(type));
}

View File

@ -79,9 +79,9 @@ Application::~Application(void)
*
* @returns The application object.
*/
Application *Application::GetInstance(void)
Application::Ptr Application::GetInstance(void)
{
return m_Instance;
return m_Instance->GetSelf();
}
int Application::GetArgC(void)
@ -285,7 +285,7 @@ void Application::SigIntHandler(int signum)
{
assert(signum == SIGINT);
Application *instance = Application::GetInstance();
Application::Ptr instance = Application::GetInstance();
if (!instance)
return;
@ -320,7 +320,7 @@ void Application::SigAbrtHandler(int signum)
*/
BOOL WINAPI Application::CtrlHandler(DWORD type)
{
Application *instance = Application::GetInstance();
Application::Ptr instance = Application::GetInstance();
if (!instance)
return TRUE;
@ -410,6 +410,8 @@ int Application::Run(void)
*/
void Application::UpdatePidFile(const String& filename)
{
ObjectLock olock(this);
ClosePidFile();
/* There's just no sane way of getting a file descriptor for a
@ -420,7 +422,15 @@ void Application::UpdatePidFile(const String& filename)
BOOST_THROW_EXCEPTION(runtime_error("Could not open PID file '" + filename + "'"));
#ifndef _WIN32
Utility::SetCloExec(fileno(m_PidFile));
int fd = fileno(m_PidFile);
Utility::SetCloExec(fd);
if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
Logger::Write(LogCritical, "base", "Could not lock PID file. Make sure that only one instance of the application is running.");
_exit(EXIT_FAILURE);
}
#endif /* _WIN32 */
fprintf(m_PidFile, "%d", Utility::GetPid());
@ -432,6 +442,8 @@ void Application::UpdatePidFile(const String& filename)
*/
void Application::ClosePidFile(void)
{
ObjectLock olock(this);
if (m_PidFile != NULL)
fclose(m_PidFile);

View File

@ -37,7 +37,7 @@ public:
Application(const Dictionary::Ptr& serializedUpdate);
~Application(void);
static Application *GetInstance(void);
static Application::Ptr GetInstance(void);
int Run(void);

View File

@ -23,6 +23,7 @@ using namespace icinga;
REGISTER_TYPE(Component);
boost::mutex Component::m_Mutex;
map<String, Component::Factory> Component::m_Factories;
/**
@ -38,18 +39,24 @@ Component::Component(const Dictionary::Ptr& properties)
(void) Utility::LoadIcingaLibrary(GetName(), true);
map<String, Factory>::iterator it;
it = m_Factories.find(GetName());
Component::Factory factory;
if (it == m_Factories.end())
BOOST_THROW_EXCEPTION(invalid_argument("Unknown component: " + GetName()));
{
boost::mutex::scoped_lock lock(m_Mutex);
IComponent::Ptr impl = it->second();
map<String, Factory>::iterator it;
it = m_Factories.find(GetName());
if (!impl)
if (it == m_Factories.end())
BOOST_THROW_EXCEPTION(invalid_argument("Unknown component: " + GetName()));
factory = it->second;
}
m_Impl = factory();
if (!m_Impl)
BOOST_THROW_EXCEPTION(runtime_error("Component factory returned NULL."));
m_Impl = impl;
}
/**
@ -67,7 +74,9 @@ Component::~Component(void)
*/
void Component::Start(void)
{
m_Impl->m_Config = GetSelf();
ObjectLock olock(this);
m_Impl->SetConfig(GetSelf());
m_Impl->Start();
}
@ -95,9 +104,21 @@ void Component::AddSearchDir(const String& componentDirectory)
*/
DynamicObject::Ptr IComponent::GetConfig(void) const
{
ObjectLock olock(this);
return m_Config.lock();
}
/**
* Sets the configuration for this component.
*/
void IComponent::SetConfig(const DynamicObject::Ptr& config)
{
ObjectLock olock(this);
m_Config = config;
}
/**
* Starts the component.
*/
@ -119,5 +140,7 @@ void IComponent::Stop(void)
*/
void Component::Register(const String& name, const Component::Factory& factory)
{
boost::mutex::scoped_lock lock(m_Mutex);
m_Factories[name] = factory;
}

View File

@ -44,6 +44,8 @@ private:
DynamicObject::WeakPtr m_Config; /**< The configuration object for this
component. */
void SetConfig(const DynamicObject::Ptr& config);
friend class Component;
};
@ -74,6 +76,7 @@ private:
IComponent::Ptr m_Impl; /**< The implementation object for this
component. */
static boost::mutex m_Mutex;
static map<String, Factory> m_Factories;
};

View File

@ -33,7 +33,7 @@ signals2::signal<void (double, const set<DynamicObject::WeakPtr>&)> DynamicObjec
signals2::signal<void (double, const DynamicObject::Ptr&)> DynamicObject::OnFlushObject;
DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject)
: m_EventSafe(false), m_ConfigTx(0), m_Registered(false)
: m_ConfigTx(0), m_Registered(false)
{
RegisterAttribute("__name", Attribute_Config, &m_Name);
RegisterAttribute("__type", Attribute_Config, &m_Type);
@ -115,7 +115,8 @@ Dictionary::Ptr DynamicObject::BuildUpdate(double sinceTx, int attributeTypes) c
void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate,
int allowedTypes)
{
assert(OwnsLock());
ObjectLock olock(this);
assert(serializedUpdate->IsSealed());
Value configTxValue = serializedUpdate->Get("configTx");
@ -132,7 +133,7 @@ void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate,
assert(attrs->IsSealed());
{
ObjectLock olock(attrs);
ObjectLock alock(attrs);
Dictionary::Iterator it;
for (it = attrs->Begin(); it != attrs->End(); it++) {
@ -233,7 +234,7 @@ void DynamicObject::InternalSetAttribute(const String& name, const Value& data,
m_ConfigTx = tx;
}
if (GetEventSafe()) {
if (m_Registered) {
/* We can't call GetSelf() in the constructor or destructor.
* The Register() function will take care of adding this
* object to the list of modified objects later on if we can't
@ -365,17 +366,16 @@ String DynamicObject::GetSource(void) const
void DynamicObject::Register(void)
{
assert(OwnsLock());
assert(!OwnsLock());
/* It's now safe to send us attribute events. */
SetEventSafe(true);
DynamicObject::Ptr self = GetSelf();
/* 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());
m_ModifiedObjects.insert(self);
}
{
@ -384,7 +384,6 @@ void DynamicObject::Register(void)
DynamicObject::Ptr dobj = dtype->GetObject(GetName());
DynamicObject::Ptr self = GetSelf();
assert(!dobj || dobj == self);
if (!dobj)
@ -394,6 +393,8 @@ void DynamicObject::Register(void)
void DynamicObject::OnRegistrationCompleted(void)
{
assert(!OwnsLock());
DynamicObject::Ptr object;
{
@ -402,14 +403,24 @@ void DynamicObject::OnRegistrationCompleted(void)
Start();
Flush();
object = GetSelf();
}
OnRegistered(object);
}
void DynamicObject::OnUnregistrationCompleted(void)
{
assert(!OwnsLock());
{
ObjectLock olock(this);
m_Registered = false;
}
OnUnregistered(GetSelf());
}
void DynamicObject::Start(void)
{
assert(OwnsLock());
@ -419,25 +430,30 @@ void DynamicObject::Start(void)
void DynamicObject::Unregister(void)
{
assert(OwnsLock());
assert(!OwnsLock());
DynamicObject::Ptr self = GetSelf();
DynamicType::Ptr dtype = GetType();
ObjectLock olock(dtype);
if (!dtype || !dtype->GetObject(GetName()))
if (!dtype)
return;
dtype->UnregisterObject(GetSelf());
OnUnregistered(GetSelf());
{
ObjectLock olock(dtype);
dtype->UnregisterObject(self);
}
}
ScriptTask::Ptr DynamicObject::MakeMethodTask(const String& method,
const vector<Value>& arguments)
{
assert(OwnsLock());
Dictionary::Ptr methods;
Dictionary::Ptr methods = m_Methods;
{
ObjectLock olock(this);
methods = m_Methods;
}
String funcName = methods->Get(method);
@ -471,13 +487,6 @@ void DynamicObject::DumpObjects(const String& filename)
sfp->Start();
BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
String type_name;
{
ObjectLock olock(type);
type_name = type->GetName();
}
BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
ObjectLock olock(object);
@ -486,7 +495,7 @@ void DynamicObject::DumpObjects(const String& filename)
Dictionary::Ptr persistentObject = boost::make_shared<Dictionary>();
persistentObject->Set("type", type_name);
persistentObject->Set("type", type->GetName());
persistentObject->Set("name", object->GetName());
int types = Attribute_Local | Attribute_Replicated;
@ -558,10 +567,8 @@ void DynamicObject::RestoreObjects(const String& filename)
if (hasConfig && !object) {
object = DynamicType::CreateObject(dt, update);
ObjectLock olock(object);
object->Register();
} else if (object) {
ObjectLock olock(object);
object->ApplyUpdate(update, Attribute_All);
}
@ -579,7 +586,6 @@ void DynamicObject::DeactivateObjects(void)
{
BOOST_FOREACH(const DynamicType::Ptr& dt, DynamicType::GetTypes()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, dt->GetObjects()) {
ObjectLock olock(object);
object->Unregister();
}
}
@ -624,31 +630,28 @@ void DynamicObject::NewTx(void)
BOOST_FOREACH(const DynamicObject::WeakPtr& wobject, objects) {
DynamicObject::Ptr object = wobject.lock();
if (!object)
if (!object || !object->IsRegistered())
continue;
map<String, Value, string_iless> attrs;
bool event_safe;
{
ObjectLock olock(object);
attrs.swap(object->m_ModifiedAttributes);
event_safe = object->GetEventSafe();
}
/* Send attribute events if it's safe to do so. */
if (event_safe) {
map<String, Value, string_iless>::iterator it;
for (it = attrs.begin(); it != attrs.end(); it++)
object->OnAttributeChanged(it->first, it->second);
}
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::OnAttributeChanged(const String&, const Value&)
{ }
{
assert(!OwnsLock());
}
/*
* @threadsafety Always.
@ -665,17 +668,3 @@ const DynamicObject::AttributeMap& DynamicObject::GetAttributes(void) const
return m_Attributes;
}
void DynamicObject::SetEventSafe(bool safe)
{
assert(OwnsLock());
m_EventSafe = safe;
}
bool DynamicObject::GetEventSafe(void) const
{
assert(OwnsLock());
return m_EventSafe;
}

View File

@ -252,9 +252,6 @@ public:
const AttributeMap& GetAttributes(void) const;
void SetEventSafe(bool initialized);
bool GetEventSafe(void) const;
static DynamicObject::Ptr GetObject(const String& type, const String& name);
static void DumpObjects(const String& filename);
@ -265,6 +262,8 @@ public:
protected:
virtual void OnRegistrationCompleted(void);
virtual void OnUnregistrationCompleted(void);
virtual void OnAttributeChanged(const String& name, const Value& oldValue);
private:
@ -284,7 +283,6 @@ private:
Attribute<Dictionary::Ptr> m_Methods;
bool m_Registered;
bool m_EventSafe;
static double m_CurrentTx;

View File

@ -103,12 +103,11 @@ void DynamicType::RegisterObject(const DynamicObject::Ptr& object)
void DynamicType::UnregisterObject(const DynamicObject::Ptr& object)
{
ObjectLock olock(object);
object->SetEventSafe(false);
assert(OwnsLock());
m_ObjectMap.erase(object->GetName());
m_ObjectSet.erase(object);
object->OnUnregistrationCompleted();
}
/**

View File

@ -21,7 +21,9 @@
using namespace icinga;
#ifdef _DEBUG
boost::mutex Object::m_DebugMutex;
#endif /* _DEBUG */
/**
* Default constructor for the Object class.
@ -49,6 +51,7 @@ Object::SharedPtrHolder Object::GetSelf(void)
return Object::SharedPtrHolder(shared_from_this());
}
#ifdef _DEBUG
/**
* Checks if the calling thread owns the lock on this object or is currently
* in the constructor or destructor and therefore implicitly owns the lock.
@ -73,3 +76,4 @@ bool Object::OwnsLock(void) const
return true;
}
#endif /* _DEBUG */

View File

@ -100,7 +100,9 @@ protected:
SharedPtrHolder GetSelf(void);
#ifdef _DEBUG
bool OwnsLock(void) const;
#endif /* _DEBUG */
private:
Object(const Object& other);
@ -110,7 +112,9 @@ private:
mutable unsigned int m_LockCount;
mutable boost::thread::id m_LockOwner;
#ifdef _DEBUG
static boost::mutex m_DebugMutex;
#endif /* _DEBUG */
friend class ObjectLock;
};

View File

@ -21,6 +21,10 @@
using namespace icinga;
#ifdef _DEBUG
static __thread int g_LockCount;
#endif /* _DEBUG */
ObjectLock::ObjectLock(void)
: m_Object(NULL), m_Lock()
{ }
@ -50,21 +54,42 @@ void ObjectLock::Lock(void)
m_Lock = recursive_mutex::scoped_lock(m_Object->m_Mutex);
#ifdef _DEBUG
{
boost::mutex::scoped_lock lock(Object::m_DebugMutex);
m_Object->m_LockCount++;
m_Object->m_LockOwner = boost::this_thread::get_id();
if (m_Object->m_LockCount == 1) {
g_LockCount++;
m_TS = Utility::GetTime();
}
}
#endif /* _DEBUG */
}
void ObjectLock::Unlock(void)
{
#ifdef _DEBUG
{
boost::mutex::scoped_lock lock(Object::m_DebugMutex);
if (m_Lock.owns_lock())
if (m_Lock.owns_lock()) {
if (m_Object->m_LockCount == 1) {
g_LockCount--;
double dt = Utility::GetTime() - m_TS;
if (dt > 0.05) {
std::cerr << "Held object lock for " << dt << " seconds at:";
Utility::PrintStacktrace(std::cerr);
}
}
m_Object->m_LockCount--;
}
}
#endif /* _DEBUG */
m_Lock = recursive_mutex::scoped_lock();
}

View File

@ -39,6 +39,9 @@ public:
private:
const Object *m_Object;
recursive_mutex::scoped_lock m_Lock;
#ifdef _DEBUG
double m_TS;
#endif /* _DEBUG */
};
}

View File

@ -35,6 +35,9 @@ Script::Script(const Dictionary::Ptr& properties)
RegisterAttribute("code", Attribute_Config, &m_Code);
}
/**
* @threadsafety Always.
*/
void Script::Start(void)
{
assert(OwnsLock());
@ -42,6 +45,9 @@ void Script::Start(void)
SpawnInterpreter();
}
/**
* @threadsafety Always.
*/
String Script::GetLanguage(void) const
{
ObjectLock olock(this);
@ -49,6 +55,9 @@ String Script::GetLanguage(void) const
return m_Language;
}
/**
* @threadsafety Always.
*/
String Script::GetCode(void) const
{
ObjectLock olock(this);
@ -56,12 +65,20 @@ String Script::GetCode(void) const
return m_Code;
}
/**
* @threadsafety Always.
*/
void Script::OnAttributeUpdate(const String& name, const Value& oldValue)
{
assert(!OwnsLock());
if (name == "language" || name == "code")
SpawnInterpreter();
}
/**
* @threadsafety Always.
*/
void Script::SpawnInterpreter(void)
{
Logger::Write(LogInformation, "base", "Reloading script '" + GetName() + "'");

View File

@ -28,25 +28,37 @@ ScriptFunction::ScriptFunction(const Callback& function)
: m_Callback(function)
{ }
/**
* @threadsafety Always.
*/
void ScriptFunction::Register(const String& name, const ScriptFunction::Ptr& function)
{
boost::mutex::scoped_lock lock(GetMutex());
InternalGetFunctions()[name] = function;
OnRegistered(name, function);
}
/**
* @threadsafety Always.
*/
void ScriptFunction::Unregister(const String& name)
{
boost::mutex::scoped_lock lock(GetMutex());
InternalGetFunctions().erase(name);
OnUnregistered(name);
}
/**
* @threadsafety Always.
*/
ScriptFunction::Ptr ScriptFunction::GetByName(const String& name)
{
boost::mutex::scoped_lock lock(GetMutex());
map<String, ScriptFunction::Ptr>::iterator it;
boost::mutex::scoped_lock lock(GetMutex());
it = InternalGetFunctions().find(name);
if (it == InternalGetFunctions().end())
@ -55,6 +67,9 @@ ScriptFunction::Ptr ScriptFunction::GetByName(const String& name)
return it->second;
}
/**
* @threadsafety Always.
*/
void ScriptFunction::Invoke(const ScriptTask::Ptr& task, const vector<Value>& arguments)
{
ObjectLock olock(this);
@ -62,9 +77,13 @@ void ScriptFunction::Invoke(const ScriptTask::Ptr& task, const vector<Value>& ar
m_Callback(task, arguments);
}
/**
* @threadsafety Always.
*/
map<String, ScriptFunction::Ptr> ScriptFunction::GetFunctions(void)
{
boost::mutex::scoped_lock lock(GetMutex());
return InternalGetFunctions(); /* makes a copy of the map */
}
@ -77,6 +96,9 @@ map<String, ScriptFunction::Ptr>& ScriptFunction::InternalGetFunctions(void)
return functions;
}
/**
* @threadsafety Always.
*/
boost::mutex& ScriptFunction::GetMutex(void)
{
static boost::mutex mtx;

View File

@ -44,8 +44,6 @@ public:
static void Unregister(const String& name);
static ScriptFunction::Ptr GetByName(const String& name);
void Invoke(const shared_ptr<ScriptTask>& task, const vector<Value>& arguments);
static map<String, ScriptFunction::Ptr> GetFunctions(void);
static signals2::signal<void (const String&, const ScriptFunction::Ptr&)> OnRegistered;
@ -56,6 +54,10 @@ private:
static map<String, ScriptFunction::Ptr>& InternalGetFunctions(void);
static boost::mutex& GetMutex(void);
void Invoke(const shared_ptr<ScriptTask>& task, const vector<Value>& arguments);
friend class ScriptTask;
};
/**

View File

@ -29,12 +29,5 @@ ScriptTask::ScriptTask(const ScriptFunction::Ptr& function,
void ScriptTask::Run(void)
{
ScriptTask::Ptr self;
{
ObjectLock olock(this);
self = GetSelf();
}
m_Function->Invoke(self, m_Arguments);
m_Function->Invoke(GetSelf(), m_Arguments);
}

View File

@ -48,6 +48,8 @@ Socket::~Socket(void)
*/
void Socket::Start(void)
{
ObjectLock olock(this);
assert(!m_ReadThread.joinable() && !m_WriteThread.joinable());
assert(GetFD() != INVALID_SOCKET);
@ -68,6 +70,8 @@ void Socket::Start(void)
*/
void Socket::SetFD(SOCKET fd)
{
ObjectLock olock(this);
/* mark the socket as non-blocking and close-on-exec */
if (fd != INVALID_SOCKET) {
Utility::SetNonBlockingSocket(fd);
@ -86,27 +90,25 @@ void Socket::SetFD(SOCKET fd)
*/
SOCKET Socket::GetFD(void) const
{
ObjectLock olock(this);
return m_FD;
}
void Socket::CloseUnlocked(void)
{
if (m_FD == INVALID_SOCKET)
return;
closesocket(m_FD);
m_FD = INVALID_SOCKET;
Stream::Close();
}
/**
* Closes the socket.
*/
void Socket::Close(void)
{
boost::mutex::scoped_lock lock(m_SocketMutex);
CloseUnlocked();
ObjectLock olock(this);
if (m_FD == INVALID_SOCKET)
return;
closesocket(m_FD);
m_FD = INVALID_SOCKET;
Stream::Close();
}
/**
@ -146,6 +148,8 @@ int Socket::GetLastSocketError(void)
*/
void Socket::HandleException(void)
{
ObjectLock olock(this);
BOOST_THROW_EXCEPTION(SocketException("select() returned fd in except fdset", GetError()));
}
@ -271,7 +275,7 @@ void Socket::ReadThreadProc(void)
} catch (...) {
SetException(boost::current_exception());
CloseUnlocked();
Close();
break;
}
@ -326,7 +330,7 @@ void Socket::WriteThreadProc(void)
} catch (...) {
SetException(boost::current_exception());
CloseUnlocked();
Close();
break;
}
@ -340,6 +344,8 @@ void Socket::WriteThreadProc(void)
*/
void Socket::SetConnected(bool connected)
{
ObjectLock olock(this);
m_Connected = connected;
}
@ -350,6 +356,8 @@ void Socket::SetConnected(bool connected)
*/
bool Socket::IsConnected(void) const
{
ObjectLock olock(this);
return m_Connected;
}
@ -360,14 +368,12 @@ bool Socket::IsConnected(void) const
*/
size_t Socket::GetAvailableBytes(void) const
{
ObjectLock olock(this);
if (m_Listening)
throw new logic_error("Socket does not support GetAvailableBytes().");
{
boost::mutex::scoped_lock lock(m_QueueMutex);
return m_RecvQueue->GetAvailableBytes();
}
return m_RecvQueue->GetAvailableBytes();
}
/**
@ -379,11 +385,13 @@ size_t Socket::GetAvailableBytes(void) const
*/
size_t Socket::Read(void *buffer, size_t size)
{
ObjectLock olock(this);
if (m_Listening)
throw new logic_error("Socket does not support Read().");
{
boost::mutex::scoped_lock lock(m_QueueMutex);
ObjectLock olock(m_RecvQueue);
if (m_RecvQueue->GetAvailableBytes() == 0)
CheckException();
@ -401,11 +409,15 @@ size_t Socket::Read(void *buffer, size_t size)
*/
size_t Socket::Peek(void *buffer, size_t size)
{
if (m_Listening)
throw new logic_error("Socket does not support Peek().");
{
ObjectLock olock(this);
if (m_Listening)
throw new logic_error("Socket does not support Peek().");
}
{
boost::mutex::scoped_lock lock(m_QueueMutex);
ObjectLock olock(m_RecvQueue);
if (m_RecvQueue->GetAvailableBytes() == 0)
CheckException();
@ -422,14 +434,14 @@ size_t Socket::Peek(void *buffer, size_t size)
*/
void Socket::Write(const void *buffer, size_t size)
{
if (m_Listening)
throw new logic_error("Socket does not support Write().");
{
boost::mutex::scoped_lock lock(m_QueueMutex);
ObjectLock olock(this);
m_SendQueue->Write(buffer, size);
if (m_Listening)
throw new logic_error("Socket does not support Write().");
}
m_SendQueue->Write(buffer, size);
}
/**
@ -437,6 +449,8 @@ void Socket::Write(const void *buffer, size_t size)
*/
void Socket::Listen(void)
{
ObjectLock olock(this);
if (listen(GetFD(), SOMAXCONN) < 0)
BOOST_THROW_EXCEPTION(SocketException("listen() failed", GetError()));
@ -472,29 +486,17 @@ void Socket::HandleWritableClient(void)
SetConnected(true);
for (;;) {
{
boost::mutex::scoped_lock lock(m_QueueMutex);
count = m_SendQueue->Peek(data, sizeof(data));
count = m_SendQueue->GetAvailableBytes();
if (count == 0)
break;
if (count > sizeof(data))
count = sizeof(data);
m_SendQueue->Peek(data, count);
}
if (count == 0)
break;
rc = send(GetFD(), data, count, 0);
if (rc <= 0)
BOOST_THROW_EXCEPTION(SocketException("send() failed", GetError()));
{
boost::mutex::scoped_lock lock(m_QueueMutex);
m_SendQueue->Read(NULL, rc);
}
m_SendQueue->Read(NULL, rc);
}
}
@ -522,11 +524,7 @@ void Socket::HandleReadableClient(void)
if (rc <= 0)
BOOST_THROW_EXCEPTION(SocketException("recv() failed", GetError()));
{
boost::mutex::scoped_lock lock(m_QueueMutex);
m_RecvQueue->Write(data, rc);
}
m_RecvQueue->Write(data, rc);
new_data = true;
}
@ -603,12 +601,8 @@ bool Socket::WantsToReadClient(void) const
*/
bool Socket::WantsToWriteClient(void) const
{
{
boost::mutex::scoped_lock lock(m_QueueMutex);
if (m_SendQueue->GetAvailableBytes() > 0)
return true;
}
if (m_SendQueue->GetAvailableBytes() > 0)
return true;
return (!IsConnected());
}

View File

@ -83,7 +83,6 @@ private:
static String GetAddressFromSockaddr(sockaddr *address, socklen_t len);
mutable boost::mutex m_QueueMutex;
FIFO::Ptr m_SendQueue;
FIFO::Ptr m_RecvQueue;
@ -105,8 +104,6 @@ private:
bool WantsToWrite(void) const;
bool WantsToRead(void) const;
void CloseUnlocked(void);
};
/**

View File

@ -43,13 +43,21 @@ StdioStream::~StdioStream(void)
m_ReadAheadBuffer->Close();
}
/**
* @threadsafety Always.
*/
void StdioStream::Start(void)
{
ObjectLock olock(this);
SetConnected(true);
Stream::Start();
}
/**
* @threadsafety Always.
*/
size_t StdioStream::GetAvailableBytes(void) const
{
ObjectLock olock(this);
@ -60,6 +68,9 @@ size_t StdioStream::GetAvailableBytes(void) const
return 1024; /* doesn't have to be accurate */
}
/**
* @threadsafety Always.
*/
size_t StdioStream::Read(void *buffer, size_t size)
{
ObjectLock olock(this);
@ -75,6 +86,9 @@ size_t StdioStream::Read(void *buffer, size_t size)
return peek_len + read_len;
}
/**
* @threadsafety Always.
*/
size_t StdioStream::Peek(void *buffer, size_t size)
{
ObjectLock olock(this);
@ -91,6 +105,9 @@ size_t StdioStream::Peek(void *buffer, size_t size)
return peek_len + read_len;
}
/**
* @threadsafety Always.
*/
void StdioStream::Write(const void *buffer, size_t size)
{
ObjectLock olock(this);
@ -98,6 +115,9 @@ void StdioStream::Write(const void *buffer, size_t size)
m_InnerStream->write(static_cast<const char *>(buffer), size);
}
/**
* @threadsafety Always.
*/
void StdioStream::Close(void)
{
ObjectLock olock(this);

View File

@ -30,48 +30,81 @@ Stream::~Stream(void)
assert(!m_Running);
}
/**
* @threadsafety Always.
*/
bool Stream::IsConnected(void) const
{
ObjectLock olock(this);
return m_Connected;
}
/**
* @threadsafety Always.
*/
void Stream::SetConnected(bool connected)
{
m_Connected = connected;
{
ObjectLock olock(this);
m_Connected = connected;
}
if (m_Connected)
if (connected)
OnConnected(GetSelf());
else
OnClosed(GetSelf());
}
/**
* Checks whether an exception is available for this socket and re-throws
* Checks whether an exception is available for this stream and re-throws
* the exception if there is one.
*
* @threadsafety Always.
*/
void Stream::CheckException(void)
{
ObjectLock olock(this);
if (m_Exception)
rethrow_exception(m_Exception);
}
/**
* @threadsafety Always.
*/
void Stream::SetException(boost::exception_ptr exception)
{
ObjectLock olock(this);
m_Exception = exception;
}
/**
* @threadsafety Always.
*/
boost::exception_ptr Stream::GetException(void)
{
return m_Exception;
}
/**
* @threadsafety Always.
*/
void Stream::Start(void)
{
ObjectLock olock(this);
m_Running = true;
}
/**
* @threadsafety Always.
*/
void Stream::Close(void)
{
ObjectLock olock(this);
assert(m_Running);
m_Running = false;

View File

@ -49,11 +49,17 @@ typedef struct I2Stream_bio_s
boost::exception_ptr Exception;
} I2Stream_bio_t;
/**
* @threadsafety Always.
*/
BIO_METHOD *BIO_s_I2Stream(void)
{
return &I2Stream_method;
}
/**
* @threadsafety Always.
*/
BIO *icinga::BIO_new_I2Stream(const Stream::Ptr& stream)
{
BIO *bi = BIO_new(BIO_s_I2Stream());
@ -68,6 +74,9 @@ BIO *icinga::BIO_new_I2Stream(const Stream::Ptr& stream)
return bi;
}
/**
* @threadsafety Always.
*/
void icinga::I2Stream_check_exception(BIO *bi) {
I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr;
@ -78,6 +87,9 @@ void icinga::I2Stream_check_exception(BIO *bi) {
}
}
/**
* @threadsafety Always.
*/
static int I2Stream_new(BIO *bi)
{
bi->shutdown = 0;
@ -88,6 +100,9 @@ static int I2Stream_new(BIO *bi)
return 1;
}
/**
* @threadsafety Always.
*/
static int I2Stream_free(BIO *bi)
{
I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr;
@ -96,6 +111,9 @@ static int I2Stream_free(BIO *bi)
return 1;
}
/**
* @threadsafety Always.
*/
static int I2Stream_read(BIO *bi, char *out, int outl)
{
I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr;
@ -119,6 +137,9 @@ static int I2Stream_read(BIO *bi, char *out, int outl)
return data_read;
}
/**
* @threadsafety Always.
*/
static int I2Stream_write(BIO *bi, const char *in, int inl)
{
I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr;
@ -127,6 +148,9 @@ static int I2Stream_write(BIO *bi, const char *in, int inl)
return inl;
}
/**
* @threadsafety Always.
*/
static long I2Stream_ctrl(BIO *, int cmd, long, void *)
{
switch (cmd) {

View File

@ -48,6 +48,9 @@ StreamLogger::~StreamLogger(void)
delete m_Stream;
}
/**
* @threadsafety Always.
*/
void StreamLogger::OpenFile(const String& filename)
{
ofstream *stream = new ofstream();
@ -62,6 +65,8 @@ void StreamLogger::OpenFile(const String& filename)
throw;
}
ObjectLock olock(this);
m_Stream = stream;
m_OwnsStream = true;
m_Tty = false;
@ -73,6 +78,7 @@ void StreamLogger::OpenFile(const String& filename)
* @param stream The output stream.
* @param tty Whether the output stream is a TTY.
* @param entry The log entry.
* @threadsafety Always.
*/
void StreamLogger::ProcessLogEntry(ostream& stream, bool tty, const LogEntry& entry)
{
@ -107,12 +113,18 @@ void StreamLogger::ProcessLogEntry(ostream& stream, bool tty, const LogEntry& en
* Processes a log entry and outputs it to a stream.
*
* @param entry The log entry.
* @threadsafety Always.
*/
void StreamLogger::ProcessLogEntry(const LogEntry& entry)
{
ObjectLock olock(this);
ProcessLogEntry(*m_Stream, m_Tty, entry);
}
/**
* @threadsafety Always.
*/
bool StreamLogger::IsTty(ostream& stream)
{
#ifndef _WIN32

View File

@ -26,6 +26,7 @@ using namespace icinga;
* Processes a log entry and outputs it to syslog.
*
* @param entry The log entry.
* @threadsafety Always.
*/
void SyslogLogger::ProcessLogEntry(const LogEntry& entry)
{

View File

@ -38,6 +38,7 @@ void TcpSocket::Bind(String service, int family)
* @param node The node.
* @param service The service.
* @param family The address family for the socket.
* @threadsafety Always.
*/
void TcpSocket::Bind(String node, String service, int family)
{
@ -99,6 +100,7 @@ void TcpSocket::Bind(String node, String service, int family)
*
* @param node The node.
* @param service The service.
* @threadsafety Always.
*/
void TcpSocket::Connect(const String& node, const String& service)
{

View File

@ -42,6 +42,8 @@ TlsStream::TlsStream(const Stream::Ptr& innerStream, TlsRole role, shared_ptr<SS
void TlsStream::Start(void)
{
ObjectLock olock(this);
m_SSL = shared_ptr<SSL>(SSL_new(m_SSLContext.get()), SSL_free);
m_SSLContext.reset();
@ -88,6 +90,8 @@ void TlsStream::Start(void)
*/
shared_ptr<X509> TlsStream::GetClientCertificate(void) const
{
ObjectLock olock(this);
return shared_ptr<X509>(SSL_get_certificate(m_SSL.get()), &Utility::NullDeleter);
}
@ -98,6 +102,8 @@ shared_ptr<X509> TlsStream::GetClientCertificate(void) const
*/
shared_ptr<X509> TlsStream::GetPeerCertificate(void) const
{
ObjectLock olock(this);
return shared_ptr<X509>(SSL_get_peer_certificate(m_SSL.get()), X509_free);
}
@ -114,6 +120,8 @@ void TlsStream::DataAvailableHandler(void)
void TlsStream::ClosedHandler(void)
{
ObjectLock olock(this);
SetException(m_InnerStream->GetException());
Close();
}
@ -123,6 +131,9 @@ void TlsStream::ClosedHandler(void)
*/
void TlsStream::HandleIO(void)
{
assert(!OwnsLock());
ObjectLock olock(this);
char data[16 * 1024];
int rc;
@ -172,8 +183,11 @@ void TlsStream::HandleIO(void)
}
}
if (new_data)
if (new_data) {
olock.Unlock();
OnDataAvailable(GetSelf());
olock.Lock();
}
while (m_SendQueue->GetAvailableBytes() > 0) {
size_t count = m_SendQueue->GetAvailableBytes();
@ -212,6 +226,8 @@ void TlsStream::HandleIO(void)
*/
void TlsStream::Close(void)
{
ObjectLock olock(this);
if (m_SSL)
SSL_shutdown(m_SSL.get());
@ -223,22 +239,32 @@ void TlsStream::Close(void)
size_t TlsStream::GetAvailableBytes(void) const
{
ObjectLock olock(this);
return m_RecvQueue->GetAvailableBytes();
}
size_t TlsStream::Peek(void *buffer, size_t count)
{
ObjectLock olock(this);
return m_RecvQueue->Peek(buffer, count);
}
size_t TlsStream::Read(void *buffer, size_t count)
{
ObjectLock olock(this);
return m_RecvQueue->Read(buffer, count);
}
void TlsStream::Write(const void *buffer, size_t count)
{
m_SendQueue->Write(buffer, count);
{
ObjectLock olock(this);
m_SendQueue->Write(buffer, count);
}
HandleIO();
}

View File

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

View File

@ -50,6 +50,8 @@ ConfigItem::ConfigItem(const String& type, const String& name,
*/
String ConfigItem::GetType(void) const
{
ObjectLock olock(this);
return m_Type;
}
@ -60,6 +62,8 @@ String ConfigItem::GetType(void) const
*/
String ConfigItem::GetName(void) const
{
ObjectLock olock(this);
return m_Name;
}
@ -70,6 +74,8 @@ String ConfigItem::GetName(void) const
*/
String ConfigItem::GetUnit(void) const
{
ObjectLock olock(this);
return m_Unit;
}
@ -80,6 +86,8 @@ String ConfigItem::GetUnit(void) const
*/
DebugInfo ConfigItem::GetDebugInfo(void) const
{
ObjectLock olock(this);
return m_DebugInfo;
}
@ -90,6 +98,8 @@ DebugInfo ConfigItem::GetDebugInfo(void) const
*/
ExpressionList::Ptr ConfigItem::GetExpressionList(void) const
{
ObjectLock olock(this);
return m_ExpressionList;
}
@ -100,11 +110,15 @@ ExpressionList::Ptr ConfigItem::GetExpressionList(void) const
*/
vector<String> ConfigItem::GetParents(void) const
{
ObjectLock olock(this);
return m_Parents;
}
set<ConfigItem::WeakPtr> ConfigItem::GetChildren(void) const
{
ObjectLock olock(this);
return m_ChildObjects;
}
@ -124,6 +138,8 @@ Dictionary::Ptr ConfigItem::Link(void) const
*/
void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
{
ObjectLock olock(this);
BOOST_FOREACH(const String& name, m_Parents) {
ConfigItem::Ptr parent;
@ -157,66 +173,67 @@ void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
*
* @returns The DynamicObject that was created/updated.
*/
DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
DynamicObject::Ptr ConfigItem::Commit(void)
{
assert(!OwnsLock());
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);
Logger::Write(LogDebug, "base", "Commit called for ConfigItem Type=" + GetType() + ", Name=" + GetName());
/* Make sure the type is valid. */
DynamicType::Ptr dtype = DynamicType::GetByName(type);
DynamicType::Ptr dtype = DynamicType::GetByName(GetType());
if (!dtype)
BOOST_THROW_EXCEPTION(runtime_error("Type '" + type + "' does not exist."));
BOOST_THROW_EXCEPTION(runtime_error("Type '" + GetType() + "' does not exist."));
/* Try to find an existing item with the same type and name. */
pair<String, String> ikey = make_pair(GetType(), GetName());
ConfigItem::Ptr oldItem;
{
recursive_mutex::scoped_lock lock(m_Mutex);
/* Try to find an existing item with the same type and name. */
pair<String, String> ikey = make_pair(type, name);
ItemMap::iterator it = m_Items.find(ikey);
set<ConfigItem::WeakPtr> children;
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 (it != m_Items.end())
oldItem = it->second;
}
set<ConfigItem::WeakPtr> children;
if (oldItem) {
ObjectLock olock(oldItem);
/* Unregister the old item from its parents. */
oldItem->UnregisterFromParents();
/* Steal the old item's children. */
children = oldItem->GetChildren();
}
{
ObjectLock olock(this);
m_ChildObjects = children;
}
{
recursive_mutex::scoped_lock lock(m_Mutex);
/* Register this item. */
m_Items[ikey] = GetSelf();
}
DynamicObject::Ptr dobj = GetDynamicObject();
if (!dobj)
dobj = dtype->GetObject(name);
dobj = dtype->GetObject(GetName());
/* Register this item with its parents. */
BOOST_FOREACH(const String& parentName, parents) {
ConfigItem::Ptr parent = GetObject(type, parentName);
BOOST_FOREACH(const String& parentName, GetParents()) {
ConfigItem::Ptr parent = GetObject(GetType(), parentName);
ObjectLock olock(parent);
parent->RegisterChild(self);
parent->RegisterChild(GetSelf());
}
/* Create a fake update in the format that
@ -225,6 +242,8 @@ DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
double tx = DynamicObject::GetCurrentTx();
Dictionary::Ptr properties = Link();
{
ObjectLock olock(properties);
@ -256,29 +275,20 @@ DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
was_null = true;
}
{
ObjectLock olock(dobj);
if (!was_null)
dobj->ApplyUpdate(update, Attribute_Config);
self->m_DynamicObject = dobj;
if (dobj->IsAbstract())
dobj->Unregister();
else
dobj->Register();
}
/* We need to make a copy of the child objects because the
* OnParentCommitted() handler is going to update the list. */
set<ConfigItem::WeakPtr> children;
if (!was_null)
dobj->ApplyUpdate(update, Attribute_Config);
{
ObjectLock olock(self);
children = self->m_ChildObjects;
ObjectLock olock(this);
m_DynamicObject = dobj;
}
if (dobj->IsAbstract())
dobj->Unregister();
else
dobj->Register();
/* notify our children of the update */
BOOST_FOREACH(const ConfigItem::WeakPtr wchild, children) {
const ConfigItem::Ptr& child = wchild.lock();
@ -289,7 +299,7 @@ DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
child->OnParentCommitted();
}
OnCommitted(self);
OnCommitted(GetSelf());
return dobj;
}
@ -299,19 +309,23 @@ DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
*/
void ConfigItem::Unregister(void)
{
DynamicObject::Ptr dobj = m_DynamicObject.lock();
assert(!OwnsLock());
if (dobj) {
ObjectLock olock(dobj);
DynamicObject::Ptr dobj = GetDynamicObject();
if (dobj)
dobj->Unregister();
{
ObjectLock olock(this);
ConfigItem::ItemMap::iterator it;
it = m_Items.find(make_pair(GetType(), GetName()));
if (it != m_Items.end())
m_Items.erase(it);
}
ConfigItem::ItemMap::iterator it;
it = m_Items.find(make_pair(GetType(), GetName()));
if (it != m_Items.end())
m_Items.erase(it);
UnregisterFromParents();
OnRemoved(GetSelf());
@ -319,23 +333,27 @@ void ConfigItem::Unregister(void)
void ConfigItem::RegisterChild(const ConfigItem::Ptr& child)
{
ObjectLock olock(this);
m_ChildObjects.insert(child);
}
void ConfigItem::UnregisterChild(const ConfigItem::Ptr& child)
{
ObjectLock olock(this);
m_ChildObjects.erase(child);
}
void ConfigItem::UnregisterFromParents(void)
{
ObjectLock olock(this);
BOOST_FOREACH(const String& parentName, m_Parents) {
ConfigItem::Ptr parent = GetObject(GetType(), parentName);
if (parent) {
ObjectLock olock(parent);
if (parent)
parent->UnregisterChild(GetSelf());
}
}
}
@ -344,6 +362,8 @@ void ConfigItem::UnregisterFromParents(void)
*/
void ConfigItem::OnParentCommitted(void)
{
assert(!OwnsLock());
ConfigItem::Ptr self;
{
@ -354,7 +374,7 @@ void ConfigItem::OnParentCommitted(void)
return;
}
Commit(self);
Commit();
}
/**
@ -364,6 +384,8 @@ void ConfigItem::OnParentCommitted(void)
*/
DynamicObject::Ptr ConfigItem::GetDynamicObject(void) const
{
ObjectLock olock(this);
return m_DynamicObject.lock();
}
@ -397,6 +419,8 @@ ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& name)
*/
void ConfigItem::Dump(ostream& fp) const
{
ObjectLock olock(this);
fp << "object \"" << m_Type << "\" \"" << m_Name << "\"";
if (m_Parents.size() > 0) {
@ -440,7 +464,6 @@ void ConfigItem::UnloadUnit(const String& unit)
}
BOOST_FOREACH(const ConfigItem::Ptr& item, obsoleteItems) {
ObjectLock olock(item);
item->Unregister();
}
}

View File

@ -47,7 +47,7 @@ public:
ExpressionList::Ptr GetExpressionList(void) const;
static DynamicObject::Ptr Commit(const ConfigItem::Ptr& self);
DynamicObject::Ptr Commit(void);
void Unregister(void);
void Dump(ostream& fp) const;

View File

@ -35,8 +35,5 @@ void API::GetAnswerToEverything(const ScriptTask::Ptr& task, const vector<Value>
Logger::Write(LogInformation, "icinga", "Hello from the Icinga 2 API: " + text);
{
ObjectLock olock(task);
task->FinishResult(42);
}
task->FinishResult(42);
}

View File

@ -44,4 +44,3 @@ void CheckResultMessage::SetCheckResult(const Dictionary::Ptr& result)
{
Set("check_result", result);
}

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(host);
Service::Ptr hc = host->GetHostCheckService();
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(host);
Service::Ptr hc = host->GetHostCheckService();
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(host);
Service::Ptr hc = host->GetHostCheckService();
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(host);
Service::Ptr hc = host->GetHostCheckService();
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(host);
Service::Ptr hc = host->GetHostCheckService();
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(host);
Service::Ptr service = host->GetHostCheckService();
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(host);
Service::Ptr service = host->GetHostCheckService();
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(host);
Service::Ptr service = host->GetHostCheckService();
if (service) {
service->ClearAcknowledgement();
}
@ -504,7 +504,7 @@ void ExternalCommandProcessor::EnableHostgroupSvcChecks(double, const vector<Str
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Enabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(true);
@ -519,7 +519,7 @@ void ExternalCommandProcessor::DisableHostgroupSvcChecks(double, const vector<St
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Disabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(false);
@ -534,7 +534,7 @@ void ExternalCommandProcessor::EnableServicegroupSvcChecks(double, const vector<
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Enabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(true);
}
@ -547,7 +547,7 @@ void ExternalCommandProcessor::DisableServicegroupSvcChecks(double, const vector
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Disabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(false);
}
@ -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(host);
Service::Ptr hc = host->GetHostCheckService();
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(host);
Service::Ptr hc = host->GetHostCheckService();
if (hc)
hc->SetEnablePassiveChecks(false);
@ -610,7 +610,7 @@ void ExternalCommandProcessor::EnableServicegroupPassiveSvcChecks(double, const
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Enabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(true);
}
@ -623,7 +623,7 @@ void ExternalCommandProcessor::DisableServicegroupPassiveSvcChecks(double, const
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Disabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(true);
}
@ -636,7 +636,7 @@ void ExternalCommandProcessor::EnableHostgroupPassiveSvcChecks(double, const vec
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Enabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(true);
@ -651,7 +651,7 @@ void ExternalCommandProcessor::DisableHostgroupPassiveSvcChecks(double, const ve
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Disabling passive checks for service '" + service->GetName() + "'");
service->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(host);
Service::Ptr service = host->GetHostCheckService();
if (service) {
(void) service->AddDowntime(arguments[6], arguments[7],
Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]),
@ -786,9 +786,9 @@ void ExternalCommandProcessor::ScheduleHostgroupHostDowntime(double, const vecto
if (triggeredByLegacy != 0)
triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy);
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Creating downtime for host " + host->GetName());
Service::Ptr service = Host::GetHostCheckService(host);
Service::Ptr service = host->GetHostCheckService();
if (service) {
(void) service->AddDowntime(arguments[6], arguments[7],
Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]),
@ -815,7 +815,7 @@ void ExternalCommandProcessor::ScheduleHostgroupSvcDowntime(double, const vector
set<Service::Ptr> services;
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) {
BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
services.insert(service);
}
@ -847,9 +847,9 @@ void ExternalCommandProcessor::ScheduleServicegroupHostDowntime(double, const ve
set<Service::Ptr> services;
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Host::Ptr host = service->GetHost();
Service::Ptr hcService = Host::GetHostCheckService(host);
Service::Ptr hcService = host->GetHostCheckService();
if (hcService)
services.insert(hcService);
}
@ -874,7 +874,7 @@ void ExternalCommandProcessor::ScheduleServicegroupSvcDowntime(double, const vec
if (triggeredByLegacy != 0)
triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy);
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) {
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Creating downtime for service " + service->GetName());
(void) service->AddDowntime(arguments[6], arguments[7],
Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]),
@ -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(host);
Service::Ptr service = host->GetHostCheckService();
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(host);
Service::Ptr service = host->GetHostCheckService();
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(host);
Service::Ptr service = host->GetHostCheckService();
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(host);
Service::Ptr service = host->GetHostCheckService();
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(host);
Service::Ptr hc = host->GetHostCheckService();
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(host);
Service::Ptr hc = host->GetHostCheckService();
if (hc)
hc->SetEnableNotifications(false);

View File

@ -55,14 +55,18 @@ Host::~Host(void)
void Host::OnRegistrationCompleted(void)
{
assert(!OwnsLock());
DynamicObject::OnRegistrationCompleted();
Host::InvalidateServicesCache();
Host::UpdateSlaveServices(GetSelf());
UpdateSlaveServices();
}
String Host::GetDisplayName(void) const
{
ObjectLock olock(this);
if (!m_DisplayName.IsEmpty())
return m_DisplayName;
else
@ -81,32 +85,44 @@ Host::Ptr Host::GetByName(const String& name)
Dictionary::Ptr Host::GetGroups(void) const
{
ObjectLock olock(this);
return m_HostGroups;;
}
Dictionary::Ptr Host::GetMacros(void) const
{
ObjectLock olock(this);
return m_Macros;
}
Dictionary::Ptr Host::GetHostDependencies(void) const
{
ObjectLock olock(this);
return m_HostDependencies;;
}
Dictionary::Ptr Host::GetServiceDependencies(void) const
{
ObjectLock olock(this);
return m_ServiceDependencies;
}
String Host::GetHostCheck(void) const
{
ObjectLock olock(this);
return m_HostCheck;
}
bool Host::IsReachable(const Host::Ptr& self)
bool Host::IsReachable(void) const
{
set<Service::Ptr> parentServices = Host::GetParentServices(self);
assert(!OwnsLock());
set<Service::Ptr> parentServices = GetParentServices();
BOOST_FOREACH(const Service::Ptr& service, parentServices) {
ObjectLock olock(service);
@ -127,14 +143,19 @@ bool Host::IsReachable(const Host::Ptr& self)
return false;
}
set<Host::Ptr> parentHosts = Host::GetParentHosts(self);
set<Host::Ptr> parentHosts = GetParentHosts();
BOOST_FOREACH(const Host::Ptr& host, parentHosts) {
Service::Ptr hc = Host::GetHostCheckService(host);
Service::Ptr hc = GetHostCheckService();
/* ignore hosts that don't have a hostcheck */
if (!hc)
continue;
ObjectLock olock(hc);
/* ignore hosts that are up */
if (hc && hc->GetState() == StateOK)
if (hc->GetState() == StateOK)
continue;
return false;
@ -190,37 +211,21 @@ static void CopyServiceAttributes(TDict serviceDesc, const ConfigItemBuilder::Pt
}
}
void Host::UpdateSlaveServices(const Host::Ptr& self)
void Host::UpdateSlaveServices(void)
{
ConfigItem::Ptr item;
Dictionary::Ptr oldServices, newServices, serviceDescs;
String host_name;
assert(!OwnsLock());
{
ObjectLock olock(self);
ConfigItem::Ptr item = ConfigItem::GetObject("Host", GetName());
host_name = self->GetName();
/* Don't create slave services unless we own this object
* and it's not a template. */
if (!item || IsAbstract())
return;
item = ConfigItem::GetObject("Host", host_name);
Dictionary::Ptr oldServices = m_SlaveServices;
Dictionary::Ptr serviceDescs = Get("services");
/* Don't create slave services unless we own this object
* and it's not a template. */
if (!item || self->IsAbstract())
return;
oldServices = self->m_SlaveServices;
serviceDescs = self->Get("services");
}
newServices = boost::make_shared<Dictionary>();
ObjectLock nlock(newServices);
DebugInfo debug_info;
{
ObjectLock olock(item);
debug_info = item->GetDebugInfo();
}
Dictionary::Ptr newServices = boost::make_shared<Dictionary>();
if (serviceDescs) {
ObjectLock olock(serviceDescs);
@ -231,17 +236,17 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
svcname = svcdesc;
stringstream namebuf;
namebuf << host_name << "-" << svcname;
namebuf << GetName() << "-" << svcname;
String name = namebuf.str();
ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(debug_info);
ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(item->GetDebugInfo());
builder->SetType("Service");
builder->SetName(name);
builder->AddExpression("host_name", OperatorSet, host_name);
builder->AddExpression("host_name", OperatorSet, GetName());
builder->AddExpression("display_name", OperatorSet, svcname);
builder->AddExpression("short_name", OperatorSet, svcname);
CopyServiceAttributes<false>(self, builder);
CopyServiceAttributes<false>(this, builder);
if (svcdesc.IsScalar()) {
builder->AddParent(svcdesc);
@ -272,7 +277,7 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
}
ConfigItem::Ptr serviceItem = builder->Compile();
DynamicObject::Ptr dobj = ConfigItem::Commit(serviceItem);
DynamicObject::Ptr dobj = serviceItem->Commit();
newServices->Set(name, serviceItem);
}
@ -293,23 +298,18 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
newServices->Seal();
ObjectLock olock(self);
self->Set("slave_services", newServices);
ObjectLock olock(this);
Set("slave_services", newServices);
}
void Host::OnAttributeChanged(const String& name, const Value&)
{
assert(!OwnsLock());
if (name == "hostgroups")
HostGroup::InvalidateMembersCache();
else if (name == "services") {
Host::Ptr self;
{
ObjectLock olock(this);
self = GetSelf();
}
UpdateSlaveServices(self);
UpdateSlaveServices();
} else if (name == "notifications") {
set<Service::Ptr> services;
@ -450,20 +450,13 @@ void Host::ValidateServiceDictionary(const ScriptTask::Ptr& task, const vector<V
task->FinishResult(Empty);
}
Service::Ptr Host::GetServiceByShortName(const Host::Ptr& self, const Value& name)
Service::Ptr Host::GetServiceByShortName(const Value& name) const
{
String host_name;
{
ObjectLock olock(self);
host_name = self->GetName();
}
if (name.IsScalar()) {
{
boost::mutex::scoped_lock lock(m_ServiceMutex);
map<String, Service::WeakPtr>& services = m_ServicesCache[host_name];
map<String, Service::WeakPtr>& services = m_ServicesCache[GetName()];
map<String, Service::WeakPtr>::iterator it = services.find(name);
if (it != services.end()) {
@ -478,35 +471,26 @@ Service::Ptr Host::GetServiceByShortName(const Host::Ptr& self, const Value& nam
Dictionary::Ptr dict = name;
String short_name;
{
ObjectLock olock(dict);
host_name = dict->Get("host");
short_name = dict->Get("service");
}
assert(dict->IsSealed());
return Service::GetByNamePair(host_name, short_name);
return Service::GetByNamePair(dict->Get("host"), dict->Get("service"));
} else {
BOOST_THROW_EXCEPTION(invalid_argument("Host/Service name pair is invalid."));
}
}
set<Host::Ptr> Host::GetParentHosts(const Host::Ptr& self)
set<Host::Ptr> Host::GetParentHosts(void) const
{
set<Host::Ptr> parents;
Dictionary::Ptr dependencies;
String host_name;
{
ObjectLock olock(self);
dependencies = self->GetHostDependencies();
host_name = self->GetName();
}
Dictionary::Ptr dependencies = GetHostDependencies();
if (dependencies) {
ObjectLock olock(dependencies);
Value value;
BOOST_FOREACH(tie(tuples::ignore, value), dependencies) {
if (value == host_name)
if (value == GetName())
continue;
Host::Ptr host = GetByName(value);
@ -521,60 +505,52 @@ set<Host::Ptr> Host::GetParentHosts(const Host::Ptr& self)
return parents;
}
Service::Ptr Host::GetHostCheckService(const Host::Ptr& self)
Service::Ptr Host::GetHostCheckService(void) const
{
String host_check;
{
ObjectLock olock(self);
host_check = self->GetHostCheck();
}
String host_check = GetHostCheck();
if (host_check.IsEmpty())
return Service::Ptr();
return GetServiceByShortName(self, host_check);
return GetServiceByShortName(host_check);
}
set<Service::Ptr> Host::GetParentServices(const Host::Ptr& self)
set<Service::Ptr> Host::GetParentServices(void) const
{
set<Service::Ptr> parents;
Dictionary::Ptr dependencies;
{
ObjectLock olock(self);
dependencies = self->GetServiceDependencies();
}
Dictionary::Ptr dependencies = GetServiceDependencies();
if (dependencies) {
ObjectLock olock(dependencies);
Value value;
BOOST_FOREACH(tie(tuples::ignore, value), dependencies) {
parents.insert(GetServiceByShortName(self, value));
parents.insert(GetServiceByShortName(value));
}
}
return parents;
}
Dictionary::Ptr Host::CalculateDynamicMacros(const Host::Ptr& self)
Dictionary::Ptr Host::CalculateDynamicMacros(void) const
{
assert(!OwnsLock());
Dictionary::Ptr macros = boost::make_shared<Dictionary>();
ObjectLock mlock(macros);
{
ObjectLock olock(self);
ObjectLock olock(this);
macros->Set("HOSTNAME", self->GetName());
macros->Set("HOSTDISPLAYNAME", self->GetDisplayName());
macros->Set("HOSTALIAS", self->GetName());
macros->Set("HOSTNAME", GetName());
macros->Set("HOSTDISPLAYNAME", GetDisplayName());
macros->Set("HOSTALIAS", GetName());
}
bool reachable = Host::IsReachable(self);
Dictionary::Ptr cr;
Service::Ptr hc = Host::GetHostCheckService(self);
Service::Ptr hc = GetHostCheckService();
if (hc) {
ObjectLock olock(hc);
@ -594,7 +570,7 @@ Dictionary::Ptr Host::CalculateDynamicMacros(const Host::Ptr& self)
break;
}
if (!reachable) {
if (!IsReachable()) {
state = "UNREACHABLE";
stateid = 2;
}

View File

@ -49,15 +49,15 @@ public:
Dictionary::Ptr GetServiceDependencies(void) const;
String GetHostCheck(void) const;
static Dictionary::Ptr CalculateDynamicMacros(const Host::Ptr& self);
Dictionary::Ptr CalculateDynamicMacros(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);
shared_ptr<Service> GetHostCheckService(void) const;
set<Host::Ptr> GetParentHosts(void) const;
set<shared_ptr<Service> > GetParentServices(void) const;
static bool IsReachable(const Host::Ptr& self);
bool IsReachable() const;
static shared_ptr<Service> GetServiceByShortName(const Host::Ptr& self, const Value& name);
shared_ptr<Service> GetServiceByShortName(const Value& name) const;
set<shared_ptr<Service> > GetServices(void) const;
static void InvalidateServicesCache(void);
@ -82,7 +82,7 @@ private:
static map<String, map<String, weak_ptr<Service> > > m_ServicesCache;
static bool m_ServicesCacheValid;
static void UpdateSlaveServices(const Host::Ptr& self);
void UpdateSlaveServices(void);
static void RefreshServicesCache(void);
};

View File

@ -40,26 +40,46 @@ HostGroup::~HostGroup(void)
InvalidateMembersCache();
}
/**
* @threadsafety Always.
*/
void HostGroup::OnRegistrationCompleted(void)
{
assert(!OwnsLock());
InvalidateMembersCache();
}
/**
* @threadsafety Always.
*/
String HostGroup::GetDisplayName(void) const
{
ObjectLock olock(this);
if (!m_DisplayName.IsEmpty())
return m_DisplayName;
else
return GetName();
}
/**
* @threadsafety Always.
*/
String HostGroup::GetNotesUrl(void) const
{
ObjectLock olock(this);
return m_NotesUrl;
}
/**
* @threadsafety Always.
*/
String HostGroup::GetActionUrl(void) const
{
ObjectLock olock(this);
return m_ActionUrl;
}
@ -76,21 +96,17 @@ HostGroup::Ptr HostGroup::GetByName(const String& name)
return dynamic_pointer_cast<HostGroup>(configObject);
}
set<Host::Ptr> HostGroup::GetMembers(const HostGroup::Ptr& self)
/**
* @threadsafety Always.
*/
set<Host::Ptr> HostGroup::GetMembers(void) const
{
String name;
{
ObjectLock olock(self);
name = self->GetName();
}
set<Host::Ptr> hosts;
{
boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const Host::WeakPtr& whost, m_MembersCache[name]) {
BOOST_FOREACH(const Host::WeakPtr& whost, m_MembersCache[GetName()]) {
Host::Ptr host = whost.lock();
if (!host)
@ -103,18 +119,22 @@ set<Host::Ptr> HostGroup::GetMembers(const HostGroup::Ptr& self)
return hosts;
}
/**
* @threadsafety Always.
*/
void HostGroup::InvalidateMembersCache(void)
{
{
boost::mutex::scoped_lock lock(m_Mutex);
boost::mutex::scoped_lock lock(m_Mutex);
if (m_MembersCacheValid)
Utility::QueueAsyncCallback(boost::bind(&HostGroup::RefreshMembersCache));
if (m_MembersCacheValid)
Utility::QueueAsyncCallback(boost::bind(&HostGroup::RefreshMembersCache));
m_MembersCacheValid = false;
}
m_MembersCacheValid = false;
}
/**
* @threadsafety Always.
*/
void HostGroup::RefreshMembersCache(void)
{
{

View File

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

View File

@ -85,13 +85,24 @@ int IcingaApplication::Main(void)
return EXIT_SUCCESS;
}
/**
* @threadsafety Always.
*/
void IcingaApplication::OnShutdown(void)
{
m_RetentionTimer->Stop();
assert(!OwnsLock());
{
ObjectLock olock(this);
m_RetentionTimer->Stop();
}
DumpProgramState();
}
/**
* @threadsafety Always.
*/
void IcingaApplication::DumpProgramState(void)
{
DynamicObject::DumpObjects(GetStatePath());
@ -102,58 +113,106 @@ IcingaApplication::Ptr IcingaApplication::GetInstance(void)
return static_pointer_cast<IcingaApplication>(Application::GetInstance());
}
/**
* @threadsafety Always.
*/
String IcingaApplication::GetCertificateFile(void) const
{
ObjectLock olock(this);
return m_CertPath;
}
/**
* @threadsafety Always.
*/
String IcingaApplication::GetCAFile(void) const
{
ObjectLock olock(this);
return m_CAPath;
}
/**
* @threadsafety Always.
*/
String IcingaApplication::GetNode(void) const
{
ObjectLock olock(this);
return m_Node;
}
/**
* @threadsafety Always.
*/
String IcingaApplication::GetService(void) const
{
ObjectLock olock(this);
return m_Service;
}
/**
* @threadsafety Always.
*/
String IcingaApplication::GetPidPath(void) const
{
ObjectLock olock(this);
if (m_PidPath.IsEmpty())
return Application::GetLocalStateDir() + "/run/icinga2.pid";
else
return m_PidPath;
}
/**
* @threadsafety Always.
*/
String IcingaApplication::GetStatePath(void) const
{
ObjectLock olock(this);
if (m_PidPath.IsEmpty())
return Application::GetLocalStateDir() + "/lib/icinga2/icinga2.state";
else
return m_PidPath;
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr IcingaApplication::GetMacros(void) const
{
ObjectLock olock(this);
return m_Macros;
}
/**
* @threadsafety Always.
*/
double IcingaApplication::GetStartTime(void) const
{
ObjectLock olock(this);
return m_StartTime;
}
/**
* @threadsafety Always.
*/
shared_ptr<SSL_CTX> IcingaApplication::GetSSLContext(void) const
{
ObjectLock olock(this);
return m_SSLContext;
}
Dictionary::Ptr IcingaApplication::CalculateDynamicMacros(const IcingaApplication::Ptr& self)
/**
* @threadsafety Always.
*/
Dictionary::Ptr IcingaApplication::CalculateDynamicMacros(void)
{
Dictionary::Ptr macros = boost::make_shared<Dictionary>();
ObjectLock mlock(macros);

View File

@ -51,7 +51,7 @@ public:
double GetStartTime(void) const;
static Dictionary::Ptr CalculateDynamicMacros(const IcingaApplication::Ptr& self);
static Dictionary::Ptr CalculateDynamicMacros(void);
private:
Attribute<String> m_CertPath;

View File

@ -21,10 +21,15 @@
using namespace icinga;
/**
* @threadsafety Always.
*/
Value MacroProcessor::ResolveMacros(const Value& cmd, const Dictionary::Ptr& macros)
{
Value result;
assert(macros->IsSealed());
if (cmd.IsScalar()) {
result = InternalResolveMacros(cmd, macros);
} else if (cmd.IsObjectType<Dictionary>()) {
@ -46,6 +51,9 @@ Value MacroProcessor::ResolveMacros(const Value& cmd, const Dictionary::Ptr& mac
return result;
}
/**
* @threadsafety Always.
*/
String MacroProcessor::InternalResolveMacros(const String& str, const Dictionary::Ptr& macros)
{
ObjectLock olock(macros);
@ -73,6 +81,9 @@ String MacroProcessor::InternalResolveMacros(const String& str, const Dictionary
return result;
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr MacroProcessor::MergeMacroDicts(const vector<Dictionary::Ptr>& dicts)
{
Dictionary::Ptr result = boost::make_shared<Dictionary>();

View File

@ -39,6 +39,9 @@ Notification::~Notification(void)
Service::InvalidateNotificationsCache();
}
/**
* @threadsafety Always.
*/
Notification::Ptr Notification::GetByName(const String& name)
{
DynamicObject::Ptr configObject = DynamicObject::GetObject("Notification", name);
@ -46,34 +49,57 @@ Notification::Ptr Notification::GetByName(const String& name)
return dynamic_pointer_cast<Notification>(configObject);
}
/**
* @threadsafety Always.
*/
Service::Ptr Notification::GetService(void) const
{
ObjectLock olock(this);
Host::Ptr host = Host::GetByName(m_HostName);
if (!host)
return Service::Ptr();
if (m_Service.IsEmpty())
return Host::GetHostCheckService(host);
return host->GetHostCheckService();
else
return Host::GetServiceByShortName(host, m_Service);
return host->GetServiceByShortName(m_Service);
}
/**
* @threadsafety Always.
*/
Value Notification::GetNotificationCommand(void) const
{
ObjectLock olock(this);
return m_NotificationCommand;
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Notification::GetMacros(void) const
{
ObjectLock olock(this);
return m_Macros;
}
/**
* @threadsafety Always.
*/
set<User::Ptr> Notification::GetUsers(void) const
{
set<User::Ptr> result;
Dictionary::Ptr users = m_Users;
Dictionary::Ptr users;
{
ObjectLock olock(this);
users = m_Users;
}
if (users) {
ObjectLock olock(users);
@ -92,11 +118,19 @@ set<User::Ptr> Notification::GetUsers(void) const
return result;
}
/**
* @threadsafety Always.
*/
set<UserGroup::Ptr> Notification::GetGroups(void) const
{
set<UserGroup::Ptr> result;
Dictionary::Ptr groups = m_Groups;
Dictionary::Ptr groups;
{
ObjectLock olock(this);
groups = m_Groups;
}
if (groups) {
ObjectLock olock(groups);
@ -115,6 +149,9 @@ set<UserGroup::Ptr> Notification::GetGroups(void) const
return result;
}
/**
* @threadsafety Always.
*/
String Notification::NotificationTypeToString(NotificationType type)
{
switch (type) {
@ -137,8 +174,12 @@ String Notification::NotificationTypeToString(NotificationType type)
}
}
void Notification::BeginExecuteNotification(const Notification::Ptr& self, NotificationType type)
/**
* @threadsafety Always.
*/
void Notification::BeginExecuteNotification(NotificationType type)
{
assert(!OwnsLock());
vector<Dictionary::Ptr> macroDicts;
@ -146,53 +187,36 @@ void Notification::BeginExecuteNotification(const Notification::Ptr& self, Notif
notificationMacros->Set("NOTIFICATIONTYPE", NotificationTypeToString(type));
macroDicts.push_back(notificationMacros);
Service::Ptr service;
set<User::Ptr> users;
set<UserGroup::Ptr> groups;
macroDicts.push_back(GetMacros());
{
ObjectLock olock(self);
macroDicts.push_back(self->GetMacros());
service = self->GetService();
users = self->GetUsers();
groups = self->GetGroups();
}
Service::Ptr service = GetService();
Host::Ptr host;
String service_name;
{
ObjectLock olock(service);
if (service) {
macroDicts.push_back(service->GetMacros());
service_name = service->GetName();
host = service->GetHost();
}
macroDicts.push_back(service->CalculateDynamicMacros());
macroDicts.push_back(Service::CalculateDynamicMacros(service));
Host::Ptr host = service->GetHost();
{
ObjectLock olock(host);
macroDicts.push_back(host->GetMacros());
macroDicts.push_back(Host::CalculateDynamicMacros(host));
if (host) {
macroDicts.push_back(host->GetMacros());
macroDicts.push_back(host->CalculateDynamicMacros());
}
}
IcingaApplication::Ptr app = IcingaApplication::GetInstance();
macroDicts.push_back(app->GetMacros());
{
ObjectLock olock(app);
macroDicts.push_back(app->GetMacros());
}
macroDicts.push_back(IcingaApplication::CalculateDynamicMacros(app));
macroDicts.push_back(IcingaApplication::CalculateDynamicMacros());
Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
set<User::Ptr> allUsers;
set<User::Ptr> users = GetUsers();
std::copy(users.begin(), users.end(), std::inserter(allUsers, allUsers.begin()));
BOOST_FOREACH(const UserGroup::Ptr& ug, groups) {
set<User::Ptr> members = UserGroup::GetMembers(ug);
BOOST_FOREACH(const UserGroup::Ptr& ug, GetGroups()) {
set<User::Ptr> members = ug->GetMembers();
std::copy(members.begin(), members.end(), std::inserter(allUsers, allUsers.begin()));
}
@ -205,58 +229,66 @@ void Notification::BeginExecuteNotification(const Notification::Ptr& self, Notif
}
Logger::Write(LogDebug, "icinga", "Sending notification for user " + user_name);
BeginExecuteNotificationHelper(self, macros, type, user);
BeginExecuteNotificationHelper(macros, type, user);
}
if (allUsers.size() == 0) {
/* Send a notification even if there are no users specified. */
BeginExecuteNotificationHelper(self, macros, type, User::Ptr());
BeginExecuteNotificationHelper(macros, type, User::Ptr());
}
}
void Notification::BeginExecuteNotificationHelper(const Notification::Ptr& self, const Dictionary::Ptr& notificationMacros, NotificationType type, const User::Ptr& user)
/**
* @threadsafety Always.
*/
void Notification::BeginExecuteNotificationHelper(const Dictionary::Ptr& notificationMacros, NotificationType type, const User::Ptr& user)
{
assert(!OwnsLock());
vector<Dictionary::Ptr> macroDicts;
if (user) {
{
ObjectLock olock(user);
macroDicts.push_back(user->GetMacros());
}
macroDicts.push_back(User::CalculateDynamicMacros(user));
macroDicts.push_back(user->GetMacros());
macroDicts.push_back(user->CalculateDynamicMacros());
}
macroDicts.push_back(notificationMacros);
Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
Notification::Ptr self = GetSelf();
vector<Value> arguments;
arguments.push_back(self);
arguments.push_back(macros);
arguments.push_back(type);
ScriptTask::Ptr task;
task = MakeMethodTask("notify", arguments);
if (!task) {
Logger::Write(LogWarning, "icinga", "Notification object '" + GetName() + "' doesn't have a 'notify' method.");
return;
}
{
ObjectLock olock(self);
vector<Value> arguments;
arguments.push_back(self);
arguments.push_back(macros);
arguments.push_back(type);
task = self->MakeMethodTask("notify", arguments);
if (!task) {
Logger::Write(LogWarning, "icinga", "Notification object '" + self->GetName() + "' doesn't have a 'notify' method.");
return;
}
ObjectLock olock(this);
/* We need to keep the task object alive until the completion handler is called. */
self->m_Tasks.insert(task);
m_Tasks.insert(task);
}
task->Start(boost::bind(&Notification::NotificationCompletedHandler, self, _1));
}
/**
* @threadsafety Always.
*/
void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task)
{
assert(!OwnsLock());
m_Tasks.erase(task);
try {
@ -273,8 +305,13 @@ void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task)
}
}
/**
* @threadsafety Always.
*/
void Notification::OnAttributeChanged(const String& name, const Value& oldValue)
{
assert(!OwnsLock());
if (name == "host_name" || name == "service")
Service::InvalidateNotificationsCache();
}

View File

@ -63,7 +63,7 @@ public:
set<User::Ptr> GetUsers(void) const;
set<UserGroup::Ptr> GetGroups(void) const;
static void BeginExecuteNotification(const Notification::Ptr& self, NotificationType type);
void BeginExecuteNotification(NotificationType type);
static String NotificationTypeToString(NotificationType type);
@ -82,8 +82,8 @@ private:
void NotificationCompletedHandler(const ScriptTask::Ptr& task);
static void BeginExecuteNotificationHelper(const Notification::Ptr& self,
const Dictionary::Ptr& notificationMacros, NotificationType type, const User::Ptr& user);
void BeginExecuteNotificationHelper(const Dictionary::Ptr& notificationMacros,
NotificationType type, const User::Ptr& user);
};
}

View File

@ -23,6 +23,9 @@ using namespace icinga;
REGISTER_SCRIPTFUNCTION("NullCheck", &NullCheckTask::ScriptFunc);
/**
* @threadsafety Always.
*/
void NullCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value>& arguments)
{
if (arguments.size() < 1)
@ -31,8 +34,5 @@ void NullCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value>&
Dictionary::Ptr cr = boost::make_shared<Dictionary>();
cr->Set("state", StateUnknown);
{
ObjectLock olock(task);
task->FinishResult(cr);
}
task->FinishResult(cr);
}

View File

@ -35,16 +35,26 @@ PerfdataWriter::~PerfdataWriter(void)
{
}
/**
* @threadsafety Always.
*/
void PerfdataWriter::OnAttributeChanged(const String& name, const Value& oldValue)
{
assert(!OwnsLock());
if (name == "rotation_interval") {
ObjectLock olock(this);
m_RotationTimer->SetInterval(GetRotationInterval());
}
}
/**
* @threadsafety Always.
*/
void PerfdataWriter::Start(void)
{
ObjectLock olock(this);
m_Endpoint = Endpoint::MakeEndpoint("perfdata_" + GetName(), false);
{
@ -62,6 +72,9 @@ void PerfdataWriter::Start(void)
RotateFile();
}
/**
* @threadsafety Always.
*/
PerfdataWriter::Ptr PerfdataWriter::GetByName(const String& name)
{
DynamicObject::Ptr configObject = DynamicObject::GetObject("PerfdataWriter", name);
@ -69,16 +82,26 @@ PerfdataWriter::Ptr PerfdataWriter::GetByName(const String& name)
return dynamic_pointer_cast<PerfdataWriter>(configObject);
}
/**
* @threadsafety Always.
*/
String PerfdataWriter::GetPathPrefix(void) const
{
ObjectLock olock(this);
if (!m_PathPrefix.IsEmpty())
return m_PathPrefix;
else
return Application::GetLocalStateDir() + "/cache/icinga2/perfdata/perfdata";
}
/**
* @threadsafety Always.
*/
String PerfdataWriter::GetFormatTemplate(void) const
{
ObjectLock olock(this);
if (!m_FormatTemplate.IsEmpty()) {
return m_FormatTemplate;
} else {
@ -95,14 +118,22 @@ String PerfdataWriter::GetFormatTemplate(void) const
}
}
/**
* @threadsafety Always.
*/
double PerfdataWriter::GetRotationInterval(void) const
{
ObjectLock olock(this);
if (!m_RotationInterval.IsEmpty())
return m_RotationInterval;
else
return 30;
}
/**
* @threadsafety Always.
*/
void PerfdataWriter::CheckResultRequestHandler(const RequestMessage& request)
{
CheckResultMessage params;
@ -119,15 +150,20 @@ void PerfdataWriter::CheckResultRequestHandler(const RequestMessage& request)
Dictionary::Ptr macros = cr->Get("macros");
String line = MacroProcessor::ResolveMacros(GetFormatTemplate(), macros);
ObjectLock olock(this);
if (!m_OutputFile.good())
return;
ObjectLock olock(this);
m_OutputFile << line << "\n";
}
/**
* @threadsafety Always.
*/
void PerfdataWriter::RotateFile(void)
{
ObjectLock olock(this);
String tempFile = GetPathPrefix();
if (m_OutputFile.good()) {
@ -143,8 +179,10 @@ void PerfdataWriter::RotateFile(void)
Logger::Write(LogWarning, "icinga", "Could not open perfdata file '" + tempFile + "' for writing. Perfdata will be lost.");
}
/**
* @threadsafety Always.
*/
void PerfdataWriter::RotationTimerHandler(void)
{
ObjectLock olock(this);
RotateFile();
}

View File

@ -27,6 +27,9 @@ PluginCheckTask::PluginCheckTask(const ScriptTask::Ptr& task, const Process::Ptr
: m_Task(task), m_Process(process), m_Command(command)
{ }
/**
* @threadsafety Always.
*/
void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value>& arguments)
{
if (arguments.size() < 1)
@ -38,13 +41,7 @@ void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value
Service::Ptr service = arguments[0];
Dictionary::Ptr macros = arguments[1];
Value raw_command;
{
ObjectLock olock(service);
raw_command = service->GetCheckCommand();
}
Value raw_command = service->GetCheckCommand();
Value command = MacroProcessor::ResolveMacros(raw_command, macros);
Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), macros);
@ -54,6 +51,9 @@ void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value
process->Start(boost::bind(&PluginCheckTask::ProcessFinishedHandler, ct));
}
/**
* @threadsafety Always.
*/
void PluginCheckTask::ProcessFinishedHandler(PluginCheckTask ct)
{
ProcessResult pr;
@ -77,6 +77,9 @@ void PluginCheckTask::ProcessFinishedHandler(PluginCheckTask ct)
ct.m_Task->FinishResult(result);
}
/**
* @threadsafety Always.
*/
ServiceState PluginCheckTask::ExitStatusToState(int exitStatus)
{
switch (exitStatus) {
@ -91,6 +94,9 @@ ServiceState PluginCheckTask::ExitStatusToState(int exitStatus)
}
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr PluginCheckTask::ParseCheckOutput(const String& output)
{
Dictionary::Ptr result = boost::make_shared<Dictionary>();

View File

@ -46,20 +46,13 @@ void PluginNotificationTask::ScriptFunc(const ScriptTask::Ptr& task, const vecto
Dictionary::Ptr macros = arguments[1];
NotificationType type = static_cast<NotificationType>(static_cast<int>(arguments[2]));
Value raw_command;
Value raw_command = notification->GetNotificationCommand();
String service_name;
Service::Ptr service;
{
ObjectLock olock(notification);
raw_command = notification->GetNotificationCommand();
service = notification->GetService();
}
{
ObjectLock olock(service);
Service::Ptr service = notification->GetService();
if (service)
service_name = service->GetName();
}
Value command = MacroProcessor::ResolveMacros(raw_command, macros);
@ -78,9 +71,7 @@ void PluginNotificationTask::ProcessFinishedHandler(PluginNotificationTask ct)
ProcessResult pr;
try {
{
pr = ct.m_Process->GetResult();
}
pr = ct.m_Process->GetResult();
if (pr.ExitStatus != 0) {
stringstream msgbuf;

View File

@ -28,58 +28,103 @@ const int Service::CheckIntervalDivisor = 5;
signals2::signal<void (const Service::Ptr&, const String&)> Service::OnCheckerChanged;
signals2::signal<void (const Service::Ptr&, const Value&)> Service::OnNextCheckChanged;
/**
* @threadsafety Always.
*/
Value Service::GetCheckCommand(void) const
{
ObjectLock olock(this);
return m_CheckCommand;
}
/**
* @threadsafety Always.
*/
long Service::GetMaxCheckAttempts(void) const
{
ObjectLock olock(this);
if (m_MaxCheckAttempts.IsEmpty())
return DefaultMaxCheckAttempts;
return m_MaxCheckAttempts;
}
/**
* @threadsafety Always.
*/
double Service::GetCheckInterval(void) const
{
ObjectLock olock(this);
if (m_CheckInterval.IsEmpty())
return DefaultCheckInterval;
return m_CheckInterval;
}
/**
* @threadsafety Always.
*/
double Service::GetRetryInterval(void) const
{
ObjectLock olock(this);
if (m_RetryInterval.IsEmpty())
return GetCheckInterval() / CheckIntervalDivisor;
return m_RetryInterval;
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetCheckers(void) const
{
ObjectLock olock(this);
return m_Checkers;
}
/**
* @threadsafety Always.
*/
void Service::SetSchedulingOffset(long offset)
{
ObjectLock olock(this);
m_SchedulingOffset = offset;
}
/**
* @threadsafety Always.
*/
long Service::GetSchedulingOffset(void)
{
ObjectLock olock(this);
return m_SchedulingOffset;
}
/**
* @threadsafety Always.
*/
void Service::SetNextCheck(double nextCheck)
{
ObjectLock olock(this);
m_NextCheck = nextCheck;
Touch("next_check");
}
/**
* @threadsafety Always.
*/
double Service::GetNextCheck(void)
{
ObjectLock olock(this);
if (m_NextCheck.IsEmpty()) {
UpdateNextCheck();
@ -90,8 +135,13 @@ double Service::GetNextCheck(void)
return m_NextCheck;
}
/**
* @threadsafety Always.
*/
void Service::UpdateNextCheck(void)
{
ObjectLock olock(this);
double interval;
if (GetStateType() == StateTypeSoft)
@ -108,39 +158,69 @@ void Service::UpdateNextCheck(void)
SetNextCheck(now - adj + interval);
}
/**
* @threadsafety Always.
*/
void Service::SetCurrentChecker(const String& checker)
{
ObjectLock olock(this);
m_CurrentChecker = checker;
Touch("current_checker");
}
/**
* @threadsafety Always.
*/
String Service::GetCurrentChecker(void) const
{
ObjectLock olock(this);
return m_CurrentChecker;
}
/**
* @threadsafety Always.
*/
void Service::SetCurrentCheckAttempt(long attempt)
{
ObjectLock olock(this);
m_CheckAttempt = attempt;
Touch("check_attempt");
}
/**
* @threadsafety Always.
*/
long Service::GetCurrentCheckAttempt(void) const
{
ObjectLock olock(this);
if (m_CheckAttempt.IsEmpty())
return 1;
return m_CheckAttempt;
}
/**
* @threadsafety Always.
*/
void Service::SetState(ServiceState state)
{
ObjectLock olock(this);
m_State = static_cast<long>(state);
Touch("state");
}
/**
* @threadsafety Always.
*/
ServiceState Service::GetState(void) const
{
ObjectLock olock(this);
if (m_State.IsEmpty())
return StateUnknown;
@ -148,14 +228,24 @@ ServiceState Service::GetState(void) const
return static_cast<ServiceState>(ivalue);
}
/**
* @threadsafety Always.
*/
void Service::SetStateType(ServiceStateType type)
{
ObjectLock olock(this);
m_StateType = static_cast<long>(type);
Touch("state_type");
}
/**
* @threadsafety Always.
*/
ServiceStateType Service::GetStateType(void) const
{
ObjectLock olock(this);
if (m_StateType.IsEmpty())
return StateTypeSoft;
@ -163,89 +253,155 @@ ServiceStateType Service::GetStateType(void) const
return static_cast<ServiceStateType>(ivalue);
}
/**
* @threadsafety Always.
*/
void Service::SetLastCheckResult(const Dictionary::Ptr& result)
{
ObjectLock olock(this);
m_LastResult = result;
Touch("last_result");
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetLastCheckResult(void) const
{
ObjectLock olock(this);
return m_LastResult;
}
/**
* @threadsafety Always.
*/
void Service::SetLastStateChange(double ts)
{
ObjectLock olock(this);
m_LastStateChange = ts;
Touch("last_state_change");
}
/**
* @threadsafety Always.
*/
double Service::GetLastStateChange(void) const
{
ObjectLock olock(this);
if (m_LastStateChange.IsEmpty())
return IcingaApplication::GetInstance()->GetStartTime();
return m_LastStateChange;
}
/**
* @threadsafety Always.
*/
void Service::SetLastHardStateChange(double ts)
{
ObjectLock olock(this);
m_LastHardStateChange = ts;
Touch("last_hard_state_change");
}
/**
* @threadsafety Always.
*/
double Service::GetLastHardStateChange(void) const
{
ObjectLock olock(this);
if (m_LastHardStateChange.IsEmpty())
return IcingaApplication::GetInstance()->GetStartTime();
return m_LastHardStateChange;
}
/**
* @threadsafety Always.
*/
bool Service::GetEnableActiveChecks(void) const
{
ObjectLock olock(this);
if (m_EnableActiveChecks.IsEmpty())
return true;
else
return m_EnableActiveChecks;
}
/**
* @threadsafety Always.
*/
void Service::SetEnableActiveChecks(bool enabled)
{
ObjectLock olock(this);
m_EnableActiveChecks = enabled ? 1 : 0;
Touch("enable_active_checks");
}
/**
* @threadsafety Always.
*/
bool Service::GetEnablePassiveChecks(void) const
{
ObjectLock olock(this);
if (m_EnablePassiveChecks.IsEmpty())
return true;
else
return m_EnablePassiveChecks;
}
/**
* @threadsafety Always.
*/
void Service::SetEnablePassiveChecks(bool enabled)
{
ObjectLock olock(this);
m_EnablePassiveChecks = enabled ? 1 : 0;
Touch("enable_passive_checks");
}
/**
* @threadsafety Always.
*/
bool Service::GetForceNextCheck(void) const
{
ObjectLock olock(this);
if (m_ForceNextCheck.IsEmpty())
return false;
return static_cast<bool>(m_ForceNextCheck);
}
/**
* @threadsafety Always.
*/
void Service::SetForceNextCheck(bool forced)
{
ObjectLock olock(this);
m_ForceNextCheck = forced ? 1 : 0;
Touch("force_next_check");
}
void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
/**
* @threadsafety Always.
*/
void Service::ProcessCheckResult(const Dictionary::Ptr& cr)
{
assert(!OwnsLock());
ObjectLock olock(this);
ServiceState old_state = GetState();
ServiceStateType old_stateType = GetStateType();
bool hardChange = false;
@ -298,13 +454,13 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
}
/* reschedule service dependencies */
BOOST_FOREACH(const Service::Ptr& parent, Service::GetParentServices(GetSelf())) {
BOOST_FOREACH(const Service::Ptr& parent, GetParentServices()) {
parent->SetNextCheck(Utility::GetTime());
}
/* reschedule host dependencies */
BOOST_FOREACH(const Host::Ptr& parent, Service::GetParentHosts(GetSelf())) {
Service::Ptr service = Host::GetHostCheckService(parent);
BOOST_FOREACH(const Host::Ptr& parent, GetParentHosts()) {
Service::Ptr service = parent->GetHostCheckService();
if (service) {
ObjectLock olock(service);
@ -313,21 +469,39 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
}
}
if (hardChange)
SetLastHardStateChange(now);
if (GetState() != StateOK)
TriggerDowntimes();
if (hardChange) {
SetLastHardStateChange(now);
Service::UpdateStatistics(cr);
/* Make sure the notification component sees the updated
* state/state_type attributes. */
Flush();
olock.Unlock();
if (IsReachable(GetSelf()) && !IsInDowntime() && !IsAcknowledged())
RequestNotifications(recovery ? NotificationRecovery : NotificationProblem);
}
/* Flush the object so other instances see the service's
* new state when they receive the CheckResult message */
Flush();
RequestMessage rm;
rm.SetMethod("checker::CheckResult");
/* TODO: add _old_ state to message */
CheckResultMessage params;
params.SetService(GetName());
params.SetCheckResult(cr);
rm.SetParams(params);
EndpointManager::GetInstance()->SendMulticastMessage(rm);
if (hardChange && IsReachable() && !IsInDowntime() && !IsAcknowledged())
RequestNotifications(recovery ? NotificationRecovery : NotificationProblem);
}
/**
* @threadsafety Always.
*/
ServiceState Service::StateFromString(const String& state)
{
if (state == "OK")
@ -342,6 +516,9 @@ ServiceState Service::StateFromString(const String& state)
return StateUnknown;
}
/**
* @threadsafety Always.
*/
String Service::StateToString(ServiceState state)
{
switch (state) {
@ -359,6 +536,9 @@ String Service::StateToString(ServiceState state)
}
}
/**
* @threadsafety Always.
*/
ServiceStateType Service::StateTypeFromString(const String& type)
{
if (type == "SOFT")
@ -367,6 +547,9 @@ ServiceStateType Service::StateTypeFromString(const String& type)
return StateTypeHard;
}
/**
* @threadsafety Always.
*/
String Service::StateTypeToString(ServiceStateType type)
{
if (type == StateTypeSoft)
@ -375,6 +558,9 @@ String Service::StateTypeToString(ServiceStateType type)
return "HARD";
}
/**
* @threadsafety Always.
*/
bool Service::IsAllowedChecker(const String& checker) const
{
Dictionary::Ptr checkers = GetCheckers();
@ -382,6 +568,8 @@ bool Service::IsAllowedChecker(const String& checker) const
if (!checkers)
return true;
ObjectLock olock(checkers);
Value pattern;
BOOST_FOREACH(tie(tuples::ignore, pattern), checkers) {
if (Utility::Match(pattern, checker))
@ -391,6 +579,9 @@ bool Service::IsAllowedChecker(const String& checker) const
return false;
}
/**
* @threadsafety Always.
*/
void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (void)>& callback)
{
ObjectLock slock(self);
@ -407,16 +598,12 @@ void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (v
/* keep track of scheduling info in case the check type doesn't provide its own information */
Dictionary::Ptr checkInfo = boost::make_shared<Dictionary>();
{
ObjectLock olock(checkInfo);
checkInfo->Set("schedule_start", self->GetNextCheck());
checkInfo->Set("execution_start", Utility::GetTime());
}
checkInfo->Set("schedule_start", self->GetNextCheck());
checkInfo->Set("execution_start", Utility::GetTime());
vector<Dictionary::Ptr> macroDicts;
macroDicts.push_back(self->GetMacros());
macroDicts.push_back(Service::CalculateDynamicMacros(self));
macroDicts.push_back(self->CalculateDynamicMacros());
Value raw_command = self->GetCheckCommand();
@ -424,21 +611,13 @@ void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (v
slock.Unlock();
{
ObjectLock olock(host);
macroDicts.push_back(host->GetMacros());
}
macroDicts.push_back(Host::CalculateDynamicMacros(host));
macroDicts.push_back(host->GetMacros());
macroDicts.push_back(host->CalculateDynamicMacros());
IcingaApplication::Ptr app = IcingaApplication::GetInstance();
macroDicts.push_back(app->GetMacros());
{
ObjectLock olock(app);
macroDicts.push_back(app->GetMacros());
}
macroDicts.push_back(IcingaApplication::CalculateDynamicMacros(app));
macroDicts.push_back(IcingaApplication::CalculateDynamicMacros());
Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
@ -459,9 +638,14 @@ void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (v
task->Start(boost::bind(&Service::CheckCompletedHandler, self, checkInfo, _1, callback));
}
/**
* @threadsafety Always.
*/
void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
const ScriptTask::Ptr& task, const function<void (void)>& callback)
{
assert(!OwnsLock());
checkInfo->Set("execution_end", Utility::GetTime());
checkInfo->Set("schedule_end", Utility::GetTime());
checkInfo->Seal();
@ -515,47 +699,25 @@ void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
result->Seal();
}
if (result)
ProcessCheckResult(result);
{
ObjectLock olock(this);
if (result)
ProcessCheckResult(result);
m_CurrentTask.reset();
/* figure out when the next check is for this service; the call to
* ApplyCheckResult() should've already done this but lets do it again
* just in case there was no check result. */
UpdateNextCheck();
}
/* figure out when the next check is for this service; the call to
* ApplyCheckResult() should've already done this but lets do it again
* just in case there was no check result. */
UpdateNextCheck();
callback();
}
void Service::ProcessCheckResult(const Dictionary::Ptr& cr)
{
ApplyCheckResult(cr);
Service::UpdateStatistics(cr);
/* Flush the object so other instances see the service's
* new state when they receive the CheckResult message */
Flush();
RequestMessage rm;
rm.SetMethod("checker::CheckResult");
/* TODO: add _old_ state to message */
CheckResultMessage params;
params.SetService(GetName());
params.SetCheckResult(cr);
rm.SetParams(params);
EndpointManager::Ptr em = EndpointManager::GetInstance();
ObjectLock olock(em);
em->SendMulticastMessage(rm);
}
/**
* @threadsafety Always.
*/
void Service::UpdateStatistics(const Dictionary::Ptr& cr)
{
time_t ts;
@ -572,15 +734,14 @@ void Service::UpdateStatistics(const Dictionary::Ptr& cr)
CIB::UpdatePassiveChecksStatistics(ts, 1);
}
/**
* @threadsafety Always.
*/
double Service::CalculateExecutionTime(const Dictionary::Ptr& cr)
{
ObjectLock olock(cr);
double execution_start = 0, execution_end = 0;
if (cr) {
ObjectLock olock(cr);
if (!cr->Contains("execution_start") || !cr->Contains("execution_end"))
return 0;
@ -591,13 +752,14 @@ double Service::CalculateExecutionTime(const Dictionary::Ptr& cr)
return (execution_end - execution_start);
}
/**
* @threadsafety Always.
*/
double Service::CalculateLatency(const Dictionary::Ptr& cr)
{
double schedule_start = 0, schedule_end = 0;
if (cr) {
ObjectLock olock(cr);
if (!cr->Contains("schedule_start") || !cr->Contains("schedule_end"))
return 0;

View File

@ -28,16 +28,29 @@ map<String, Service::WeakPtr> Service::m_CommentsCache;
bool Service::m_CommentsCacheValid = true;
Timer::Ptr Service::m_CommentsExpireTimer;
/**
* @threadsafety Always.
*/
int Service::GetNextCommentID(void)
{
boost::mutex::scoped_lock lock(m_CommentMutex);
return m_NextCommentID;
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetComments(void) const
{
ObjectLock olock(this);
return m_Comments;
}
/**
* @threadsafety Always.
*/
String Service::AddComment(CommentType entryType, const String& author,
const String& text, double expireTime)
{
@ -57,7 +70,9 @@ String Service::AddComment(CommentType entryType, const String& author,
comment->Set("legacy_id", legacy_id);
Dictionary::Ptr comments = m_Comments;
ObjectLock olock(this);
Dictionary::Ptr comments = GetComments();
if (!comments)
comments = boost::make_shared<Dictionary>();
@ -71,12 +86,20 @@ String Service::AddComment(CommentType entryType, const String& author,
return id;
}
/**
* @threadsafety Always.
*/
void Service::RemoveAllComments(void)
{
ObjectLock olock(this);
m_Comments = Empty;
Touch("comments");
}
/**
* @threadsafety Always.
*/
void Service::RemoveComment(const String& id)
{
Service::Ptr owner = GetOwnerByCommentID(id);
@ -84,7 +107,9 @@ void Service::RemoveComment(const String& id)
if (!owner)
return;
Dictionary::Ptr comments = owner->m_Comments;
ObjectLock olock(owner);
Dictionary::Ptr comments = owner->GetComments();
if (comments) {
comments->Remove(id);
@ -92,6 +117,9 @@ void Service::RemoveComment(const String& id)
}
}
/**
* @threadsafety Always.
*/
String Service::GetCommentIDFromLegacyID(int id)
{
boost::mutex::scoped_lock lock(m_CommentMutex);
@ -104,6 +132,9 @@ String Service::GetCommentIDFromLegacyID(int id)
return it->second;
}
/**
* @threadsafety Always.
*/
Service::Ptr Service::GetOwnerByCommentID(const String& id)
{
boost::mutex::scoped_lock lock(m_CommentMutex);
@ -111,6 +142,9 @@ Service::Ptr Service::GetOwnerByCommentID(const String& id)
return m_CommentsCache[id].lock();
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetCommentByID(const String& id)
{
Service::Ptr owner = GetOwnerByCommentID(id);
@ -118,36 +152,40 @@ Dictionary::Ptr Service::GetCommentByID(const String& id)
if (!owner)
return Dictionary::Ptr();
Dictionary::Ptr comments = owner->m_Comments;
Dictionary::Ptr comments = owner->GetComments();
if (comments) {
Dictionary::Ptr comment = comments->Get(id);
return comment;
}
if (comments)
return comments->Get(id);
return Dictionary::Ptr();
}
/**
* @threadsafety Always.
*/
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());
}
/**
* @threadsafety Always.
*/
void Service::InvalidateCommentsCache(void)
{
{
boost::mutex::scoped_lock lock(m_CommentMutex);
boost::mutex::scoped_lock lock(m_CommentMutex);
if (m_CommentsCacheValid)
Utility::QueueAsyncCallback(boost::bind(&Service::RefreshCommentsCache));
if (m_CommentsCacheValid)
Utility::QueueAsyncCallback(boost::bind(&Service::RefreshCommentsCache));
m_CommentsCacheValid = false;
}
m_CommentsCacheValid = false;
}
/**
* @threadsafety Always.
*/
void Service::RefreshCommentsCache(void)
{
{
@ -214,16 +252,21 @@ void Service::RefreshCommentsCache(void)
}
}
/**
* @threadsafety Always.
*/
void Service::RemoveExpiredComments(void)
{
Dictionary::Ptr comments = m_Comments;
ObjectLock olock(this);
Dictionary::Ptr comments = GetComments();
if (!comments)
return;
vector<String> expiredComments;
ObjectLock olock(comments);
ObjectLock dlock(comments);
String id;
Dictionary::Ptr comment;
@ -241,11 +284,13 @@ void Service::RemoveExpiredComments(void)
}
}
/**
* @threadsafety Always.
*/
void Service::CommentsExpireTimerHandler(void)
{
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
ObjectLock olock(service);
service->RemoveExpiredComments();
}
}

View File

@ -28,16 +28,27 @@ map<String, Service::WeakPtr> Service::m_DowntimesCache;
bool Service::m_DowntimesCacheValid = true;
Timer::Ptr Service::m_DowntimesExpireTimer;
/**
* @threadsafety Always.
*/
int Service::GetNextDowntimeID(void)
{
boost::mutex::scoped_lock lock(m_DowntimeMutex);
return m_NextDowntimeID;
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetDowntimes(void) const
{
return m_Downtimes;
}
/**
* @threadsafety Always.
*/
String Service::AddDowntime(const String& author, const String& comment,
double startTime, double endTime, bool fixed,
const String& triggeredBy, double duration)
@ -86,6 +97,9 @@ String Service::AddDowntime(const String& author, const String& comment,
return id;
}
/**
* @threadsafety Always.
*/
void Service::RemoveDowntime(const String& id)
{
Service::Ptr owner = GetOwnerByDowntimeID(id);
@ -93,22 +107,23 @@ void Service::RemoveDowntime(const String& id)
if (!owner)
return;
Dictionary::Ptr downtimes = owner->m_Downtimes;
ObjectLock olock(owner);
Dictionary::Ptr downtimes = owner->GetDowntimes();
if (!downtimes)
return;
{
ObjectLock olock(downtimes);
downtimes->Remove(id);
}
downtimes->Remove(id);
owner->Touch("downtimes");
}
/**
* @threadsafety Always.
*/
void Service::TriggerDowntimes(void)
{
Dictionary::Ptr downtimes = m_Downtimes;
Dictionary::Ptr downtimes = GetDowntimes();
if (!downtimes)
return;
@ -121,6 +136,9 @@ void Service::TriggerDowntimes(void)
}
}
/**
* @threadsafety Always.
*/
void Service::TriggerDowntime(const String& id)
{
Service::Ptr owner = GetOwnerByDowntimeID(id);
@ -150,6 +168,9 @@ void Service::TriggerDowntime(const String& id)
owner->Touch("downtimes");
}
/**
* @threadsafety Always.
*/
String Service::GetDowntimeIDFromLegacyID(int id)
{
boost::mutex::scoped_lock lock(m_DowntimeMutex);
@ -162,12 +183,18 @@ String Service::GetDowntimeIDFromLegacyID(int id)
return it->second;
}
/**
* @threadsafety Always.
*/
Service::Ptr Service::GetOwnerByDowntimeID(const String& id)
{
boost::mutex::scoped_lock lock(m_DowntimeMutex);
return m_DowntimesCache[id].lock();
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetDowntimeByID(const String& id)
{
Service::Ptr owner = GetOwnerByDowntimeID(id);
@ -175,17 +202,17 @@ Dictionary::Ptr Service::GetDowntimeByID(const String& id)
if (!owner)
return Dictionary::Ptr();
Dictionary::Ptr downtimes = owner->m_Downtimes;
Dictionary::Ptr downtimes = owner->GetDowntimes();
if (downtimes) {
ObjectLock olock(downtimes);
Dictionary::Ptr downtime = downtimes->Get(id);
return downtime;
}
if (downtimes)
return downtimes->Get(id);
return Dictionary::Ptr();
}
/**
* @threadsafety Always.
*/
bool Service::IsDowntimeActive(const Dictionary::Ptr& downtime)
{
double now = Utility::GetTime();
@ -207,24 +234,30 @@ bool Service::IsDowntimeActive(const Dictionary::Ptr& downtime)
return (triggerTime + downtime->Get("duration") < now);
}
/**
* @threadsafety Always.
*/
bool Service::IsDowntimeExpired(const Dictionary::Ptr& downtime)
{
ObjectLock olock(downtime);
return (downtime->Get("end_time") < Utility::GetTime());
}
/**
* @threadsafety Always.
*/
void Service::InvalidateDowntimesCache(void)
{
{
boost::mutex::scoped_lock lock(m_DowntimeMutex);
boost::mutex::scoped_lock lock(m_DowntimeMutex);
if (m_DowntimesCacheValid)
Utility::QueueAsyncCallback(boost::bind(&Service::RefreshDowntimesCache));
if (m_DowntimesCacheValid)
Utility::QueueAsyncCallback(boost::bind(&Service::RefreshDowntimesCache));
m_DowntimesCacheValid = false;
}
m_DowntimesCacheValid = false;
}
/**
* @threadsafety Always.
*/
void Service::RefreshDowntimesCache(void)
{
{
@ -289,16 +322,21 @@ void Service::RefreshDowntimesCache(void)
}
}
/**
* @threadsafety Always.
*/
void Service::RemoveExpiredDowntimes(void)
{
Dictionary::Ptr downtimes = m_Downtimes;
ObjectLock olock(this);
Dictionary::Ptr downtimes = GetDowntimes();
if (!downtimes)
return;
vector<String> expiredDowntimes;
ObjectLock olock(downtimes);
ObjectLock dlock(downtimes);
String id;
Dictionary::Ptr downtime;
@ -316,15 +354,20 @@ void Service::RemoveExpiredDowntimes(void)
}
}
/**
* @threadsafety Always.
*/
void Service::DowntimesExpireTimerHandler(void)
{
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
ObjectLock slock(service);
service->RemoveExpiredDowntimes();
}
}
/**
* @threadsafety Always.
*/
bool Service::IsInDowntime(void) const
{
Dictionary::Ptr downtimes = GetDowntimes();

View File

@ -25,8 +25,13 @@ boost::mutex Service::m_NotificationMutex;
map<String, set<Notification::WeakPtr> > Service::m_NotificationsCache;
bool Service::m_NotificationsCacheValid = true;
/**
* @threadsafety Always.
*/
void Service::RequestNotifications(NotificationType type)
{
SetLastNotification(Utility::GetTime());
RequestMessage msg;
msg.SetMethod("icinga::SendNotifications");
@ -38,40 +43,32 @@ void Service::RequestNotifications(NotificationType type)
Logger::Write(LogDebug, "icinga", "Sending notification anycast request for service '" + GetName() + "'");
EndpointManager::GetInstance()->SendAnycastMessage(Endpoint::Ptr(), msg);
SetLastNotification(Utility::GetTime());
}
void Service::SendNotifications(const Service::Ptr& self, NotificationType type)
/**
* @threadsafety Always.
*/
void Service::SendNotifications(NotificationType type)
{
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 + "'.");
if (!GetEnableNotifications()) {
Logger::Write(LogInformation, "icinga", "Notifications are disabled for service '" + GetName() + "'.");
return;
}
Logger::Write(LogInformation, "icinga", "Sending notifications for service '" + service_name + "'");
Logger::Write(LogInformation, "icinga", "Sending notifications for service '" + GetName() + "'");
set<Notification::Ptr> notifications = GetNotifications(self);
set<Notification::Ptr> notifications = GetNotifications();
if (notifications.size() == 0)
Logger::Write(LogInformation, "icinga", "Service '" + service_name + "' does not have any notifications.");
Logger::Write(LogInformation, "icinga", "Service '" + GetName() + "' does not have any notifications.");
BOOST_FOREACH(const Notification::Ptr& notification, notifications) {
try {
Notification::BeginExecuteNotification(notification, type);
notification->BeginExecuteNotification(type);
} catch (const exception& ex) {
stringstream msgbuf;
msgbuf << "Exception occured during notification for service '"
<< service_name << "': " << diagnostic_information(ex);
<< GetName() << "': " << diagnostic_information(ex);
String message = msgbuf.str();
Logger::Write(LogWarning, "icinga", message);
@ -79,18 +76,22 @@ void Service::SendNotifications(const Service::Ptr& self, NotificationType type)
}
}
/**
* @threadsafety Always.
*/
void Service::InvalidateNotificationsCache(void)
{
{
boost::mutex::scoped_lock lock(m_NotificationMutex);
boost::mutex::scoped_lock lock(m_NotificationMutex);
if (m_NotificationsCacheValid)
Utility::QueueAsyncCallback(boost::bind(&Service::RefreshNotificationsCache));
if (m_NotificationsCacheValid)
Utility::QueueAsyncCallback(boost::bind(&Service::RefreshNotificationsCache));
m_NotificationsCacheValid = false;
}
m_NotificationsCacheValid = false;
}
/**
* @threadsafety Always.
*/
void Service::RefreshNotificationsCache(void)
{
{
@ -107,42 +108,29 @@ void Service::RefreshNotificationsCache(void)
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Notification")) {
const Notification::Ptr& notification = static_pointer_cast<Notification>(object);
Service::Ptr service;
Service::Ptr service = notification->GetService();
{
ObjectLock olock(notification);
service = notification->GetService();
}
if (!service)
continue;
String service_name;
{
ObjectLock olock(service);
service_name = service->GetName();
}
newNotificationsCache[service_name].insert(notification);
newNotificationsCache[service->GetName()].insert(notification);
}
boost::mutex::scoped_lock lock(m_NotificationMutex);
m_NotificationsCache.swap(newNotificationsCache);
}
set<Notification::Ptr> Service::GetNotifications(const Service::Ptr& self)
/**
* @threadsafety Always.
*/
set<Notification::Ptr> Service::GetNotifications(void) const
{
String name;
{
ObjectLock olock(self);
name = self->GetName();
}
set<Notification::Ptr> notifications;
{
boost::mutex::scoped_lock lock(m_NotificationMutex);
BOOST_FOREACH(const Notification::WeakPtr& wservice, m_NotificationsCache[name]) {
BOOST_FOREACH(const Notification::WeakPtr& wservice, m_NotificationsCache[GetName()]) {
Notification::Ptr notification = wservice.lock();
if (!notification)
@ -155,6 +143,9 @@ set<Notification::Ptr> Service::GetNotifications(const Service::Ptr& self)
return notifications;
}
/**
* @threadsafety Always.
*/
template<typename TDict>
static void CopyNotificationAttributes(TDict notificationDesc, const ConfigItemBuilder::Ptr& builder)
{
@ -276,7 +267,7 @@ void Service::UpdateSlaveNotifications(const Service::Ptr& self)
}
ConfigItem::Ptr notificationItem = builder->Compile();
ConfigItem::Commit(notificationItem);
notificationItem->Commit();
newNotifications->Set(name, notificationItem);
}
@ -301,36 +292,61 @@ void Service::UpdateSlaveNotifications(const Service::Ptr& self)
}
}
/**
* @threadsafety Always.
*/
double Service::GetLastNotification(void) const
{
ObjectLock olock(this);
if (m_LastNotification.IsEmpty())
return 0;
else
return m_LastNotification;
}
/**
* @threadsafety Always.
*/
void Service::SetLastNotification(double time)
{
ObjectLock olock(this);
m_LastNotification = time;
Touch("last_notification");
}
/**
* @threadsafety Always.
*/
bool Service::GetEnableNotifications(void) const
{
ObjectLock olock(this);
if (m_EnableNotifications.IsEmpty())
return true;
else
return m_EnableNotifications;
}
/**
* @threadsafety Always.
*/
void Service::SetEnableNotifications(bool enabled)
{
ObjectLock olock(this);
m_EnableNotifications = enabled;
Touch("enable_notifications");
}
/**
* @threadsafety Always.
*/
double Service::GetNotificationInterval(void) const
{
ObjectLock olock(this);
if (m_NotificationInterval.IsEmpty())
return 300;
else

View File

@ -76,13 +76,25 @@ Service::~Service(void)
Service::InvalidateCommentsCache();
}
/**
* @threadsafety Always.
*/
void Service::OnRegistrationCompleted(void)
{
assert(!OwnsLock());
DynamicObject::OnRegistrationCompleted();
InvalidateNotificationsCache();
}
/**
* @threadsafety Always.
*/
String Service::GetDisplayName(void) const
{
ObjectLock olock(this);
if (m_DisplayName.IsEmpty())
return GetShortName();
else
@ -113,66 +125,99 @@ Service::Ptr Service::GetByNamePair(const String& hostName, const String& servic
if (!host)
return Service::Ptr();
return Host::GetServiceByShortName(host, serviceName);
return host->GetServiceByShortName(serviceName);
} else {
return Service::GetByName(serviceName);
}
}
/**
* @threadsafety Always.
*/
Host::Ptr Service::GetHost(void) const
{
ObjectLock olock(this);
return Host::GetByName(m_HostName);
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetMacros(void) const
{
ObjectLock olock(this);
return m_Macros;
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetHostDependencies(void) const
{
ObjectLock olock(this);
return m_HostDependencies;
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetServiceDependencies(void) const
{
ObjectLock olock(this);
return m_ServiceDependencies;
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetGroups(void) const
{
ObjectLock olock(this);
return m_ServiceGroups;
}
/**
* @threadsafety Always.
*/
String Service::GetHostName(void) const
{
ObjectLock olock(this);
return m_HostName;
}
/**
* @threadsafety Always.
*/
String Service::GetShortName(void) const
{
ObjectLock olock(this);
if (m_ShortName.IsEmpty())
return GetName();
else
return m_ShortName;
}
bool Service::IsReachable(const Service::Ptr& self)
/**
* @threadsafety Always.
*/
bool Service::IsReachable(void) const
{
String service_name;
{
ObjectLock olock(self);
service_name = self->GetName();
}
BOOST_FOREACH(const Service::Ptr& service, Service::GetParentServices(self)) {
ObjectLock olock(service);
assert(!OwnsLock());
BOOST_FOREACH(const Service::Ptr& service, GetParentServices()) {
/* ignore ourselves */
if (service->GetName() == service_name)
if (service->GetName() == GetName())
continue;
ObjectLock olock(service);
/* ignore pending services */
if (!service->GetLastCheckResult())
continue;
@ -189,21 +234,25 @@ bool Service::IsReachable(const Service::Ptr& self)
return false;
}
BOOST_FOREACH(const Host::Ptr& host, Service::GetParentHosts(self)) {
Service::Ptr hc = Host::GetHostCheckService(host);
BOOST_FOREACH(const Host::Ptr& host, GetParentHosts()) {
Service::Ptr hc = host->GetHostCheckService();
/* ignore hosts that don't have a hostcheck */
if (!hc)
continue;
/* ignore ourselves */
if (hc->GetName() == GetName())
continue;
ObjectLock olock(hc);
/* ignore ourselves */
if (hc->GetName() == service_name)
/* ignore soft states */
if (hc->GetStateType() == StateTypeSoft)
continue;
/* ignore hosts that are up */
if (hc && hc->GetState() == StateOK)
if (hc->GetState() == StateOK)
continue;
return false;
@ -212,8 +261,13 @@ bool Service::IsReachable(const Service::Ptr& self)
return true;
}
/**
* @threadsafety Always.
*/
AcknowledgementType Service::GetAcknowledgement(void)
{
ObjectLock olock(this);
if (m_Acknowledgement.IsEmpty())
return AcknowledgementNone;
@ -233,47 +287,78 @@ AcknowledgementType Service::GetAcknowledgement(void)
return avalue;
}
/**
* @threadsafety Always.
*/
void Service::SetAcknowledgement(AcknowledgementType acknowledgement)
{
ObjectLock olock(this);
m_Acknowledgement = acknowledgement;
Touch("acknowledgement");
}
/**
* @threadsafety Always.
*/
bool Service::IsAcknowledged(void)
{
return GetAcknowledgement() != AcknowledgementNone;
}
/**
* @threadsafety Always.
*/
double Service::GetAcknowledgementExpiry(void) const
{
ObjectLock olock(this);
if (m_AcknowledgementExpiry.IsEmpty())
return 0;
return static_cast<double>(m_AcknowledgementExpiry);
}
/**
* @threadsafety Always.
*/
void Service::SetAcknowledgementExpiry(double timestamp)
{
ObjectLock olock(this);
m_AcknowledgementExpiry = timestamp;
Touch("acknowledgement_expiry");
}
/**
* @threadsafety Always.
*/
void Service::AcknowledgeProblem(AcknowledgementType type, double expiry)
{
ObjectLock olock(this);
SetAcknowledgement(type);
SetAcknowledgementExpiry(expiry);
RequestNotifications(NotificationAcknowledgement);
}
/**
* @threadsafety Always.
*/
void Service::ClearAcknowledgement(void)
{
SetAcknowledgement(AcknowledgementNone);
SetAcknowledgementExpiry(0);
}
/**
* @threadsafety Always.
*/
void Service::OnAttributeChanged(const String& name, const Value& oldValue)
{
assert(!OwnsLock());
Service::Ptr self;
String service_name;
bool abstract;
@ -311,23 +396,24 @@ void Service::OnAttributeChanged(const String& name, const Value& oldValue)
}
}
set<Host::Ptr> Service::GetParentHosts(const Service::Ptr& self)
/**
* @threadsafety Always.
*/
set<Host::Ptr> Service::GetParentHosts(void) const
{
set<Host::Ptr> parents;
Dictionary::Ptr dependencies;
Host::Ptr host = GetHost();
{
ObjectLock olock(self);
/* The service's host is implicitly a parent. */
parents.insert(self->GetHost());
dependencies = self->GetHostDependencies();
}
/* The service's host is implicitly a parent. */
if (host)
parents.insert(host);
Dictionary::Ptr dependencies = GetHostDependencies();
if (dependencies) {
ObjectLock olock(dependencies);
String key;
BOOST_FOREACH(tie(key, tuples::ignore), dependencies) {
Host::Ptr host = Host::GetByName(key);
@ -342,29 +428,26 @@ set<Host::Ptr> Service::GetParentHosts(const Service::Ptr& self)
return parents;
}
set<Service::Ptr> Service::GetParentServices(const Service::Ptr& self)
/**
* @threadsafety Always.
*/
set<Service::Ptr> Service::GetParentServices(void) const
{
set<Service::Ptr> parents;
Dictionary::Ptr dependencies;
Host::Ptr host;
String service_name;
Host::Ptr host = GetHost();
Dictionary::Ptr dependencies = GetServiceDependencies();
{
ObjectLock olock(self);
dependencies = self->GetServiceDependencies();
host = self->GetHost();
service_name = self->GetName();
}
if (dependencies) {
if (host && dependencies) {
String key;
Value value;
BOOST_FOREACH(tie(key, value), dependencies) {
Service::Ptr service = Host::GetServiceByShortName(host, value);
ObjectLock olock(service);
Service::Ptr service = host->GetServiceByShortName(value);
if (service->GetName() == service_name)
if (!service)
continue;
if (service->GetName() == GetName())
continue;
parents.insert(service);
@ -374,25 +457,27 @@ set<Service::Ptr> Service::GetParentServices(const Service::Ptr& self)
return parents;
}
Dictionary::Ptr Service::CalculateDynamicMacros(const Service::Ptr& self)
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::CalculateDynamicMacros(void) const
{
Dictionary::Ptr macros = boost::make_shared<Dictionary>();
ObjectLock mlock(macros);
Dictionary::Ptr cr;
{
ObjectLock olock(self);
macros->Set("SERVICEDESC", self->GetShortName());
macros->Set("SERVICEDISPLAYNAME", self->GetDisplayName());
macros->Set("SERVICESTATE", StateToString(self->GetState()));
macros->Set("SERVICESTATEID", self->GetState());
macros->Set("SERVICESTATETYPE", StateTypeToString(self->GetStateType()));
macros->Set("SERVICEATTEMPT", self->GetCurrentCheckAttempt());
macros->Set("MAXSERVICEATTEMPT", self->GetMaxCheckAttempts());
ObjectLock olock(this);
macros->Set("SERVICEDESC", GetShortName());
macros->Set("SERVICEDISPLAYNAME", GetDisplayName());
macros->Set("SERVICESTATE", StateToString(GetState()));
macros->Set("SERVICESTATEID", GetState());
macros->Set("SERVICESTATETYPE", StateTypeToString(GetStateType()));
macros->Set("SERVICEATTEMPT", GetCurrentCheckAttempt());
macros->Set("MAXSERVICEATTEMPT", GetMaxCheckAttempts());
macros->Set("SERVICECHECKCOMMAND", "check_i2");
cr = self->GetLastCheckResult();
cr = GetLastCheckResult();
}
if (cr) {

View File

@ -106,12 +106,12 @@ public:
String GetHostName(void) const;
String GetShortName(void) const;
static Dictionary::Ptr CalculateDynamicMacros(const Service::Ptr& self);
Dictionary::Ptr CalculateDynamicMacros(void) const;
static set<Host::Ptr> GetParentHosts(const Service::Ptr& self);
static set<Service::Ptr> GetParentServices(const Service::Ptr& self);
set<Host::Ptr> GetParentHosts(void) const;
set<Service::Ptr> GetParentServices(void) const;
static bool IsReachable(const Service::Ptr& self);
bool IsReachable(void) const;
AcknowledgementType GetAcknowledgement(void);
void SetAcknowledgement(AcknowledgementType acknowledgement);
@ -165,7 +165,6 @@ public:
double GetAcknowledgementExpiry(void) const;
void SetAcknowledgementExpiry(double timestamp);
void ApplyCheckResult(const Dictionary::Ptr& cr);
static void UpdateStatistics(const Dictionary::Ptr& cr);
void AcknowledgeProblem(AcknowledgementType type, double expiry = 0);
@ -238,9 +237,9 @@ public:
double GetNotificationInterval(void) const;
void RequestNotifications(NotificationType type);
static void SendNotifications(const Service::Ptr& self, NotificationType type);
void SendNotifications(NotificationType type);
static set<Notification::Ptr> GetNotifications(const Service::Ptr& self);
set<Notification::Ptr> GetNotifications(void) const;
static void InvalidateNotificationsCache(void);

View File

@ -37,29 +37,49 @@ ServiceGroup::ServiceGroup(const Dictionary::Ptr& properties)
ServiceGroup::~ServiceGroup(void)
{
RefreshMembersCache();
InvalidateMembersCache();
}
/**
* @threadsafety Always.
*/
void ServiceGroup::OnRegistrationCompleted(void)
{
RefreshMembersCache();
assert(!OwnsLock());
InvalidateMembersCache();
}
/**
* @threadsafety Always.
*/
String ServiceGroup::GetDisplayName(void) const
{
ObjectLock olock(this);
if (!m_DisplayName.Get().IsEmpty())
return m_DisplayName;
else
return GetName();
}
/**
* @threadsafety Always.
*/
String ServiceGroup::GetNotesUrl(void) const
{
ObjectLock olock(this);
return m_NotesUrl;
}
/**
* @threadsafety Always.
*/
String ServiceGroup::GetActionUrl(void) const
{
ObjectLock olock(this);
return m_ActionUrl;
}
@ -76,21 +96,17 @@ ServiceGroup::Ptr ServiceGroup::GetByName(const String& name)
return dynamic_pointer_cast<ServiceGroup>(configObject);
}
set<Service::Ptr> ServiceGroup::GetMembers(const ServiceGroup::Ptr& self)
/**
* @threadsafety Always.
*/
set<Service::Ptr> ServiceGroup::GetMembers(void) const
{
String name;
{
ObjectLock olock(self);
name = self->GetName();
}
set<Service::Ptr> services;
{
boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const Service::WeakPtr& wservice, m_MembersCache[name]) {
BOOST_FOREACH(const Service::WeakPtr& wservice, m_MembersCache[GetName()]) {
Service::Ptr service = wservice.lock();
if (!service)
@ -103,18 +119,22 @@ set<Service::Ptr> ServiceGroup::GetMembers(const ServiceGroup::Ptr& self)
return services;
}
/**
* @threadsafety Always.
*/
void ServiceGroup::InvalidateMembersCache(void)
{
{
boost::mutex::scoped_lock lock(m_Mutex);
boost::mutex::scoped_lock lock(m_Mutex);
if (m_MembersCacheValid)
Utility::QueueAsyncCallback(boost::bind(&ServiceGroup::RefreshMembersCache));
if (m_MembersCacheValid)
Utility::QueueAsyncCallback(boost::bind(&ServiceGroup::RefreshMembersCache));
m_MembersCacheValid = false;
}
m_MembersCacheValid = false;
}
/**
* @threadsafety Always.
*/
void ServiceGroup::RefreshMembersCache(void)
{
{

View File

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

View File

@ -36,12 +36,20 @@ User::~User(void)
UserGroup::InvalidateMembersCache();
}
/**
* @threadsafety Always.
*/
void User::OnAttributeChanged(const String& name, const Value& oldValue)
{
assert(!OwnsLock());
if (name == "groups")
UserGroup::InvalidateMembersCache();
}
/**
* @threadsafety Always.
*/
User::Ptr User::GetByName(const String& name)
{
DynamicObject::Ptr configObject = DynamicObject::GetObject("User", name);
@ -49,33 +57,48 @@ User::Ptr User::GetByName(const String& name)
return dynamic_pointer_cast<User>(configObject);
}
/**
* @threadsafety Always.
*/
String User::GetDisplayName(void) const
{
ObjectLock olock(this);
if (!m_DisplayName.IsEmpty())
return m_DisplayName;
else
return GetName();
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr User::GetGroups(void) const
{
ObjectLock olock(this);
return m_Groups;
}
/**
* @threadsafety Always.
*/
Dictionary::Ptr User::GetMacros(void) const
{
ObjectLock olock(this);
return m_Macros;
}
Dictionary::Ptr User::CalculateDynamicMacros(const User::Ptr& self)
/**
* @threadsafety Always.
*/
Dictionary::Ptr User::CalculateDynamicMacros(void) const
{
Dictionary::Ptr macros = boost::make_shared<Dictionary>();
{
ObjectLock olock(self);
macros->Set("CONTACTNAME", self->GetName());
macros->Set("CONTACTALIAS", self->GetName());
}
macros->Set("CONTACTNAME", GetName());
macros->Set("CONTACTALIAS", GetName());
macros->Seal();

View File

@ -43,7 +43,7 @@ public:
Dictionary::Ptr GetGroups(void) const;
Dictionary::Ptr GetMacros(void) const;
static Dictionary::Ptr CalculateDynamicMacros(const User::Ptr& self);
Dictionary::Ptr CalculateDynamicMacros(void) const;
protected:
void OnAttributeChanged(const String& name, const Value& oldValue);

View File

@ -38,13 +38,23 @@ UserGroup::~UserGroup(void)
InvalidateMembersCache();
}
/**
* @threadsafety Always.
*/
void UserGroup::OnRegistrationCompleted(void)
{
assert(!OwnsLock());
InvalidateMembersCache();
}
/**
* @threadsafety Always.
*/
String UserGroup::GetDisplayName(void) const
{
ObjectLock olock(this);
if (!m_DisplayName.IsEmpty())
return m_DisplayName;
else
@ -64,21 +74,17 @@ UserGroup::Ptr UserGroup::GetByName(const String& name)
return dynamic_pointer_cast<UserGroup>(configObject);
}
set<User::Ptr> UserGroup::GetMembers(const UserGroup::Ptr& self)
/**
* @threadsafety Always.
*/
set<User::Ptr> UserGroup::GetMembers(void) const
{
String name;
{
ObjectLock olock(self);
name = self->GetName();
}
set<User::Ptr> users;
{
boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const User::WeakPtr& wuser, m_MembersCache[name]) {
BOOST_FOREACH(const User::WeakPtr& wuser, m_MembersCache[GetName()]) {
User::Ptr user = wuser.lock();
if (!user)
@ -91,18 +97,22 @@ set<User::Ptr> UserGroup::GetMembers(const UserGroup::Ptr& self)
return users;
}
/**
* @threadsafety Always.
*/
void UserGroup::InvalidateMembersCache(void)
{
{
boost::mutex::scoped_lock lock(m_Mutex);
boost::mutex::scoped_lock lock(m_Mutex);
if (m_MembersCacheValid)
Utility::QueueAsyncCallback(boost::bind(&UserGroup::RefreshMembersCache));
if (m_MembersCacheValid)
Utility::QueueAsyncCallback(boost::bind(&UserGroup::RefreshMembersCache));
m_MembersCacheValid = false;
}
m_MembersCacheValid = false;
}
/**
* @threadsafety Always.
*/
void UserGroup::RefreshMembersCache(void)
{
{

View File

@ -41,7 +41,7 @@ public:
String GetDisplayName(void) const;
static set<User::Ptr> GetMembers(const UserGroup::Ptr& self);
set<User::Ptr> GetMembers(void) const;
static void InvalidateMembersCache(void);

View File

@ -54,6 +54,8 @@ PythonInterpreter::~PythonInterpreter(void)
void PythonInterpreter::RegisterPythonFunction(const String& name, PyObject *function)
{
ObjectLock olock(this);
SubscribeFunction(name);
Py_INCREF(function);
@ -62,6 +64,8 @@ void PythonInterpreter::RegisterPythonFunction(const String& name, PyObject *fun
void PythonInterpreter::UnregisterPythonFunction(const String& name)
{
ObjectLock olock(this);
UnsubscribeFunction(name);
m_Functions.erase(name);
@ -70,6 +74,8 @@ void PythonInterpreter::UnregisterPythonFunction(const String& name)
void PythonInterpreter::ProcessCall(const ScriptTask::Ptr& task, const String& function,
const vector<Value>& arguments)
{
ObjectLock olock(this);
PyEval_AcquireThread(m_ThreadState);
PythonInterpreter *interp = m_Language->GetCurrentInterpreter();
m_Language->SetCurrentInterpreter(this);

View File

@ -36,6 +36,8 @@ PythonLanguage::PythonLanguage(void)
void PythonLanguage::InitializeOnce(void)
{
ObjectLock olock(this);
if (m_Initialized)
return;
@ -85,6 +87,8 @@ ScriptInterpreter::Ptr PythonLanguage::CreateInterpreter(const Script::Ptr& scri
PyThreadState *PythonLanguage::GetMainThreadState(void) const
{
ObjectLock olock(this);
return m_MainThreadState;
}
@ -139,6 +143,8 @@ PyObject *PythonLanguage::MarshalToPython(const Value& value)
return result;
} else if (value.IsObjectType<Dictionary>()) {
Dictionary::Ptr dict = value;
ObjectLock olock(dict);
PyObject *pdict = PyDict_New();
String key;
@ -214,6 +220,8 @@ Value PythonLanguage::MarshalFromPython(PyObject *value)
String PythonLanguage::ExceptionInfoToString(PyObject *type, PyObject *exc, PyObject *tb) const
{
ObjectLock olock(this);
PyObject *tb_dict = PyModule_GetDict(m_TracebackModule);
PyObject *format_exception = PyDict_GetItemString(tb_dict, "format_exception");
@ -304,6 +312,8 @@ PyObject *PythonLanguage::PyCallNativeFunction(PyObject *self, PyObject *args)
*/
void PythonLanguage::RegisterNativeFunction(const String& name, const ScriptFunction::Ptr& function)
{
ObjectLock olock(this);
PyThreadState *tstate = PyThreadState_Swap(m_MainThreadState);
PyObject *pname = PyString_FromString(name.CStr());
@ -327,6 +337,8 @@ void PythonLanguage::RegisterNativeFunction(const String& name, const ScriptFunc
*/
void PythonLanguage::UnregisterNativeFunction(const String& name)
{
ObjectLock olock(this);
PyThreadState *tstate = PyThreadState_Swap(m_MainThreadState);
PyObject *pdict = PyModule_GetDict(m_NativeModule);
@ -378,6 +390,8 @@ PyObject *PythonLanguage::PyRegisterFunction(PyObject *self, PyObject *args)
*/
PythonInterpreter *PythonLanguage::GetCurrentInterpreter(void)
{
ObjectLock olock(this);
return m_CurrentInterpreter;
}
@ -388,5 +402,7 @@ PythonInterpreter *PythonLanguage::GetCurrentInterpreter(void)
*/
void PythonLanguage::SetCurrentInterpreter(PythonInterpreter *interpreter)
{
ObjectLock olock(this);
m_CurrentInterpreter = interpreter;
}

View File

@ -72,7 +72,8 @@ Endpoint::Ptr Endpoint::MakeEndpoint(const String& name, bool replicated, bool l
endpointConfig->SetLocal(!replicated);
endpointConfig->AddExpression("local", OperatorSet, local);
DynamicObject::Ptr object = ConfigItem::Commit(endpointConfig->Compile());
ConfigItem::Ptr item = endpointConfig->Compile();
DynamicObject::Ptr object = item->Commit();
return dynamic_pointer_cast<Endpoint>(object);
}
@ -83,6 +84,8 @@ Endpoint::Ptr Endpoint::MakeEndpoint(const String& name, bool replicated, bool l
*/
bool Endpoint::IsLocalEndpoint(void) const
{
ObjectLock olock(this);
return m_Local;
}
@ -104,15 +107,22 @@ bool Endpoint::IsConnected(void) const
JsonRpcConnection::Ptr Endpoint::GetClient(void) const
{
ObjectLock olock(this);
return m_Client;
}
void Endpoint::SetClient(const JsonRpcConnection::Ptr& client)
{
m_Client = client;
client->OnNewMessage.connect(boost::bind(&Endpoint::NewMessageHandler, this, _2));
client->OnClosed.connect(boost::bind(&Endpoint::ClientClosedHandler, this));
{
ObjectLock olock(this);
m_Client = client;
}
OnConnected(GetSelf());
}
@ -128,11 +138,8 @@ void Endpoint::RegisterSubscription(const String& topic)
if (!subscriptions)
subscriptions = boost::make_shared<Dictionary>();
ObjectLock olock(subscriptions);
if (!subscriptions->Contains(topic)) {
Dictionary::Ptr newSubscriptions = subscriptions->ShallowClone();
ObjectLock nlock(newSubscriptions);
newSubscriptions->Set(topic, topic);
SetSubscriptions(newSubscriptions);
}
@ -150,11 +157,8 @@ void Endpoint::UnregisterSubscription(const String& topic)
if (!subscriptions)
return;
ObjectLock olock(subscriptions);
if (subscriptions->Contains(topic)) {
Dictionary::Ptr newSubscriptions = subscriptions->ShallowClone();
ObjectLock nlock(newSubscriptions);
newSubscriptions->Remove(topic);
SetSubscriptions(newSubscriptions);
}
@ -178,6 +182,8 @@ bool Endpoint::HasSubscription(const String& topic) const
*/
void Endpoint::ClearSubscriptions(void)
{
ObjectLock olock(this);
m_Subscriptions = Empty;
Touch("subscriptions");
}
@ -189,12 +195,17 @@ Dictionary::Ptr Endpoint::GetSubscriptions(void) const
void Endpoint::SetSubscriptions(const Dictionary::Ptr& subscriptions)
{
ObjectLock olock(this);
subscriptions->Seal();
m_Subscriptions = subscriptions;
Touch("subscriptions");
}
void Endpoint::RegisterTopicHandler(const String& topic, const function<Endpoint::Callback>& callback)
{
ObjectLock olock(this);
map<String, shared_ptr<signals2::signal<Endpoint::Callback> > >::iterator it;
it = m_TopicHandlers.find(topic);
@ -223,6 +234,8 @@ void Endpoint::UnregisterTopicHandler(const String& topic, const function<Endpoi
void Endpoint::OnAttributeChanged(const String& name, const Value& oldValue)
{
assert(!OwnsLock());
if (name == "subscriptions") {
Dictionary::Ptr oldSubscriptions, newSubscriptions;
@ -231,10 +244,9 @@ void Endpoint::OnAttributeChanged(const String& name, const Value& oldValue)
newSubscriptions = GetSubscriptions();
ObjectLock olock(oldSubscriptions);
ObjectLock nlock(newSubscriptions);
if (oldSubscriptions) {
ObjectLock olock(oldSubscriptions);
String subscription;
BOOST_FOREACH(tie(tuples::ignore, subscription), oldSubscriptions) {
if (!newSubscriptions || !newSubscriptions->Contains(subscription)) {
@ -245,6 +257,8 @@ void Endpoint::OnAttributeChanged(const String& name, const Value& oldValue)
}
if (newSubscriptions) {
ObjectLock olock(newSubscriptions);
String subscription;
BOOST_FOREACH(tie(tuples::ignore, subscription), newSubscriptions) {
if (!oldSubscriptions || !oldSubscriptions->Contains(subscription)) {
@ -264,6 +278,8 @@ void Endpoint::ProcessRequest(const Endpoint::Ptr& sender, const RequestMessage&
}
if (IsLocalEndpoint()) {
ObjectLock olock(this);
String method;
if (!request.GetMethod(&method))
return;
@ -317,6 +333,8 @@ void Endpoint::NewMessageHandler(const MessagePart& message)
void Endpoint::ClientClosedHandler(void)
{
assert(!OwnsLock());
/*try {
GetClient()->CheckException();
} catch (const exception& ex) {
@ -328,12 +346,16 @@ void Endpoint::ClientClosedHandler(void)
Logger::Write(LogWarning, "jsonrpc", "Lost connection to endpoint: identity=" + GetName());
// TODO: _only_ clear non-persistent subscriptions
// unregister ourselves if no persistent subscriptions are left (use a
// timer for that, once we have a TTL property for the topics)
ClearSubscriptions();
{
ObjectLock olock(this);
m_Client.reset();
// TODO: _only_ clear non-persistent subscriptions
// unregister ourselves if no persistent subscriptions are left (use a
// timer for that, once we have a TTL property for the topics)
ClearSubscriptions();
m_Client.reset();
}
OnDisconnected(GetSelf());
}
@ -345,6 +367,8 @@ void Endpoint::ClientClosedHandler(void)
*/
String Endpoint::GetNode(void) const
{
ObjectLock olock(this);
return m_Node;
}
@ -355,5 +379,7 @@ String Endpoint::GetNode(void) const
*/
String Endpoint::GetService(void) const
{
ObjectLock olock(this);
return m_Service;
}

View File

@ -50,6 +50,8 @@ EndpointManager::EndpointManager(void)
*/
void EndpointManager::SetSSLContext(const shared_ptr<SSL_CTX>& sslContext)
{
ObjectLock olock(this);
m_SSLContext = sslContext;
}
@ -60,6 +62,8 @@ void EndpointManager::SetSSLContext(const shared_ptr<SSL_CTX>& sslContext)
*/
shared_ptr<SSL_CTX> EndpointManager::GetSSLContext(void) const
{
ObjectLock olock(this);
return m_SSLContext;
}
@ -71,6 +75,8 @@ shared_ptr<SSL_CTX> EndpointManager::GetSSLContext(void) const
*/
void EndpointManager::SetIdentity(const String& identity)
{
ObjectLock olock(this);
m_Identity = identity;
if (m_Endpoint)
@ -91,6 +97,8 @@ void EndpointManager::SetIdentity(const String& identity)
*/
String EndpointManager::GetIdentity(void) const
{
ObjectLock olock(this);
return m_Identity;
}
@ -101,6 +109,8 @@ String EndpointManager::GetIdentity(void) const
*/
void EndpointManager::AddListener(const String& service)
{
ObjectLock olock(this);
shared_ptr<SSL_CTX> sslContext = GetSSLContext();
if (!sslContext)
@ -128,6 +138,8 @@ void EndpointManager::AddListener(const String& service)
* @param service The remote port.
*/
void EndpointManager::AddConnection(const String& node, const String& service) {
ObjectLock olock(this);
shared_ptr<SSL_CTX> sslContext = GetSSLContext();
if (!sslContext)
@ -145,6 +157,8 @@ void EndpointManager::AddConnection(const String& node, const String& service) {
*/
void EndpointManager::NewClientHandler(const Socket::Ptr& client, TlsRole role)
{
ObjectLock olock(this);
String peerAddress = client->GetPeerAddress();
TlsStream::Ptr tlsStream = boost::make_shared<TlsStream>(client, role, GetSSLContext());
tlsStream->Start();
@ -158,6 +172,8 @@ void EndpointManager::NewClientHandler(const Socket::Ptr& client, TlsRole role)
void EndpointManager::ClientConnectedHandler(const Stream::Ptr& client, const String& peerAddress)
{
ObjectLock olock(this);
TlsStream::Ptr tlsStream = static_pointer_cast<TlsStream>(client);
JsonRpcConnection::Ptr jclient = boost::make_shared<JsonRpcConnection>(tlsStream);
@ -178,6 +194,8 @@ void EndpointManager::ClientConnectedHandler(const Stream::Ptr& client, const St
void EndpointManager::ClientClosedHandler(const Stream::Ptr& client)
{
ObjectLock olock(this);
TlsStream::Ptr tlsStream = static_pointer_cast<TlsStream>(client);
m_PendingClients.erase(tlsStream);
}
@ -293,6 +311,8 @@ void EndpointManager::SendAPIMessage(const Endpoint::Ptr& sender, const Endpoint
RequestMessage& message,
const EndpointManager::APICallback& callback, double timeout)
{
ObjectLock olock(this);
m_NextMessageID++;
stringstream idstream;
@ -337,7 +357,7 @@ void EndpointManager::SubscriptionTimerHandler(void)
ObjectLock olock(endpointSubscriptions);
String topic;
BOOST_FOREACH(tie(tuples::ignore, topic), endpoint->GetSubscriptions()) {
BOOST_FOREACH(tie(tuples::ignore, topic), endpointSubscriptions) {
subscriptions->Set(topic, topic);
}
}
@ -374,6 +394,8 @@ void EndpointManager::ReconnectTimerHandler(void)
void EndpointManager::RequestTimerHandler(void)
{
ObjectLock olock(this);
map<String, PendingRequest>::iterator it;
for (it = m_Requests.begin(); it != m_Requests.end(); it++) {
if (it->second.HasTimedOut()) {
@ -390,6 +412,8 @@ void EndpointManager::RequestTimerHandler(void)
void EndpointManager::ProcessResponseMessage(const Endpoint::Ptr& sender,
const ResponseMessage& message)
{
ObjectLock olock(this);
String id;
if (!message.GetID(&id))
BOOST_THROW_EXCEPTION(invalid_argument("Response message must have a message ID."));

View File

@ -37,6 +37,8 @@ JsonRpcConnection::JsonRpcConnection(const Stream::Ptr& stream)
*/
void JsonRpcConnection::SendMessage(const MessagePart& message)
{
ObjectLock olock(this);
Value value = message.GetDictionary();
String json = value.Serialize();
//std::cerr << ">> " << json << std::endl;
@ -48,6 +50,8 @@ void JsonRpcConnection::SendMessage(const MessagePart& message)
*/
void JsonRpcConnection::ProcessData(void)
{
ObjectLock olock(this);
String jsonString;
while (NetString::ReadStringFromStream(GetStream(), &jsonString)) {