github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/stateio/stateio.go (about) 1 // Copyright 2019 GRAIL, Inc. All rights reserved. 2 // Use of this source code is governed by the Apache 2.0 3 // license that can be found in the LICENSE file. 4 5 // Package stateio implements persistent state mechanism based on log 6 // files that interleave indexed state snapshots with state updates. Users maintain 7 // state by interaction with Reader and Writer objects. A typical application 8 // should reconcile to the current state before writing new log entries. New 9 // log entries should be written only after they are known to apply cleanly. 10 // (In the following examples, error handling is left as an exercise to the 11 // reader): 12 // 13 // file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE) 14 // state, epoch, updates, err := stateio.RestoreFile(file) 15 // application.Reset(state) 16 // for { 17 // entry, err := updates.Read() 18 // if err == io.EOF { 19 // break 20 // } 21 // application.Update(entry) 22 // } 23 // 24 // w, err := stateio.NewFileWriter(file) 25 // 26 // // Apply new state updates: 27 // var update []byte = ... 28 // application.Update(update) 29 // err := w.Update(update) 30 // 31 // // Produce a new snapshot: 32 // var snap []byte = application.Snapshot() 33 // w.Snapshot(snap) 34 // 35 // Data format 36 // 37 // State files maintained by package stateio builds on package logio. 38 // The log file contains a sequence of epochs, each beginning with a 39 // state snapshot (with the exception of the first epoch, which does 40 // not need a state snapshot). Each entry is prefixed with the type 41 // of the entry as well as the the epoch to which the entry belongs. 42 // Snapshot entries are are prefixed with the previous epoch, so that 43 // log files can efficiently rewound. 44 // 45 // TODO(marius): support log file truncation 46 package stateio 47 48 import "encoding/binary" 49 50 const ( 51 entryUpdate = 1 + iota 52 entrySnap 53 54 entryMax 55 ) 56 57 func parse(entry []byte) (typ uint8, epoch uint64, data []byte, ok bool) { 58 if len(entry) < 9 { 59 ok = false 60 return 61 } 62 typ = entry[0] 63 epoch = binary.LittleEndian.Uint64(entry[1:]) 64 data = entry[9:] 65 ok = typ < entryMax 66 return 67 }