目录
Apollo record文件格式
1 Record文件总体格式
Record文件由许多的Section组成:
- Section Type为枚举类型,大小为8字节(来自
apollo/cyber/proto/record.proto
文件):
enum SectionType {
SECTION_HEADER = 0;
SECTION_CHUNK_HEADER = 1;
SECTION_CHUNK_BODY = 2;
SECTION_INDEX = 3;
SECTION_CHANNEL = 4;
};
- 第一个Section 0为HEADER类型。
- 每个CHUNK_HEADER类型的Section后,必然跟着一个CHUNK_BODY。
- 除此之外,其他位置的Section没有固定类型。
- Data Size为int64_t类型,8字节,表示Data的长度。
- Data为数据部分。
2 Section中的Data格式
2.1 HEADER Data
- HEADER Data包含了record文件的基本信息,其有效长度由Data Size指定。
- 注意,Data Size的值不一定等于Header结构体的大小。
- 整个HEADER Data在文件中会占据2048字节,多出来的位置需填充。
- Header结构体定义(来自
apollo/cyber/proto/record.proto
文件):
message Header {
optional uint32 major_version = 1;
optional uint32 minor_version = 2;
optional CompressType compress = 3;
optional uint64 chunk_interval = 4;
optional uint64 segment_interval = 5;
optional uint64 index_position = 6 [default = 0];
optional uint64 chunk_number = 7 [default = 0];
optional uint64 channel_number = 8 [default = 0];
optional uint64 begin_time = 9 [default = 0];
optional uint64 end_time = 10 [default = 0];
optional uint64 message_number = 11 [default = 0];
optional uint64 size = 12 [default = 0];
optional bool is_complete = 13 [default = false];
optional uint64 chunk_raw_size = 14;
optional uint64 segment_raw_size = 15;
}
enum CompressType {
COMPRESS_NONE = 0;
COMPRESS_BZ2 = 1;
COMPRESS_LZ4 = 2;
};
2.2 CHUNK_HEADER Data
- ChunkHeader Data 包含了紧跟其后的ChunkBody Section的信息。
- 定义(来自
apollo/cyber/proto/record.proto
文件):
message ChunkHeader {
optional uint64 begin_time = 1;
optional uint64 end_time = 2;
optional uint64 message_number = 3;
optional uint64 raw_size = 4;
}
2.3 CHUNK_BODY Data
- ChunkBody Data是一个SingleMessage类型的数组。
- 定义(来自
apollo/cyber/proto/record.proto
文件):
message ChunkBody {
repeated SingleMessage messages = 1;
}
message SingleMessage {
optional string channel_name = 1;
optional uint64 time = 2;
optional bytes content = 3;
}
2.4 INDEX Data
- Index Data包含一个SingleIndex类型数组,作为Section的索引,保存了Channel、ChunkHeader、ChunkBody三种Section的位置和简要数据。
- Index定义(来自
apollo/cyber/proto/record.proto
文件):
message Index {
repeated SingleIndex indexes = 1;
}
message SingleIndex {
optional SectionType type = 1;
optional uint64 position = 2;
oneof cache {
ChannelCache channel_cache = 101;
ChunkHeaderCache chunk_header_cache = 102;
ChunkBodyCache chunk_body_cache = 103;
}
}
message ChunkHeaderCache {
optional uint64 message_number = 1;
optional uint64 begin_time = 2;
optional uint64 end_time = 3;
optional uint64 raw_size = 4;
}
message ChunkBodyCache {
optional uint64 message_number = 1;
}
message ChannelCache {
optional uint64 message_number = 1;
optional string name = 2;
optional string message_type = 3;
optional bytes proto_desc = 4;
}
2.5 CHANNEL Data
- Channel定义(来自record.proto文件):
message Channel {
optional string name = 1;
optional string message_type = 2;
optional bytes proto_desc = 3;
}
3 序列化与反序列化
3.1 序列化
- 生成record文件时,需要将每个Section的数据部分通过protobuf提供的函数进行序列化。
apollo/cyber/record/file/record_file_writer.h
文件中:
google::protobuf::io::FileOutputStream raw_output(fd_);
message.SerializeToZeroCopyStream(&raw_output);
3.2 反序列化
- 读取record文件时,需要将每个Section的数据部分通过protobuf提供的函数进行反序列化。
apollo/cyber/record/file/record_file_reader.h
文件中:
FileInputStream raw_input(fd_, static_cast<int>(size));
CodedInputStream coded_input(&raw_input);
CodedInputStream::Limit limit = coded_input.PushLimit(static_cast<int>(size)); message->ParseFromCodedStream(&coded_input)
coded_input.ConsumedEntireMessage()
coded_input.PopLimit(limit);