libmoost
/home/mhx/git/github/libmoost/include/moost/io/async_writer.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #ifndef MOOST_IO_ASYNCWRITER_HPP__
00029 #define MOOST_IO_ASYNCWRITER_HPP__
00030 
00031 #include <string>
00032 #include <fstream>
00033 #include <sstream>
00034 #include <boost/filesystem/path.hpp>
00035 #include <boost/filesystem/operations.hpp>
00036 
00037 #include <boost/date_time/posix_time/posix_time.hpp>
00038 
00039 #include "../thread/async_worker.hpp"
00040 
00041 namespace moost { namespace io {
00042 
00045 class count_rollover
00046 {
00047 private:
00048 
00049   size_t m_rollover;
00050   size_t m_count;
00051 
00052 public:
00053 
00057   count_rollover(size_t rollover = 0)
00058   : m_rollover(rollover),
00059     m_count(0)
00060   {
00061 
00062   }
00063 
00065   bool operator()()
00066   {
00067     return (m_rollover != 0 && (m_count++ % m_rollover == 0));
00068   }
00069 
00070   // returns an pathname related to the type of rollover
00071   std::string get_path(const std::string & base_path)
00072   {
00073     if (m_rollover == 0)
00074       return base_path;
00075     std::ostringstream oss;
00076     oss << base_path << '.' << m_count;
00077     return oss.str();
00078   }
00079 };
00080 
00083 class timeofday_rollover
00084 {
00085 private:
00086 
00087   boost::posix_time::time_duration m_rollover_timeofday;
00088   boost::posix_time::ptime         m_next_rollover;
00089 
00090 public:
00091 
00097   timeofday_rollover(int hour = 0, int minute = 0, int second = 0)
00098   : m_rollover_timeofday(hour, minute, second, 0)
00099   {
00100     boost::posix_time::ptime now(boost::posix_time::second_clock::universal_time());
00101     if ( now.time_of_day() < m_rollover_timeofday )
00102       m_next_rollover = boost::posix_time::ptime(now.date(), m_rollover_timeofday);
00103     else
00104       m_next_rollover = boost::posix_time::ptime((now + boost::gregorian::days(1)).date(), m_rollover_timeofday);
00105   }
00106 
00108   bool operator()()
00109   {
00110     boost::posix_time::ptime now(boost::posix_time::second_clock::universal_time());
00111     if (now >= m_next_rollover)
00112     {
00113       m_next_rollover = boost::posix_time::ptime((m_next_rollover + boost::gregorian::days(1)).date(), m_rollover_timeofday);
00114       return true;
00115     }
00116     return false;
00117   }
00118 
00119   // returns an pathname related to the type of rollover
00120   std::string get_path(const std::string & base_path, boost::gregorian::date * path_date = NULL)
00121   {
00122     boost::gregorian::date now;
00123     if (path_date == NULL)
00124     {
00125       now = (boost::posix_time::second_clock::universal_time()).date();
00126       path_date = &now;
00127     }
00128     std::ostringstream oss;
00129     oss << base_path << '.' << boost::gregorian::to_iso_extended_string(*path_date);
00130     return oss.str();
00131   }
00132 };
00133 
00139 template<typename TWork, class TRolloverPolicy = count_rollover>
00140 class async_writer : public moost::thread::async_worker<TWork>
00141 {
00142 private:
00143 
00144   std::string     m_base_path;
00145   TRolloverPolicy m_rollover_policy;
00146   std::ofstream   m_out;
00147 
00149   void reload_out()
00150   {
00151     // get a suitable filename
00152     boost::filesystem::path p;
00153     std::string path_name = m_rollover_policy.get_path(m_base_path);
00154 
00155     for (int i = 0; ;++i)
00156     {
00157       std::ostringstream oss;
00158       oss << path_name;
00159       if (i != 0)
00160         oss << '.' << i;
00161       p = boost::filesystem::path(oss.str());
00162       if (!boost::filesystem::exists(p))
00163         break;
00164     }
00165 
00166     m_out.close();
00167     m_out.clear();
00168     m_out.open(p.string().c_str(), std::ios::binary);
00169   }
00170 
00171 protected:
00172 
00173   void do_work(TWork & work)
00174   {
00175     if (m_rollover_policy() || !m_out.is_open())
00176       reload_out();
00177     work.write(m_out);
00178   }
00179 
00180 public:
00181 
00188   async_writer(const std::string & base_path,
00189                const TRolloverPolicy & rollover_policy = TRolloverPolicy(),
00190                size_t max_queue = 0,
00191                size_t enqueue_timeout = 0)
00192   : moost::thread::async_worker<TWork>(1, max_queue, enqueue_timeout),
00193     m_base_path(base_path),
00194     m_rollover_policy(rollover_policy)
00195   {
00196   }
00197 
00202   ~async_writer()
00203   {
00204     stop();
00205   }
00206 
00207   void stop()
00208   {
00209     moost::thread::async_worker<TWork>::stop();
00210     m_out.close();
00211   }
00212 
00213 };
00214 
00215 }} // moost::io
00216 
00217 #endif // MOOST_IO_ASYNCWRITER_HPP__