日志

“日志”有两个意思:
诊断日志
交易日志

muduo没有采用标准库的iostream,而是自己写的logStream Class,这主要是出于性能原因
LogStream做到了类型安全和类型可扩展,效率也较高。
整数转换字符串是最忌写的额,用的是Matthew Wilson(http://m.blog.csdn.net/article/details?id=46524267)的算法 这个算法比stdio和iostream都要快
muduo日志库采用双缓冲技术,基本思路准备两块buffer:A和B。前端负责往buffer A填数据,后端负责将buffer的数据写入到文件,当bufferA写满的之后,交换A和B 。让后端将buffer的数据写入到文件中,而前端往buffer B中填入新的日志消息

//所有LOG_*最终都会调用append函数。  
voidAsyncLogging::append(const char* logline, int len)  
{  
  //可能有多个线程同时调用LOG_*写入日志,所以需要同步。  
  muduo::MutexLockGuard lock(mutex_);  
  if ( currentBuffer_->avail()  >  len) //buffer还够大,可以装下新一条日志内容。  
  {  
    currentBuffer_->append(logline, len);  
  }  
  else  
  {  
    //currentBuffer_已经满了,要将之存放到buffers_中。  
   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(); //通知后台线程,已经有一个满了的buffer了。  
  }  
}   

currentBuffer //当前缓冲区
nextBuffer_ //预备缓冲区
buffers_ //待吸入文件的已填满的缓冲
上面是发送方的代码,如果当前currentBuffer_剩余空间足够大,则会直接把日志消息追加到当前换缓冲区中,否则说明当前缓冲区已满,就把它移入buffers_,并将另一块预备缓冲区移为当前缓冲区。当前端写入速度太快,一下子把这两块缓冲区都用完了,那么只好分配一块新的buffer作为当前缓冲区。

voidAsyncLogging::threadFunc()  
{  
  LogFile output(basename_, rollSize_, false);//定义一个直接进行IO的类。  
  BufferPtr newBuffer1(new Buffer); //这两个是后台线程的buffer  
  BufferPtr newBuffer2(new Buffer);  
  BufferVector buffersToWrite; //用来和前台线程的buffers_进行swap.  

  while (running_)  
  {  
    {  
      muduo::MutexLockGuard lock(mutex_);  
      if (buffers_.empty())  // unusual usage!  
      {  
        cond_.waitForSeconds(flushInterval_);//睡眠的时间是日志库flush时间。  
      }  

      //无论cond是因何而醒来,都要将currentBuffer_放到buffers_中。  
      //如果是因为时间到而醒,那么currentBuffer_还没满,此时也要将之写入LogFile中。  
      //如果已经有一个前台buffer满了,那么在前台线程中就已经把一个前台buffer放到buffers_中  
      //了。此时,还是需要把currentBuffer_放到buffers_中(注意,前后放置是不同的buffer,  
      //因为在前台线程中,currentBuffer_已经被换成nextBuffer_指向的buffer了)  
     buffers_.push_back(currentBuffer_.release());  

      currentBuffer_ =boost::ptr_container::move(newBuffer1); /*---归还一个buffer---*/  
      buffersToWrite.swap(buffers_); //交换  
      if (!nextBuffer_)  
      { //the nextBuffer_ is still free. notuse for swap with currentBuffer_  
        nextBuffer_ = boost::ptr_container::move(newBuffer2); /*-----假如需要,归还第二个----*/  
      }  
    }  

    //将已经满了的buffer内容写入到LogFile中。由LogFile进行IO操作。  
    for (size_t i = 0; i <buffersToWrite.size(); ++i)  
    {  
      // FIXME: use unbuffered stdio FILE ? oruse ::writev ?  
      output.append(buffersToWrite[i].data(),buffersToWrite[i].length());  
    }  

    if (!newBuffer1)  
    {  
      newBuffer1= buffersToWrite.pop_back();  
      newBuffer1->reset();  
}  
    //前台buffer是由newBuffer1 2 归还的。现在把buffersToWrite的buffer归还给后台buffer  
    if (!newBuffer2)  
    {  
      newBuffer2 = buffersToWrite.pop_back();  
      newBuffer2->reset();  
    }  

    buffersToWrite.clear();  
    output.flush(); //flush to drive. less than3 mins a time  
  }  
  output.flush();  
}  

以上代码是接收方(后端)实现
准备好两块空闲的buffer(newBuffer1,newBuffer2)以备临界区交换 。
先将当前缓冲(currentBuffer)移入到buffers_,并立刻将空闲的newBuffer1移为当前的缓冲,临界区最后干的是将buffer2移入buffer1保证时刻都有一个空闲的预备buffer

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值