new timer event proxy to reduce scheduler load
jmo [Tue, 13 Apr 2010 09:51:58 +0000 (09:51 +0000)]
the documentation need to be enriched

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1591 270642c3-0616-0410-b53a-bc976706d245

senf/Scheduler/TimerEventProxy.ct [new file with mode: 0644]
senf/Scheduler/TimerEventProxy.hh [new file with mode: 0644]
senf/Scheduler/TimerEventProxy.test.cc [new file with mode: 0644]

diff --git a/senf/Scheduler/TimerEventProxy.ct b/senf/Scheduler/TimerEventProxy.ct
new file mode 100644 (file)
index 0000000..cb665b6
--- /dev/null
@@ -0,0 +1,114 @@
+// $Id$
+//
+// Copyright (C) 2010
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Mathias Kretschmer <mtk@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+ \brief TimerEventProxy public header */
+
+#define prefix_ 
+
+template<class T>
+prefix_ senf::scheduler::TimerEventProxy<T>::TimerEventProxy() :
+    timer("timer", senf::membind(&TimerEventProxy<T>::timerEvent, this), 0,
+            false), entrySetById(entrySet.template get<Id> ()),
+            entrySetByTimeout(entrySet.template get<Timeout> ())
+{
+
+}
+
+template<class T>
+prefix_ senf::scheduler::TimerEventProxy<T>::TimerEventProxy( std::string const & name,
+        senf::console::DirectoryNode & node) :
+    timer("timer", senf::membind(&TimerEventProxy<T>::timerEvent, this), 0,
+            false), entrySetById(entrySet.template get<Id> ()),
+            entrySetByTimeout(entrySet.template get<Timeout> ())
+{
+    node.add(name, senf::console::factory::Command(
+            &TimerEventProxy<T>::listTimers, this) .doc("List active Timers"));
+}
+
+template<class T>
+prefix_ void senf::scheduler::TimerEventProxy<T>::timerEvent() {
+
+    senf::ClockService::clock_type actual = senf::ClockService::now();
+    typename EntrySetByTimeout_t::iterator it;
+
+    // execute the timer callbacks first
+
+    it = entrySetByTimeout.begin();
+    while (it != entrySetByTimeout.end() && it->timeout <= actual) {
+        Entry<T> item(*it);
+        // remove due entry from set
+        entrySetByTimeout.erase(it);
+        // call callback
+        item.fkt(actual, item.id);
+
+        it = entrySetByTimeout.begin();
+    }
+
+    if (entrySet.size() > 0) {
+        timer.timeout(entrySetByTimeout.begin()->timeout);
+    }
+}
+
+template<class T>
+prefix_ void senf::scheduler::TimerEventProxy<T>::add(
+        senf::ClockService::clock_type timeout, T const & id, Callback fkt)
+{
+    // insert new entry
+    entrySetByTimeout.insert(Entry<T> (timeout, id, fkt));
+
+    // the scheduler time to the first earliest timeout (ordered index)
+    timer.timeout(entrySetByTimeout.begin()->timeout);
+
+    //  // if map was empty before, hence we need to activate the time event object
+    //  if( entrySetByTimeout.size() >= 1){
+    //      timer.enable();
+    //  }
+}
+
+template<class T>
+prefix_ bool senf::scheduler::TimerEventProxy<T>::del(T const & id)
+{
+    typename EntrySetById_t::iterator it(entrySetById.find(Entry<T> (0, id, NULL)));
+
+    if (it != entrySetById.end()) {
+        entrySetById.erase(it);
+        return true;
+    }
+    return false;
+}
+
+template<class T>
+prefix_ std::vector<std::pair<senf::ClockService::clock_type, T> > senf::scheduler::TimerEventProxy<T>::list()
+{
+    std::vector<std::pair<senf::ClockService::clock_type, T> > tmp;
+
+    typename EntrySetByTimeout_t::iterator it;
+    for (it = entrySetByTimeout.begin(); it != entrySetByTimeout.end(); ++it) {
+        tmp.push_back(std::make_pair<senf::ClockService::clock_type, T>( it->timeout, it->id));
+    }
+
+    return tmp;
+}
+
+#undef prefix_
+
diff --git a/senf/Scheduler/TimerEventProxy.hh b/senf/Scheduler/TimerEventProxy.hh
new file mode 100644 (file)
index 0000000..ae77e58
--- /dev/null
@@ -0,0 +1,136 @@
+// $Id$
+//
+// Copyright (C) 2010
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Mathias Kretschmer <mtk@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+ \brief TimerEventProxy public header */
+
+#ifndef HH_SENF_Scheduler_TimerEventProxy_
+#define HH_SENF_Scheduler_TimerEventProxy_ 1
+
+#ifdef SENF_DEBUG
+#   define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
+#   define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
+#endif
+
+#include <boost/range/iterator_range.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+#include <boost/multi_index/random_access_index.hpp>
+#include <boost/multi_index/identity.hpp>
+#include <boost/multi_index/member.hpp>
+
+#include <senf/Scheduler/ClockService.hh>
+#include <senf/Scheduler/TimerEvent.hh>
+#include <senf/Utils/Console/Console.hh>
+
+namespace senf {
+namespace scheduler {
+
+
+    /** \brief Deadline timer proxy
+
+        The TimerEventProxy is meant to host long term deadline timers to reduce the load of the
+        Scheduler with a hugh count of TimerEvent items. It registers deadline timer callbacks which
+        will be called when the timer expires.
+
+        The functionality is based on one TimerEvent instance per TimerEventProxy instance and could
+        host a big count of timers.
+     */
+    template<class T>
+    class TimerEventProxy {
+    private:
+
+        template<class T_>
+        struct Entry {
+        public:
+            senf::ClockService::clock_type timeout;
+            T id;
+            boost::function<void(senf::ClockService::clock_type, T_ const &)> fkt;
+
+            bool operator<(const Entry<T_> & e) const {
+                return id < e.id;
+            }
+            //  bool operator==(const Entry<T> &e)const{return id == e.id;}
+            Entry(senf::ClockService::clock_type _timeout, T_ _id, boost::function<void(
+                    senf::ClockService::clock_type, T_)> _fkt) :
+                timeout(_timeout), id(_id), fkt(_fkt) {
+            }
+        };
+
+
+        senf::scheduler::TimerEvent timer;
+
+        //
+        // data structure to hold active timers
+        //
+        struct Timeout {};
+        struct Id {};
+        typedef boost::multi_index_container<Entry<T> ,
+                boost::multi_index::indexed_by<
+                        boost::multi_index::ordered_non_unique<
+                                boost::multi_index::tag<Timeout>,
+                                boost::multi_index::member<Entry<T> ,
+                                        senf::ClockService::clock_type,
+                                        &Entry<T>::timeout> >,
+                        boost::multi_index::ordered_unique<boost::multi_index::tag<
+                                Id>, boost::multi_index::identity<Entry<T> > > > >
+                EntrySet;
+
+        typedef typename EntrySet::template index<Timeout>::type
+                EntrySetByTimeout_t;
+        typedef typename EntrySet::template index<Id>::type EntrySetById_t;
+
+        EntrySet entrySet;
+        EntrySetById_t & entrySetById;
+        EntrySetByTimeout_t & entrySetByTimeout;
+
+    private:
+        // callback for the Scheduler timer event
+        void timerEvent();
+
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+        typedef boost::function<void(senf::ClockService::clock_type, T const &)> Callback;
+
+        TimerEventProxy();
+        ///< Instantiate a TimerEventProxy
+
+        TimerEventProxy(std::string const & name, senf::console::DirectoryNode & node);
+        ///< Instantiate a TimerEventProxy and add the list command to the give DirectoryNode
+
+        void add(senf::ClockService::clock_type timeout, T const &id, Callback cb);
+        ///< Add new deadline timer
+        bool del(T const & id);
+        ///< Remove timer by given \a id.
+        std::vector<std::pair<senf::ClockService::clock_type, T> > list();
+        ///< Returns a vector of all active timers with timeout and id.
+    };
+}
+}
+
+#include "TimerEventProxy.ct"
+
+#endif
diff --git a/senf/Scheduler/TimerEventProxy.test.cc b/senf/Scheduler/TimerEventProxy.test.cc
new file mode 100644 (file)
index 0000000..eb07187
--- /dev/null
@@ -0,0 +1,100 @@
+// $Id$
+//
+// Copyright (C) 2010
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Jens Moedeker <jens.moedeker@fokus.fraunhofer.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+ \brief TimerEventProxy public header */
+//
+
+/** \file
+    \brief TimerEventProxy.test non-inline non-template implementation */
+
+//#include "TimerEventProxy.test.hh"
+//#include "TimerEventProxy.test.ih"
+
+// Custom includes
+#include "TimerEventProxy.hh"
+#include "Scheduler.hh"
+#include <boost/bind.hpp>
+
+#include <senf/Utils/auto_unit_test.hh>
+#include <boost/test/test_tools.hpp>
+#include <boost/random.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+namespace {
+
+    int count = 0;
+
+    void handler( senf::ClockService::clock_type time, int const &id)
+    {
+        std::cerr << "TimerEventProxy handler count="<<count<<" id="<<id<<"\n";
+        ++count;
+    }
+
+    void myexit(){
+        std::cerr << "TimerEventProxy terminating\n";
+        senf::scheduler::terminate();
+    }
+
+}
+
+SENF_AUTO_UNIT_TEST(timerEventProxy)
+{
+
+//    // abort on watchdog timeout
+//    senf::scheduler::watchdogAbort( true);
+//    senf::scheduler::watchdogTimeout(5000);
+
+    senf::ClockService::clock_type t (senf::ClockService::now());
+    {
+        senf::scheduler::TimerEventProxy<int> timers;
+
+        SENF_CHECK_NO_THROW( timers.add( t + senf::ClockService::milliseconds(10000), 0 , &handler));
+        SENF_CHECK_NO_THROW( timers.add( t + senf::ClockService::milliseconds(800), 3, &handler));
+        SENF_CHECK_NO_THROW( timers.add( t + senf::ClockService::milliseconds(200), 1, &handler));
+        SENF_CHECK_NO_THROW( timers.del( 3));
+        SENF_CHECK_NO_THROW( timers.add( t + senf::ClockService::milliseconds(700), 2, &handler));
+
+        // set timeout for termination
+        senf::scheduler::TimerEvent te_exit( "myexit", &myexit, t + senf::ClockService::milliseconds( 1000));
+
+        SENF_CHECK_NO_THROW( senf::scheduler::process() );
+
+        BOOST_CHECK( count == 2);
+    }
+}
+
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End: