2017-04-10 20:59:45 +02:00
// Copyright 2017 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2017-05-03 01:32:09 +02:00
// The code in this file was largely written by Damian Gryski as part of
// https://github.com/dgryski/go-tsz and published under the license below.
2018-04-08 11:28:30 +02:00
// It was modified to accommodate reading from byte slices without modifying
2019-10-10 17:47:30 +08:00
// the underlying bytes, which would panic when reading from mmap'd
2017-05-03 01:32:09 +02:00
// read-only byte slices.
2017-04-28 11:34:35 +02:00
// Copyright (c) 2015,2016 Damian Gryski <damian@gryski.com>
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2017-11-30 15:34:49 +01:00
package chunkenc
2016-11-15 10:33:34 +01:00
import (
2016-11-29 22:02:58 +01:00
"encoding/binary"
2016-11-15 10:33:34 +01:00
"math"
2017-11-08 23:18:33 +01:00
"math/bits"
2016-11-15 10:33:34 +01:00
)
2020-01-24 08:44:52 +01:00
const (
chunkCompactCapacityThreshold = 32
)
2016-11-15 10:33:34 +01:00
// XORChunk holds XOR encoded sample data.
type XORChunk struct {
2019-02-13 22:41:12 +00:00
b bstream
2016-11-15 10:33:34 +01:00
}
// NewXORChunk returns a new chunk with XOR encoding of the given size.
2016-12-31 10:10:27 +01:00
func NewXORChunk ( ) * XORChunk {
2016-12-09 20:45:46 +01:00
b := make ( [ ] byte , 2 , 128 )
2019-02-13 22:41:12 +00:00
return & XORChunk { b : bstream { stream : b , count : 0 } }
2016-11-20 16:14:21 +01:00
}
2017-03-19 21:35:01 +05:30
// Encoding returns the encoding type.
2016-12-09 20:45:46 +01:00
func ( c * XORChunk ) Encoding ( ) Encoding {
return EncXOR
}
2016-11-29 22:02:58 +01:00
// Bytes returns the underlying byte slice of the chunk.
func ( c * XORChunk ) Bytes ( ) [ ] byte {
2017-01-02 10:34:55 +01:00
return c . b . bytes ( )
2016-11-15 10:33:34 +01:00
}
2017-07-12 18:31:26 +02:00
// NumSamples returns the number of samples in the chunk.
func ( c * XORChunk ) NumSamples ( ) int {
return int ( binary . BigEndian . Uint16 ( c . Bytes ( ) ) )
}
2020-01-24 08:44:52 +01:00
func ( c * XORChunk ) Compact ( ) {
if l := len ( c . b . stream ) ; cap ( c . b . stream ) > l + chunkCompactCapacityThreshold {
buf := make ( [ ] byte , l )
copy ( buf , c . b . stream )
c . b . stream = buf
}
}
2016-11-15 10:33:34 +01:00
// Appender implements the Chunk interface.
2016-11-29 22:02:58 +01:00
func ( c * XORChunk ) Appender ( ) ( Appender , error ) {
2019-07-09 15:19:34 +05:30
it := c . iterator ( nil )
2016-11-29 22:02:58 +01:00
// To get an appender we must know the state it would have if we had
// appended all existing data from scratch.
// We iterate through the end and populate via the iterator's state.
for it . Next ( ) {
}
if err := it . Err ( ) ; err != nil {
return nil , err
}
2016-11-30 23:01:01 +01:00
a := & xorAppender {
2019-02-13 22:41:12 +00:00
b : & c . b ,
2016-11-29 22:02:58 +01:00
t : it . t ,
v : it . val ,
tDelta : it . tDelta ,
leading : it . leading ,
trailing : it . trailing ,
2016-11-30 23:01:01 +01:00
}
2017-01-02 10:34:55 +01:00
if binary . BigEndian . Uint16 ( a . b . bytes ( ) ) == 0 {
2016-11-30 23:01:01 +01:00
a . leading = 0xff
}
return a , nil
2016-11-29 22:02:58 +01:00
}
2019-07-09 15:19:34 +05:30
func ( c * XORChunk ) iterator ( it Iterator ) * xorIterator {
2016-11-29 22:02:58 +01:00
// Should iterators guarantee to act on a copy of the data so it doesn't lock append?
// When using striped locks to guard access to chunks, probably yes.
// Could only copy data if the chunk is not completed yet.
2019-07-09 15:19:34 +05:30
if xorIter , ok := it . ( * xorIterator ) ; ok {
xorIter . Reset ( c . b . bytes ( ) )
return xorIter
}
2016-11-29 22:02:58 +01:00
return & xorIterator {
2019-07-09 15:19:34 +05:30
// The first 2 bytes contain chunk headers.
// We skip that for actual samples.
2016-12-09 20:45:46 +01:00
br : newBReader ( c . b . bytes ( ) [ 2 : ] ) ,
2017-01-02 10:34:55 +01:00
numTotal : binary . BigEndian . Uint16 ( c . b . bytes ( ) ) ,
2020-03-24 20:15:47 +00:00
t : math . MinInt64 ,
2016-11-29 22:02:58 +01:00
}
2016-11-15 10:33:34 +01:00
}
// Iterator implements the Chunk interface.
2019-07-09 15:19:34 +05:30
func ( c * XORChunk ) Iterator ( it Iterator ) Iterator {
return c . iterator ( it )
2016-11-15 10:33:34 +01:00
}
type xorAppender struct {
2016-11-29 22:02:58 +01:00
b * bstream
2016-11-15 10:33:34 +01:00
2016-11-20 16:14:21 +01:00
t int64
v float64
tDelta uint64
2016-11-20 14:33:00 +01:00
leading uint8
trailing uint8
2016-11-15 10:33:34 +01:00
}
2016-12-31 10:10:27 +01:00
func ( a * xorAppender ) Append ( t int64 , v float64 ) {
2016-11-20 16:14:21 +01:00
var tDelta uint64
2017-01-02 10:34:55 +01:00
num := binary . BigEndian . Uint16 ( a . b . bytes ( ) )
2016-11-20 16:14:21 +01:00
2017-01-02 10:34:55 +01:00
if num == 0 {
2016-11-30 22:10:10 +01:00
buf := make ( [ ] byte , binary . MaxVarintLen64 )
for _ , b := range buf [ : binary . PutVarint ( buf , t ) ] {
a . b . writeByte ( b )
}
2016-11-29 22:02:58 +01:00
a . b . writeBits ( math . Float64bits ( v ) , 64 )
2016-11-20 14:33:00 +01:00
2017-01-02 10:34:55 +01:00
} else if num == 1 {
2016-11-20 16:14:21 +01:00
tDelta = uint64 ( t - a . t )
2016-11-30 22:10:10 +01:00
buf := make ( [ ] byte , binary . MaxVarintLen64 )
for _ , b := range buf [ : binary . PutUvarint ( buf , tDelta ) ] {
a . b . writeByte ( b )
}
2016-11-20 16:14:21 +01:00
a . writeVDelta ( v )
} else {
tDelta = uint64 ( t - a . t )
2016-11-20 14:33:00 +01:00
dod := int64 ( tDelta - a . tDelta )
// Gorilla has a max resolution of seconds, Prometheus milliseconds.
// Thus we use higher value range steps with larger bit size.
switch {
case dod == 0 :
2016-11-29 22:02:58 +01:00
a . b . writeBit ( zero )
2016-12-07 15:37:37 +01:00
case bitRange ( dod , 14 ) :
2016-11-29 22:02:58 +01:00
a . b . writeBits ( 0x02 , 2 ) // '10'
a . b . writeBits ( uint64 ( dod ) , 14 )
2016-12-07 15:37:37 +01:00
case bitRange ( dod , 17 ) :
2016-11-29 22:02:58 +01:00
a . b . writeBits ( 0x06 , 3 ) // '110'
a . b . writeBits ( uint64 ( dod ) , 17 )
2016-12-07 15:37:37 +01:00
case bitRange ( dod , 20 ) :
2016-11-29 22:02:58 +01:00
a . b . writeBits ( 0x0e , 4 ) // '1110'
a . b . writeBits ( uint64 ( dod ) , 20 )
2016-11-20 14:33:00 +01:00
default :
2016-11-29 22:02:58 +01:00
a . b . writeBits ( 0x0f , 4 ) // '1111'
a . b . writeBits ( uint64 ( dod ) , 64 )
2016-11-15 10:33:34 +01:00
}
2016-11-20 14:33:00 +01:00
a . writeVDelta ( v )
2016-11-15 10:33:34 +01:00
}
2016-11-20 14:33:00 +01:00
a . t = t
a . v = v
2017-01-02 10:34:55 +01:00
binary . BigEndian . PutUint16 ( a . b . bytes ( ) , num + 1 )
2016-11-20 16:14:21 +01:00
a . tDelta = tDelta
2016-11-15 10:33:34 +01:00
}
2016-12-07 15:37:37 +01:00
func bitRange ( x int64 , nbits uint8 ) bool {
return - ( ( 1 << ( nbits - 1 ) ) - 1 ) <= x && x <= 1 << ( nbits - 1 )
}
2016-11-20 14:33:00 +01:00
func ( a * xorAppender ) writeVDelta ( v float64 ) {
vDelta := math . Float64bits ( v ) ^ math . Float64bits ( a . v )
if vDelta == 0 {
2016-11-29 22:02:58 +01:00
a . b . writeBit ( zero )
2016-11-20 14:33:00 +01:00
return
}
2016-11-29 22:02:58 +01:00
a . b . writeBit ( one )
2016-11-20 14:33:00 +01:00
2017-11-08 23:18:33 +01:00
leading := uint8 ( bits . LeadingZeros64 ( vDelta ) )
trailing := uint8 ( bits . TrailingZeros64 ( vDelta ) )
2016-11-20 14:33:00 +01:00
2016-11-30 23:01:01 +01:00
// Clamp number of leading zeros to avoid overflow when encoding.
2016-11-20 14:33:00 +01:00
if leading >= 32 {
leading = 31
}
2016-11-30 23:01:01 +01:00
if a . leading != 0xff && leading >= a . leading && trailing >= a . trailing {
2016-11-29 22:02:58 +01:00
a . b . writeBit ( zero )
a . b . writeBits ( vDelta >> a . trailing , 64 - int ( a . leading ) - int ( a . trailing ) )
2016-11-20 14:33:00 +01:00
} else {
a . leading , a . trailing = leading , trailing
2016-11-29 22:02:58 +01:00
a . b . writeBit ( one )
a . b . writeBits ( uint64 ( leading ) , 5 )
2016-11-20 14:33:00 +01:00
// Note that if leading == trailing == 0, then sigbits == 64. But that value doesn't actually fit into the 6 bits we have.
// Luckily, we never need to encode 0 significant bits, since that would put us in the other case (vdelta == 0).
// So instead we write out a 0 and adjust it back to 64 on unpacking.
sigbits := 64 - leading - trailing
2016-11-29 22:02:58 +01:00
a . b . writeBits ( uint64 ( sigbits ) , 6 )
a . b . writeBits ( vDelta >> trailing , int ( sigbits ) )
2016-11-20 14:33:00 +01:00
}
}
2016-11-15 10:33:34 +01:00
type xorIterator struct {
2020-06-15 17:44:40 +02:00
br bstreamReader
2016-11-20 14:33:00 +01:00
numTotal uint16
numRead uint16
t int64
val float64
leading uint8
trailing uint8
2016-11-29 22:02:58 +01:00
tDelta uint64
2016-11-20 14:33:00 +01:00
err error
}
2020-02-06 15:58:38 +00:00
func ( it * xorIterator ) Seek ( t int64 ) bool {
if it . err != nil {
return false
}
for t > it . t || it . numRead == 0 {
if ! it . Next ( ) {
return false
}
}
return true
}
2017-01-02 13:27:52 +01:00
func ( it * xorIterator ) At ( ) ( int64 , float64 ) {
2016-11-20 14:33:00 +01:00
return it . t , it . val
}
2016-11-29 22:02:58 +01:00
func ( it * xorIterator ) Err ( ) error {
return it . err
}
2019-07-09 15:19:34 +05:30
func ( it * xorIterator ) Reset ( b [ ] byte ) {
// The first 2 bytes contain chunk headers.
// We skip that for actual samples.
it . br = newBReader ( b [ 2 : ] )
it . numTotal = binary . BigEndian . Uint16 ( b )
it . numRead = 0
it . t = 0
it . val = 0
it . leading = 0
it . trailing = 0
it . tDelta = 0
it . err = nil
}
2016-11-29 22:02:58 +01:00
func ( it * xorIterator ) Next ( ) bool {
2016-11-20 14:33:00 +01:00
if it . err != nil || it . numRead == it . numTotal {
return false
}
if it . numRead == 0 {
2018-11-22 07:51:57 +00:00
t , err := binary . ReadVarint ( & it . br )
2016-11-20 14:33:00 +01:00
if err != nil {
it . err = err
return false
}
v , err := it . br . readBits ( 64 )
if err != nil {
it . err = err
return false
}
2018-03-21 21:23:47 +01:00
it . t = t
2016-11-20 14:33:00 +01:00
it . val = math . Float64frombits ( v )
it . numRead ++
return true
}
if it . numRead == 1 {
2018-11-22 07:51:57 +00:00
tDelta , err := binary . ReadUvarint ( & it . br )
2016-11-20 14:33:00 +01:00
if err != nil {
it . err = err
return false
}
2016-11-29 22:02:58 +01:00
it . tDelta = tDelta
it . t = it . t + int64 ( it . tDelta )
2016-11-20 14:33:00 +01:00
2016-11-29 22:02:58 +01:00
return it . readValue ( )
2016-11-20 14:33:00 +01:00
}
2016-11-29 22:02:58 +01:00
var d byte
2016-11-20 14:33:00 +01:00
// read delta-of-delta
for i := 0 ; i < 4 ; i ++ {
d <<= 1
2020-06-15 17:44:40 +02:00
bit , err := it . br . readBitFast ( )
if err != nil {
bit , err = it . br . readBit ( )
}
2016-11-20 14:33:00 +01:00
if err != nil {
it . err = err
return false
}
if bit == zero {
break
}
d |= 1
}
2016-11-29 22:02:58 +01:00
var sz uint8
var dod int64
2016-11-20 14:33:00 +01:00
switch d {
case 0x00 :
// dod == 0
case 0x02 :
sz = 14
case 0x06 :
sz = 17
case 0x0e :
sz = 20
case 0x0f :
2020-06-15 17:44:40 +02:00
// Do not use fast because it's very unlikely it will succeed.
2016-11-20 14:33:00 +01:00
bits , err := it . br . readBits ( 64 )
if err != nil {
it . err = err
return false
}
2016-11-29 22:02:58 +01:00
dod = int64 ( bits )
2016-11-20 14:33:00 +01:00
}
if sz != 0 {
2020-06-15 17:44:40 +02:00
bits , err := it . br . readBitsFast ( sz )
if err != nil {
bits , err = it . br . readBits ( sz )
}
2016-11-20 14:33:00 +01:00
if err != nil {
it . err = err
return false
}
if bits > ( 1 << ( sz - 1 ) ) {
// or something
bits = bits - ( 1 << sz )
}
2016-11-29 22:02:58 +01:00
dod = int64 ( bits )
2016-11-20 14:33:00 +01:00
}
2016-11-29 22:02:58 +01:00
it . tDelta = uint64 ( int64 ( it . tDelta ) + dod )
it . t = it . t + int64 ( it . tDelta )
2016-11-20 14:33:00 +01:00
2016-11-29 22:02:58 +01:00
return it . readValue ( )
}
2016-11-20 14:33:00 +01:00
2016-11-29 22:02:58 +01:00
func ( it * xorIterator ) readValue ( ) bool {
2020-06-15 17:44:40 +02:00
bit , err := it . br . readBitFast ( )
if err != nil {
bit , err = it . br . readBit ( )
}
2016-11-20 14:33:00 +01:00
if err != nil {
it . err = err
return false
}
if bit == zero {
// it.val = it.val
} else {
2020-06-15 17:44:40 +02:00
bit , err := it . br . readBitFast ( )
if err != nil {
bit , err = it . br . readBit ( )
}
2016-11-29 22:02:58 +01:00
if err != nil {
2016-11-20 14:33:00 +01:00
it . err = err
return false
}
if bit == zero {
// reuse leading/trailing zero bits
// it.leading, it.trailing = it.leading, it.trailing
} else {
2020-06-15 17:44:40 +02:00
bits , err := it . br . readBitsFast ( 5 )
if err != nil {
bits , err = it . br . readBits ( 5 )
}
2016-11-20 14:33:00 +01:00
if err != nil {
it . err = err
return false
}
it . leading = uint8 ( bits )
2020-06-15 17:44:40 +02:00
bits , err = it . br . readBitsFast ( 6 )
if err != nil {
bits , err = it . br . readBits ( 6 )
}
2016-11-20 14:33:00 +01:00
if err != nil {
it . err = err
return false
}
mbits := uint8 ( bits )
// 0 significant bits here means we overflowed and we actually need 64; see comment in encoder
if mbits == 0 {
mbits = 64
}
it . trailing = 64 - it . leading - mbits
}
2020-06-15 17:44:40 +02:00
mbits := 64 - it . leading - it . trailing
bits , err := it . br . readBitsFast ( mbits )
if err != nil {
bits , err = it . br . readBits ( mbits )
}
2016-11-20 14:33:00 +01:00
if err != nil {
it . err = err
return false
}
vbits := math . Float64bits ( it . val )
2020-06-15 17:44:40 +02:00
vbits ^ = bits << it . trailing
2016-11-20 14:33:00 +01:00
it . val = math . Float64frombits ( vbits )
}
it . numRead ++
return true
2016-11-15 10:33:34 +01:00
}