Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

record文件中的时间戳可能是乱序的 #15615

Open
FlyingMusic opened this issue Dec 16, 2024 · 10 comments
Open

record文件中的时间戳可能是乱序的 #15615

FlyingMusic opened this issue Dec 16, 2024 · 10 comments

Comments

@FlyingMusic
Copy link

Describe the bug
当系统CPU资源紧张时,录制的record文件中的时间戳存在乱序可能

To Reproduce
Steps to reproduce the behavior:

Expected behavior
record文件中的数据保持时间顺序

Screenshots
利用python cyber_record读取某个record文件中的topic,打印其序列号录制时间,其中有一段是这样的:
seq: 49191, timestamp: 1733739177304346029
seq: 49194, timestamp: 1733739177598199183
seq: 49196, timestamp: 1733739177800743325
seq: 49197, timestamp: 1733739177929194262
seq: 49131, timestamp: 1733739171047058551 <- 开始出现乱序
seq: 49132, timestamp: 1733739171117104758
seq: 49133, timestamp: 1733739171234804341

Additional context
bug可能的原因
文件名:cyber/record/file/record_file_writer.cc
代码段:

bool RecordFileWriter::WriteMessage(const proto::SingleMessage& message) {
  chunk_active_->add(message);
  auto it = channel_message_number_map_.find(message.channel_name());
  if (it != channel_message_number_map_.end()) {
    it->second++;
  } else {
    channel_message_number_map_.insert(
        std::make_pair(message.channel_name(), 1));
  }
  bool need_flush = false;
  if (header_.chunk_interval() > 0 &&
      message.time() - chunk_active_->header_.begin_time() >
          header_.chunk_interval()) {
    need_flush = true;
  }
  if (!in_writing_ && header_.chunk_raw_size() > 0 &&
      chunk_active_->header_.raw_size() > header_.chunk_raw_size()) {
    need_flush = true;
  }
  if (!need_flush) {
    return true;
  }
  {
    std::unique_lock<std::mutex> flush_lock(flush_mutex_);
    chunk_flush_.swap(chunk_active_);  //这个Write线程notify_noe()后,下面的Flush线程不一定会获得执行机会(尤其当CPU紧张时),这种情况可能会持续到下一次Write线程写满chunk_active_,这个时候两个线程抢一把锁,属于未定义行为,如果还是Write线程抢到了CPU,会再进行一次swap,此后写入的数据就会追加到还没来得及落盘的chunk内,导致时间戳错乱;
//这个地方应该加一个判断chunk_flush_是否为空,只有为空是才进行swap,不知是否合适?
    flush_cv_.notify_one();
  }
  return true;
}

void RecordFileWriter::Flush() {
  while (is_writing_) {
    std::unique_lock<std::mutex> flush_lock(flush_mutex_);
    flush_cv_.wait(flush_lock,
                   [this] { return !chunk_flush_->empty() || !is_writing_; });
    if (!is_writing_) {
      break;
    }
    if (chunk_flush_->empty()) {
      continue;
    }
    in_writing_ = true;
    if (!WriteChunk(chunk_flush_->header_, *(chunk_flush_->body_.get()))) {
      AERROR << "Write chunk fail.";
    }
    in_writing_ = false;
    chunk_flush_->clear();
  }
}
@1012327963
Copy link

你那边有出现在10.0的时候会出现cyber_recorder record -a录不全的情况吗

@FlyingMusic
Copy link
Author

你那边有出现在10.0的时候会出现cyber_recorder record -a录不全的情况吗

偶尔有丢帧的情况,但录的topic是全的

@1012327963
Copy link

你那边有出现在10.0的时候会出现cyber_recorder记录-a记录不完整的情况吗?

偶尔会有丢帧的情况,但记录的主题是完整的

奇怪,我这边是topic是按照顺序的,但是数据会丢

@FlyingMusic
Copy link
Author

FlyingMusic commented Dec 16, 2024

你那边有出现在10.0的时候会出现cyber_recorder记录-a记录不完整的情况吗?

偶尔会有丢帧的情况,但记录的主题是完整的

奇怪,我这边是topic是按照顺序的,但是数据会丢

会丢啥意思?丢了某个topic?

@1012327963
Copy link

你那边有出现在10.0的时候会出现cyber_recorder记录-a记录不完整的情况吗?

有时会出现丢帧的情况,但记录的主题是完整的

奇怪,我的这篇文章的主题是按照顺序的,但是数据会丢失

会丢啥意思?丢了某个话题?

对的,某些话题没有办法正常录制下来

@FlyingMusic
Copy link
Author

你那边有出现在10.0的时候会出现cyber_recorder记录-a记录不完整的情况吗?

有时会出现丢帧的情况,但记录的主题是完整的

奇怪,我的这篇文章的主题是按照顺序的,但是数据会丢失

会丢啥意思?丢了某个话题?

对的,某些话题没有办法正常录制下来

奥 我也不是很懂,你可以看看cyber_monitor 能不能看到这些topic,确认是发出来了

@hearto1314
Copy link
Contributor

10.0 cyber_recorder 的使用问题我们尽快修复,修复完这个issue下面同步大家,谢谢。

@hearto1314
Copy link
Contributor

10.0 cyber_recorder的问题已经解决了,请大家pull最新代码编译使用。

@FlyingMusic 乱序的问题理论上不会发生,cyber_recorder 是双buffer写的机制,一个buffer没有flush完,另一个buffer如果满了会阻塞,可以使用最新版本试试。

@FlyingMusic
Copy link
Author

FlyingMusic commented Dec 19, 2024

10.0 cyber_recorder的问题已经解决了,请大家pull最新代码编译使用。

@FlyingMusic 乱序的问题理论上不会发生,cyber_recorder 是双buffer写的机制,一个buffer没有flush完,另一个buffer如果满了会阻塞,可以使用最新版本试试。

@hearto1314
你说的阻塞式等待 std::unique_lockstd::mutex flush_lock(flush_mutex_);这个锁吗,这个时候可能Flush线程也在等这个锁,两个线程谁抢到锁是不一定的,如果还是WriteMessage这个线程抢到了,不就会连续两次swap吗?
我们用的代码都是record/下的,这部分已经好几个月没动了,新版本应该没啥改变

@FlyingMusic
Copy link
Author

FlyingMusic commented Dec 19, 2024

我的描述可能有误,Flush线程不是也在等这个锁;
因为它在wait时是解开锁等的,极限条件下,Flush可能永远也得不到CPU,所以连尝试获取锁的机会都没有,而WriteMessage可能一直获取到CPU,也能获取锁,从而连续进行swap @hearto1314

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants