serial.go raw

   1  // Package store is torly's storage engine.
   2  //
   3  // It follows the design used by morly: an append-only segmented write-ahead
   4  // log holds event bytes, and fixed-width sorted flat files hold the indexes.
   5  // Nothing is memory-mapped and no record is updated in place, which is what
   6  // makes the design a good fit for TinyGo and for immutable signed messages.
   7  //
   8  // A serial is a physical address in the log: segment<<32 | offset. Index
   9  // records carry the serial of the event they point at, so a lookup is
  10  // index search followed by one log read.
  11  package store
  12  
  13  import (
  14  	"crypto/sha256"
  15  	"encoding/binary"
  16  )
  17  
  18  const (
  19  	// SerialLen is the byte length of a serial (uint40).
  20  	SerialLen = 5
  21  	// MaxSerial is the largest uint40 value.
  22  	MaxSerial uint64 = 1<<40 - 1
  23  	// HashLen is the byte length of truncated hashes in index keys.
  24  	HashLen = 8
  25  )
  26  
  27  // Hash8 returns the first eight bytes of SHA-256(data).
  28  func Hash8(data []byte) (out [HashLen]byte) {
  29  	sum := sha256.Sum256(data)
  30  	copy(out[:], sum[:HashLen])
  31  	return out
  32  }
  33  
  34  // PutSerial writes v as a 5-byte big-endian serial.
  35  func PutSerial(dst []byte, v uint64) {
  36  	dst[0] = byte(v >> 32)
  37  	dst[1] = byte(v >> 24)
  38  	dst[2] = byte(v >> 16)
  39  	dst[3] = byte(v >> 8)
  40  	dst[4] = byte(v)
  41  }
  42  
  43  // GetSerial reads a 5-byte big-endian serial.
  44  func GetSerial(src []byte) uint64 {
  45  	return uint64(src[0])<<32 | uint64(src[1])<<24 | uint64(src[2])<<16 | uint64(src[3])<<8 | uint64(src[4])
  46  }
  47  
  48  // AppendSerial appends v as a serial.
  49  func AppendSerial(dst []byte, v uint64) []byte {
  50  	return append(dst, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
  51  }
  52  
  53  // PutTimestamp writes ts as an 8-byte big-endian value, preserving ordering.
  54  func PutTimestamp(dst []byte, ts int64) { binary.BigEndian.PutUint64(dst, uint64(ts)) }
  55  
  56  // GetTimestamp reads an 8-byte big-endian timestamp.
  57  func GetTimestamp(src []byte) int64 { return int64(binary.BigEndian.Uint64(src)) }
  58  
  59  // PutKind writes a 2-byte big-endian kind.
  60  func PutKind(dst []byte, k int) { binary.BigEndian.PutUint16(dst, uint16(k)) }
  61  
  62  // GetKind reads a 2-byte big-endian kind.
  63  func GetKind(src []byte) int { return int(binary.BigEndian.Uint16(src)) }
  64