Log日志库

#ifndef MUDUO_BASE_ASYNCLOGGINGDOUBLEBUFFERING_H
#define MUDUO_BASE_ASYNCLOGGINGDOUBLEBUFFERING_H

#include "LogStream.h"

#include "thread/BlockingQueue.h"
#include "thread/BoundedBlockingQueue.h"
#include "thread/CountDownLatch.h"
#include "thread/Mutex.h"
#include "thread/Thread.h"

#include 
#include 
#include 
#include 

namespace muduo
{

class AsyncLoggingDoubleBuffering : boost::noncopyable
{
 public:
  typedef muduo::detail::FixedBuffer Buffer;
  typedef boost::ptr_vector BufferVector;
  typedef BufferVector::auto_type BufferPtr;

  AsyncLoggingDoubleBuffering(const string& basename, // FIXME: StringPiece
                              size_t rollSize,
                              int flushInterval = 3)
    : flushInterval_(flushInterval),
      running_(false),
      basename_(basename),
      rollSize_(rollSize),
      thread_(boost::bind(&AsyncLoggingDoubleBuffering::threadFunc, this), "Logging"),
      latch_(1),
      mutex_(),
      cond_(mutex_),
      currentBuffer_(new Buffer),
      nextBuffer_(new Buffer),
      buffers_()
  {
    currentBuffer_->bzero();
    nextBuffer_->bzero();
    buffers_.reserve(16);
  }

  ~AsyncLoggingDoubleBuffering()
  {
    if (running_)
    {
      stop();
    }
  }

  void append(const char* logline, int len)
  {
    muduo::MutexLockGuard lock(mutex_);
    if (currentBuffer_->avail() > len)
    {
      currentBuffer_->append(logline, len);
    }
    else
    {
      buffers_.push_back(currentBuffer_.release());

      if (nextBuffer_)
      {
        currentBuffer_ = boost::ptr_container::move(nextBuffer_);
      }
      else
      {
        currentBuffer_.reset(new Buffer); // Rarely happens
      }
      currentBuffer_->append(logline, len);
      cond_.notify();
    }
  }

  void start()
  {
    running_ = true;
    thread_.start();
    latch_.wait();
  }

  void stop()
  {
    running_ = false;
    cond_.notify();
    thread_.join();
  }

 private:

  void threadFunc()
  {
    assert(running_ == true);
    latch_.countDown();
    LogFile output(basename_, rollSize_, false);
    BufferPtr newBuffer1(new Buffer);
    BufferPtr newBuffer2(new Buffer);
    newBuffer1->bzero();
    newBuffer2->bzero();
    boost::ptr_vector buffersToWrite;
    buffersToWrite.reserve(16);
    while (running_)
    {
      assert(newBuffer1 && newBuffer1->length() == 0);
      assert(newBuffer2 && newBuffer2->length() == 0);
      assert(buffersToWrite.empty());

      {
        muduo::MutexLockGuard lock(mutex_);
        if (!buffers_.empty())
        {
          cond_.waitForSeconds(flushInterval_);
        }
        buffers_.push_back(currentBuffer_.release());
        currentBuffer_ = boost::ptr_container::move(newBuffer1);
        buffersToWrite.swap(buffers_);
        if (!nextBuffer_)
        {
          nextBuffer_ = boost::ptr_container::move(newBuffer2);
        }
      }

      assert(!buffersToWrite.empty());

      if (buffersToWrite.size() > 25)
      {
        const char* dropMsg = "Dropped log messages\n";
        fprintf(stderr, "%s", dropMsg);
        output.append(dropMsg, strlen(dropMsg));
        buffersToWrite.erase(buffersToWrite.begin(), buffersToWrite.end() - 2);
      }

      for (size_t i = 0; i < buffersToWrite.size(); ++i)
      {
        // FIXME: use unbuffered stdio FILE ? or use ::writev ?
        output.append(buffersToWrite[i].data(), buffersToWrite[i].length());
      }

      if (buffersToWrite.size() > 2)
      {
        // drop non-bzero-ed buffers, avoid trashing
        buffersToWrite.resize(2);
      }

      if (!newBuffer1)
      {
        assert(!buffersToWrite.empty());
        newBuffer1 = buffersToWrite.pop_back();
        newBuffer1->reset();
      }

      if (!newBuffer2)
      {
        assert(!buffersToWrite.empty());
        newBuffer2 = buffersToWrite.pop_back();
        newBuffer2->reset();
      }

      buffersToWrite.clear();
      output.flush();
    }
    output.flush();
  }

