binlog相關的文件包含兩部分:manifest和write2file,其中manifest記錄了日誌元信息,包括當前日誌文件編號、當前日誌文件偏移量,write2file+num記錄了pika接收到的全部redis寫命令、參數。redis
日誌偏移量(8字節)|con_offset(8字節,未使用)|元素個數(4字節,未使用)|日誌文件編號(4字節)。bash
Header|Cmdapp
Header: Record Length(3字節)|時間戳(4字節)|記錄類型(1字節)。ui
Cmd: redis命令的一部分或者所有,取決於當前Block剩餘空間是否能夠存放該Record。spa
Version: 元信息類,經過mmap與manifest文件映射。指針
Binlog: 日誌類,經過mmap與write2file文件映射。日誌
PikaBinlogSenderThread: 日誌消費類,順序讀取日誌文件內容,消費日誌。code
//file_size能夠在配置文件指定,默認爲100MB
Binlog::Binlog(const std::string& binlog_path, const int file_size)
1.1 建立binlog文件目錄。
1.2 檢查log目錄下manifest文件是否存在,不存在則新建。
1.3 根據manifest文件初始化Version類。
1.4 根據manifest中的filenum找到對應的日誌文件,根據pro_offset定位到文件append的位置,初始化日誌指針、記錄日誌內容長度、Block塊數量。
複製代碼
//pro_num: 日誌文件編號
//pro_offset: 日誌文件偏移量
//用在須要全量同步時更新slave實例對應的binlog信息
Status Binlog::SetProducerStatus(uint32_t pro_num, uint64_t pro_offset)
2.1 刪除write2file0。
2.2 刪除write2file+pro_num。
2.3 構造新的write2file+pro_num文件,填充pro_offset個空格,初始化version->pro_num爲pro_num,version->pro_offset爲pro_offset,並刷新到manifest文件中。
2.4 初始化當前filesize、block_offset。
複製代碼
//filenum: 當前日誌編號
//pro_offset: 當前日誌偏移量
Status Binlog::GetProducerStatus(uint32_t* filenum, uint64_t* pro_offset)
3.1 讀取version中的pro_num、pro_offset並返回。
複製代碼
//Put->Produce->EmitPhysicalRecord
Status Binlog::Put(const std::string &item)
4.1檢查當前日誌文件是否知足切割條件,若是知足則進行切割。
4.1.1 pro_num自增長1,初始化新的日誌文件,version->pro_num=pro_num,version->pro_offset = 0,binlog->filesize = 0,binlog->block_offset = 0。
4.1.2 若是當前block剩餘大小<kHeaderSize(8字節),則填充剩餘空間爲'\x00"。 4.1.3 Produce是一個循環,保證在item大小超過kBlockSize時,能夠進行屢次EmitPhysicalRecord,完成item所有數據落入binlog文件,循環正常退出的條件是left==0。 4.1.3.1 若是left<avail,表明當前block能夠存放完整的item,則type=kFullType,調用EmitPhysicalRecord一次,循環退出。 4.1.3.2 若是left > avail,表明須要多個Block存放item,則第一次Type=kFirstType,調用EmitPhysicalRecord屢次。 4.1.3.3 若是left > avail,且不是第一次EmitPhysicalRecord,則Type=kMiddleType,調用EmitPhysicalRecord屢次。 4.1.4EmitPhysicalRecord。 4.1.4.1 拼接RecordHeader(3字節長度+4字節時間+1字節Type),寫入數據,更新block_offset、pro_offset。 複製代碼
//scratch: 消費結果返回一個完整的redis cmd
//Consume->ReadPhysicalRecord,ReadPhysicalRecord每次讀取一個完整的Record,多個Record構成一個完整的redis cmd
Status PikaBinlogSenderThread::Consume(std::string &scratch)
5.1Consume是一個循環,可能屢次調用ReadPhysicalRecord,循環退出的條件是讀取到的record_type==kFullType或record_type==kLastType。
5.1.1若是讀取到的kBlockSize-last_record_offset_ <= kHeaderSize表明讀到了Block的末尾,且爲填充數據,skip掉。
5.1.2讀取數據,更新last_record_offset_,con_offset。
複製代碼