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