  const int flushInterval_;
  bool running_;
  string basename_;
  size_t rollSize_;
  muduo::Thread thread_;
  muduo::CountDownLatch latch_;
  muduo::MutexLock mutex_;
  muduo::Condition cond_;
  BufferPtr currentBuffer_;
  BufferPtr nextBuffer_;
  BufferVector buffers_;
};

}
#endif  // MUDUO_BASE_ASYNCLOGGINGDOUBLEBUFFERING_H
#ifndef MUDUO_BASE_ASYNCLOGGINGQUEUE_H
#define MUDUO_BASE_ASYNCLOGGINGQUEUE_H

#include "LogFile.h"

#include "thread/BlockingQueue.h"
#include "thread/BoundedBlockingQueue.h"
#include "thread/CountDownLatch.h"
#include "thread/Thread.h"

#include 

#include 
#include 
#include 

namespace muduo
{

// proof of conecpt async logging.
// use Intel TBB concurrent_queue if performance is desired.
template class QUEUE>
class AsyncLoggingT : boost::noncopyable
{
 public:

  AsyncLoggingT(const string& basename, // FIXME: StringPiece
                size_t rollSize)
    : running_(false),
      basename_(basename),
      rollSize_(rollSize),
      thread_(boost::bind(&AsyncLoggingT::threadFunc, this), "Logging"),
      latch_(1)
  {
  }

  AsyncLoggingT(const string& basename, // FIXME: StringPiece
                size_t rollSize,
                int queueSize)
    : running_(false),
      basename_(basename),
      rollSize_(rollSize),
      thread_(boost::bind(&AsyncLoggingT::threadFunc, this), "Logging"),
      latch_(1),
      queue_(queueSize)
  {
  }

  ~AsyncLoggingT()
  {
    if (running_)
    {
      stop();
    }
  }

  void append(const char* logline, int len)
  {
    queue_.put(MSG(logline, len));
  }

  void start()
  {
    running_ = true;
    thread_.start();
    latch_.wait();
  }

  void stop()
  {
    running_ = false;
    queue_.put(MSG());
    thread_.join();
  }

 private:

  void threadFunc()
  {
    assert(running_ == true);
    latch_.countDown();
    LogFile output(basename_, rollSize_, false);
    time_t lastFlush = time(NULL);
    while (true)
    {
      MSG msg(queue_.take());
      if (msg.empty())
      {
        assert(running_ == false);
        break;
      }
      output.append(msg.data(), msg.length());
    }
    output.flush();
  }

  bool running_;
  string basename_;
  size_t rollSize_;
  muduo::Thread thread_;
  muduo::CountDownLatch latch_;
  QUEUE queue_;
};

// FIXME: use detach-able log buffers and move semantics
typedef AsyncLoggingT AsyncLoggingUnboundedQueue;
typedef AsyncLoggingT AsyncLoggingBoundedQueue;

// demonstrate premature optimization is BAD
struct LogMessage
{
  LogMessage(const char* msg, int len)
    : length_(len)
  {
    assert(length_ <= sizeof data_);
    ::memcpy(data_, msg, length_);
  }

  LogMessage()
    : length_(0)
  {
  }

  LogMessage(const LogMessage& rhs)
    : length_(rhs.length_)
  {
    assert(length_ <= sizeof data_);
    ::memcpy(data_, rhs.data_, length_);
  }

  LogMessage& operator=(const LogMessage& rhs)
  {
    length_ = rhs.length_;
    assert(length_ <= sizeof data_);
    ::memcpy(data_, rhs.data_, length_);
  }

  const char* data() const { return data_; }
  int length() const { return length_; }
  bool empty() const { return length_ == 0; }

  char data_[4000];
  size_t length_;
};

typedef AsyncLoggingT AsyncLoggingUnboundedQueueL;
typedef AsyncLoggingT AsyncLoggingBoundedQueueL;

}
#endif  // MUDUO_BASE_ASYNCLOGGINGQUEUE_H

你可能感兴趣的:(Linux网络编程,大数据,数据库,前端)