时间精度引发的一个问题
文章目录
问题描述
最近在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); // 为什么要睡眠
}
}
产生这么俩个问题。
- 为什么要睡眠?
- 当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秒之内这个级别分出俩个日志文件。就会导致无法正常日志滚动。因此我们的时间精读选取需要考量。在某一些领域,记得老师谈过,好像是在石油领域。需要比秒精度更高的日志级别划分。