// ********************************************************************** // // Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** #ifndef ICE_METRICSADMIN_I_H #define ICE_METRICSADMIN_I_H #include #include #include #include #ifdef _MSC_VER # define ICE_CPP11_COMPILER_REGEXP #endif #ifdef __MINGW32__ // // No regexp support with MinGW, when MinGW C++11 mode is not experimental // we can use std::regex. // #elif defined(ICE_CPP11_COMPILER_REGEXP) # include #else # include #endif #include namespace IceMX { class Updater; template class MetricsHelperT; } namespace IceInternal { class ICE_API MetricsMapI; ICE_DEFINE_PTR(MetricsMapIPtr, MetricsMapI); class ICE_API MetricsMapI : public Ice::EnableSharedFromThis { public: class ICE_API RegExp : public IceUtil::Shared { public: RegExp(const std::string&, const std::string&); ~RegExp(); template bool match(const IceMX::MetricsHelperT& helper, bool reject) { std::string value; try { value = helper(_attribute); } catch(const std::exception&) { return !reject; } return match(value); } private: bool match(const std::string&); const std::string _attribute; #ifdef __MINGW32__ // // No regexp support with MinGW, when MinGW C++11 mode is not experimental // we can use std::regex. // #elif defined(ICE_CPP11_COMPILER_REGEXP) # if _MSC_VER < 1600 std::tr1::regex _regex; # else std::regex _regex; # endif #else regex_t _preg; #endif }; ICE_DEFINE_PTR(RegExpPtr, RegExp); MetricsMapI(const std::string&, const Ice::PropertiesPtr&); MetricsMapI(const MetricsMapI&); virtual void destroy() = 0; virtual IceMX::MetricsFailuresSeq getFailures() = 0; virtual IceMX::MetricsFailures getFailures(const std::string&) = 0; virtual IceMX::MetricsMap getMetrics() const = 0; virtual MetricsMapIPtr clone() const = 0; const Ice::PropertyDict& getProperties() const; protected: const Ice::PropertyDict _properties; const std::vector _groupByAttributes; const std::vector _groupBySeparators; const int _retain; const std::vector _accept; const std::vector _reject; }; class ICE_API MetricsMapFactory : #ifdef ICE_CPP11_MAPPING public virtual Ice::VirtualEnableSharedFromThisBase #else public Ice::LocalObject #endif { public: MetricsMapFactory(IceMX::Updater*); virtual MetricsMapIPtr create(const std::string&, const Ice::PropertiesPtr&) = 0; void update(); private: IceMX::Updater* _updater; }; ICE_DEFINE_PTR(MetricsMapFactoryPtr, MetricsMapFactory); template class MetricsMapT : public MetricsMapI, private IceUtil::Mutex { public: typedef MetricsType T; typedef ICE_INTERNAL_HANDLE TPtr; ICE_DEFINE_PTR(MetricsMapTPtr, MetricsMapT); typedef IceMX::MetricsMap MetricsType::* SubMapMember; class EntryT; ICE_DEFINE_PTR(EntryTPtr, EntryT); class EntryT : #ifdef ICE_CPP11_MAPPING public virtual Ice::VirtualEnableSharedFromThisBase #else public Ice::LocalObject #endif { public: EntryT(MetricsMapTPtr map, const TPtr& object, const typename std::list::iterator& p) : _map(map), _object(object), _detachedPos(p) { } ~EntryT() { assert(_object->total > 0); for(typename std::map >::const_iterator p = _subMaps.begin(); p != _subMaps.end(); ++p) { p->second.first->destroy(); // Break cyclic reference counts. } } void failed(const std::string& exceptionName) { IceUtil::Mutex::Lock sync(*_map); ++_object->failures; ++_failures[exceptionName]; } template typename MetricsMapT::EntryTPtr getMatching(const std::string& mapName, const IceMX::MetricsHelperT& helper) { MetricsMapIPtr m; { IceUtil::Mutex::Lock sync(*_map); typename std::map >::iterator p = _subMaps.find(mapName); if(p == _subMaps.end()) { std::pair map = _map->createSubMap(mapName); if(map.first) { p = _subMaps.insert(make_pair(mapName, map)).first; } } if(p == _subMaps.end()) { return 0; } m = p->second.first; } MetricsMapT* map = dynamic_cast*>(m.get()); assert(map); return map->getMatching(helper); } void detach(Ice::Long lifetime) { IceUtil::Mutex::Lock sync(*_map); _object->totalLifetime += lifetime; if(--_object->current == 0) { #ifdef ICE_CPP11_MAPPING _map->detached(std::dynamic_pointer_cast(shared_from_this())); #else _map->detached(this); #endif } } template void execute(Function func) { IceUtil::Mutex::Lock sync(*_map); func(_object); } MetricsMapT* getMap() { return _map.get(); } private: IceMX::MetricsFailures getFailures() const { IceMX::MetricsFailures f; f.id = _object->id; f.failures = _failures; return f; } IceMX::MetricsPtr clone() const { TPtr metrics = ICE_DYNAMIC_CAST(T, _object->ice_clone()); for(typename std::map >::const_iterator p = _subMaps.begin(); p != _subMaps.end(); ++p) { metrics.get()->*p->second.second = p->second.first->getMetrics(); } return metrics; } bool isDetached() const { return _object->current == 0; } void attach(const IceMX::MetricsHelperT& helper) { ++_object->total; ++_object->current; helper.initMetrics(_object); } friend class MetricsMapT; MetricsMapTPtr _map; TPtr _object; IceMX::StringIntDict _failures; std::map > _subMaps; typename std::list::iterator _detachedPos; }; MetricsMapT(const std::string& mapPrefix, const Ice::PropertiesPtr& properties, const std::map >& subMaps) : MetricsMapI(mapPrefix, properties), _destroyed(false) { std::vector subMapNames; typename std::map >::const_iterator p; for(p = subMaps.begin(); p != subMaps.end(); ++p) { subMapNames.push_back(p->first); const std::string subMapsPrefix = mapPrefix + "Map."; std::string subMapPrefix = subMapsPrefix + p->first + '.'; if(properties->getPropertiesForPrefix(subMapPrefix).empty()) { if(properties->getPropertiesForPrefix(subMapsPrefix).empty()) { subMapPrefix = mapPrefix; } else { continue; // This sub-map isn't configured. } } _subMaps.insert(std::make_pair(p->first, std::make_pair(p->second.first, p->second.second->create(subMapPrefix, properties)))); } } MetricsMapT(const MetricsMapT& other) : MetricsMapI(other), _destroyed(false) { } virtual void destroy() { Lock sync(*this); _destroyed = true; _objects.clear(); // Break cyclic reference counts _detachedQueue.clear(); // Break cyclic reference counts } virtual IceMX::MetricsMap getMetrics() const { IceMX::MetricsMap objects; Lock sync(*this); for(typename std::map::const_iterator p = _objects.begin(); p != _objects.end(); ++p) { objects.push_back(p->second->clone()); } return objects; } virtual IceMX::MetricsFailuresSeq getFailures() { IceMX::MetricsFailuresSeq failures; Lock sync(*this); for(typename std::map::const_iterator p = _objects.begin(); p != _objects.end(); ++p) { IceMX::MetricsFailures f = p->second->getFailures(); if(!f.failures.empty()) { failures.push_back(f); } } return failures; } virtual IceMX::MetricsFailures getFailures(const std::string& id) { Lock sync(*this); typename std::map::const_iterator p = _objects.find(id); if(p != _objects.end()) { return p->second->getFailures(); } return IceMX::MetricsFailures(); } std::pair createSubMap(const std::string& subMapName) { typename std::map >::const_iterator p = _subMaps.find(subMapName); if(p != _subMaps.end()) { #ifdef ICE_CPP11_MAPPING return std::pair(p->second.second->clone()->shared_from_this(), p->second.first); #else return std::pair(p->second.second->clone(), p->second.first); #endif } return std::pair(MetricsMapIPtr(ICE_NULLPTR), static_cast(0)); } EntryTPtr getMatching(const IceMX::MetricsHelperT& helper, const EntryTPtr& previous = EntryTPtr()) { // // Check the accept and reject filters. // for(std::vector::const_iterator p = _accept.begin(); p != _accept.end(); ++p) { if(!(*p)->match(helper, false)) { return ICE_NULLPTR; } } for(std::vector::const_iterator p = _reject.begin(); p != _reject.end(); ++p) { if((*p)->match(helper, true)) { return ICE_NULLPTR; } } // // Compute the key from the GroupBy property. // std::string key; try { if(_groupByAttributes.size() == 1) { key = helper(_groupByAttributes.front()); } else { std::ostringstream os; std::vector::const_iterator q = _groupBySeparators.begin(); for(std::vector::const_iterator p = _groupByAttributes.begin(); p != _groupByAttributes.end(); ++p) { os << helper(*p); if(q != _groupBySeparators.end()) { os << *q++; } } key = os.str(); } } catch(const std::exception&) { return ICE_NULLPTR; } // // Lookup the metrics object. // Lock sync(*this); if(_destroyed) { return ICE_NULLPTR; } if(previous && previous->_object->id == key) { assert(_objects[key] == previous); return previous; } typename std::map::const_iterator p = _objects.find(key); if(p == _objects.end()) { TPtr t = ICE_MAKE_SHARED(T); t->id = key; #ifdef ICE_CPP11_MAPPING p = _objects.insert(typename std::map::value_type( key, std::make_shared( std::dynamic_pointer_cast>(shared_from_this()), t, _detachedQueue.end()))).first; #else p = _objects.insert(typename std::map::value_type( key, new EntryT(this, t, _detachedQueue.end()))).first; #endif } p->second->attach(helper); return p->second; } private: virtual MetricsMapIPtr clone() const { return ICE_MAKE_SHARED(MetricsMapT, *this); } void detached(EntryTPtr entry) { // This is called with the map mutex locked. if(_retain == 0 || _destroyed) { return; } assert(static_cast(_detachedQueue.size()) <= _retain); // If the entry is already detached and in the queue, just move it to the back. if(entry->_detachedPos != _detachedQueue.end()) { if(entry->_detachedPos != --_detachedQueue.end()) // If not already at the end { _detachedQueue.splice(_detachedQueue.end(), _detachedQueue, entry->_detachedPos); entry->_detachedPos = --_detachedQueue.end(); } return; } // Otherwise, compress the queue by removing entries which are no longer detached. if(static_cast(_detachedQueue.size()) == _retain) { // Remove entries which are no longer detached typename std::list::iterator p = _detachedQueue.begin(); while(p != _detachedQueue.end()) { if(!(*p)->isDetached()) { (*p)->_detachedPos = _detachedQueue.end(); p = _detachedQueue.erase(p); } else { ++p; } } } // If there's still no room, remove the oldest entry (at the front). if(static_cast(_detachedQueue.size()) == _retain) { _objects.erase(_detachedQueue.front()->_object->id); _detachedQueue.pop_front(); } // Add the entry at the back of the queue. entry->_detachedPos = _detachedQueue.insert(_detachedQueue.end(), entry); assert(entry->_detachedPos != _detachedQueue.end()); return; } friend class EntryT; bool _destroyed; std::map _objects; std::list _detachedQueue; std::map > _subMaps; }; template class MetricsMapFactoryT : public MetricsMapFactory { public: MetricsMapFactoryT(IceMX::Updater* updater) : MetricsMapFactory(updater) { } virtual MetricsMapIPtr create(const std::string& mapPrefix, const Ice::PropertiesPtr& properties) { return ICE_MAKE_SHARED(MetricsMapT, mapPrefix, properties, _subMaps); } template void registerSubMap(const std::string& subMap, IceMX::MetricsMap MetricsType::* member) { _subMaps[subMap] = std::pair(member, ICE_MAKE_SHARED(MetricsMapFactoryT, ICE_NULLPTR)); } private: std::map > _subMaps; }; class MetricsViewI : public IceUtil::Shared { public: MetricsViewI(const std::string&); void destroy(); bool addOrUpdateMap(const Ice::PropertiesPtr&, const std::string&, const MetricsMapFactoryPtr&, const Ice::LoggerPtr&); bool removeMap(const std::string&); IceMX::MetricsView getMetrics(); IceMX::MetricsFailuresSeq getFailures(const std::string&); IceMX::MetricsFailures getFailures(const std::string&, const std::string&); std::vector getMaps() const; MetricsMapIPtr getMap(const std::string&) const; private: const std::string _name; std::map _maps; }; ICE_DEFINE_PTR(MetricsViewIPtr, MetricsViewI); class ICE_API MetricsAdminI : public IceMX::MetricsAdmin, public Ice::PropertiesAdminUpdateCallback, private IceUtil::Mutex { public: MetricsAdminI(const ::Ice::PropertiesPtr&, const Ice::LoggerPtr&); ~MetricsAdminI(); void destroy(); void updateViews(); template void registerMap(const std::string& map, IceMX::Updater* updater) { bool updated; MetricsMapFactoryPtr factory; { Lock sync(*this); factory = ICE_MAKE_SHARED(MetricsMapFactoryT, updater); _factories[map] = factory; updated = addOrUpdateMap(map, factory); } if(updated) { factory->update(); } } template void registerSubMap(const std::string& map, const std::string& subMap, IceMX::MetricsMap MetricsType::* member) { bool updated; ICE_HANDLE > factory; { Lock sync(*this); std::map::const_iterator p = _factories.find(map); if(p == _factories.end()) { return; } #ifdef ICE_CPP11_MAPPING factory = ::std::dynamic_pointer_cast>(p->second); #else factory = dynamic_cast*>(p->second.get()); #endif factory->template registerSubMap(subMap, member); removeMap(map); updated = addOrUpdateMap(map, factory); } if(updated) { factory->update(); } } void unregisterMap(const std::string&); virtual Ice::StringSeq getMetricsViewNames(Ice::StringSeq&, const ::Ice::Current&); #ifdef ICE_CPP11_MAPPING virtual void enableMetricsView(std::string, const ::Ice::Current&); virtual void disableMetricsView(std::string, const ::Ice::Current&); virtual IceMX::MetricsView getMetricsView(std::string, Ice::Long&, const ::Ice::Current&); virtual IceMX::MetricsFailuresSeq getMapMetricsFailures(std::string, std::string, const ::Ice::Current&); virtual IceMX::MetricsFailures getMetricsFailures(std::string, std::string, std::string, const ::Ice::Current&); #else virtual void enableMetricsView(const std::string&, const ::Ice::Current&); virtual void disableMetricsView(const std::string&, const ::Ice::Current&); virtual IceMX::MetricsView getMetricsView(const std::string&, Ice::Long&, const ::Ice::Current&); virtual IceMX::MetricsFailuresSeq getMapMetricsFailures(const std::string&, const std::string&, const ::Ice::Current&); virtual IceMX::MetricsFailures getMetricsFailures(const std::string&, const std::string&, const std::string&, const ::Ice::Current&); #endif std::vector getMaps(const std::string&) const; const Ice::LoggerPtr& getLogger() const; private: MetricsViewIPtr getMetricsView(const std::string&); void updated(const Ice::PropertyDict&); bool addOrUpdateMap(const std::string&, const MetricsMapFactoryPtr&); bool removeMap(const std::string&); std::map _views; std::set _disabledViews; std::map _factories; const Ice::LoggerPtr _logger; Ice::PropertiesPtr _properties; }; ICE_DEFINE_PTR(MetricsAdminIPtr, MetricsAdminI); }; #endif