Head connects chunkenc and WAL: label-to-ref resolution with striped concurrent maps, active Gorilla chunk per series sealing at 120 samples, and an Appender that buffers samples, writes WAL on commit, then applies to head. OOO rejection checks both committed and batch state. WAL replay on Open rebuilds the full in-memory state. Exported ChunkAppender/ChunkIterator interfaces from chunkenc.
75 lines
1.6 KiB
Go
75 lines
1.6 KiB
Go
// Package labels defines the data model for time-series label pairs.
|
|
package labels
|
|
|
|
import (
|
|
"errors"
|
|
"hash/fnv"
|
|
"sort"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
// Label is a name/value pair identifying a time series.
|
|
type Label struct {
|
|
Name string
|
|
Value string
|
|
}
|
|
|
|
var (
|
|
ErrEmptyName = errors.New("labels: empty label name")
|
|
ErrInvalidUTF8 = errors.New("labels: label contains invalid UTF-8")
|
|
ErrDuplicateName = errors.New("labels: duplicate label name")
|
|
)
|
|
|
|
// Sort sorts labels by name in place and returns them.
|
|
func Sort(ls []Label) []Label {
|
|
sort.Slice(ls, func(i, j int) bool { return ls[i].Name < ls[j].Name })
|
|
return ls
|
|
}
|
|
|
|
// Hash returns a 64-bit FNV-1a hash of the sorted label set.
|
|
// Labels must be sorted by name before calling.
|
|
func Hash(ls []Label) uint64 {
|
|
h := fnv.New64a()
|
|
for _, l := range ls {
|
|
h.Write([]byte(l.Name))
|
|
h.Write([]byte{0})
|
|
h.Write([]byte(l.Value))
|
|
h.Write([]byte{0})
|
|
}
|
|
return h.Sum64()
|
|
}
|
|
|
|
// Equal reports whether two sorted label sets are identical.
|
|
func Equal(a, b []Label) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
for i := range a {
|
|
if a[i] != b[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Validate checks that labels are sorted, non-empty named, valid UTF-8,
|
|
// and have no duplicate names.
|
|
func Validate(ls []Label) error {
|
|
for i, l := range ls {
|
|
if l.Name == "" {
|
|
return ErrEmptyName
|
|
}
|
|
if !utf8.ValidString(l.Name) || !utf8.ValidString(l.Value) {
|
|
return ErrInvalidUTF8
|
|
}
|
|
if i > 0 && ls[i-1].Name >= l.Name {
|
|
if ls[i-1].Name == l.Name {
|
|
return ErrDuplicateName
|
|
}
|
|
// Not sorted — caller should sort first.
|
|
return ErrDuplicateName
|
|
}
|
|
}
|
|
return nil
|
|
}
|