1// Copyright 2018 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package tsdb 15 16import ( 17 "encoding/binary" 18 "hash" 19 "hash/crc32" 20 "unsafe" 21 22 "github.com/pkg/errors" 23) 24 25var errInvalidSize = errors.New("invalid size") 26 27// encbuf is a helper type to populate a byte slice with various types. 28type encbuf struct { 29 b []byte 30 c [binary.MaxVarintLen64]byte 31} 32 33func (e *encbuf) reset() { e.b = e.b[:0] } 34func (e *encbuf) get() []byte { return e.b } 35func (e *encbuf) len() int { return len(e.b) } 36 37func (e *encbuf) putString(s string) { e.b = append(e.b, s...) } 38func (e *encbuf) putBytes(b []byte) { e.b = append(e.b, b...) } 39func (e *encbuf) putByte(c byte) { e.b = append(e.b, c) } 40 41func (e *encbuf) putBE32int(x int) { e.putBE32(uint32(x)) } 42func (e *encbuf) putBE64int(x int) { e.putBE64(uint64(x)) } 43func (e *encbuf) putBE64int64(x int64) { e.putBE64(uint64(x)) } 44func (e *encbuf) putUvarint32(x uint32) { e.putUvarint64(uint64(x)) } 45func (e *encbuf) putUvarint(x int) { e.putUvarint64(uint64(x)) } 46 47func (e *encbuf) putBE32(x uint32) { 48 binary.BigEndian.PutUint32(e.c[:], x) 49 e.b = append(e.b, e.c[:4]...) 50} 51 52func (e *encbuf) putBE64(x uint64) { 53 binary.BigEndian.PutUint64(e.c[:], x) 54 e.b = append(e.b, e.c[:8]...) 55} 56 57func (e *encbuf) putUvarint64(x uint64) { 58 n := binary.PutUvarint(e.c[:], x) 59 e.b = append(e.b, e.c[:n]...) 60} 61 62func (e *encbuf) putVarint64(x int64) { 63 n := binary.PutVarint(e.c[:], x) 64 e.b = append(e.b, e.c[:n]...) 65} 66 67// putVarintStr writes a string to the buffer prefixed by its varint length (in bytes!). 68func (e *encbuf) putUvarintStr(s string) { 69 b := *(*[]byte)(unsafe.Pointer(&s)) 70 e.putUvarint(len(b)) 71 e.putString(s) 72} 73 74// putHash appends a hash over the buffers current contents to the buffer. 75func (e *encbuf) putHash(h hash.Hash) { 76 h.Reset() 77 _, err := h.Write(e.b) 78 if err != nil { 79 panic(err) // The CRC32 implementation does not error 80 } 81 e.b = h.Sum(e.b) 82} 83 84// decbuf provides safe methods to extract data from a byte slice. It does all 85// necessary bounds checking and advancing of the byte slice. 86// Several datums can be extracted without checking for errors. However, before using 87// any datum, the err() method must be checked. 88type decbuf struct { 89 b []byte 90 e error 91} 92 93func (d *decbuf) uvarint() int { return int(d.uvarint64()) } 94func (d *decbuf) uvarint32() uint32 { return uint32(d.uvarint64()) } 95func (d *decbuf) be32int() int { return int(d.be32()) } 96func (d *decbuf) be64int64() int64 { return int64(d.be64()) } 97 98// crc32 returns a CRC32 checksum over the remaining bytes. 99func (d *decbuf) crc32() uint32 { 100 return crc32.Checksum(d.b, castagnoliTable) 101} 102 103func (d *decbuf) uvarintStr() string { 104 l := d.uvarint64() 105 if d.e != nil { 106 return "" 107 } 108 if len(d.b) < int(l) { 109 d.e = errInvalidSize 110 return "" 111 } 112 s := string(d.b[:l]) 113 d.b = d.b[l:] 114 return s 115} 116 117func (d *decbuf) varint64() int64 { 118 if d.e != nil { 119 return 0 120 } 121 x, n := binary.Varint(d.b) 122 if n < 1 { 123 d.e = errInvalidSize 124 return 0 125 } 126 d.b = d.b[n:] 127 return x 128} 129 130func (d *decbuf) uvarint64() uint64 { 131 if d.e != nil { 132 return 0 133 } 134 x, n := binary.Uvarint(d.b) 135 if n < 1 { 136 d.e = errInvalidSize 137 return 0 138 } 139 d.b = d.b[n:] 140 return x 141} 142 143func (d *decbuf) be64() uint64 { 144 if d.e != nil { 145 return 0 146 } 147 if len(d.b) < 4 { 148 d.e = errInvalidSize 149 return 0 150 } 151 x := binary.BigEndian.Uint64(d.b) 152 d.b = d.b[8:] 153 return x 154} 155 156func (d *decbuf) be32() uint32 { 157 if d.e != nil { 158 return 0 159 } 160 if len(d.b) < 4 { 161 d.e = errInvalidSize 162 return 0 163 } 164 x := binary.BigEndian.Uint32(d.b) 165 d.b = d.b[4:] 166 return x 167} 168 169func (d *decbuf) byte() byte { 170 if d.e != nil { 171 return 0 172 } 173 if len(d.b) < 1 { 174 d.e = errInvalidSize 175 return 0 176 } 177 x := d.b[0] 178 d.b = d.b[1:] 179 return x 180} 181 182func (d *decbuf) decbuf(l int) decbuf { 183 if d.e != nil { 184 return decbuf{e: d.e} 185 } 186 if l > len(d.b) { 187 return decbuf{e: errInvalidSize} 188 } 189 r := decbuf{b: d.b[:l]} 190 d.b = d.b[l:] 191 return r 192} 193 194func (d *decbuf) err() error { return d.e } 195func (d *decbuf) len() int { return len(d.b) } 196func (d *decbuf) get() []byte { return d.b } 197