时间精度引发的一个问题

时间精度引发的一个问题

问题描述

最近在muduo库-LogFile类中遇到这么一个问题。

测试程序如下

std::unique_ptr<muduo::LogFile> g_logFile;

void outputFunc(const char* msg, int len)
{
  g_logFile->append(msg, len);
}

void flushFunc()
{
  g_logFile->flush();
}

int main(int argc, char* argv[])
{
  char name[256] = { 0 };
  strncpy(name, argv[0], sizeof name - 1);
  g_logFile.reset(new muduo::LogFile(::basename(name), 200*1000)); // 200k就发生滚动,当设置为50k,或者20k时会出现日志无法正常分割。
  muduo::Logger::setOutput(outputFunc);
  muduo::Logger::setFlush(flushFunc);

  muduo::string line = "1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ ";

  for (int i = 0; i < 10000; ++i)
  {
    LOG_INFO << line << i;

    usleep(1000); // 为什么要睡眠
  }
}

产生这么俩个问题。

  1. 为什么要睡眠?
  2. 当rollSize设置较小时,20k或者50k左右时,出现日志文件无法正常滚动的问题。

取消睡眠后,同样会出现日志文件无法进行正常分割问题。

1. 原因

这里是进行日志滚动的俩个核心函数

void LogFile::append_unlocked(const char* logline, int len)
{
  file_->append(logline, len);

  if (file_->writtenBytes() > rollSize_) // 按理来说,这里写入字节数大于rollSize后,应该发生日志滚动。
  {
    rollFile(); // 只关注这里
  }
  else
  {
	/*
	这 里 的 逻 辑 忽 略
	*/
  }
}

bool LogFile::rollFile() // 
{
  time_t now = 0;
  string filename = getLogFileName(basename_, &now); 
  time_t start = now / kRollPerSeconds_ * kRollPerSeconds_; // 对 齐 时 间 到 今 天 的 0 点

  if (now > lastRoll_) // 如 果 当 前 时 间 大 于 上 一 次 滚 动 时 间, 这 里 的 比 较 可 能 会 失 败
  {
    lastRoll_ = now;
    lastFlush_ = now;
    startOfPeriod_ = start;
    file_.reset(new FileUtil::AppendFile(filename)); // 新 打 开 一 个 文 件 ,这 里 是 unique 指 针,会 销 毁 原 来 的,掌 控 新 的
    return true;
  }
  return false;
}

原因主要在于时间精读的问题。我们的time_t代表的是秒的类型。因此if (now > lastRoll_)这里的比较实际上是基于秒的比较。然而在计算机的世界里,一秒的时间对于人类来说就是一年。如此粗的颗粒度。导致了我们在1秒之内多次触发rollFile,但全部失败。

2. 结论

如果我们试图在1秒之内这个级别分出俩个日志文件。就会导致无法正常日志滚动。因此我们的时间精读选取需要考量。在某一些领域,记得老师谈过,好像是在石油领域。需要比秒精度更高的日志级别划分。

猜你喜欢

转载自blog.csdn.net/weixin_43468441/article/details/89003915