- 로그의 구조는 32KB 크기의 블럭의 시퀀스로 되어있다.
- 한 블럭 안에는
Checksum(4bytes), Length(2bytes), Type(1byte), Data부분으로 나뉘어져 있다.
checksum은 데이터의 손상을 확인할 때 사용한다.length는 데이터의 길이를 말한다.- 쓰고자 하는 데이터의 크기가 한 블럭에 담긴다면
type부분에Full(1)이 표기되겠지만,
그러지 못하고 데이터가 여러 블럭에 담겨야 할 때 그 데이터가 기록되는 가장 앞 부분의 블럭의type에는First(2)가 표기되고
가장 마지막 블록은Last(4)가 표기된다.
그리고 그 중간에 담기는 모든 블럭들은Middle(3)로 표기된다. data부분에는 데이터가 쓰인다.
log::reader 파일에는
Reader 클래스와 몇 가지 함수가 있다.
나는 이 중 bool Reader::ReadRecord(Slice* record, std::string* scratch) 함수를 중심으로 이 파일의 흐름을 살펴보고자 했다.
ReadRecord()함수가 실행되면 먼저 이니셜 블록의 위치를 찾는데
SkipToInitialBlock()함수는 이니셜 블록의 위치가 있는 곳까지 오프셋을 옮긴다.- 이후
while문을 돌면서 읽고자 하는 데이터를 읽게 된다. while문을 도는 동안에는record_type이라는 정수형 변수에ReadPhysicalRecord()함수의 리턴 값을 받는다.- 이 함수는 위에서 언급했듯이
record의type을 읽고 그를 반환하거나 에러가 있으면 그 에러를 알려준다. 그래서type의 종류가 조금 늘었는데,
kEof, kBadRecord가 그것이다.
-
읽으려는 데이터가 몇 개의 블럭에 걸쳐 있는지 알기 위해서 혹은 에러가 있는지 확인하기 위해
위에ReadPhysicalRecord()함수를 호출하고 받은record_type값을 이용한다. -
switch문에서는 각 블럭의type을 읽고 블럭을 더 읽을 것인지 판단하며
에러가 있으면 이 또한 처리하는 과정이 있다. -
그리고
ReadRecord()함수의 매개변수로는record와scratch를 받는데,
읽고자 하는 데이터가 여러 블록으로 나뉘어져 있을 경우scratch에 각 블럭의 데이터를append해주었다가
마지막 블럭을 만나면 한번에record에 준다. -
또한
in_fragmented_record라는 변수가 있는데,
이 변수는 읽고자 하는 블럭이 여러 개로 나뉘어져 있는지 판단할 때 사용하며 기본값은false이다.
-
kFullType의 경우 데이터를 읽어 바로record에 준다음true를 반환하며 그대로 함수를 마친다. -
kFirstType의 경우scratch에 데이터를append한 후
in_fragmented_record변수를true로 설정하여 뒤에 블럭이 더 있음을 알리는 역할을 하게끔 만든다.
여기서는in_fragmented_record가false여야 정상이므로 그렇지 않다면 에러를 Report해준다. -
kMiddleType의 경우scratch에 데이터를append해준다.
여기서는in_fragmented_record가false라면 핸들링 해준다. -
kLastType의 경우scratch에 데이터를append해준 후
여태 추가했던 데이터가 담겨있는scratch를Slice객체로 바꿔서record에 준다.
마찬가지로in_fragmented_record가false라면 핸들링 해준다. -
kEof의 경우는 더이상 읽을 블럭이 없을 때이다.
그러므로false를 반환하여 그대로 함수를 마친다. -
kBadRecord의 경우checksum이 맞지 않거나 레코드의 길이가 0이거나 등
오류가 있어 물리 레코드에서 읽어오지 못한 경우에 처리된다. -
모든 keyType에 해당되지 않는 경우는 오류를 알린다.
지금까지 Log format를 살펴보고 log::reader파일을
bool Reader::ReadRecord(Slice* record, std::string* scratch) 함수를 중심으로 보았다.