open Wire let magic = 0x53504F53 type t = { magic : int; format_version : int; reserved : int; tenant_id : int; total_blocks : int; dp_start : int; dp_size : int; epoch : int64; uuid : string; crc32 : int; } let codec = let open Codec in record "Superblock" (fun magic format_version reserved tenant_id total_blocks dp_start dp_size epoch uuid crc32 -> { magic; format_version; reserved; tenant_id; total_blocks; dp_start; dp_size; epoch; uuid; crc32; }) |+ field "magic" uint32be (fun t -> t.magic) |+ field "format_version" uint8 (fun t -> t.format_version) |+ field "reserved" uint8 (fun t -> t.reserved) |+ field "tenant_id" uint16be (fun t -> t.tenant_id) |+ field "total_blocks" uint32be (fun t -> t.total_blocks) |+ field "dp_start" uint32be (fun t -> t.dp_start) |+ field "dp_size" uint32be (fun t -> t.dp_size) |+ field "epoch" uint64be (fun t -> t.epoch) |+ field "uuid" (byte_array ~size:(int 16)) (fun t -> t.uuid) |+ field "crc32" uint32be (fun t -> t.crc32) |> seal let crc32c data = let v = Checkseum.Crc32c.digest_string data 0 (String.length data) Checkseum.Crc32c.default in Optint.to_unsigned_int v let compute_crc t = (* CRC covers bytes 0-47 (everything before the CRC field) *) let wire_size = Codec.wire_size codec in let buf = Bytes.create wire_size in Codec.encode codec t buf 0; (* CRC covers first 48 bytes (wire_size - 4) *) let crc_len = wire_size - 4 in crc32c (Bytes.sub_string buf 0 crc_len) let v ~tenant_id ~total_blocks ~dp_start ~dp_size ~epoch ~uuid = let t = { magic; format_version = 0x01; reserved = 0; tenant_id; total_blocks; dp_start; dp_size; epoch; uuid; crc32 = 0; } in { t with crc32 = compute_crc t } let check_magic t = t.magic = magic let check_crc t = let expected = compute_crc { t with crc32 = 0 } in t.crc32 = expected let pp ppf t = Fmt.pf ppf "@[superblock(magic=0x%08x ver=%d tenant=%d blocks=%d dp=%d+%d \ crc=0x%08x)@]" t.magic t.format_version t.tenant_id t.total_blocks t.dp_start t.dp_size t.crc32 let equal a b = a.magic = b.magic && a.format_version = b.format_version && a.tenant_id = b.tenant_id && a.total_blocks = b.total_blocks && a.dp_start = b.dp_start && a.dp_size = b.dp_size && Int64.equal a.epoch b.epoch && String.equal a.uuid b.uuid && a.crc32 = b.crc32