github.com/grailbio/base@v0.0.11/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  }