mirror of https://github.com/prometheus/prometheus
Change series and symbol table format
parent
da068500c6
commit
433e73f865
|
@ -3,27 +3,11 @@
|
||||||
The following describes the format of a single chunks file, which is created in the `chunks/` directory of a block.
|
The following describes the format of a single chunks file, which is created in the `chunks/` directory of a block.
|
||||||
|
|
||||||
```
|
```
|
||||||
┌────────────────────────────┬──────────────────┐
|
┌─────────────────────────────┬─────────────────────┐
|
||||||
│ magic(0x85BD40DD) <4 byte> | version <1 byte> │
|
│ magic(0x85BD40DD) <4 byte> │ version(1) <1 byte> │
|
||||||
├────────────────────────────┴──────────────────┤
|
├─────────────────────────────┴─────────────────────┤
|
||||||
│ Body ... │
|
│ ┌──────────────┬───────────────────┬────────┐ │
|
||||||
└───────────────────────────────────────────────┘
|
│ │ len <varint> │ encoding <1 byte> │ data │ ... │
|
||||||
|
│ └──────────────┴───────────────────┴────────┘ │
|
||||||
|
└───────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
Available versions:
|
|
||||||
* v1 (`1`)
|
|
||||||
|
|
||||||
## Body (v1)
|
|
||||||
|
|
||||||
The body contains a sequence of chunks, each of which has the following format.
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ ┌──────────────┬───────────────────┬────────────┐ │
|
|
||||||
│ │ len <varint> | encoding <1 byte> │ data │ ... │
|
|
||||||
│ └──────────────┴───────────────────┴────────────┘ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
The length marks the length of the encoding byte and data combined.
|
|
||||||
The CRC checksum is calculated over the encoding byte and data.
|
|
|
@ -3,31 +3,25 @@
|
||||||
The following describes the format of the `index` file found in each block directory.
|
The following describes the format of the `index` file found in each block directory.
|
||||||
|
|
||||||
```
|
```
|
||||||
┌────────────────────────────┬──────────────────┐
|
┌────────────────────────────┬─────────────────────┐
|
||||||
│ magic(0xBAAAD700) <4 byte> │ version <1 byte> │
|
│ magic(0xBAAAD700) <4 byte> │ version(1) <1 byte> │
|
||||||
├────────────────────────────┴──────────────────┤
|
├────────────────────────────┴─────────────────────┤
|
||||||
│ Body ... │
|
│ ┌──────────────────────────────────────────────┐ │
|
||||||
└───────────────────────────────────────────────┘
|
│ │ Symbol Table │ │
|
||||||
```
|
│ ├──────────────────────────────────────────────┤ │
|
||||||
|
│ │ Series │ │
|
||||||
## Body (v1)
|
│ ├──────────────────────────────────────────────┤ │
|
||||||
|
│ │ Label Index │ │
|
||||||
The body is split into the following parts:
|
│ ├──────────────────────────────────────────────┤ │
|
||||||
|
│ │ Postings │ │
|
||||||
```
|
│ ├──────────────────────────────────────────────┤ │
|
||||||
┌───────────────────────────────────────────────┐
|
│ │ Body ... │ │
|
||||||
│ Symbol Table │
|
│ ├──────────────────────────────────────────────┤ │
|
||||||
├───────────────────────────────────────────────┤
|
│ │ Body ... │ │
|
||||||
│ Series │
|
│ ├──────────────────────────────────────────────┤ │
|
||||||
├───────────────────────────────────────────────┤
|
│ │ Body ... │ │
|
||||||
│ Label Index │
|
│ └──────────────────────────────────────────────┘ │
|
||||||
├───────────────────────────────────────────────┤
|
└──────────────────────────────────────────────────┘
|
||||||
│ Postings │
|
|
||||||
├───────────────────────────────────────────────┤
|
|
||||||
│ Body ... │
|
|
||||||
├───────────────────────────────────────────────┤
|
|
||||||
│ Body ... │
|
|
||||||
└───────────────────────────────────────────────┘
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,15 +29,13 @@ The body is split into the following parts:
|
||||||
|
|
||||||
The symbol table holds all strings encountered in our index. All other index sections just reference strings in the table as they are highly repetitive.
|
The symbol table holds all strings encountered in our index. All other index sections just reference strings in the table as they are highly repetitive.
|
||||||
|
|
||||||
#### v1, section(`1`)
|
|
||||||
|
|
||||||
The section contains a sequence of the raw string data, each prefixed with the string's length.
|
The section contains a sequence of the raw string data, each prefixed with the string's length.
|
||||||
Strings are referenced by pointing to the beginning of their length field. The strings are sorted in lexicographically ascending order.
|
Strings are referenced by pointing to the beginning of their length field. The strings are sorted in lexicographically ascending order.
|
||||||
|
|
||||||
```
|
```
|
||||||
┌────────────────────┬────────────────────┐
|
┌─────────────────────────┬───────────────┐
|
||||||
│ version <1 byte> │ len <4 byte> │
|
│ count(symbols) <4 byte> │ len <4 byte> │
|
||||||
├────────────────────┴────────────────────┤
|
├─────────────────────────┴───────────────┤
|
||||||
│ ┌─────────────────────┬───────────────┐ │
|
│ ┌─────────────────────┬───────────────┐ │
|
||||||
│ │ len(str_1) <varint> │ str_1 <bytes> │ │
|
│ │ len(str_1) <varint> │ str_1 <bytes> │ │
|
||||||
│ ├─────────────────────┴───────────────┤ │
|
│ ├─────────────────────┴───────────────┤ │
|
||||||
|
@ -52,38 +44,56 @@ Strings are referenced by pointing to the beginning of their length field. The s
|
||||||
│ │ len(str_n) <varint> │ str_1 <bytes> │ │
|
│ │ len(str_n) <varint> │ str_1 <bytes> │ │
|
||||||
│ └─────────────────────┴───────────────┘ │
|
│ └─────────────────────┴───────────────┘ │
|
||||||
├─────────────────────────────────────────┤
|
├─────────────────────────────────────────┤
|
||||||
│ CRC <4 byte> │
|
│ CRC32 <4 byte> │
|
||||||
└─────────────────────────────────────────┘
|
└─────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Series
|
### Series
|
||||||
|
|
||||||
#### v1, section(`1`)
|
|
||||||
|
|
||||||
The section contains a sequence of series that hold the label set of the series as well as the chunks within the block. The series are sorted lexicographically by their label sets.
|
The section contains a sequence of series that hold the label set of the series as well as the chunks within the block. The series are sorted lexicographically by their label sets.
|
||||||
The file offset to the beginning of a series serves as the series' ID in all subsequent references. Thereby, a sorted list of series IDs implies a lexicographically sorted list of series label sets.
|
The file offset to the beginning of a series serves as the series' ID in all subsequent references. Thereby, a sorted list of series IDs implies a lexicographically sorted list of series label sets.
|
||||||
|
|
||||||
```
|
```
|
||||||
┌────────────┬─────────┬────────────┐
|
┌───────────────────────────────────────┐
|
||||||
│ series_1 │ . . . │ series_n │
|
│ count(series) <4 byte> │
|
||||||
└────────────┴─────────┴────────────┘
|
├───────────────────────────────────────┤
|
||||||
|
│ ┌───────────────────────────────────┐ │
|
||||||
|
│ │ series_1 │ │
|
||||||
|
│ ├───────────────────────────────────┤ │
|
||||||
|
│ │ . . . │ │
|
||||||
|
│ ├───────────────────────────────────┤ │
|
||||||
|
│ │ series_n │ │
|
||||||
|
│ └───────────────────────────────────┘ │
|
||||||
|
└───────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
Every series holds a list of label pairs and chunks. The label pairs reference the symbol table and the chunks an address in one of the block's chunk files.
|
Every series holds a list of label pairs and chunks. The label pairs reference the symbol table and the chunks an address in one of the block's chunk files.
|
||||||
|
|
||||||
```
|
```
|
||||||
┌──────────────────┬────────────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────┐
|
||||||
│ │ ┌────────────────────────┬─────────────────────────┐ │
|
│ len <varint> │
|
||||||
│ #labels <varint> │ │ ref(l_i.name) <varint> │ ref(l_i.value) <varint> │ ... │
|
├─────────────────────────────────────────────────────────┤
|
||||||
│ │ └────────────────────────┴─────────────────────────┘ │
|
│ ┌──────────────────┬──────────────────────────────────┐ │
|
||||||
├──────────────────┼────────────────────────────────────────────────────────────────────────┤
|
│ │ │ ┌──────────────────────────┐ │ │
|
||||||
│ │ ┌───────────────────┬───────────────────┬────────────────────────┐ │
|
│ │ │ │ ref(l_i.name) <varint> │ │ │
|
||||||
│ #chunks <varint> │ │ c_i.mint <varint> │ c_i.maxt <varint> │ ref(c_i.data) <varint> │ ... │
|
│ │ #labels <varint> │ ├──────────────────────────┤ ... │ │
|
||||||
│ │ └───────────────────┴───────────────────┴────────────────────────┘ │
|
│ │ │ │ ref(l_i.value) <varint> │ │ │
|
||||||
├──────────────────┴────────────────────────────────────────────────────────────────────────┤
|
│ │ │ └──────────────────────────┘ │ │
|
||||||
|
│ ├──────────────────┼──────────────────────────────────┤ │
|
||||||
|
│ │ │ ┌──────────────────────────┐ │ │
|
||||||
|
│ │ │ │ c_i.mint <varint> │ │ │
|
||||||
|
│ │ │ ├──────────────────────────┤ │ │
|
||||||
|
│ │ │ │ c_i.maxt <varint> │ │ │
|
||||||
|
│ │ #chunks <varint> │ ├──────────────────────────┤ ... │ │
|
||||||
|
│ │ │ │ ref(c_i.data) <varint> │ │ │
|
||||||
|
│ │ │ ├──────────────────────────┤ │ │
|
||||||
|
│ │ │ │ crc32(c_i.data) <varint> │ │ │
|
||||||
|
│ │ │ └──────────────────────────┘ │ │
|
||||||
|
│ └──────────────────┴──────────────────────────────────┘ │
|
||||||
|
├─────────────────────────────────────────────────────────┤
|
||||||
│ CRC32 <4 byte> │
|
│ CRC32 <4 byte> │
|
||||||
└───────────────────────────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
The CRC checksum is calculated over the series contents of the index concatenated with the data of its chunks (with encoding byte, without length).
|
The CRC checksum is calculated over the series contents of the index concatenated with the data of its chunks (with encoding byte, without length).
|
||||||
|
|
24
chunks.go
24
chunks.go
|
@ -17,6 +17,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -41,6 +42,16 @@ type ChunkMeta struct {
|
||||||
MinTime, MaxTime int64 // time range the data covers
|
MinTime, MaxTime int64 // time range the data covers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cm *ChunkMeta) hash(h hash.Hash) error {
|
||||||
|
if _, err := h.Write([]byte{byte(cm.Chunk.Encoding())}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := h.Write(cm.Chunk.Bytes()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ChunkWriter serializes a time block of chunked series data.
|
// ChunkWriter serializes a time block of chunked series data.
|
||||||
type ChunkWriter interface {
|
type ChunkWriter interface {
|
||||||
// WriteChunks writes several chunks. The Chunk field of the ChunkMetas
|
// WriteChunks writes several chunks. The Chunk field of the ChunkMetas
|
||||||
|
@ -194,14 +205,14 @@ func (w *chunkWriter) WriteChunks(chks ...*ChunkMeta) error {
|
||||||
for _, chk := range chks {
|
for _, chk := range chks {
|
||||||
chk.Ref = seq | uint64(w.n)
|
chk.Ref = seq | uint64(w.n)
|
||||||
|
|
||||||
if err := w.write([]byte{byte(chk.Chunk.Encoding())}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
n = binary.PutUvarint(b, uint64(len(chk.Chunk.Bytes())))
|
n = binary.PutUvarint(b, uint64(len(chk.Chunk.Bytes())))
|
||||||
|
|
||||||
if err := w.write(b[:n]); err != nil {
|
if err := w.write(b[:n]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := w.write([]byte{byte(chk.Chunk.Encoding())}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := w.write(chk.Chunk.Bytes()); err != nil {
|
if err := w.write(chk.Chunk.Bytes()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -283,17 +294,16 @@ func (s *chunkReader) Chunk(ref uint64) (chunks.Chunk, error) {
|
||||||
if int(off) >= len(b) {
|
if int(off) >= len(b) {
|
||||||
return nil, errors.Errorf("offset %d beyond data size %d", off, len(b))
|
return nil, errors.Errorf("offset %d beyond data size %d", off, len(b))
|
||||||
}
|
}
|
||||||
|
b = b[off:]
|
||||||
enc := chunks.Encoding(b[off])
|
|
||||||
b = b[off+1:]
|
|
||||||
|
|
||||||
l, n := binary.Uvarint(b)
|
l, n := binary.Uvarint(b)
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
return nil, fmt.Errorf("reading chunk length failed")
|
return nil, fmt.Errorf("reading chunk length failed")
|
||||||
}
|
}
|
||||||
b = b[n:]
|
b = b[n:]
|
||||||
|
enc := chunks.Encoding(b[0])
|
||||||
|
|
||||||
c, err := chunks.FromData(enc, b[0:l])
|
c, err := chunks.FromData(enc, b[1:1+l])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
203
index.go
203
index.go
|
@ -35,6 +35,8 @@ const (
|
||||||
MagicIndex = 0xBAAAD700
|
MagicIndex = 0xBAAAD700
|
||||||
|
|
||||||
indexFormatV1 = 1
|
indexFormatV1 = 1
|
||||||
|
|
||||||
|
indexSeriesFormatV1 = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
const compactionPageBytes = minSectorSize * 64
|
const compactionPageBytes = minSectorSize * 64
|
||||||
|
@ -71,8 +73,8 @@ type indexWriterSeries struct {
|
||||||
// serialization format.
|
// serialization format.
|
||||||
type indexWriter struct {
|
type indexWriter struct {
|
||||||
f *os.File
|
f *os.File
|
||||||
bufw *bufio.Writer
|
fbuf *bufio.Writer
|
||||||
n int64
|
pos int
|
||||||
started bool
|
started bool
|
||||||
|
|
||||||
// Reusable memory.
|
// Reusable memory.
|
||||||
|
@ -102,8 +104,8 @@ func newIndexWriter(dir string) (*indexWriter, error) {
|
||||||
|
|
||||||
iw := &indexWriter{
|
iw := &indexWriter{
|
||||||
f: f,
|
f: f,
|
||||||
bufw: bufio.NewWriterSize(f, 1<<22),
|
fbuf: bufio.NewWriterSize(f, 1<<22),
|
||||||
n: 0,
|
pos: 0,
|
||||||
|
|
||||||
// Reusable memory.
|
// Reusable memory.
|
||||||
b: make([]byte, 0, 1<<23),
|
b: make([]byte, 0, 1<<23),
|
||||||
|
@ -120,40 +122,19 @@ func newIndexWriter(dir string) (*indexWriter, error) {
|
||||||
return iw, nil
|
return iw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *indexWriter) write(wr io.Writer, b []byte) error {
|
func (w *indexWriter) write(b []byte) error {
|
||||||
n, err := wr.Write(b)
|
n, err := w.fbuf.Write(b)
|
||||||
w.n += int64(n)
|
w.pos += n
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// section writes a CRC32 checksummed section of length l and guarded by flag.
|
|
||||||
func (w *indexWriter) section(l int, flag byte, f func(w io.Writer) error) error {
|
|
||||||
w.crc32.Reset()
|
|
||||||
wr := io.MultiWriter(w.crc32, w.bufw)
|
|
||||||
|
|
||||||
b := [5]byte{flag, 0, 0, 0, 0}
|
|
||||||
binary.BigEndian.PutUint32(b[1:], uint32(l))
|
|
||||||
|
|
||||||
if err := w.write(wr, b[:]); err != nil {
|
|
||||||
return errors.Wrap(err, "writing header")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := f(wr); err != nil {
|
|
||||||
return errors.Wrap(err, "write contents")
|
|
||||||
}
|
|
||||||
if err := w.write(w.bufw, w.crc32.Sum(nil)); err != nil {
|
|
||||||
return errors.Wrap(err, "writing checksum")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *indexWriter) writeMeta() error {
|
func (w *indexWriter) writeMeta() error {
|
||||||
b := [8]byte{}
|
b := [5]byte{}
|
||||||
|
|
||||||
binary.BigEndian.PutUint32(b[:4], MagicIndex)
|
binary.BigEndian.PutUint32(b[:4], MagicIndex)
|
||||||
b[4] = flagStd
|
b[4] = flagStd
|
||||||
|
|
||||||
return w.write(w.bufw, b[:])
|
return w.write(b[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *indexWriter) AddSeries(ref uint32, lset labels.Labels, chunks ...*ChunkMeta) error {
|
func (w *indexWriter) AddSeries(ref uint32, lset labels.Labels, chunks ...*ChunkMeta) error {
|
||||||
|
@ -181,24 +162,36 @@ func (w *indexWriter) writeSymbols() error {
|
||||||
}
|
}
|
||||||
sort.Strings(symbols)
|
sort.Strings(symbols)
|
||||||
|
|
||||||
// The start of the section plus a 5 byte section header are our base.
|
buf := make([]byte, 8)
|
||||||
// TODO(fabxc): switch to relative offsets and hold sections in a TOC.
|
|
||||||
base := uint32(w.n) + 5
|
|
||||||
|
|
||||||
buf := [binary.MaxVarintLen32]byte{}
|
// 8 byte header of symbol count and serialization length.
|
||||||
w.b = append(w.b[:0], flagStd)
|
binary.BigEndian.PutUint32(buf[:4], uint32(len(symbols)))
|
||||||
|
|
||||||
|
w.b = w.b[:0]
|
||||||
|
w.b = append(w.b, buf...)
|
||||||
|
|
||||||
for _, s := range symbols {
|
for _, s := range symbols {
|
||||||
w.symbols[s] = base + uint32(len(w.b))
|
w.symbols[s] = uint32(w.pos + len(w.b))
|
||||||
|
|
||||||
n := binary.PutUvarint(buf[:], uint64(len(s)))
|
n := binary.PutUvarint(buf, uint64(len(s)))
|
||||||
w.b = append(w.b, buf[:n]...)
|
w.b = append(w.b, buf[:n]...)
|
||||||
w.b = append(w.b, s...)
|
w.b = append(w.b, s...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.section(len(w.b), flagStd, func(wr io.Writer) error {
|
binary.BigEndian.PutUint32(buf[:4], uint32(len(w.b))-8)
|
||||||
return w.write(wr, w.b)
|
copy(w.b[4:], buf[:4])
|
||||||
})
|
|
||||||
|
w.crc32.Reset()
|
||||||
|
// Write checksum over contents excluding the 8 byte header.
|
||||||
|
if _, err := w.crc32.Write(w.b[8:]); err != nil {
|
||||||
|
return errors.Wrap(err, "calculate symbols CRC32 checksum")
|
||||||
|
}
|
||||||
|
w.b = w.crc32.Sum(w.b)
|
||||||
|
|
||||||
|
if err := w.write(w.b); err != nil {
|
||||||
|
return errors.Wrap(err, "write symbols")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type indexWriterSeriesSlice []*indexWriterSeries
|
type indexWriterSeriesSlice []*indexWriterSeries
|
||||||
|
@ -219,17 +212,16 @@ func (w *indexWriter) writeSeries() error {
|
||||||
}
|
}
|
||||||
sort.Sort(series)
|
sort.Sort(series)
|
||||||
|
|
||||||
// Current end of file plus 5 bytes for section header.
|
|
||||||
// TODO(fabxc): switch to relative offsets.
|
|
||||||
base := uint32(w.n) + 5
|
|
||||||
|
|
||||||
w.b = w.b[:0]
|
|
||||||
buf := make([]byte, binary.MaxVarintLen64)
|
buf := make([]byte, binary.MaxVarintLen64)
|
||||||
|
|
||||||
|
// Header holds number of series.
|
||||||
|
binary.BigEndian.PutUint32(buf, uint32(len(series)))
|
||||||
|
if err := w.write(buf[:4]); err != nil {
|
||||||
|
return errors.Wrap(err, "write series count")
|
||||||
|
}
|
||||||
|
|
||||||
for _, s := range series {
|
for _, s := range series {
|
||||||
// Write label set symbol references.
|
w.b = w.b[:0]
|
||||||
start := len(w.b)
|
|
||||||
s.offset = base + uint32(start)
|
|
||||||
|
|
||||||
n := binary.PutUvarint(buf, uint64(len(s.labels)))
|
n := binary.PutUvarint(buf, uint64(len(s.labels)))
|
||||||
w.b = append(w.b, buf[:n]...)
|
w.b = append(w.b, buf[:n]...)
|
||||||
|
@ -253,28 +245,33 @@ func (w *indexWriter) writeSeries() error {
|
||||||
|
|
||||||
n = binary.PutUvarint(buf, uint64(c.Ref))
|
n = binary.PutUvarint(buf, uint64(c.Ref))
|
||||||
w.b = append(w.b, buf[:n]...)
|
w.b = append(w.b, buf[:n]...)
|
||||||
}
|
|
||||||
|
|
||||||
// Write checksum over series index entry and all its chunk data.
|
|
||||||
w.crc32.Reset()
|
w.crc32.Reset()
|
||||||
w.crc32.Write(w.b[start:])
|
if err := c.hash(w.crc32); err != nil {
|
||||||
|
return errors.Wrap(err, "calculate chunk CRC32")
|
||||||
for _, c := range s.chunks {
|
|
||||||
fmt.Println(c)
|
|
||||||
if _, err := w.crc32.Write([]byte{byte(c.Chunk.Encoding())}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if _, err := w.crc32.Write(c.Chunk.Bytes()); err != nil {
|
w.b = w.crc32.Sum(w.b)
|
||||||
return err
|
}
|
||||||
|
|
||||||
|
s.offset = uint32(w.pos)
|
||||||
|
|
||||||
|
n = binary.PutUvarint(buf, uint64(len(w.b)))
|
||||||
|
if err := w.write(buf[:n]); err != nil {
|
||||||
|
return errors.Wrap(err, "write series data size")
|
||||||
|
}
|
||||||
|
|
||||||
|
w.crc32.Reset()
|
||||||
|
if _, err := w.crc32.Write(w.b); err != nil {
|
||||||
|
return errors.Wrap(err, "calculate series CRC32")
|
||||||
|
}
|
||||||
|
w.b = w.crc32.Sum(w.b)
|
||||||
|
|
||||||
|
if err := w.write(w.b); err != nil {
|
||||||
|
return errors.Wrap(err, "write series data")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.b = append(w.b, w.crc32.Sum(nil)...)
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
return w.section(len(w.b), flagStd, func(wr io.Writer) error {
|
|
||||||
return w.write(wr, w.b)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *indexWriter) init() error {
|
func (w *indexWriter) init() error {
|
||||||
|
@ -304,7 +301,7 @@ func (w *indexWriter) WriteLabelIndex(names []string, values []string) error {
|
||||||
|
|
||||||
w.labelIndexes = append(w.labelIndexes, hashEntry{
|
w.labelIndexes = append(w.labelIndexes, hashEntry{
|
||||||
name: strings.Join(names, string(sep)),
|
name: strings.Join(names, string(sep)),
|
||||||
offset: uint32(w.n),
|
offset: uint32(w.pos),
|
||||||
})
|
})
|
||||||
|
|
||||||
buf := make([]byte, binary.MaxVarintLen32)
|
buf := make([]byte, binary.MaxVarintLen32)
|
||||||
|
@ -312,21 +309,23 @@ func (w *indexWriter) WriteLabelIndex(names []string, values []string) error {
|
||||||
|
|
||||||
l := n + len(values)*4
|
l := n + len(values)*4
|
||||||
|
|
||||||
return w.section(l, flagStd, func(wr io.Writer) error {
|
w.b = append(w.b[:0], flagStd, 0, 0, 0, 0)
|
||||||
// First byte indicates tuple size for index.
|
binary.BigEndian.PutUint32(w.b[1:], uint32(l))
|
||||||
if err := w.write(wr, buf[:n]); err != nil {
|
|
||||||
return err
|
w.b = append(w.b, buf[:n]...)
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range valt.s {
|
for _, v := range valt.s {
|
||||||
binary.BigEndian.PutUint32(buf, w.symbols[v])
|
binary.BigEndian.PutUint32(buf, w.symbols[v])
|
||||||
|
w.b = append(w.b, buf[:4]...)
|
||||||
|
}
|
||||||
|
|
||||||
if err := w.write(wr, buf[:4]); err != nil {
|
w.crc32.Reset()
|
||||||
return err
|
if _, err := w.crc32.Write(w.b[5:]); err != nil {
|
||||||
|
return errors.Wrap(err, "calculate label index CRC32 checksum")
|
||||||
}
|
}
|
||||||
}
|
w.b = w.crc32.Sum(w.b)
|
||||||
return nil
|
|
||||||
})
|
return w.write(w.b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *indexWriter) WritePostings(name, value string, it Postings) error {
|
func (w *indexWriter) WritePostings(name, value string, it Postings) error {
|
||||||
|
@ -340,7 +339,7 @@ func (w *indexWriter) WritePostings(name, value string, it Postings) error {
|
||||||
|
|
||||||
w.postings = append(w.postings, hashEntry{
|
w.postings = append(w.postings, hashEntry{
|
||||||
name: key,
|
name: key,
|
||||||
offset: uint32(w.n),
|
offset: uint32(w.pos),
|
||||||
})
|
})
|
||||||
|
|
||||||
// Order of the references in the postings list does not imply order
|
// Order of the references in the postings list does not imply order
|
||||||
|
@ -361,7 +360,7 @@ func (w *indexWriter) WritePostings(name, value string, it Postings) error {
|
||||||
|
|
||||||
sort.Sort(uint32slice(refs))
|
sort.Sort(uint32slice(refs))
|
||||||
|
|
||||||
w.b = w.b[:0]
|
w.b = append(w.b[:0], flagStd, 0, 0, 0, 0)
|
||||||
buf := make([]byte, 4)
|
buf := make([]byte, 4)
|
||||||
|
|
||||||
for _, r := range refs {
|
for _, r := range refs {
|
||||||
|
@ -371,9 +370,15 @@ func (w *indexWriter) WritePostings(name, value string, it Postings) error {
|
||||||
|
|
||||||
w.uint32s = refs[:0]
|
w.uint32s = refs[:0]
|
||||||
|
|
||||||
return w.section(len(w.b), flagStd, func(wr io.Writer) error {
|
binary.BigEndian.PutUint32(w.b[1:], uint32(len(w.b)-5))
|
||||||
return w.write(wr, w.b)
|
|
||||||
})
|
w.crc32.Reset()
|
||||||
|
if _, err := w.crc32.Write(w.b[5:]); err != nil {
|
||||||
|
return errors.Wrap(err, "calculate label index CRC32 checksum")
|
||||||
|
}
|
||||||
|
w.b = w.crc32.Sum(w.b)
|
||||||
|
|
||||||
|
return w.write(w.b)
|
||||||
}
|
}
|
||||||
|
|
||||||
type uint32slice []uint32
|
type uint32slice []uint32
|
||||||
|
@ -388,7 +393,7 @@ type hashEntry struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *indexWriter) writeHashmap(h []hashEntry) error {
|
func (w *indexWriter) writeHashmap(h []hashEntry) error {
|
||||||
w.b = w.b[:0]
|
w.b = append(w.b[:0], flagStd, 0, 0, 0, 0)
|
||||||
buf := [binary.MaxVarintLen32]byte{}
|
buf := [binary.MaxVarintLen32]byte{}
|
||||||
|
|
||||||
for _, e := range h {
|
for _, e := range h {
|
||||||
|
@ -400,19 +405,25 @@ func (w *indexWriter) writeHashmap(h []hashEntry) error {
|
||||||
w.b = append(w.b, buf[:n]...)
|
w.b = append(w.b, buf[:n]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.section(len(w.b), flagStd, func(wr io.Writer) error {
|
binary.BigEndian.PutUint32(w.b[1:], uint32(len(w.b)-5))
|
||||||
return w.write(wr, w.b)
|
|
||||||
})
|
w.crc32.Reset()
|
||||||
|
if _, err := w.crc32.Write(w.b[5:]); err != nil {
|
||||||
|
return errors.Wrap(err, "calculate label index CRC32 checksum")
|
||||||
|
}
|
||||||
|
w.b = w.crc32.Sum(w.b)
|
||||||
|
|
||||||
|
return w.write(w.b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *indexWriter) finalize() error {
|
func (w *indexWriter) finalize() error {
|
||||||
// Write out hash maps to jump to correct label index and postings sections.
|
// Write out hash maps to jump to correct label index and postings sections.
|
||||||
lo := uint32(w.n)
|
lo := uint32(w.pos)
|
||||||
if err := w.writeHashmap(w.labelIndexes); err != nil {
|
if err := w.writeHashmap(w.labelIndexes); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
po := uint32(w.n)
|
po := uint32(w.pos)
|
||||||
if err := w.writeHashmap(w.postings); err != nil {
|
if err := w.writeHashmap(w.postings); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -425,14 +436,14 @@ func (w *indexWriter) finalize() error {
|
||||||
binary.BigEndian.PutUint32(b[:4], lo)
|
binary.BigEndian.PutUint32(b[:4], lo)
|
||||||
binary.BigEndian.PutUint32(b[4:], po)
|
binary.BigEndian.PutUint32(b[4:], po)
|
||||||
|
|
||||||
return w.write(w.bufw, b[:])
|
return w.write(b[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *indexWriter) Close() error {
|
func (w *indexWriter) Close() error {
|
||||||
if err := w.finalize(); err != nil {
|
if err := w.finalize(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := w.bufw.Flush(); err != nil {
|
if err := w.fbuf.Flush(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := fileutil.Fsync(w.f); err != nil {
|
if err := fileutil.Fsync(w.f); err != nil {
|
||||||
|
@ -588,7 +599,7 @@ func (r *indexReader) lookupSymbol(o uint32) (string, error) {
|
||||||
|
|
||||||
end := int(o) + n + int(l)
|
end := int(o) + n + int(l)
|
||||||
if end > len(r.b) {
|
if end > len(r.b) {
|
||||||
return "", errors.New("invalid length")
|
return "", errors.Errorf("invalid length %d", l)
|
||||||
}
|
}
|
||||||
b := r.b[int(o)+n : end]
|
b := r.b[int(o)+n : end]
|
||||||
|
|
||||||
|
@ -640,12 +651,16 @@ func (r *indexReader) LabelIndices() ([][]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexReader) Series(ref uint32) (labels.Labels, []*ChunkMeta, error) {
|
func (r *indexReader) Series(ref uint32) (labels.Labels, []*ChunkMeta, error) {
|
||||||
k, n := binary.Uvarint(r.b[ref:])
|
// Read away length of series data.
|
||||||
|
_, n := binary.Uvarint(r.b[ref:])
|
||||||
|
b := r.b[int(ref)+n:]
|
||||||
|
|
||||||
|
k, n := binary.Uvarint(b)
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
return nil, nil, errors.Wrap(errInvalidSize, "number of labels")
|
return nil, nil, errors.Wrap(errInvalidSize, "number of labels")
|
||||||
}
|
}
|
||||||
|
|
||||||
b := r.b[int(ref)+n:]
|
b = b[n:]
|
||||||
lbls := make(labels.Labels, 0, k)
|
lbls := make(labels.Labels, 0, k)
|
||||||
|
|
||||||
for i := 0; i < 2*int(k); i += 2 {
|
for i := 0; i < 2*int(k); i += 2 {
|
||||||
|
@ -703,6 +718,9 @@ func (r *indexReader) Series(ref uint32) (labels.Labels, []*ChunkMeta, error) {
|
||||||
}
|
}
|
||||||
b = b[n:]
|
b = b[n:]
|
||||||
|
|
||||||
|
// TODO(fabxc): read and potentially verify checksum.
|
||||||
|
b = b[4:]
|
||||||
|
|
||||||
chunks = append(chunks, &ChunkMeta{
|
chunks = append(chunks, &ChunkMeta{
|
||||||
Ref: o,
|
Ref: o,
|
||||||
MinTime: firstTime,
|
MinTime: firstTime,
|
||||||
|
@ -710,6 +728,8 @@ func (r *indexReader) Series(ref uint32) (labels.Labels, []*ChunkMeta, error) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(fabxc): read and potentially verify checksum.
|
||||||
|
|
||||||
return lbls, chunks, nil
|
return lbls, chunks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,6 +754,7 @@ func (r *indexReader) Postings(name, value string) (Postings, error) {
|
||||||
if len(b)%4 != 0 {
|
if len(b)%4 != 0 {
|
||||||
return nil, errors.Wrap(errInvalidSize, "plain postings entry")
|
return nil, errors.Wrap(errInvalidSize, "plain postings entry")
|
||||||
}
|
}
|
||||||
|
|
||||||
return newBigEndianPostings(b), nil
|
return newBigEndianPostings(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue