66#include < logging.h>
77#include < utiltime.h>
88#include < ringbuffer.h>
9+ #include < reverselock.h>
910
11+ #include < chrono>
1012#include < mutex>
1113
1214const char * const DEFAULT_DEBUGLOGFILE = " debug.log" ;
@@ -45,7 +47,7 @@ bool BCLog::Logger::OpenDebugLog()
4547 return false ;
4648 }
4749
48- setbuf (m_fileout, nullptr ); // unbuffered
50+ // setbuf(m_fileout, nullptr); // unbuffered
4951 // dump buffered messages from before we opened the log
5052 while (!m_msgs_before_open.empty ()) {
5153 FileWriteStr (m_msgs_before_open.front (), m_fileout);
@@ -211,7 +213,7 @@ void BCLog::Logger::LogPrintStr(const std::string &str)
211213 fflush (stdout);
212214 }
213215 if (m_print_to_file) {
214- std::lock_guard<std::mutex> scoped_lock (m_file_mutex);
216+ // std::lock_guard<std::mutex> scoped_lock(m_file_mutex);
215217
216218 // buffer if we haven't opened the log yet
217219 if (m_fileout == nullptr ) {
@@ -226,14 +228,19 @@ void BCLog::Logger::LogPrintStr(const std::string &str)
226228 if (!m_fileout) {
227229 return ;
228230 }
229- setbuf (m_fileout, nullptr ); // unbuffered
231+ // setbuf(m_fileout, nullptr); // unbuffered
230232 }
231233
232234 FileWriteStr (strTimestamped, m_fileout);
233235 }
234236 }
235237}
236238
239+ void BCLog::Logger::FlushFile ()
240+ {
241+ fflush (m_fileout);
242+ }
243+
237244void BCLog::Logger::ShrinkDebugFile ()
238245{
239246 // Amount of debug.log to save at end when shrinking (must fit in memory)
@@ -275,43 +282,82 @@ void BCLog::Logger::ShrinkDebugFile()
275282 fclose (file);
276283}
277284
278- namespace async_logging {
279- using LogArgs = std::string;
280- RingBuffer<LogArgs, 1024 > log_buffer;
281- std::unique_ptr<std::thread> flush_logs_thread;
282- std::once_flag flush_logs_thread_started;
285+ class AsyncLogger
286+ {
287+ public:
288+ AsyncLogger () : m_size( 0 ) {}
289+ ~AsyncLogger () {}
283290
284- static void ConsumeLogs ( )
291+ void Push (std::string&& line )
285292 {
286- std::unique_ptr<LogArgs> next_log_line;
287- while (next_log_line = log_buffer.PollForOne ()) {
288- g_logger->LogPrintStr (*next_log_line);
293+ {
294+ std::unique_lock<std::mutex> l (m_lock);
295+
296+ m_buffer_accumulating[m_end ()] = std::forward<std::string>(line);
297+ m_size = std::min (m_size + 1 , m_capacity);
289298 }
299+
300+ // doesnt matter that much if we slightly over or undernotify
301+ if (m_size > 100 )
302+ m_cv.notify_one ();
290303 }
291304
292- void FlushAll ( )
305+ void Thread ( void )
293306 {
294- for (LogArgs& s : log_buffer.PopAll ()) {
295- g_logger->LogPrintStr (s);
307+ std::unique_lock<std::mutex> l (m_lock);
308+ while (true )
309+ {
310+ // if theres still a lot to do don't wait
311+ if (m_size < 100 ) {
312+ // sleep until there's a lot to do or some time has passed
313+ m_cv.wait_for (l, std::chrono::milliseconds (100 ));
314+ }
315+
316+ if (m_size > 0 ) {
317+ std::swap (m_buffer_accumulating, m_buffer_flushing);
318+
319+ unsigned int size = m_size;
320+ m_size = 0 ;
321+
322+ {
323+ // drop the lock while flushing
324+ reverse_lock<std::unique_lock<std::mutex>> release (l);
325+
326+ g_logger->LogPrintStr (" flushing\n " );
327+ for (size_t i = 0 ; i < size; ++i) {
328+ g_logger->LogPrintStr (std::move (m_buffer_flushing[i]));
329+ }
330+ g_logger->FlushFile ();
331+ }
332+ }
296333 }
297334 }
298335
299- void Queue (const std::string& str)
336+ private:
337+ std::mutex m_lock;
338+ std::condition_variable m_cv;
339+
340+ static constexpr long unsigned int m_capacity = 1024 ;
341+
342+ std::array<std::string, m_capacity> m_buffer_accumulating;
343+ std::array<std::string, m_capacity> m_buffer_flushing;
344+
345+ size_t m_size;
346+ inline size_t m_end (){ return m_size; }
347+ };
348+
349+ namespace async_logging {
350+ AsyncLogger log_buffer;
351+ std::thread flush_logs_thread;
352+
353+ void Init (void )
300354 {
301- std::call_once (flush_logs_thread_started, [](){
302- flush_logs_thread.reset (new std::thread (ConsumeLogs));
303- });
304- log_buffer.PushBack (std::move (str));
355+ flush_logs_thread = std::thread (&AsyncLogger::Thread, &log_buffer);
356+ LogPrintf (" If you are seeing this message the async logger has started\n " );
305357 }
306358
307- void Shutdown ( )
359+ void Queue (std::string&& str )
308360 {
309- if (flush_logs_thread) {
310- log_buffer.SignalStopWaiting ();
311- FlushAll ();
312- if (flush_logs_thread->joinable ()) {
313- flush_logs_thread->join ();
314- }
315- }
361+ log_buffer.Push (std::forward<std::string>(str));
316362 }
317363}
0 commit comments