libmoost
|
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__