Immutable blocks with mmap reads

Flush sealed head chunks to ULID-named block directories on disk. Each
block contains CRC'd chunk segment files (mmap'd for reads), a binary
index (symbol table, series, postings with TOC), and a meta.json written
last as the immutability gate. WAL is truncated after block fsync,
preserving the crash-safety ording invariant.
This commit is contained in:
2026-07-04 14:59:39 -04:00
parent 376d3faf25
commit 42b03db2fa
16 changed files with 2176 additions and 2 deletions
+9
View File
@@ -28,6 +28,15 @@ func NewXORChunk() *XORChunk {
return &XORChunk{b: bstream{stream: make([]byte, 2), count: 0}}
}
// XORChunkFromBytes creates a read-only XORChunk from raw bytes.
// The data must include the 2-byte sample count header (as returned by Bytes).
// The returned chunk supports Iterator, NumSamples, and Bytes but not Appender.
func XORChunkFromBytes(data []byte) *XORChunk {
cp := make([]byte, len(data))
copy(cp, data)
return &XORChunk{b: bstream{stream: cp}}
}
func (c *XORChunk) NumSamples() int {
return int(binary.BigEndian.Uint16(c.b.bytes()))
}
+52
View File
@@ -298,6 +298,58 @@ func TestXORChunk(t *testing.T) {
}
}
func TestXORChunkFromBytes(t *testing.T) {
rnd := rand.New(rand.NewSource(99))
tests := []struct {
name string
samples [][2]float64
}{
{"single", [][2]float64{{1000, 71.3}}},
{"two", [][2]float64{{1000, 71.3}, {1015, 71.4}}},
{"full_chunk", func() [][2]float64 {
out := make([][2]float64, 120)
ts, v := int64(0), 70.0
for i := range out {
out[i] = [2]float64{float64(ts), v}
ts += 15000 + int64(rnd.Intn(100)) - 50
v += rnd.Float64() - 0.5
}
return out
}()},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
orig := NewXORChunk()
a, _ := orig.Appender()
for _, s := range tc.samples {
a.Append(int64(s[0]), s[1])
}
reconstituted := XORChunkFromBytes(orig.Bytes())
assert.Equal(t, orig.NumSamples(), reconstituted.NumSamples())
assert.Equal(t, orig.Bytes(), reconstituted.Bytes())
// Verify iteration produces identical samples.
it := reconstituted.Iterator()
for i, s := range tc.samples {
assert.True(t, it.Next(), "sample %d", i)
gotT, gotV := it.At()
assert.Equal(t, int64(s[0]), gotT, "sample %d t", i)
assert.Equal(t, math.Float64bits(s[1]), math.Float64bits(gotV), "sample %d v", i)
}
assert.False(t, it.Next())
assert.NoError(t, it.Err())
// Appender on non-empty reconstituted chunk should fail.
_, err := reconstituted.Appender()
assert.Error(t, err)
})
}
}
func FuzzXORIterator(f *testing.F) {
c := NewXORChunk()
a, _ := c.Appender()