muduo库阅读(16)——异步日志类

来源:互联网 发布:从零开始学python 编辑:程序博客网 时间:2024/05/18 01:58
/* * 异步日志 */namespace muduo{class AsyncLogging : boost::noncopyable{public:AsyncLogging(const string& basename,size_t rollSize,int flushInterval = 3);~AsyncLogging(){if (running_){stop();}}void append(const char* logline, int len);// 开始启动异步日志void start(){running_ = true;// 在构造函数中latch_的值为1// 线程运行之后将latch_的减为0thread_.start();// 必须等到latch_变为0才能从start函数中返回,这表明初始化已经完成latch_.wait();}// 停止异步日志void stop(){running_ = false;cond_.notify();thread_.join();}private:// declare but not define, prevent compiler-synthesized functionsAsyncLogging(const AsyncLogging&);  // ptr_containervoid operator=(const AsyncLogging&);  // ptr_container// 线程调用的函数,主要用于周期性的flush数据到日志文件中void threadFunc();typedef muduo::detail::FixedBuffer<muduo::detail::kLargeBuffer> Buffer;typedef boost::ptr_vector<Buffer> BufferVector;// buffer队列typedef BufferVector::auto_type BufferPtr;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_;// 缓冲区队列};}

// 构造函数AsyncLogging::AsyncLogging(const string& basename,size_t rollSize,int flushInterval): flushInterval_(flushInterval),  running_(false),  basename_(basename),  rollSize_(rollSize),  thread_(boost::bind(&AsyncLogging::threadFunc, this), "Logging"),  latch_(1),  mutex_(),  cond_(mutex_),  currentBuffer_(new Buffer),  nextBuffer_(new Buffer),  buffers_(){currentBuffer_->bzero();nextBuffer_->bzero();buffers_.reserve(16);}// 添加日志void AsyncLogging::append(const char* logline, int len){// 加锁muduo::MutexLockGuard lock(mutex_);// 如果当前buffer还有空间,就添加到当前日志if (currentBuffer_->avail() > len){currentBuffer_->append(logline, len);}// 当前buffer已满else{// 把当前buffer添加到buffer列表中buffers_.push_back(currentBuffer_.release());// 重新设置当前bufferif (nextBuffer_){currentBuffer_ = boost::ptr_container::move(nextBuffer_);}else{currentBuffer_.reset(new Buffer); // Rarely happens}currentBuffer_->append(logline, len);// 通知日志线程,有数据可写// 也就是说,只有当缓冲区满了之后才会将数据写入日志文件中cond_.notify();}}// 日志线程调用的函数void AsyncLogging::threadFunc(){assert(running_ == true);latch_.countDown();// 日志对象LogFile output(basename_, rollSize_, false);// buffer指针BufferPtr newBuffer1(new Buffer);BufferPtr newBuffer2(new Buffer);newBuffer1->bzero();newBuffer2->bzero();// 将要写入文件的bufferBufferVector buffersToWrite;buffersToWrite.reserve(16);while (running_){assert(newBuffer1 && newBuffer1->length() == 0);assert(newBuffer2 && newBuffer2->length() == 0);assert(buffersToWrite.empty());{// 加锁muduo::MutexLockGuard lock(mutex_);// 如果buffer为空,那么表示没有数据需要写入文件,那么就等待指定的时间(注意这里没有用倒数计数器)if (buffers_.empty())  // unusual usage!{cond_.waitForSeconds(flushInterval_);}// 将当前buffer的数据倒入buffer列表中buffers_.push_back(currentBuffer_.release());// 将新的buffer转成当前缓冲区currentBuffer_ = boost::ptr_container::move(newBuffer1);// buffers_和buffersToWrite交换数据,此时buffers_所有的数据存放在buffersToWrite,而buffers_变为空buffersToWrite.swap(buffers_);// 如果备份缓冲区(或者说下一个缓存区)为空就设置下一个缓冲区if (!nextBuffer_){nextBuffer_ = boost::ptr_container::move(newBuffer2);}}assert(!buffersToWrite.empty());// 如果将要写入文件的buffer列表中buffer的个数大于25,那么将这些数据删除// 什么要这样做?if (buffersToWrite.size() > 25){char buf[256];snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n",Timestamp::now().toFormattedString().c_str(),buffersToWrite.size()-2);fputs(buf, stderr);output.append(buf, static_cast<int>(strlen(buf)));// 删除buffersToWrite的所有数据buffersToWrite.erase(buffersToWrite.begin()+2, buffersToWrite.end());}// 将buffersToWrite的数据写入到日志中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());}// 重新调整buffersToWrite的大小if (buffersToWrite.size() > 2){// drop non-bzero-ed buffers, avoid trashing// 防止被破坏buffersToWrite.resize(2);}/* * 不知道下面两个这样做的目的是什么,难道不能直接new吗? */if (!newBuffer1){assert(!buffersToWrite.empty());// 从buffersToWrite中弹出一个作为newBuffer1newBuffer1 = buffersToWrite.pop_back();// 清理newBuffer1newBuffer1->reset();}if (!newBuffer2){assert(!buffersToWrite.empty());// 从buffersToWrite中弹出一个作为newBuffer2newBuffer2 = buffersToWrite.pop_back();// 清理newBuffer2newBuffer2->reset();}// 清理buffersToWrite.clear();// 冲刷output.flush();}output.flush();}


0 0