Level 1 Record format and crash recovery
A log file is a sequence of records. Each record holds an opaque payload of at most 1024 bytes and is stored as:
[length: 4 bytes, big-endian unsigned][payload: length bytes][checksum: 4 bytes, big-endian unsigned]
The checksum is zlib.crc32(payload).
Write two functions:
encode_record(payload: bytes) -> bytesreturns the stored form. RaiseValueErrorif the payload is longer than 1024 bytes. An empty payload is fine.recover(path) -> list[bytes]repairs a log that may have been cut off by a crash. Read records from the start and stop at the first bad one. A record is bad if its header or body runs past the end of the file, if its length is over 1024, or if its checksum doesn't match. Truncate the file so it ends right after the last good record, then return the good payloads in order. Anything after a bad record is dropped, even if it looks valid. If the file doesn't exist, return[]and don't create it.
with open(p, "wb") as f:
f.write(encode_record(b"alpha") + encode_record(b"beta")[:-2]) # torn write
recover(p) # [b"alpha"], and the file is now 13 bytes long
encode_record(b"hi") # b"\x00\x00\x00\x02hi" + crc32(b"hi").to_bytes(4, "big")