// Copyright (c) 2005-2007 Andre Merzky (andre@merzky.net) // Copyright (c) 2005-2007 Hartmut Kaiser (hartmut.kaiser@gmail.com) // Copyright (c) 2005 Stephan Hirmer (stephan.hirmer@gmail.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef SAGA_IMPL_ENGINE_METRIC_HPP #define SAGA_IMPL_ENGINE_METRIC_HPP #include #include // lexical_cast will be in TR2 #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// namespace saga { namespace impl { /** * This class stores monitoring information. * * Saga adaptors or saga proxy classes are able to define metrics * and add them to a metric-list, which is kept by a task. * Therefor, there is a function cpi::addMetric (metric m), * which adds a TR1::shared_ptr of a metric to this metric-list. * * FIXME: is that naming useful? * @note the name of a metric has to be in the following form: * _<-monitored-operation>[_] * e.g.: standard-local-file-adaptor_FILE-COPY_progress */ class metric : public saga::impl::object, public saga::impl::attribute { private: typedef saga::impl::attribute attribute_base; typedef saga::metric::frequency frequency; typedef std::map metric_callbacks; metric_callbacks callbacks_; TR1::weak_ptr target_; static saga::metric::metric_cookie get_next_cookie() { static boost::mutex mtx; static saga::metric::metric_cookie cookie = 0; boost::mutex::scoped_lock lock(mtx); return ++cookie; } explicit metric (saga::object target, attribute const& rhs_attr) : saga::impl::object(saga::object::Metric), attribute_base(rhs_attr), target_(runtime::get_impl_object(target)) { } public: //! Destructor. ~metric(void) { } metric () : object(saga::object::Metric) { } //! verbose constructor metric (saga::object target) : object(saga::object::Metric), target_(runtime::get_impl_object(target)) { } // promote the current value to the subscribed callbacks void fire (saga::context ctx) { std::string mode; this->get_attribute(mode, saga::attributes::metric_mode, true); if (mode == saga::attributes::metric_mode_readonly) { std::string name; this->get_attribute(name, saga::attributes::metric_name, true); SAGA_THROW("Metric: '" + name + "' is readonly.", saga::ReadOnly); } saga::object target ( runtime::get_object(TR1::shared_ptr(target_))); saga::metric m (runtime::get_object(this->shared_from_this())); exception_list exceptions; metric_callbacks::iterator end = callbacks_.end(); for (metric_callbacks::iterator it = callbacks_.begin(); it != end; /**/) { try { bool result = (*it).second(target, m, ctx); if (!result) { // remove this callback from the list metric_callbacks::iterator next = it; ++next; callbacks_.erase(it); it = next; } else { ++it; } } catch (saga::exception const& e) { exceptions.add(e); ++it; } } if (0 != exceptions.get_error_count()) SAGA_THROW(exceptions.get_message(), exceptions.get_error()) } saga::metric::metric_cookie add_callback (saga::callback cb) { saga::metric::metric_cookie new_cookie = get_next_cookie(); callbacks_.insert(metric_callbacks::value_type(new_cookie, cb)); return new_cookie; } void remove_callback(saga::metric::metric_cookie cookie) { metric_callbacks::const_iterator it = callbacks_.find(cookie); if (it == callbacks_.end()) { std::string c (boost::lexical_cast(cookie)); SAGA_THROW("Could not find callback: '" + c + "'.", saga::DoesNotExist); } callbacks_.erase(cookie); } // saga::object interface // deep copy operation saga::object clone() const { saga::object target ( runtime::get_object(TR1::shared_ptr(target_))); return saga::metric(new saga::impl::metric(target, static_cast(*this))); } // return interface's saga::impl::attribute* get_attributes() { return this; } saga::impl::attribute const* get_attributes() const { return this; } }; /////////////////////////////////////////////////////////////////////////////// }} // namespace saga::impl #endif // SAGA_IMPL_ENGINE_METRIC_HPP