wp
This commit is contained in:
163
enc/cumdelta.go
163
enc/cumdelta.go
@@ -1,6 +1,7 @@
|
||||
package enc
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
|
||||
@@ -47,32 +48,32 @@ type CumulativeDeltaCompressor struct {
|
||||
}
|
||||
|
||||
// Після відновлення із снапшота
|
||||
func NewCumulativeDeltaCompressor(buf []byte, payloadSize int, fracDigits byte) *CumulativeDeltaCompressor {
|
||||
func NewCumulativeDeltaCompressor(buf []byte, fracDigits byte) *CumulativeDeltaCompressor {
|
||||
var coef float64 = 1
|
||||
if fracDigits > 0 {
|
||||
coef = math.Pow(10, float64(fracDigits))
|
||||
}
|
||||
s := &CumulativeDeltaCompressor{
|
||||
return &CumulativeDeltaCompressor{
|
||||
buf: buf,
|
||||
pos: payloadSize, // перший вільний байт
|
||||
coef: coef,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CumulativeDeltaCompressor) RestoreState(payloadSize int) {
|
||||
if payloadSize > 0 {
|
||||
u64, _, err := bin.GetVarUint64(buf)
|
||||
s.pos = payloadSize - 1 // завжди показує на h
|
||||
// base value на початку
|
||||
u64, _, err := bin.GetVarUint64(s.buf)
|
||||
if err != nil {
|
||||
log.Fatalf("bug: get base value: %s", err)
|
||||
}
|
||||
s.baseValue = float64(u64) / s.coef
|
||||
s.pos--
|
||||
s.h = s.buf[s.pos]
|
||||
var n int
|
||||
s.lastDelta, n, err = bin.ReverseGetVarUint64(s.buf[:s.pos])
|
||||
s.lastDelta, _, err = bin.ReverseGetVarUint64(s.buf[:s.pos-1])
|
||||
if err != nil {
|
||||
log.Fatalf("bug: get last delta: %s", err)
|
||||
}
|
||||
s.pos -= n
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// func (s *CumulativeDeltaCompressor) Size() int {
|
||||
@@ -80,83 +81,73 @@ func NewCumulativeDeltaCompressor(buf []byte, payloadSize int, fracDigits byte)
|
||||
// }
|
||||
|
||||
func (s *CumulativeDeltaCompressor) Evaluate(value float64) (compressionWay int, requiredSpace int) {
|
||||
var (
|
||||
delta = uint64((value-s.baseValue)*s.coef + eps)
|
||||
)
|
||||
delta := uint64((value-s.baseValue)*s.coef + eps) // fix - if delta 0, no eps
|
||||
requiredSpace = s.pos
|
||||
// fix - requiredSpace - all space
|
||||
if s.pos > 0 {
|
||||
if s.h < 128 {
|
||||
// run
|
||||
if delta == s.lastDelta && s.h < 127 {
|
||||
compressionWay = incrementRun
|
||||
requiredSpace += bin.CountVarUint64(uint64(s.lastDelta)) + // current delta
|
||||
hSize
|
||||
} else {
|
||||
compressionWay = endSeries
|
||||
requiredSpace += bin.CountVarUint64(uint64(s.lastDelta)) + // previous delta
|
||||
hSize + // h - end of run
|
||||
bin.CountVarUint64(uint64(delta)) + // new literal
|
||||
hSize // new h
|
||||
requiredSpace += bin.CountVarUint64(uint64(delta)) + hSize
|
||||
}
|
||||
} else {
|
||||
// literal
|
||||
if delta != s.lastDelta {
|
||||
if s.h < 255 {
|
||||
compressionWay = incrementLiteral
|
||||
requiredSpace += bin.CountVarUint64(uint64(s.lastDelta)) + // previous delta
|
||||
bin.CountVarUint64(uint64(delta)) + // new delta
|
||||
hSize
|
||||
requiredSpace += bin.CountVarUint64(uint64(delta))
|
||||
} else {
|
||||
compressionWay = endSeries
|
||||
requiredSpace += bin.CountVarUint64(uint64(s.lastDelta)) + // previous delta
|
||||
hSize + // h - end of literal
|
||||
bin.CountVarUint64(uint64(delta)) + // new literal
|
||||
hSize // new h
|
||||
requiredSpace += bin.CountVarUint64(uint64(delta)) + hSize
|
||||
}
|
||||
} else {
|
||||
compressionWay = startRun
|
||||
if s.h > 128 {
|
||||
requiredSpace += hSize // h - end of literal
|
||||
requiredSpace += hSize // h - end of run
|
||||
}
|
||||
requiredSpace += bin.CountVarUint64(uint64(delta)) + // new delta
|
||||
hSize // new h
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// encode base value
|
||||
compressionWay = addBaseValue
|
||||
requiredSpace = bin.CountVarUint64(uint64(value*s.coef)) + // base value
|
||||
bin.CountVarUint64(uint64(delta)) + // new delta
|
||||
+hSize // new h
|
||||
bin.CountVarUint64(0) + // new delta
|
||||
hSize // new h
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// pos завжди вказує на h
|
||||
func (s *CumulativeDeltaCompressor) Compress(compressionWay int, value float64) {
|
||||
delta := uint64((value-s.baseValue)*s.coef + eps)
|
||||
switch compressionWay {
|
||||
case incrementRun:
|
||||
s.h++
|
||||
case incrementLiteral:
|
||||
// write previous delta and increment counter
|
||||
n, _ := bin.ReversePutVarUint64(s.buf[s.pos:], uint64(s.lastDelta))
|
||||
s.pos += n
|
||||
s.lastDelta = delta
|
||||
s.h++
|
||||
case endSeries:
|
||||
n, _ := bin.ReversePutVarUint64(s.buf[s.pos:], uint64(s.lastDelta))
|
||||
// write previous delta and increment counter
|
||||
n, _ := bin.ReversePutVarUint64(s.buf[s.pos:], delta)
|
||||
s.pos += n
|
||||
// write h - end of run
|
||||
s.buf[s.pos] = s.h
|
||||
s.pos++
|
||||
// start new literal (length=1)
|
||||
case endSeries:
|
||||
s.lastDelta = delta
|
||||
s.h = 128
|
||||
n, _ := bin.ReversePutVarUint64(s.buf[s.pos:], delta)
|
||||
s.pos += n
|
||||
s.h = 128 // start new literal (length=1)
|
||||
case startRun:
|
||||
if s.h > 128 {
|
||||
// write h - end of literal (because length > 1)
|
||||
s.pos -= 1 + bin.CountVarUint64(s.lastDelta)
|
||||
s.h--
|
||||
s.buf[s.pos] = s.h
|
||||
s.pos++
|
||||
// run delta
|
||||
n, _ := bin.ReversePutVarUint64(s.buf[s.pos:], delta)
|
||||
s.pos += n
|
||||
} else {
|
||||
}
|
||||
// start new run (length=2)
|
||||
s.h = 0
|
||||
@@ -165,10 +156,14 @@ func (s *CumulativeDeltaCompressor) Compress(compressionWay int, value float64)
|
||||
n, _ := bin.PutVarUint64(s.buf[s.pos:], uint64(value*s.coef))
|
||||
s.pos += n
|
||||
s.baseValue = value
|
||||
// start new literal (length=1)
|
||||
|
||||
s.lastDelta = 0
|
||||
n, _ = bin.ReversePutVarUint64(s.buf[s.pos:], s.lastDelta)
|
||||
s.pos += n
|
||||
// start new literal (length=1)
|
||||
s.h = 128
|
||||
}
|
||||
s.buf[s.pos] = s.h
|
||||
}
|
||||
|
||||
func (s *CumulativeDeltaCompressor) DeleteLast() {
|
||||
@@ -186,10 +181,11 @@ func (s *CumulativeDeltaCompressor) CaptureState() {
|
||||
qb.Abort(qb.RepeatableLock, nil)
|
||||
}
|
||||
// позиція посувається вліво, отже може перескочити на попередній chunk
|
||||
pos := s.pos - hSize - bin.CountVarUint64(s.lastDelta)
|
||||
s.state = &CumulativeDeltaCapturedState{
|
||||
H: s.h,
|
||||
LastDelta: s.lastDelta,
|
||||
Payload: s.buf[:s.pos],
|
||||
Payload: s.buf[:pos],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,31 +201,65 @@ func (s *CumulativeDeltaCompressor) Offset() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Snapshot - для створення снапшота.
|
||||
func (s *CumulativeDeltaCompressor) Snapshot() (left []byte, right []byte) {
|
||||
func (s *CumulativeDeltaCompressor) Size() int {
|
||||
if s.state == nil {
|
||||
left = s.buf[:s.pos]
|
||||
right = s.encodeTail(s.lastDelta, s.h)
|
||||
return s.pos
|
||||
} else {
|
||||
left = s.state.Payload
|
||||
right = s.encodeTail(s.state.LastDelta, s.state.H)
|
||||
return len(s.state.Payload)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *CumulativeDeltaCompressor) encodeTail(lastDelta uint64, h byte) []byte {
|
||||
tail := make([]byte, 10) // max var uint64 + h
|
||||
n, _ := bin.PutVarUint64(tail, lastDelta)
|
||||
tail[n] = h
|
||||
return tail[:n+1]
|
||||
// Snapshot - для створення снапшота.
|
||||
func (s *CumulativeDeltaCompressor) Payload() []byte {
|
||||
if s.state == nil {
|
||||
return s.buf[:s.pos]
|
||||
} else {
|
||||
return s.state.Payload
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CumulativeDeltaCompressor) Rotate(newbuf []byte) (payloadSize int) {
|
||||
n, _ := bin.PutVarUint64(s.buf[s.pos:], s.lastDelta)
|
||||
s.pos += n
|
||||
s.buf[s.pos] = s.h
|
||||
s.pos++
|
||||
payloadSize = s.pos
|
||||
func (s *CumulativeDeltaCompressor) WritePayloadTo(w io.Writer) (err error) {
|
||||
if s.state == nil {
|
||||
err = bin.WriteUint16(w, uint16(s.pos))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = w.Write(s.buf[:s.pos])
|
||||
return
|
||||
} else {
|
||||
size := bin.CountVarUint64(s.state.LastDelta) + hSize + len(s.state.Payload)
|
||||
err = bin.WriteUint16(w, uint16(size))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = w.Write(s.state.Payload)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = bin.WriteVarUint64(w, s.state.LastDelta)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
w.Write([]byte{
|
||||
s.state.H,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// func (s *CumulativeDeltaCompressor) encodeTail(lastDelta uint64, h byte) []byte {
|
||||
// tail := make([]byte, 10) // max var uint64 + h
|
||||
// n, _ := bin.PutVarUint64(tail, lastDelta)
|
||||
// tail[n] = h
|
||||
// return tail[:n+1]
|
||||
// }
|
||||
|
||||
func (s *CumulativeDeltaCompressor) Rotate(newbuf []byte) {
|
||||
// n, _ := bin.PutVarUint64(s.buf[s.pos:], s.lastDelta)
|
||||
// s.pos += n
|
||||
// s.buf[s.pos] = s.h
|
||||
// s.pos++
|
||||
// payloadSize = s.pos
|
||||
// УВАГА!
|
||||
// state не чіпаємо
|
||||
s.buf = newbuf
|
||||
@@ -237,7 +267,14 @@ func (s *CumulativeDeltaCompressor) Rotate(newbuf []byte) (payloadSize int) {
|
||||
s.baseValue = 0
|
||||
s.lastDelta = 0
|
||||
s.h = 0
|
||||
return
|
||||
}
|
||||
|
||||
func (s *CumulativeDeltaCompressor) LastValue() float64 {
|
||||
if s.state == nil {
|
||||
return s.baseValue + float64(s.lastDelta)*s.coef
|
||||
} else {
|
||||
return s.baseValue + float64(s.state.LastDelta)*s.coef
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CumulativeDeltaCompressor) CreateDecompressor() qb.ValueDecompressor {
|
||||
@@ -259,10 +296,6 @@ func (s *CumulativeDeltaCompressor) CreateDecompressor() qb.ValueDecompressor {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *CumulativeDeltaCompressor) Chunks() []byte {
|
||||
return s.buf
|
||||
}
|
||||
|
||||
// DECOMPRESSOR
|
||||
|
||||
type CumulativeDeltaDecompressor struct {
|
||||
|
||||
@@ -165,11 +165,10 @@ func TestCumulativeDeltaCompressor(t *testing.T) {
|
||||
var (
|
||||
fracDigits byte = 1
|
||||
buf = make([]byte, 8)
|
||||
payloadSize = 0
|
||||
compressionWay int
|
||||
requiredSpace int
|
||||
)
|
||||
c := NewCumulativeDeltaCompressor(buf, payloadSize, fracDigits)
|
||||
c := NewCumulativeDeltaCompressor(buf, fracDigits)
|
||||
for _, num := range testCase.Nums {
|
||||
compressionWay, requiredSpace = c.Evaluate(num)
|
||||
c.Compress(compressionWay, num)
|
||||
@@ -282,10 +281,9 @@ func TestCumulativeDeltaDecompressorFromState(t *testing.T) {
|
||||
var (
|
||||
fracDigits byte = 1
|
||||
buf = make([]byte, 16)
|
||||
payloadSize = 0
|
||||
decodedNums []float64
|
||||
)
|
||||
c := NewCumulativeDeltaCompressor(buf, payloadSize, fracDigits)
|
||||
c := NewCumulativeDeltaCompressor(buf, fracDigits)
|
||||
for _, num := range testCase.Nums {
|
||||
compressionWay, _ := c.Evaluate(num)
|
||||
c.Compress(compressionWay, num)
|
||||
@@ -526,11 +524,10 @@ func TestInstantDeltaCompressor(t *testing.T) {
|
||||
var (
|
||||
fracDigits byte = 1
|
||||
buf = make([]byte, 8)
|
||||
payloadSize = 0
|
||||
compressionWay int
|
||||
requiredSpace int
|
||||
)
|
||||
c := NewInstantDeltaCompressor(buf, payloadSize, fracDigits)
|
||||
c := NewInstantDeltaCompressor(buf, fracDigits)
|
||||
for _, num := range testCase.Nums {
|
||||
compressionWay, requiredSpace = c.Evaluate(num)
|
||||
c.Compress(compressionWay, num)
|
||||
@@ -643,10 +640,9 @@ func TestInstantDeltaDecompressorFromState(t *testing.T) {
|
||||
var (
|
||||
fracDigits byte = 1
|
||||
buf = make([]byte, 16)
|
||||
payloadSize = 0
|
||||
decodedNums []float64
|
||||
)
|
||||
c := NewInstantDeltaCompressor(buf, payloadSize, fracDigits)
|
||||
c := NewInstantDeltaCompressor(buf, fracDigits)
|
||||
for _, num := range testCase.Nums {
|
||||
compressionWay, _ := c.Evaluate(num)
|
||||
c.Compress(compressionWay, num)
|
||||
@@ -847,7 +843,7 @@ func TestTimeDeltaCompressor(t *testing.T) {
|
||||
compressionWay int
|
||||
requiredSpace int
|
||||
)
|
||||
c := NewTimeDeltaCompressor(buf, 0)
|
||||
c := NewTimeDeltaCompressor(buf)
|
||||
for _, num := range testCase.Nums {
|
||||
compressionWay, requiredSpace = c.Evaluate(num)
|
||||
c.Compress(compressionWay, num)
|
||||
@@ -963,7 +959,7 @@ func TestTimeDeltaDecompressorFromState(t *testing.T) {
|
||||
buf = make([]byte, 16)
|
||||
decodedNums []uint32
|
||||
)
|
||||
c := NewTimeDeltaCompressor(buf, 0)
|
||||
c := NewTimeDeltaCompressor(buf)
|
||||
for _, num := range testCase.Nums {
|
||||
compressionWay, _ := c.Evaluate(num)
|
||||
c.Compress(compressionWay, num)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package enc
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
|
||||
@@ -18,32 +19,33 @@ type InstantDeltaCompressor struct {
|
||||
state *InstantDeltaCapturedState
|
||||
}
|
||||
|
||||
func NewInstantDeltaCompressor(buf []byte, payloadSize int, fracDigits byte) *InstantDeltaCompressor {
|
||||
func NewInstantDeltaCompressor(buf []byte, fracDigits byte) *InstantDeltaCompressor {
|
||||
var coef float64 = 1
|
||||
if fracDigits > 0 {
|
||||
coef = math.Pow(10, float64(fracDigits))
|
||||
}
|
||||
s := &InstantDeltaCompressor{
|
||||
buf: buf,
|
||||
pos: payloadSize,
|
||||
coef: coef,
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *InstantDeltaCompressor) RestoreState(payloadSize int) {
|
||||
if payloadSize > 0 {
|
||||
u64, _, err := bin.GetVarInt64(buf)
|
||||
s.pos = payloadSize - 1 // завжди показує на h
|
||||
// base value на початку
|
||||
u64, _, err := bin.GetVarUint64(s.buf)
|
||||
if err != nil {
|
||||
log.Fatalf("bug: get base value: %s", err)
|
||||
}
|
||||
s.baseValue = float64(u64) / s.coef
|
||||
s.pos--
|
||||
s.h = s.buf[s.pos]
|
||||
var n int
|
||||
s.lastDelta, n, err = bin.ReverseGetVarInt64(s.buf[:s.pos])
|
||||
s.lastDelta, _, err = bin.ReverseGetVarInt64(s.buf[:s.pos-1])
|
||||
if err != nil {
|
||||
log.Fatalf("bug: get last delta: %s", err)
|
||||
}
|
||||
s.pos -= n
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// func (s *InstantDeltaCompressor) Size() int {
|
||||
@@ -184,31 +186,60 @@ func (s *InstantDeltaCompressor) Offset() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Snapshot - для створення снапшота.
|
||||
func (s *InstantDeltaCompressor) Snapshot() (left []byte, right []byte) {
|
||||
func (s *InstantDeltaCompressor) Size() int {
|
||||
if s.state == nil {
|
||||
left = s.buf[:s.pos]
|
||||
right = s.encodeTail(s.lastDelta, s.h)
|
||||
return s.pos
|
||||
} else {
|
||||
left = s.state.Payload
|
||||
right = s.encodeTail(s.state.LastDelta, s.state.H)
|
||||
return len(s.state.Payload)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *InstantDeltaCompressor) encodeTail(lastDelta int64, h byte) []byte {
|
||||
tail := make([]byte, 10) // max var uint64 + h
|
||||
n, _ := bin.PutVarInt64(tail, lastDelta)
|
||||
tail[n] = h
|
||||
return tail[:n+1]
|
||||
// Snapshot - для створення снапшота.
|
||||
func (s *InstantDeltaCompressor) Payload() []byte {
|
||||
if s.state == nil {
|
||||
return s.buf[:s.pos]
|
||||
} else {
|
||||
return s.state.Payload
|
||||
}
|
||||
}
|
||||
|
||||
func (s *InstantDeltaCompressor) Rotate(newbuf []byte) (payloadSize int) {
|
||||
n, _ := bin.PutVarInt64(s.buf[s.pos:], s.lastDelta)
|
||||
s.pos += n
|
||||
s.buf[s.pos] = s.h
|
||||
s.pos++
|
||||
payloadSize = s.pos
|
||||
func (s *InstantDeltaCompressor) WritePayloadTo(w io.Writer) (err error) {
|
||||
if s.state == nil {
|
||||
err = bin.WriteUint16(w, uint16(s.pos))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = w.Write(s.buf[:s.pos])
|
||||
return
|
||||
} else {
|
||||
size := bin.CountVarInt64(s.state.LastDelta) + hSize + len(s.state.Payload)
|
||||
err = bin.WriteUint16(w, uint16(size))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = w.Write(s.state.Payload)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = bin.WriteVarInt64(w, s.state.LastDelta)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
w.Write([]byte{
|
||||
s.state.H,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// func (s *InstantDeltaCompressor) encodeTail(lastDelta int64, h byte) []byte {
|
||||
// tail := make([]byte, 10) // max var uint64 + h
|
||||
// n, _ := bin.PutVarInt64(tail, lastDelta)
|
||||
// tail[n] = h
|
||||
// return tail[:n+1]
|
||||
// }
|
||||
|
||||
func (s *InstantDeltaCompressor) Rotate(newbuf []byte) {
|
||||
// УВАГА!
|
||||
// state не чіпаємо
|
||||
s.buf = newbuf
|
||||
@@ -216,7 +247,14 @@ func (s *InstantDeltaCompressor) Rotate(newbuf []byte) (payloadSize int) {
|
||||
s.baseValue = 0
|
||||
s.lastDelta = 0
|
||||
s.h = 0
|
||||
return
|
||||
}
|
||||
|
||||
func (s *InstantDeltaCompressor) LastValue() float64 {
|
||||
if s.state == nil {
|
||||
return s.baseValue + float64(s.lastDelta)*s.coef
|
||||
} else {
|
||||
return s.baseValue + float64(s.state.LastDelta)*s.coef
|
||||
}
|
||||
}
|
||||
|
||||
func (s *InstantDeltaCompressor) CreateDecompressor() qb.ValueDecompressor {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package enc
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
|
||||
bin "gordenko.dev/dima/bin/little"
|
||||
@@ -27,125 +28,125 @@ type TimeDeltaCompressor struct {
|
||||
state *TimeDeltaCapturedState
|
||||
}
|
||||
|
||||
// Кодує значення справа наліво футнкціями TailPut*. Читає значення зліва направо функціями Get*
|
||||
func NewTimeDeltaCompressor(buf []byte, payloadSize int) *TimeDeltaCompressor {
|
||||
s := &TimeDeltaCompressor{
|
||||
// Початкове створення, коли даних немає
|
||||
// Створення після page filled, коли одразу є початкове значення
|
||||
// Відновлення стану із снапшота. LastTimestamp передаю окермо від payload,
|
||||
// а lastDelta і h треба прочитати із payload (якщо є)
|
||||
|
||||
// Кодує значення справа наліво функціями TailPut*. Читає значення зліва направо функціями Get*
|
||||
func NewTimeDeltaCompressor(buf []byte) *TimeDeltaCompressor {
|
||||
return &TimeDeltaCompressor{
|
||||
buf: buf,
|
||||
pos: len(buf) - payloadSize,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TimeDeltaCompressor) RestoreState(payloadSize int, lastTimestamp uint32) {
|
||||
if payloadSize > 0 {
|
||||
var err error
|
||||
s.lastUnixtime, err = bin.GetUint32(s.buf[s.pos:])
|
||||
if err != nil {
|
||||
log.Fatalf("bug: get last unixtime: %s", err)
|
||||
}
|
||||
s.pos += 4
|
||||
if s.pos < len(buf) {
|
||||
s.lastUnixtime = lastTimestamp
|
||||
s.pos = len(s.buf) - payloadSize
|
||||
if payloadSize > 4 {
|
||||
s.h = s.buf[s.pos]
|
||||
s.pos++
|
||||
u64, n, err := bin.GetVarUint64(s.buf[s.pos:])
|
||||
u64, _, err := bin.GetVarUint64(s.buf[s.pos+1:])
|
||||
if err != nil {
|
||||
log.Fatalf("bug: get last delta: %s", err)
|
||||
}
|
||||
s.lastDelta = uint32(u64)
|
||||
s.pos += n
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// func (s *TimeDeltaCompressor) Size() int {
|
||||
// return len(s.buf) - s.pos
|
||||
// }
|
||||
|
||||
// retrun
|
||||
func (s *TimeDeltaCompressor) Evaluate(unixtime uint32) (compressionWay int, requiredSpace int) {
|
||||
requiredSpace = 4 // last unixtime
|
||||
if s.lastUnixtime > 0 {
|
||||
requiredSpace = len(s.buf) - s.pos
|
||||
if requiredSpace > 0 {
|
||||
delta := unixtime - s.lastUnixtime
|
||||
if s.lastDelta > 0 {
|
||||
// 3rd value
|
||||
if s.h < 128 {
|
||||
// run
|
||||
if delta == s.lastDelta && s.h < 127 {
|
||||
compressionWay = incrementRun
|
||||
requiredSpace += bin.CountVarUint64(uint64(s.lastDelta)) + // current delta
|
||||
hSize
|
||||
} else {
|
||||
compressionWay = endSeries
|
||||
requiredSpace += bin.CountVarUint64(uint64(s.lastDelta)) + // previous delta
|
||||
hSize + // h - end of run
|
||||
bin.CountVarUint64(uint64(delta)) + // new literal
|
||||
hSize // new h
|
||||
requiredSpace += bin.CountVarUint64(uint64(delta)) + hSize
|
||||
}
|
||||
} else {
|
||||
// literal
|
||||
if delta != s.lastDelta {
|
||||
if s.h < 255 {
|
||||
compressionWay = incrementLiteral
|
||||
requiredSpace += bin.CountVarUint64(uint64(s.lastDelta)) + // previous delta
|
||||
bin.CountVarUint64(uint64(delta)) + // new delta
|
||||
hSize
|
||||
requiredSpace += bin.CountVarUint64(uint64(delta))
|
||||
} else {
|
||||
compressionWay = endSeries
|
||||
requiredSpace += bin.CountVarUint64(uint64(s.lastDelta)) + // previous delta
|
||||
hSize + // h - end of literal
|
||||
bin.CountVarUint64(uint64(delta)) + // new literal
|
||||
hSize // new h
|
||||
requiredSpace += bin.CountVarUint64(uint64(delta)) + hSize
|
||||
}
|
||||
} else {
|
||||
compressionWay = startRun
|
||||
if s.h > 128 {
|
||||
requiredSpace += hSize // h - end of literal
|
||||
requiredSpace += hSize // h - end of run
|
||||
}
|
||||
requiredSpace += bin.CountVarUint64(uint64(delta)) + // new delta
|
||||
hSize // new h
|
||||
}
|
||||
}
|
||||
} else {
|
||||
compressionWay = add1stDelta
|
||||
requiredSpace += bin.CountVarUint64(uint64(delta)) + // new literal
|
||||
hSize // new h
|
||||
requiredSpace += bin.CountVarUint64(uint64(delta)) + hSize
|
||||
}
|
||||
} else {
|
||||
compressionWay = addUnixtime
|
||||
requiredSpace += 4
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// pos вказує на h byte
|
||||
func (s *TimeDeltaCompressor) Compress(compressionWay int, unixtime uint32) {
|
||||
delta := unixtime - s.lastUnixtime
|
||||
switch compressionWay {
|
||||
case incrementRun:
|
||||
s.h++
|
||||
s.buf[s.pos] = s.h
|
||||
case incrementLiteral:
|
||||
// write previous delta and increment counter
|
||||
n, _ := bin.TailPutVarUint64(s.buf[:s.pos], uint64(s.lastDelta))
|
||||
s.pos -= n
|
||||
s.lastDelta = delta
|
||||
s.h++
|
||||
case endSeries:
|
||||
n, _ := bin.TailPutVarUint64(s.buf[:s.pos], uint64(s.lastDelta))
|
||||
// тому що перезаписую h
|
||||
s.pos++
|
||||
n, _ := bin.TailPutVarUint64(s.buf[:s.pos], uint64(delta))
|
||||
s.pos -= n
|
||||
// write h - end of run
|
||||
s.pos--
|
||||
s.buf[s.pos] = s.h
|
||||
case endSeries:
|
||||
// start new literal (length=1)
|
||||
s.lastDelta = delta
|
||||
s.h = 128
|
||||
n, _ := bin.TailPutVarUint64(s.buf[:s.pos], uint64(delta))
|
||||
s.pos -= n
|
||||
s.pos--
|
||||
s.buf[s.pos] = s.h
|
||||
case startRun:
|
||||
if s.h > 128 {
|
||||
// write h - end of literal (because length > 1)
|
||||
s.h--
|
||||
s.pos += bin.CountVarUint64(uint64(s.lastDelta)) // забираю останню дельту у literal
|
||||
s.buf[s.pos] = s.h // write h - end of literal (because length > 1)
|
||||
s.pos--
|
||||
// run delta
|
||||
n, _ := bin.TailPutVarUint64(s.buf[:s.pos], uint64(delta))
|
||||
s.pos -= n
|
||||
// для h
|
||||
s.pos--
|
||||
s.buf[s.pos] = s.h
|
||||
}
|
||||
// start new run (length=2)
|
||||
s.h = 0
|
||||
s.buf[s.pos] = s.h
|
||||
case add1stDelta:
|
||||
// start new literal (length=1)
|
||||
s.lastDelta = delta
|
||||
s.h = 128
|
||||
n, _ := bin.TailPutVarUint64(s.buf[:s.pos], uint64(delta))
|
||||
s.pos -= n
|
||||
s.pos--
|
||||
s.buf[s.pos] = s.h
|
||||
case addUnixtime:
|
||||
s.pos -= 4
|
||||
bin.PutUint32(s.buf[s.pos:], unixtime)
|
||||
}
|
||||
// 1st value or update after every update
|
||||
// do not write immediatelly because of update after every update
|
||||
@@ -184,6 +185,14 @@ func (s *TimeDeltaCompressor) ForgetCapturedState() {
|
||||
s.state = nil
|
||||
}
|
||||
|
||||
// коли сторінка заповнена і відправляється в txlog, since замінюю на until
|
||||
func (s *TimeDeltaCompressor) ReplaceSinceWithUntil() uint32 {
|
||||
pos := len(s.buf) - 4
|
||||
since, _ := bin.GetUint32(s.buf[pos:])
|
||||
bin.PutUint32(s.buf[pos:], s.lastUnixtime)
|
||||
return since
|
||||
}
|
||||
|
||||
// fix
|
||||
func (s *TimeDeltaCompressor) Offset() int {
|
||||
// if s.state != nil {
|
||||
@@ -192,35 +201,64 @@ func (s *TimeDeltaCompressor) Offset() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Snapshot - для створення снапшота.
|
||||
func (s *TimeDeltaCompressor) Snapshot() (left []byte, right []byte) {
|
||||
func (s *TimeDeltaCompressor) Size() int {
|
||||
if s.state == nil {
|
||||
left = s.encodeTail(s.lastUnixtime, s.lastDelta, s.h)
|
||||
right = s.buf[s.pos:]
|
||||
return len(s.buf) - s.pos
|
||||
} else {
|
||||
left = s.encodeTail(s.state.LastUnixtime, s.state.LastDelta, s.state.H)
|
||||
right = s.state.Payload
|
||||
return len(s.state.Payload)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *TimeDeltaCompressor) encodeTail(lastUnixtime, lastDelta uint32, h byte) []byte {
|
||||
tail := make([]byte, 9)
|
||||
bin.PutUint32(tail, lastUnixtime)
|
||||
tail[4] = h
|
||||
n, _ := bin.PutVarUint64(tail[5:], uint64(lastDelta))
|
||||
return tail[:n+5]
|
||||
// Snapshot - для створення снапшота.
|
||||
// FIX - encode firstUnixtime in 1st 4 bytes
|
||||
//
|
||||
// while page not completed - has first unixtime, after - last unixtime
|
||||
func (s *TimeDeltaCompressor) Payload() []byte {
|
||||
if s.state == nil {
|
||||
return s.buf[s.pos:]
|
||||
} else {
|
||||
return s.state.Payload
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TimeDeltaCompressor) Rotate(newbuf []byte) (payloadSize int) {
|
||||
var n int
|
||||
n, _ = bin.TailPutVarUint64(s.buf[:s.pos], uint64(s.lastDelta))
|
||||
s.pos -= n
|
||||
s.pos--
|
||||
s.buf[s.pos] = s.h
|
||||
n, _ = bin.TailPutVarUint64(s.buf[:s.pos], uint64(s.lastUnixtime))
|
||||
s.pos -= n
|
||||
payloadSize = len(s.buf) - s.pos
|
||||
func (s *TimeDeltaCompressor) WritePayloadTo(w io.Writer) (err error) {
|
||||
if s.state == nil {
|
||||
err = bin.WriteUint16(w, uint16(s.pos))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = w.Write(s.buf[:s.pos])
|
||||
return
|
||||
} else {
|
||||
size := bin.CountVarUint64(uint64(s.state.LastDelta)) + hSize + len(s.state.Payload)
|
||||
err = bin.WriteUint16(w, uint16(size))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = w.Write(s.state.Payload)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = bin.WriteVarUint64(w, uint64(s.state.LastDelta))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
w.Write([]byte{
|
||||
s.state.H,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// func (s *TimeDeltaCompressor) encodeTail(lastUnixtime, lastDelta uint32, h byte) []byte {
|
||||
// tail := make([]byte, 9)
|
||||
// bin.PutUint32(tail, lastUnixtime)
|
||||
// tail[4] = h
|
||||
// n, _ := bin.PutVarUint64(tail[5:], uint64(lastDelta))
|
||||
// return tail[:n+5]
|
||||
// }
|
||||
|
||||
func (s *TimeDeltaCompressor) Rotate(newbuf []byte) {
|
||||
// УВАГА!
|
||||
// state не чіпаємо
|
||||
s.buf = newbuf
|
||||
@@ -228,7 +266,6 @@ func (s *TimeDeltaCompressor) Rotate(newbuf []byte) (payloadSize int) {
|
||||
s.lastUnixtime = 0
|
||||
s.lastDelta = 0
|
||||
s.h = 0
|
||||
return
|
||||
}
|
||||
|
||||
func (s *TimeDeltaCompressor) CreateDecompressor() qb.TimestampDecompressor {
|
||||
@@ -252,8 +289,8 @@ func (s *TimeDeltaCompressor) CreateDecompressor() qb.TimestampDecompressor {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *TimeDeltaCompressor) Chunks() []byte {
|
||||
return s.buf
|
||||
func (s *TimeDeltaCompressor) LastTimestamp() uint32 {
|
||||
return s.lastUnixtime
|
||||
}
|
||||
|
||||
// DECOMPRESSOR
|
||||
|
||||
Reference in New Issue
Block a user