xor encoding is fast enough for our purposes and provides very good compression. We remove all other ones that partially don't support floats for the sake of simplicity.pull/5805/head
parent
e67cf768dc
commit
fa181a34c1
@ -1,192 +0,0 @@ |
||||
package chunks |
||||
|
||||
import ( |
||||
"encoding/binary" |
||||
"errors" |
||||
"io" |
||||
"math" |
||||
|
||||
"github.com/prometheus/common/model" |
||||
) |
||||
|
||||
// DoubleDeltaChunk stores delta-delta encoded sample data.
|
||||
type DoubleDeltaChunk struct { |
||||
rawChunk |
||||
} |
||||
|
||||
// NewDoubleDeltaChunk returns a new chunk using double delta encoding.
|
||||
func NewDoubleDeltaChunk(sz int) *DoubleDeltaChunk { |
||||
return &DoubleDeltaChunk{rawChunk: newRawChunk(sz, EncDoubleDelta)} |
||||
} |
||||
|
||||
// Iterator implements the Chunk interface.
|
||||
func (c *DoubleDeltaChunk) Iterator() Iterator { |
||||
return &doubleDeltaIterator{d: c.d[1:c.l]} |
||||
} |
||||
|
||||
// Appender implements the Chunk interface.
|
||||
func (c *DoubleDeltaChunk) Appender() Appender { |
||||
return &doubleDeltaAppender{c: &c.rawChunk} |
||||
} |
||||
|
||||
type doubleDeltaIterator struct { |
||||
d []byte |
||||
|
||||
err error |
||||
pos, num int |
||||
curT, curV int64 |
||||
nextT, nextV int64 |
||||
deltaV int64 |
||||
deltaT uint64 |
||||
} |
||||
|
||||
func (it *doubleDeltaIterator) Err() error { |
||||
return it.err |
||||
} |
||||
|
||||
func (it *doubleDeltaIterator) readPair() bool { |
||||
if len(it.d) == it.pos { |
||||
return false |
||||
} |
||||
var ( |
||||
n, m int |
||||
ddv int64 |
||||
ddt uint64 |
||||
) |
||||
it.curT = it.nextT |
||||
it.curV = it.nextV |
||||
|
||||
if it.num > 1 { |
||||
ddt, n = binary.Uvarint(it.d[it.pos:]) |
||||
ddv, m = binary.Varint(it.d[it.pos+n:]) |
||||
it.deltaT += ddt |
||||
it.deltaV += ddv |
||||
it.nextT += int64(it.deltaT) |
||||
it.nextV += it.deltaV |
||||
} else if it.num == 1 { |
||||
it.deltaT, n = binary.Uvarint(it.d[it.pos:]) |
||||
it.deltaV, m = binary.Varint(it.d[it.pos+n:]) |
||||
it.nextT += int64(it.deltaT) |
||||
it.nextV += it.deltaV |
||||
} else { |
||||
it.nextT, n = binary.Varint(it.d[it.pos:]) |
||||
it.nextV, m = binary.Varint(it.d[it.pos+n:]) |
||||
} |
||||
it.pos += n + m |
||||
it.num++ |
||||
return true |
||||
} |
||||
|
||||
func (it *doubleDeltaIterator) First() (model.SamplePair, bool) { |
||||
it.pos = 0 |
||||
it.num = 0 |
||||
if !it.readPair() { |
||||
it.err = io.EOF |
||||
return model.SamplePair{}, false |
||||
} |
||||
return it.Next() |
||||
} |
||||
|
||||
func (it *doubleDeltaIterator) Seek(ts model.Time) (model.SamplePair, bool) { |
||||
if int64(ts) < it.nextT { |
||||
it.pos = 0 |
||||
it.num = 0 |
||||
if !it.readPair() { |
||||
it.err = io.EOF |
||||
return model.SamplePair{}, false |
||||
} |
||||
if _, ok := it.Next(); !ok { |
||||
return model.SamplePair{}, false |
||||
} |
||||
} |
||||
for { |
||||
if it.nextT > int64(ts) { |
||||
if it.num < 2 { |
||||
it.err = io.EOF |
||||
return model.SamplePair{}, false |
||||
} |
||||
return model.SamplePair{ |
||||
Timestamp: model.Time(it.curT), |
||||
Value: model.SampleValue(it.curV), |
||||
}, true |
||||
} |
||||
if _, ok := it.Next(); !ok { |
||||
return model.SamplePair{}, false |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (it *doubleDeltaIterator) Next() (model.SamplePair, bool) { |
||||
if it.err == io.EOF { |
||||
return model.SamplePair{}, false |
||||
} |
||||
res := model.SamplePair{ |
||||
Timestamp: model.Time(it.nextT), |
||||
Value: model.SampleValue(it.nextV), |
||||
} |
||||
if !it.readPair() { |
||||
it.err = io.EOF |
||||
} |
||||
return res, true |
||||
} |
||||
|
||||
type doubleDeltaAppender struct { |
||||
c *rawChunk |
||||
buf [16]byte |
||||
num int // stored values so far.
|
||||
|
||||
lastV, lastVDelta int64 |
||||
lastT int64 |
||||
lastTDelta uint64 |
||||
} |
||||
|
||||
func isInt(f model.SampleValue) (int64, bool) { |
||||
x, frac := math.Modf(float64(f)) |
||||
if frac != 0 { |
||||
return 0, false |
||||
} |
||||
return int64(x), true |
||||
} |
||||
|
||||
// ErrNoInteger is returned if a non-integer is appended to
|
||||
// a double delta chunk.
|
||||
var ErrNoInteger = errors.New("not an integer") |
||||
|
||||
func (a *doubleDeltaAppender) Append(ts model.Time, fv model.SampleValue) error { |
||||
v, ok := isInt(fv) |
||||
if !ok { |
||||
return ErrNoInteger |
||||
} |
||||
if a.num == 0 { |
||||
n := binary.PutVarint(a.buf[:], int64(ts)) |
||||
n += binary.PutVarint(a.buf[n:], v) |
||||
if err := a.c.append(a.buf[:n]); err != nil { |
||||
return err |
||||
} |
||||
a.lastT, a.lastV = int64(ts), v |
||||
a.num++ |
||||
return nil |
||||
} |
||||
if a.num == 1 { |
||||
a.lastTDelta, a.lastVDelta = uint64(int64(ts)-a.lastT), v-a.lastV |
||||
n := binary.PutUvarint(a.buf[:], a.lastTDelta) |
||||
n += binary.PutVarint(a.buf[n:], a.lastVDelta) |
||||
if err := a.c.append(a.buf[:n]); err != nil { |
||||
return err |
||||
} |
||||
} else { |
||||
predT, predV := a.lastT+int64(a.lastTDelta), a.lastV+a.lastVDelta |
||||
tdd := uint64(int64(ts) - predT) |
||||
vdd := v - predV |
||||
n := binary.PutUvarint(a.buf[:], tdd) |
||||
n += binary.PutVarint(a.buf[n:], vdd) |
||||
if err := a.c.append(a.buf[:n]); err != nil { |
||||
return err |
||||
} |
||||
a.lastTDelta += tdd |
||||
a.lastVDelta += vdd |
||||
} |
||||
a.lastT, a.lastV = int64(ts), v |
||||
a.num++ |
||||
return nil |
||||
} |
||||
@ -1,58 +0,0 @@ |
||||
package chunks |
||||
|
||||
import ( |
||||
"io" |
||||
"math/rand" |
||||
"testing" |
||||
|
||||
"github.com/prometheus/common/model" |
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
func testDoubleDeltaChunk(t *testing.T) { |
||||
ts := model.Time(14345645) |
||||
v := int64(123123) |
||||
|
||||
var input []model.SamplePair |
||||
for i := 0; i < 2000; i++ { |
||||
ts += model.Time(rand.Int63n(100) + 1) |
||||
v += rand.Int63n(1000) |
||||
if rand.Int() > 0 { |
||||
v *= -1 |
||||
} |
||||
|
||||
input = append(input, model.SamplePair{ |
||||
Timestamp: ts, |
||||
Value: model.SampleValue(v), |
||||
}) |
||||
} |
||||
|
||||
c := NewDoubleDeltaChunk(rand.Intn(3000)) |
||||
|
||||
app := c.Appender() |
||||
for i, s := range input { |
||||
err := app.Append(s.Timestamp, s.Value) |
||||
if err == ErrChunkFull { |
||||
input = input[:i] |
||||
break |
||||
} |
||||
require.NoError(t, err, "at sample %d: %v", i, s) |
||||
} |
||||
|
||||
result := []model.SamplePair{} |
||||
|
||||
it := c.Iterator() |
||||
for s, ok := it.First(); ok; s, ok = it.Next() { |
||||
result = append(result, s) |
||||
} |
||||
if it.Err() != io.EOF { |
||||
require.NoError(t, it.Err()) |
||||
} |
||||
require.Equal(t, input, result) |
||||
} |
||||
|
||||
func TestDoubleDeltaChunk(t *testing.T) { |
||||
for i := 0; i < 10000; i++ { |
||||
testDoubleDeltaChunk(t) |
||||
} |
||||
} |
||||
@ -1,61 +0,0 @@ |
||||
package chunks |
||||
|
||||
import ( |
||||
"math/rand" |
||||
"testing" |
||||
|
||||
"github.com/prometheus/common/model" |
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
func testXORChunk(t *testing.T) { |
||||
ts := model.Time(124213233) |
||||
v := int64(99954541) |
||||
|
||||
var input []model.SamplePair |
||||
for i := 0; i < 10000; i++ { |
||||
ts += model.Time(rand.Int63n(50000) + 1) |
||||
v += rand.Int63n(1000) |
||||
if rand.Int() > 0 { |
||||
v *= -1 |
||||
} |
||||
|
||||
input = append(input, model.SamplePair{ |
||||
Timestamp: ts, |
||||
Value: model.SampleValue(v), |
||||
}) |
||||
} |
||||
|
||||
c := NewXORChunk(rand.Intn(3000)) |
||||
|
||||
app := c.Appender() |
||||
for i, s := range input { |
||||
err := app.Append(s.Timestamp, s.Value) |
||||
if err == ErrChunkFull { |
||||
input = input[:i] |
||||
break |
||||
} |
||||
require.NoError(t, err, "at sample %d: %v", i, s) |
||||
} |
||||
|
||||
result := []model.SamplePair{} |
||||
|
||||
it := c.Iterator().(*xorIterator) |
||||
for { |
||||
ok := it.NextB() |
||||
if !ok { |
||||
break |
||||
} |
||||
t, v := it.Values() |
||||
result = append(result, model.SamplePair{Timestamp: model.Time(t), Value: model.SampleValue(v)}) |
||||
} |
||||
|
||||
require.NoError(t, it.Err()) |
||||
require.Equal(t, input, result) |
||||
} |
||||
|
||||
func TestXORChunk(t *testing.T) { |
||||
for i := 0; i < 10; i++ { |
||||
testXORChunk(t) |
||||
} |
||||
} |
||||
Loading…
Reference in new issue