Fine-grained locks (WIP, Part 3).

This commit is contained in:
Gunnar Beutner 2013-02-18 23:44:24 +01:00
parent a4c7052a6e
commit 3dace35cf1
27 changed files with 344 additions and 281 deletions

View File

@ -91,7 +91,7 @@ String CompatComponent::GetCommandPath(void) const
void CompatComponent::Start(void)
{
m_StatusTimer = boost::make_shared<Timer>();
m_StatusTimer->SetInterval(15);
m_StatusTimer->SetInterval(5);
m_StatusTimer->OnTimerExpired.connect(boost::bind(&CompatComponent::StatusTimerHandler, this));
m_StatusTimer->Start();
m_StatusTimer->Reschedule(0);
@ -450,10 +450,18 @@ 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=" << IcingaApplication::GetInstance()->GetStartTime() << "\n"
<< "\t" << "program_start=" << startTime << "\n"
<< "\t" << "active_service_checks_enabled=1" << "\n"
<< "\t" << "passive_service_checks_enabled=1" << "\n"
<< "\t" << "active_host_checks_enabled=0" << "\n"
@ -478,85 +486,61 @@ void CompatComponent::StatusTimerHandler(void)
<< "# This file is auto-generated. Do not modify this file." << "\n"
<< "\n";
{
DynamicType::Ptr dt = DynamicType::GetByName("Host");
ObjectLock dlock(dt);
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Host")) {
Host::Ptr host = static_pointer_cast<Host>(object);
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) {
Host::Ptr host = static_pointer_cast<Host>(object);
DumpHostStatus(statusfp, host);
DumpHostObject(objectfp, host);
}
DumpHostStatus(statusfp, host);
DumpHostObject(objectfp, host);
}
{
DynamicType::Ptr dt = DynamicType::GetByName("Host");
ObjectLock dlock(dt);
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("HostGroup")) {
HostGroup::Ptr hg = static_pointer_cast<HostGroup>(object);
ObjectLock olock(hg);
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) {
HostGroup::Ptr hg = static_pointer_cast<HostGroup>(object);
ObjectLock olock(hg);
objectfp << "define hostgroup {" << "\n"
<< "\t" << "hostgroup_name" << "\t" << hg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << hg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << hg->GetActionUrl() << "\n";
objectfp << "define hostgroup {" << "\n"
<< "\t" << "hostgroup_name" << "\t" << hg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << hg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << hg->GetActionUrl() << "\n";
objectfp << "\t" << "members" << "\t";
DumpNameList(objectfp, hg->GetMembers());
objectfp << "\n"
<< "}" << "\n";
}
objectfp << "\t" << "members" << "\t";
DumpNameList(objectfp, hg->GetMembers());
objectfp << "\n"
<< "}" << "\n";
}
{
DynamicType::Ptr dt = DynamicType::GetByName("Service");
ObjectLock dlock(dt);
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = static_pointer_cast<Service>(object);
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) {
Service::Ptr service = static_pointer_cast<Service>(object);
DumpServiceStatus(statusfp, service);
DumpServiceObject(objectfp, service);
}
DumpServiceStatus(statusfp, service);
DumpServiceObject(objectfp, service);
}
{
DynamicType::Ptr dt = DynamicType::GetByName("ServiceGroup");
ObjectLock dlock(dt);
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("ServiceGroup")) {
ServiceGroup::Ptr sg = static_pointer_cast<ServiceGroup>(object);
ObjectLock olock(sg);
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) {
ServiceGroup::Ptr sg = static_pointer_cast<ServiceGroup>(object);
ObjectLock olock(sg);
objectfp << "define servicegroup {" << "\n"
<< "\t" << "servicegroup_name" << "\t" << sg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << sg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << sg->GetActionUrl() << "\n";
objectfp << "define servicegroup {" << "\n"
<< "\t" << "servicegroup_name" << "\t" << sg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << sg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << sg->GetActionUrl() << "\n";
objectfp << "\t" << "members" << "\t";
objectfp << "\t" << "members" << "\t";
vector<String> sglist;
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
ObjectLock slock(service);
Host::Ptr host = service->GetHost();
vector<String> sglist;
BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
ObjectLock slock(service);
Host::Ptr host = service->GetHost();
ObjectLock hlock(host);
sglist.push_back(host->GetName());
ObjectLock hlock(host);
sglist.push_back(host->GetName());
sglist.push_back(service->GetShortName());
}
DumpStringList(objectfp, sglist);
objectfp << "\n"
<< "}" << "\n";
sglist.push_back(service->GetShortName());
}
DumpStringList(objectfp, sglist);
objectfp << "\n"
<< "}" << "\n";
}
statusfp.close();

View File

@ -85,7 +85,7 @@ double CompatIdoComponent::GetReconnectInterval(void) const
if (interval.IsEmpty())
return DefaultReconnectInterval;
else
else
return interval;
}
@ -174,7 +174,7 @@ void CompatIdoComponent::OpenIdoSocket(void)
#define COMPATIDO_PROTOCOL 2
#define COMPATIDO_NAME "ICINGA2 COMPATIDO"
#define COMPATIDO_RELEASE_VERSION "2.0"
/* connection is always TCP */
/* connecttype is always initial */
stringstream msgHello;
@ -340,7 +340,7 @@ void CompatIdoComponent::DisableServiceObject(const Service::Ptr& service)
<< 53 << "=" << service->GetHost()->GetName() << "\n" /* host */
<< 114 << "=" << service->GetShortName() << "\n" /* service */
<< 999 << "\n\n"; /* enddata */
m_IdoConnection->SendMessage(message.str());
}
@ -442,7 +442,7 @@ void CompatIdoComponent::DumpHostStatus(const Host::Ptr& host)
state = 2; /* unreachable */
else if (!host->IsUp())
state = 1; /* down */
else
else
state = 0; /* up */
stringstream message;
@ -581,7 +581,7 @@ void CompatIdoComponent::DumpServiceObject(const Service::Ptr& service)
* dump service status to ido
*
* @param service Pointer to Service object
*/
*/
void CompatIdoComponent::DumpServiceStatus(const Service::Ptr& service)
{
stringstream log;
@ -673,7 +673,7 @@ void CompatIdoComponent::DumpServiceStatus(const Service::Ptr& service)
}
/**
/**
* dumps programstatus to ido
*/
void CompatIdoComponent::DumpProgramStatusData(void)
@ -738,7 +738,7 @@ void CompatIdoComponent::DumpConfigObjects(void)
/* hosts and hostgroups */
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Host")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Host")) {
const Host::Ptr& host = static_pointer_cast<Host>(object);
DumpHostObject(host);
@ -746,7 +746,7 @@ void CompatIdoComponent::DumpConfigObjects(void)
//DisableHostObject(host);
}
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("HostGroup")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("HostGroup")) {
const HostGroup::Ptr& hg = static_pointer_cast<HostGroup>(object);
/* dump the hostgroup and its attributes/members to ido */
@ -764,14 +764,14 @@ void CompatIdoComponent::DumpConfigObjects(void)
}
SendMessageList(message, hglist, 171); /* hostgroupmember */
message << 999 << "\n\n"; /* enddata */
m_IdoConnection->SendMessage(message.str());
}
/* services and servicegroups */
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Service")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = static_pointer_cast<Service>(object);
DumpServiceObject(service);
@ -779,7 +779,7 @@ void CompatIdoComponent::DumpConfigObjects(void)
//DisableServiceObject(service);
}
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("ServiceGroup")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("ServiceGroup")) {
const ServiceGroup::Ptr& sg = static_pointer_cast<ServiceGroup>(object);
/* dump the servicegroup and its attributes/members to ido */
@ -797,7 +797,7 @@ void CompatIdoComponent::DumpConfigObjects(void)
sglist.push_back(service->GetHost()->GetName());
sglist.push_back(service->GetShortName());
}
SendMessageList(message, sglist, 219); /* servicegroupmember */
message << 999 << "\n\n"; /* enddata */
@ -817,13 +817,13 @@ void CompatIdoComponent::DumpConfigObjects(void)
}
/**
* process and dump all status data
* process and dump all status data
*/
void CompatIdoComponent::DumpStatusData(void)
{
/* hosts */
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Host")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Host")) {
const Host::Ptr& host = static_pointer_cast<Host>(object);
DumpHostStatus(host);
@ -831,7 +831,7 @@ void CompatIdoComponent::DumpStatusData(void)
/* services */
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Service")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = static_pointer_cast<Service>(object);
DumpServiceStatus(service);

View File

@ -52,11 +52,7 @@ set<Endpoint::Ptr> DelegationComponent::GetCheckerCandidates(const Service::Ptr&
{
set<Endpoint::Ptr> candidates;
DynamicType::Ptr dt = DynamicType::GetByName("Endpoint");
ObjectLock dlock(dt);
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Endpoint")) {
Endpoint::Ptr endpoint = dynamic_pointer_cast<Endpoint>(object);
ObjectLock olock(endpoint);
@ -88,46 +84,34 @@ void DelegationComponent::DelegationTimerHandler(void)
{
map<Endpoint::Ptr, int> histogram;
{
DynamicType::Ptr dt = DynamicType::GetByName("Endpoint");
ObjectLock dlock(dt);
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Endpoint")) {
Endpoint::Ptr endpoint = dynamic_pointer_cast<Endpoint>(object);
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) {
Endpoint::Ptr endpoint = dynamic_pointer_cast<Endpoint>(object);
histogram[endpoint] = 0;
}
histogram[endpoint] = 0;
}
vector<Service::Ptr> services;
{
/* build "checker -> service count" histogram */
DynamicType::Ptr dt = DynamicType::GetByName("Service");
ObjectLock dlock(dt);
/* build "checker -> service count" histogram */
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
if (!service)
continue;
if (!service)
continue;
services.push_back(service);
services.push_back(service);
ObjectLock olock(service);
String checker = service->GetChecker();
if (checker.IsEmpty())
continue;
ObjectLock olock(service);
String checker = service->GetChecker();
if (checker.IsEmpty())
continue;
if (!Endpoint::Exists(checker))
continue;
if (!Endpoint::Exists(checker))
continue;
Endpoint::Ptr endpoint = Endpoint::GetByName(checker);
Endpoint::Ptr endpoint = Endpoint::GetByName(checker);
histogram[endpoint]++;
}
histogram[endpoint]++;
}
//std::random_shuffle(services.begin(), services.end());

View File

@ -75,23 +75,40 @@ void ReplicationComponent::CheckResultRequestHandler(const RequestMessage& reque
void ReplicationComponent::EndpointConnectedHandler(const Endpoint::Ptr& endpoint)
{
/* no need to sync the config with local endpoints */
if (endpoint->IsLocalEndpoint())
return;
{
ObjectLock olock(endpoint);
/* we just assume the other endpoint wants object updates */
endpoint->RegisterSubscription("config::ObjectUpdate");
endpoint->RegisterSubscription("config::ObjectRemoved");
/* no need to sync the config with local endpoints */
if (endpoint->IsLocalEndpoint())
return;
/* we just assume the other endpoint wants object updates */
endpoint->RegisterSubscription("config::ObjectUpdate");
endpoint->RegisterSubscription("config::ObjectRemoved");
}
DynamicType::Ptr type;
BOOST_FOREACH(tie(tuples::ignore, type), DynamicType::GetTypes()) {
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), type->GetObjects()) {
BOOST_FOREACH(const DynamicType::Ptr& dt, DynamicType::GetTypes()) {
set<DynamicObject::Ptr> objects;
{
ObjectLock olock(dt);
objects = dt->GetObjects();
}
BOOST_FOREACH(const DynamicObject::Ptr& object, objects) {
if (!ShouldReplicateObject(object))
continue;
RequestMessage request = MakeObjectMessage(object, "config::ObjectUpdate", 0, true);
EndpointManager::GetInstance()->SendUnicastMessage(m_Endpoint, endpoint, request);
EndpointManager::Ptr em = EndpointManager::GetInstance();
{
ObjectLock elock(em);
em->SendUnicastMessage(m_Endpoint, endpoint, request);
}
}
}
}

View File

@ -19,8 +19,6 @@
local object Component "checker" {}
local object Component "delegation" {
delegation_interval = 120
}
local object Component "delegation" {}
local object Component "notification" {}

View File

@ -24,7 +24,6 @@ using namespace icinga;
Application *Application::m_Instance = NULL;
bool Application::m_ShuttingDown = false;
bool Application::m_Debugging = false;
boost::thread::id Application::m_MainThreadID;
String Application::m_PrefixDir;
String Application::m_LocalStateDir;
String Application::m_PkgLibDir;
@ -402,6 +401,7 @@ void Application::InstallExceptionHandlers(void)
* Runs the application.
*
* @returns The application's exit code.
* @threadsafety Always.
*/
int Application::Run(void)
{

View File

@ -93,7 +93,6 @@ private:
static char **m_ArgV; /**< Command-line arguments. */
FILE *m_PidFile; /**< The PID file */
static bool m_Debugging; /**< Whether debugging is enabled. */
static boost::thread::id m_MainThreadID; /**< ID of the main thread. */
static String m_PrefixDir; /**< The installation prefix. */
static String m_LocalStateDir; /**< The local state dir. */
static String m_PkgLibDir; /**< The package lib dir. */

View File

@ -32,7 +32,7 @@ signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnUnregistered
signals2::signal<void (double, const set<DynamicObject *>&)> DynamicObject::OnTransactionClosing;
DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject)
: m_ConfigTx(0)
: m_Events(false), m_ConfigTx(0)
{
RegisterAttribute("__name", Attribute_Config);
RegisterAttribute("__type", Attribute_Config);
@ -41,13 +41,20 @@ DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject)
RegisterAttribute("__source", Attribute_Local);
RegisterAttribute("methods", Attribute_Config);
if (!serializedObject->Contains("configTx"))
BOOST_THROW_EXCEPTION(invalid_argument("Serialized object must contain a config snapshot."));
{
ObjectLock olock(serializedObject);
if (!serializedObject->Contains("configTx"))
BOOST_THROW_EXCEPTION(invalid_argument("Serialized object must contain a config snapshot."));
}
/* apply config state from the config item/remote update;
* The DynamicObject::Create function takes care of restoring
* non-config state after the object has been fully constructed */
ApplyUpdate(serializedObject, Attribute_Config);
{
ObjectLock olock(this);
ApplyUpdate(serializedObject, Attribute_Config);
}
boost::call_once(m_TransactionOnce, &DynamicObject::Initialize);
}
@ -75,9 +82,12 @@ void DynamicObject::Initialize(void)
*/
void DynamicObject::SendLocalUpdateEvents(void)
{
map<String, Value, string_iless>::iterator it;
for (it = m_ModifiedAttributes.begin(); it != m_ModifiedAttributes.end(); it++) {
OnAttributeChanged(it->first, it->second);
/* Check if it's safe to send events. */
if (GetEvents()) {
map<String, Value, string_iless>::iterator it;
for (it = m_ModifiedAttributes.begin(); it != m_ModifiedAttributes.end(); it++) {
OnAttributeChanged(it->first, it->second);
}
}
m_ModifiedAttributes.clear();
@ -124,39 +134,50 @@ Dictionary::Ptr DynamicObject::BuildUpdate(double sinceTx, int attributeTypes) c
void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate,
int allowedTypes)
{
double configTx = 0;
if ((allowedTypes & Attribute_Config) != 0 &&
serializedUpdate->Contains("configTx")) {
configTx = serializedUpdate->Get("configTx");
Dictionary::Ptr attrs;
if (configTx > m_ConfigTx)
ClearAttributesByType(Attribute_Config);
{
ObjectLock olock(serializedUpdate);
double configTx = 0;
if ((allowedTypes & Attribute_Config) != 0 &&
serializedUpdate->Contains("configTx")) {
configTx = serializedUpdate->Get("configTx");
if (configTx > m_ConfigTx)
ClearAttributesByType(Attribute_Config);
}
attrs = serializedUpdate->Get("attrs");
}
Dictionary::Ptr attrs = serializedUpdate->Get("attrs");
{
ObjectLock olock(attrs);
Dictionary::Iterator it;
for (it = attrs->Begin(); it != attrs->End(); it++) {
if (!it->second.IsObjectType<Dictionary>())
continue;
Dictionary::Iterator it;
for (it = attrs->Begin(); it != attrs->End(); it++) {
if (!it->second.IsObjectType<Dictionary>())
continue;
Dictionary::Ptr attr = it->second;
Dictionary::Ptr attr = it->second;
ObjectLock alock(attr);
int type = attr->Get("type");
int type = attr->Get("type");
if ((type & ~allowedTypes) != 0)
continue;
if ((type & ~allowedTypes) != 0)
continue;
Value data = attr->Get("data");
double tx = attr->Get("tx");
Value data = attr->Get("data");
double tx = attr->Get("tx");
if (type & Attribute_Config)
RegisterAttribute(it->first, Attribute_Config);
if (type & Attribute_Config)
RegisterAttribute(it->first, Attribute_Config);
if (!HasAttribute(it->first))
RegisterAttribute(it->first, static_cast<DynamicAttributeType>(type));
if (!HasAttribute(it->first))
RegisterAttribute(it->first, static_cast<DynamicAttributeType>(type));
InternalSetAttribute(it->first, data, tx, true);
InternalSetAttribute(it->first, data, tx, true);
}
}
}
@ -296,13 +317,18 @@ String DynamicObject::GetSource(void) const
void DynamicObject::Register(void)
{
DynamicType::Ptr dtype = GetType();
{
DynamicType::Ptr dtype = GetType();
ObjectLock olock(dtype);
DynamicObject::Ptr dobj = dtype->GetObject(GetName());
DynamicObject::Ptr self = GetSelf();
assert(!dobj || dobj == self);
DynamicObject::Ptr dobj = dtype->GetObject(GetName());
dtype->RegisterObject(self);
DynamicObject::Ptr self = GetSelf();
assert(!dobj || dobj == self);
if (!dobj)
dtype->RegisterObject(self);
}
OnRegistered(GetSelf());
@ -375,10 +401,9 @@ void DynamicObject::DumpObjects(const String& filename)
StdioStream::Ptr sfp = boost::make_shared<StdioStream>(&fp, false);
sfp->Start();
DynamicType::Ptr type;
BOOST_FOREACH(tie(tuples::ignore, type), DynamicType::GetTypes()) {
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), type->GetObjects()) {
;
BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
if (object->IsLocal())
continue;
@ -472,13 +497,16 @@ void DynamicObject::RestoreObjects(const String& filename)
void DynamicObject::DeactivateObjects(void)
{
DynamicType::TypeMap::iterator tt;
for (tt = DynamicType::GetTypes().begin(); tt != DynamicType::GetTypes().end(); tt++) {
DynamicType::NameMap::iterator nt;
BOOST_FOREACH(const DynamicType::Ptr& dt, DynamicType::GetTypes()) {
set<DynamicObject::Ptr> objects;
while ((nt = tt->second->GetObjects().begin()) != tt->second->GetObjects().end()) {
DynamicObject::Ptr object = nt->second;
{
ObjectLock olock(dt);
objects = dt->GetObjects();
}
BOOST_FOREACH(const DynamicObject::Ptr& object, objects) {
ObjectLock olock(object);
object->Unregister();
}
}
@ -543,3 +571,13 @@ const DynamicObject::AttributeMap& DynamicObject::GetAttributes(void) const
{
return m_Attributes;
}
void DynamicObject::SetEvents(bool events)
{
m_Events = events;
}
bool DynamicObject::GetEvents(void) const
{
return m_Events;
}

View File

@ -122,6 +122,9 @@ public:
const AttributeMap& GetAttributes(void) const;
void SetEvents(bool events);
bool GetEvents(void) const;
static DynamicObject::Ptr GetObject(const String& type, const String& name);
static void DumpObjects(const String& filename);
@ -144,6 +147,8 @@ private:
map<String, Value, string_iless> m_ModifiedAttributes;
double m_ConfigTx;
bool m_Events;
static double m_CurrentTx;
/* This has to be a set of raw pointers because the DynamicObject

View File

@ -32,9 +32,9 @@ DynamicType::Ptr DynamicType::GetByName(const String& name)
{
boost::mutex::scoped_lock lock(GetStaticMutex());
DynamicType::TypeMap::const_iterator tt = GetTypes().find(name);
DynamicType::TypeMap::const_iterator tt = InternalGetTypeMap().find(name);
if (tt == GetTypes().end())
if (tt == InternalGetTypeMap().end())
return DynamicType::Ptr();
return tt->second;
@ -43,18 +43,34 @@ DynamicType::Ptr DynamicType::GetByName(const String& name)
/**
* @threadsafety Caller must hold DynamicType::GetStaticMutex() while using the map.
*/
DynamicType::TypeMap& DynamicType::GetTypes(void)
DynamicType::TypeMap& DynamicType::InternalGetTypeMap(void)
{
static DynamicType::TypeMap types;
return types;
static DynamicType::TypeMap typemap;
return typemap;
}
/**
* @threadsafety Caller must hold DynamicType::GetStaticMutex() while using the map.
*/
DynamicType::NameMap& DynamicType::GetObjects(void)
DynamicType::TypeSet& DynamicType::InternalGetTypeSet(void)
{
return m_Objects;
static DynamicType::TypeSet typeset;
return typeset;
}
DynamicType::TypeSet DynamicType::GetTypes(void)
{
boost::mutex::scoped_lock lock(GetStaticMutex());
return InternalGetTypeSet(); /* Making a copy of the set here. */
}
set<DynamicObject::Ptr> DynamicType::GetObjects(const String& type)
{
DynamicType::Ptr dt = GetByName(type);
ObjectLock olock(dt);
return dt->GetObjects();
}
set<DynamicObject::Ptr> DynamicType::GetObjects(void) const
{
return m_ObjectSet; /* Making a copy of the set here. */
}
String DynamicType::GetName(void) const
@ -64,19 +80,30 @@ String DynamicType::GetName(void) const
void DynamicType::RegisterObject(const DynamicObject::Ptr& object)
{
m_Objects[object->GetName()] = object;
ObjectLock olock(object);
object->SetEvents(true);
if (m_ObjectMap.find(object->GetName()) != m_ObjectMap.end())
BOOST_THROW_EXCEPTION(runtime_error("RegisterObject() found existing object with the same name: " + object->GetName()));
m_ObjectMap[object->GetName()] = object;
m_ObjectSet.insert(object);
}
void DynamicType::UnregisterObject(const DynamicObject::Ptr& object)
{
m_Objects.erase(object->GetName());
ObjectLock olock(object);
object->SetEvents(false);
m_ObjectMap.erase(object->GetName());
m_ObjectSet.erase(object);
}
DynamicObject::Ptr DynamicType::GetObject(const String& name) const
{
DynamicType::NameMap::const_iterator nt = m_Objects.find(name);
DynamicType::ObjectMap::const_iterator nt = m_ObjectMap.find(name);
if (nt == m_Objects.end())
if (nt == m_ObjectMap.end())
return DynamicObject::Ptr();
return nt->second;
@ -89,18 +116,20 @@ void DynamicType::RegisterType(const DynamicType::Ptr& type)
{
boost::mutex::scoped_lock lock(GetStaticMutex());
DynamicType::TypeMap::const_iterator tt = GetTypes().find(type->GetName());
DynamicType::TypeMap::const_iterator tt = InternalGetTypeMap().find(type->GetName());
if (tt != GetTypes().end())
if (tt != InternalGetTypeMap().end())
BOOST_THROW_EXCEPTION(runtime_error("Cannot register class for type '" +
type->GetName() + "': Objects of this type already exist."));
GetTypes()[type->GetName()] = type;
InternalGetTypeMap()[type->GetName()] = type;
InternalGetTypeSet().insert(type);
}
DynamicObject::Ptr DynamicType::CreateObject(const Dictionary::Ptr& serializedUpdate) const
{
DynamicObject::Ptr obj = m_ObjectFactory(serializedUpdate);
ObjectLock olock(obj);
/* register attributes */
String name;

View File

@ -36,8 +36,6 @@ public:
typedef weak_ptr<DynamicType> WeakPtr;
typedef function<DynamicObject::Ptr (const Dictionary::Ptr&)> ObjectFactory;
typedef map<String, DynamicType::Ptr, string_iless> TypeMap;
typedef map<String, DynamicObject::Ptr, string_iless> NameMap;
DynamicType(const String& name, const ObjectFactory& factory);
@ -54,8 +52,10 @@ public:
void RegisterObject(const DynamicObject::Ptr& object);
void UnregisterObject(const DynamicObject::Ptr& object);
/* TODO(thread) make private */ static TypeMap& GetTypes(void);
/* TODO(thread) make private */ NameMap& GetObjects(void);
static set<DynamicType::Ptr> GetTypes(void);
set<DynamicObject::Ptr> GetObjects(void) const;
static set<DynamicObject::Ptr> GetObjects(const String& type);
void AddAttribute(const String& name, DynamicAttributeType type);
void RemoveAttribute(const String& name);
@ -68,8 +68,17 @@ private:
ObjectFactory m_ObjectFactory;
map<String, DynamicAttributeType> m_Attributes;
NameMap m_Objects;
typedef map<String, DynamicObject::Ptr, string_iless> ObjectMap;
typedef set<DynamicObject::Ptr> ObjectSet;
ObjectMap m_ObjectMap;
ObjectSet m_ObjectSet;
typedef map<String, DynamicType::Ptr, string_iless> TypeMap;
typedef set<DynamicType::Ptr> TypeSet;
static TypeMap& InternalGetTypeMap(void);
static TypeSet& InternalGetTypeSet(void);
static boost::mutex& GetStaticMutex(void);
};

View File

@ -107,24 +107,17 @@ void Logger::ForwardLogEntry(const LogEntry& entry)
{
bool processed = false;
DynamicType::Ptr dt = DynamicType::GetByName("Logger");
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Logger")) {
Logger::Ptr logger = dynamic_pointer_cast<Logger>(object);
DynamicObject::Ptr object;
{
ObjectLock llock(logger);
{
ObjectLock olock(dt);
BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) {
Logger::Ptr logger = dynamic_pointer_cast<Logger>(object);
{
ObjectLock llock(logger);
if (entry.Severity >= logger->GetMinSeverity())
logger->m_Impl->ProcessLogEntry(entry);
}
processed = true;
if (entry.Severity >= logger->GetMinSeverity())
logger->m_Impl->ProcessLogEntry(entry);
}
processed = true;
}
LogSeverity defaultLogLevel;

View File

@ -112,35 +112,22 @@ private:
struct ObjectLock {
public:
ObjectLock(const Object::Ptr& object)
#ifdef _DEBUG
: m_Lock(), m_Object(object)
#endif /* _DEBUG */
: m_Lock()
{
if (object)
m_Lock = recursive_mutex::scoped_lock(object->GetMutex());
}
ObjectLock(const Object *object)
#ifdef _DEBUG
: m_Lock(), m_Object(object->GetSelf())
#endif /* _DEBUG */
: m_Lock()
{
if (object)
m_Lock = recursive_mutex::scoped_lock(object->GetMutex());
}
#ifdef _DEBUG
~ObjectLock(void)
{
assert(m_Object.lock());
}
#endif /* _DEBUG */
private:
recursive_mutex::scoped_lock m_Lock;
#ifdef _DEBUG
Object::WeakPtr m_Object;
#endif /* _DEBUG */
};
/**

View File

@ -13,7 +13,7 @@
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* aRingBuffer::SizeType with this program; if not, write to the Free Software Foundation *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
@ -22,7 +22,7 @@
using namespace icinga;
RingBuffer::RingBuffer(RingBuffer::SizeType slots)
: m_Slots(slots, 0), m_Offset(0)
: m_Slots(slots, 0), m_TimeValue(0)
{ }
RingBuffer::SizeType RingBuffer::GetLength(void) const
@ -34,17 +34,23 @@ void RingBuffer::InsertValue(RingBuffer::SizeType tv, int num)
{
vector<int>::size_type offsetTarget = tv % m_Slots.size();
/* walk towards the target offset, resetting slots to 0 */
while (m_Offset != offsetTarget) {
m_Offset++;
if (tv > m_TimeValue) {
vector<int>::size_type offset = m_TimeValue % m_Slots.size();
if (m_Offset >= m_Slots.size())
m_Offset = 0;
/* walk towards the target offset, resetting slots to 0 */
while (offset != offsetTarget) {
offset++;
m_Slots[m_Offset] = 0;
if (offset >= m_Slots.size())
offset = 0;
m_Slots[offset] = 0;
}
m_TimeValue = tv;
}
m_Slots[m_Offset] += num;
m_Slots[offsetTarget] += num;
}
int RingBuffer::GetValues(RingBuffer::SizeType span) const
@ -52,7 +58,7 @@ int RingBuffer::GetValues(RingBuffer::SizeType span) const
if (span > m_Slots.size())
span = m_Slots.size();
int off = m_Offset;
int off = m_TimeValue % m_Slots.size();;
int sum = 0;
while (span > 0) {
sum += m_Slots[off];

View File

@ -41,7 +41,7 @@ public:
private:
vector<int> m_Slots;
SizeType m_Offset;
int m_TimeValue;
};
}

View File

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

View File

@ -111,14 +111,20 @@ void ConfigCompilerContext::Validate(void)
SetContext(this);
BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) {
ConfigType::Ptr ctype = GetType(item->GetType());
ConfigType::Ptr ctype;
if (!ctype) {
AddError(true, "No validation type found for object '" + item->GetName() + "' of type '" + item->GetType() + "'");
{
ObjectLock olock(item);
ctype = GetType(item->GetType());
continue;
if (!ctype) {
AddError(true, "No validation type found for object '" + item->GetName() + "' of type '" + item->GetType() + "'");
continue;
}
}
ObjectLock olock(ctype);
ctype->ValidateItem(item);
}
@ -131,7 +137,7 @@ void ConfigCompilerContext::ActivateItems(void)
Logger::Write(LogInformation, "config", "Activating config items in compilation unit '" + m_Unit + "'");
BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) {
ObjectLock olock(item);
item->Commit();
}
}

View File

@ -132,7 +132,11 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
ScriptTask::Ptr task = boost::make_shared<ScriptTask>(func, arguments);
task->Start();
task->Wait();
task->GetResult();
{
ObjectLock olock(task);
task->GetResult();
}
}
}

View File

@ -311,8 +311,7 @@ void Host::ValidateServicesCache(void)
m_ServicesCache.clear();
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Service")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
const Service::Ptr& service = static_pointer_cast<Service>(object);
// TODO: assert for duplicate short_names

View File

@ -21,6 +21,7 @@
using namespace icinga;
boost::mutex HostGroup::m_Mutex;
map<String, vector<Host::WeakPtr> > HostGroup::m_MembersCache;
bool HostGroup::m_MembersCacheValid = true;
@ -77,13 +78,16 @@ set<Host::Ptr> HostGroup::GetMembers(void) const
ValidateMembersCache();
BOOST_FOREACH(const Host::WeakPtr& hst, m_MembersCache[GetName()]) {
Host::Ptr host = hst.lock();
{
boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const Host::WeakPtr& hst, m_MembersCache[GetName()]) {
Host::Ptr host = hst.lock();
if (!host)
continue;
if (!host)
continue;
hosts.insert(host);
hosts.insert(host);
}
}
return hosts;
@ -91,25 +95,29 @@ set<Host::Ptr> HostGroup::GetMembers(void) const
void HostGroup::InvalidateMembersCache(void)
{
boost::mutex::scoped_lock lock(m_Mutex);
m_MembersCacheValid = false;
m_MembersCache.clear();
}
void HostGroup::ValidateMembersCache(void)
{
boost::mutex::scoped_lock lock(m_Mutex);
if (m_MembersCacheValid)
return;
m_MembersCache.clear();
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Host")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Host")) {
const Host::Ptr& host = static_pointer_cast<Host>(object);
ObjectLock olock(host);
Dictionary::Ptr dict;
dict = host->GetGroups();
if (dict) {
ObjectLock mlock(dict);
Value hostgroup;
BOOST_FOREACH(tie(tuples::ignore, hostgroup), dict) {
if (!HostGroup::Exists(hostgroup))

View File

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

View File

@ -167,8 +167,7 @@ void Service::ValidateCommentsCache(void)
m_CommentsCache.clear();
m_LegacyCommentsCache.clear();
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Service")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
service->AddCommentsToCache();
}
@ -210,11 +209,7 @@ void Service::RemoveExpiredComments(void)
void Service::CommentsExpireTimerHandler(void)
{
DynamicType::Ptr dt = DynamicType::GetByName("Service");
ObjectLock dlock(dt);
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
ObjectLock olock(service);
service->RemoveExpiredComments();

View File

@ -232,8 +232,7 @@ void Service::ValidateDowntimesCache(void)
m_DowntimesCache.clear();
m_LegacyDowntimesCache.clear();
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Service")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
service->AddDowntimesToCache();
}
@ -275,11 +274,7 @@ void Service::RemoveExpiredDowntimes(void)
void Service::DowntimesExpireTimerHandler(void)
{
DynamicType::Ptr dt = DynamicType::GetByName("Service");
ObjectLock dlock(dt);
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), dt->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object);
ObjectLock slock(service);
service->RemoveExpiredDowntimes();

View File

@ -68,8 +68,7 @@ void Service::ValidateNotificationsCache(void)
m_NotificationsCache.clear();
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Notification")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Notification")) {
const Notification::Ptr& notification = static_pointer_cast<Notification>(object);
m_NotificationsCache[notification->GetService()->GetName()].insert(notification);

View File

@ -21,6 +21,7 @@
using namespace icinga;
boost::mutex ServiceGroup::m_Mutex;
map<String, vector<Service::WeakPtr> > ServiceGroup::m_MembersCache;
bool ServiceGroup::m_MembersCacheValid;
@ -77,13 +78,16 @@ set<Service::Ptr> ServiceGroup::GetMembers(void) const
ValidateMembersCache();
BOOST_FOREACH(const Service::WeakPtr& svc, m_MembersCache[GetName()]) {
Service::Ptr service = svc.lock();
{
boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const Service::WeakPtr& svc, m_MembersCache[GetName()]) {
Service::Ptr service = svc.lock();
if (!service)
continue;
if (!service)
continue;
services.insert(service);
services.insert(service);
}
}
return services;
@ -91,25 +95,29 @@ set<Service::Ptr> ServiceGroup::GetMembers(void) const
void ServiceGroup::InvalidateMembersCache(void)
{
boost::mutex::scoped_lock lock(m_Mutex);
m_MembersCacheValid = false;
m_MembersCache.clear();
}
void ServiceGroup::ValidateMembersCache(void)
{
boost::mutex::scoped_lock lock(m_Mutex);
if (m_MembersCacheValid)
return;
m_MembersCache.clear();
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Service")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
const Service::Ptr& service = static_pointer_cast<Service>(object);
ObjectLock olock(service);
Dictionary::Ptr dict;
dict = service->GetGroups();
if (dict) {
ObjectLock mlock(dict);
Value servicegroup;
BOOST_FOREACH(tie(tuples::ignore, servicegroup), dict) {
if (!ServiceGroup::Exists(servicegroup))

View File

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

View File

@ -232,8 +232,8 @@ void EndpointManager::SendAnycastMessage(const Endpoint::Ptr& sender,
BOOST_THROW_EXCEPTION(invalid_argument("Message is missing the 'method' property."));
vector<Endpoint::Ptr> candidates;
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Endpoint")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Endpoint")) {
Endpoint::Ptr endpoint = dynamic_pointer_cast<Endpoint>(object);
/* don't forward messages between non-local endpoints */
if ((sender && !sender->IsLocal()) && !endpoint->IsLocal())
@ -279,8 +279,7 @@ void EndpointManager::SendMulticastMessage(const Endpoint::Ptr& sender,
if (!message.GetMethod(&method))
BOOST_THROW_EXCEPTION(invalid_argument("Message is missing the 'method' property."));
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Endpoint")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Endpoint")) {
Endpoint::Ptr recipient = dynamic_pointer_cast<Endpoint>(object);
/* don't forward messages back to the sender */
@ -327,8 +326,7 @@ void EndpointManager::SubscriptionTimerHandler(void)
{
Dictionary::Ptr subscriptions = boost::make_shared<Dictionary>();
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Endpoint")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Endpoint")) {
Endpoint::Ptr endpoint = dynamic_pointer_cast<Endpoint>(object);
/* don't copy subscriptions from non-local endpoints or the identity endpoint */
@ -349,8 +347,7 @@ void EndpointManager::SubscriptionTimerHandler(void)
void EndpointManager::ReconnectTimerHandler(void)
{
DynamicObject::Ptr object;
BOOST_FOREACH(tie(tuples::ignore, object), DynamicType::GetByName("Endpoint")->GetObjects()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Endpoint")) {
Endpoint::Ptr endpoint = dynamic_pointer_cast<Endpoint>(object);
if (endpoint->IsConnected() || endpoint == m_Endpoint)