package store import ( "encoding/binary" "hash/crc32" "io" "os" ) // The checkpoint names the WAL position up to which every index has been made // durable, plus the next pubkey serial. Recovery replays the WAL from pos. // // "TCK1" | pos uint64 | nextPubSer uint64 | crc32(first 20) uint32 const ( ckptMagic = "TCK1" ckptSize = 24 ckptCRCOff = 20 ) type checkpoint struct { f *os.File pos uint64 nextPub uint64 } func openCheckpoint(path string) (*checkpoint, error) { f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0o644) if err != nil { return nil, err } c := &checkpoint{f: f} buf := make([]byte, ckptSize) n, err := f.ReadAt(buf, 0) if err != nil && err != io.EOF { f.Close() return nil, err } if n == ckptSize && string(buf[0:4]) == ckptMagic && crc32.ChecksumIEEE(buf[:ckptCRCOff]) == binary.BigEndian.Uint32(buf[ckptCRCOff:]) { c.pos = binary.BigEndian.Uint64(buf[4:12]) c.nextPub = binary.BigEndian.Uint64(buf[12:20]) } return c, nil } func (c *checkpoint) Get() (pos, nextPub uint64) { return c.pos, c.nextPub } func (c *checkpoint) Set(pos, nextPub uint64) error { buf := make([]byte, ckptSize) copy(buf, ckptMagic) binary.BigEndian.PutUint64(buf[4:12], pos) binary.BigEndian.PutUint64(buf[12:20], nextPub) binary.BigEndian.PutUint32(buf[ckptCRCOff:], crc32.ChecksumIEEE(buf[:ckptCRCOff])) if _, err := c.f.WriteAt(buf, 0); err != nil { return err } c.pos = pos c.nextPub = nextPub return nil } func (c *checkpoint) Sync() error { return c.f.Sync() } func (c *checkpoint) Close() error { return c.f.Close() }