mirror of
https://github.com/prometheus/prometheus.git
synced 2025-02-21 03:16:00 -08:00
vendor: remove unused dependency and last ref to fabxc/tsdb
This commit is contained in:
parent
73b8ff0ddc
commit
37deb21c45
|
@ -5,7 +5,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/fabxc/tsdb/labels"
|
"github.com/prometheus/prometheus/pkg/labels"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
169
vendor/github.com/fabxc/tsdb/chunks/bstream.go
generated
vendored
169
vendor/github.com/fabxc/tsdb/chunks/bstream.go
generated
vendored
|
@ -1,169 +0,0 @@
|
||||||
package chunks
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
// bstream is a stream of bits
|
|
||||||
type bstream struct {
|
|
||||||
stream []byte // the data stream
|
|
||||||
count uint8 // how many bits are valid in current byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBReader(b []byte) *bstream {
|
|
||||||
return &bstream{stream: b, count: 8}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBWriter(size int) *bstream {
|
|
||||||
return &bstream{stream: make([]byte, 0, size), count: 0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bstream) clone() *bstream {
|
|
||||||
d := make([]byte, len(b.stream))
|
|
||||||
copy(d, b.stream)
|
|
||||||
return &bstream{stream: d, count: b.count}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bstream) bytes() []byte {
|
|
||||||
return b.stream
|
|
||||||
}
|
|
||||||
|
|
||||||
type bit bool
|
|
||||||
|
|
||||||
const (
|
|
||||||
zero bit = false
|
|
||||||
one bit = true
|
|
||||||
)
|
|
||||||
|
|
||||||
func (b *bstream) writeBit(bit bit) {
|
|
||||||
if b.count == 0 {
|
|
||||||
b.stream = append(b.stream, 0)
|
|
||||||
b.count = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
i := len(b.stream) - 1
|
|
||||||
|
|
||||||
if bit {
|
|
||||||
b.stream[i] |= 1 << (b.count - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
b.count--
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bstream) writeByte(byt byte) {
|
|
||||||
if b.count == 0 {
|
|
||||||
b.stream = append(b.stream, 0)
|
|
||||||
b.count = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
i := len(b.stream) - 1
|
|
||||||
|
|
||||||
// fill up b.b with b.count bits from byt
|
|
||||||
b.stream[i] |= byt >> (8 - b.count)
|
|
||||||
|
|
||||||
b.stream = append(b.stream, 0)
|
|
||||||
i++
|
|
||||||
b.stream[i] = byt << b.count
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bstream) writeBits(u uint64, nbits int) {
|
|
||||||
u <<= (64 - uint(nbits))
|
|
||||||
for nbits >= 8 {
|
|
||||||
byt := byte(u >> 56)
|
|
||||||
b.writeByte(byt)
|
|
||||||
u <<= 8
|
|
||||||
nbits -= 8
|
|
||||||
}
|
|
||||||
|
|
||||||
for nbits > 0 {
|
|
||||||
b.writeBit((u >> 63) == 1)
|
|
||||||
u <<= 1
|
|
||||||
nbits--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bstream) readBit() (bit, error) {
|
|
||||||
if len(b.stream) == 0 {
|
|
||||||
return false, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.count == 0 {
|
|
||||||
b.stream = b.stream[1:]
|
|
||||||
|
|
||||||
if len(b.stream) == 0 {
|
|
||||||
return false, io.EOF
|
|
||||||
}
|
|
||||||
b.count = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
d := (b.stream[0] << (8 - b.count)) & 0x80
|
|
||||||
b.count--
|
|
||||||
return d != 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bstream) ReadByte() (byte, error) {
|
|
||||||
return b.readByte()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bstream) readByte() (byte, error) {
|
|
||||||
if len(b.stream) == 0 {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.count == 0 {
|
|
||||||
b.stream = b.stream[1:]
|
|
||||||
|
|
||||||
if len(b.stream) == 0 {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
return b.stream[0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.count == 8 {
|
|
||||||
b.count = 0
|
|
||||||
return b.stream[0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
byt := b.stream[0] << (8 - b.count)
|
|
||||||
b.stream = b.stream[1:]
|
|
||||||
|
|
||||||
if len(b.stream) == 0 {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
// We just advanced the stream and can assume the shift to be 0.
|
|
||||||
byt |= b.stream[0] >> b.count
|
|
||||||
|
|
||||||
return byt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bstream) readBits(nbits int) (uint64, error) {
|
|
||||||
var u uint64
|
|
||||||
|
|
||||||
for nbits >= 8 {
|
|
||||||
byt, err := b.readByte()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
u = (u << 8) | uint64(byt)
|
|
||||||
nbits -= 8
|
|
||||||
}
|
|
||||||
|
|
||||||
if nbits == 0 {
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if nbits > int(b.count) {
|
|
||||||
u = (u << uint(b.count)) | uint64((b.stream[0]<<(8-b.count))>>(8-b.count))
|
|
||||||
nbits -= int(b.count)
|
|
||||||
b.stream = b.stream[1:]
|
|
||||||
|
|
||||||
if len(b.stream) == 0 {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
b.count = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
u = (u << uint(nbits)) | uint64((b.stream[0]<<(8-b.count))>>(8-uint(nbits)))
|
|
||||||
b.count -= uint8(nbits)
|
|
||||||
return u, nil
|
|
||||||
}
|
|
57
vendor/github.com/fabxc/tsdb/chunks/chunk.go
generated
vendored
57
vendor/github.com/fabxc/tsdb/chunks/chunk.go
generated
vendored
|
@ -1,57 +0,0 @@
|
||||||
package chunks
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Encoding is the identifier for a chunk encoding
|
|
||||||
type Encoding uint8
|
|
||||||
|
|
||||||
func (e Encoding) String() string {
|
|
||||||
switch e {
|
|
||||||
case EncNone:
|
|
||||||
return "none"
|
|
||||||
case EncXOR:
|
|
||||||
return "XOR"
|
|
||||||
}
|
|
||||||
return "<unknown>"
|
|
||||||
}
|
|
||||||
|
|
||||||
// The different available chunk encodings.
|
|
||||||
const (
|
|
||||||
EncNone Encoding = iota
|
|
||||||
EncXOR
|
|
||||||
)
|
|
||||||
|
|
||||||
// Chunk holds a sequence of sample pairs that can be iterated over and appended to.
|
|
||||||
type Chunk interface {
|
|
||||||
Bytes() []byte
|
|
||||||
Encoding() Encoding
|
|
||||||
Appender() (Appender, error)
|
|
||||||
Iterator() Iterator
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData returns a chunk from a byte slice of chunk data.
|
|
||||||
func FromData(e Encoding, d []byte) (Chunk, error) {
|
|
||||||
switch e {
|
|
||||||
case EncXOR:
|
|
||||||
return &XORChunk{
|
|
||||||
b: &bstream{count: 0, stream: d},
|
|
||||||
num: binary.BigEndian.Uint16(d),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("unknown chunk encoding: %d", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Appender adds sample pairs to a chunk.
|
|
||||||
type Appender interface {
|
|
||||||
Append(int64, float64)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterator is a simple iterator that can only get the next value.
|
|
||||||
type Iterator interface {
|
|
||||||
At() (int64, float64)
|
|
||||||
Err() error
|
|
||||||
Next() bool
|
|
||||||
}
|
|
341
vendor/github.com/fabxc/tsdb/chunks/xor.go
generated
vendored
341
vendor/github.com/fabxc/tsdb/chunks/xor.go
generated
vendored
|
@ -1,341 +0,0 @@
|
||||||
package chunks
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"math"
|
|
||||||
|
|
||||||
bits "github.com/dgryski/go-bits"
|
|
||||||
)
|
|
||||||
|
|
||||||
// XORChunk holds XOR encoded sample data.
|
|
||||||
type XORChunk struct {
|
|
||||||
b *bstream
|
|
||||||
num uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewXORChunk returns a new chunk with XOR encoding of the given size.
|
|
||||||
func NewXORChunk() *XORChunk {
|
|
||||||
b := make([]byte, 2, 128)
|
|
||||||
return &XORChunk{b: &bstream{stream: b, count: 0}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *XORChunk) Encoding() Encoding {
|
|
||||||
return EncXOR
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns the underlying byte slice of the chunk.
|
|
||||||
func (c *XORChunk) Bytes() []byte {
|
|
||||||
return c.b.bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Appender implements the Chunk interface.
|
|
||||||
func (c *XORChunk) Appender() (Appender, error) {
|
|
||||||
it := c.iterator()
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
a := &xorAppender{
|
|
||||||
c: c,
|
|
||||||
b: c.b,
|
|
||||||
t: it.t,
|
|
||||||
v: it.val,
|
|
||||||
tDelta: it.tDelta,
|
|
||||||
leading: it.leading,
|
|
||||||
trailing: it.trailing,
|
|
||||||
}
|
|
||||||
if binary.BigEndian.Uint16(a.b.bytes()) == 0 {
|
|
||||||
a.leading = 0xff
|
|
||||||
}
|
|
||||||
return a, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *XORChunk) iterator() *xorIterator {
|
|
||||||
// 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.
|
|
||||||
return &xorIterator{
|
|
||||||
br: newBReader(c.b.bytes()[2:]),
|
|
||||||
numTotal: binary.BigEndian.Uint16(c.b.bytes()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterator implements the Chunk interface.
|
|
||||||
func (c *XORChunk) Iterator() Iterator {
|
|
||||||
return c.iterator()
|
|
||||||
}
|
|
||||||
|
|
||||||
type xorAppender struct {
|
|
||||||
c *XORChunk
|
|
||||||
b *bstream
|
|
||||||
|
|
||||||
t int64
|
|
||||||
v float64
|
|
||||||
tDelta uint64
|
|
||||||
|
|
||||||
leading uint8
|
|
||||||
trailing uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *xorAppender) Append(t int64, v float64) {
|
|
||||||
var tDelta uint64
|
|
||||||
num := binary.BigEndian.Uint16(a.b.bytes())
|
|
||||||
|
|
||||||
if num == 0 {
|
|
||||||
buf := make([]byte, binary.MaxVarintLen64)
|
|
||||||
for _, b := range buf[:binary.PutVarint(buf, t)] {
|
|
||||||
a.b.writeByte(b)
|
|
||||||
}
|
|
||||||
a.b.writeBits(math.Float64bits(v), 64)
|
|
||||||
|
|
||||||
} else if num == 1 {
|
|
||||||
tDelta = uint64(t - a.t)
|
|
||||||
|
|
||||||
buf := make([]byte, binary.MaxVarintLen64)
|
|
||||||
for _, b := range buf[:binary.PutUvarint(buf, tDelta)] {
|
|
||||||
a.b.writeByte(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
a.writeVDelta(v)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
tDelta = uint64(t - a.t)
|
|
||||||
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:
|
|
||||||
a.b.writeBit(zero)
|
|
||||||
case bitRange(dod, 14):
|
|
||||||
a.b.writeBits(0x02, 2) // '10'
|
|
||||||
a.b.writeBits(uint64(dod), 14)
|
|
||||||
case bitRange(dod, 17):
|
|
||||||
a.b.writeBits(0x06, 3) // '110'
|
|
||||||
a.b.writeBits(uint64(dod), 17)
|
|
||||||
case bitRange(dod, 20):
|
|
||||||
a.b.writeBits(0x0e, 4) // '1110'
|
|
||||||
a.b.writeBits(uint64(dod), 20)
|
|
||||||
default:
|
|
||||||
a.b.writeBits(0x0f, 4) // '1111'
|
|
||||||
a.b.writeBits(uint64(dod), 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
a.writeVDelta(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
a.t = t
|
|
||||||
a.v = v
|
|
||||||
binary.BigEndian.PutUint16(a.b.bytes(), num+1)
|
|
||||||
a.tDelta = tDelta
|
|
||||||
}
|
|
||||||
|
|
||||||
func bitRange(x int64, nbits uint8) bool {
|
|
||||||
return -((1<<(nbits-1))-1) <= x && x <= 1<<(nbits-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *xorAppender) writeVDelta(v float64) {
|
|
||||||
vDelta := math.Float64bits(v) ^ math.Float64bits(a.v)
|
|
||||||
|
|
||||||
if vDelta == 0 {
|
|
||||||
a.b.writeBit(zero)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
a.b.writeBit(one)
|
|
||||||
|
|
||||||
leading := uint8(bits.Clz(vDelta))
|
|
||||||
trailing := uint8(bits.Ctz(vDelta))
|
|
||||||
|
|
||||||
// Clamp number of leading zeros to avoid overflow when encoding.
|
|
||||||
if leading >= 32 {
|
|
||||||
leading = 31
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.leading != 0xff && leading >= a.leading && trailing >= a.trailing {
|
|
||||||
a.b.writeBit(zero)
|
|
||||||
a.b.writeBits(vDelta>>a.trailing, 64-int(a.leading)-int(a.trailing))
|
|
||||||
} else {
|
|
||||||
a.leading, a.trailing = leading, trailing
|
|
||||||
|
|
||||||
a.b.writeBit(one)
|
|
||||||
a.b.writeBits(uint64(leading), 5)
|
|
||||||
|
|
||||||
// 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
|
|
||||||
a.b.writeBits(uint64(sigbits), 6)
|
|
||||||
a.b.writeBits(vDelta>>trailing, int(sigbits))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type xorIterator struct {
|
|
||||||
br *bstream
|
|
||||||
numTotal uint16
|
|
||||||
numRead uint16
|
|
||||||
|
|
||||||
t int64
|
|
||||||
val float64
|
|
||||||
|
|
||||||
leading uint8
|
|
||||||
trailing uint8
|
|
||||||
|
|
||||||
tDelta uint64
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *xorIterator) At() (int64, float64) {
|
|
||||||
return it.t, it.val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *xorIterator) Err() error {
|
|
||||||
return it.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *xorIterator) Next() bool {
|
|
||||||
if it.err != nil || it.numRead == it.numTotal {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if it.numRead == 0 {
|
|
||||||
t, err := binary.ReadVarint(it.br)
|
|
||||||
if err != nil {
|
|
||||||
it.err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
v, err := it.br.readBits(64)
|
|
||||||
if err != nil {
|
|
||||||
it.err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
it.t = int64(t)
|
|
||||||
it.val = math.Float64frombits(v)
|
|
||||||
|
|
||||||
it.numRead++
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if it.numRead == 1 {
|
|
||||||
tDelta, err := binary.ReadUvarint(it.br)
|
|
||||||
if err != nil {
|
|
||||||
it.err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
it.tDelta = tDelta
|
|
||||||
it.t = it.t + int64(it.tDelta)
|
|
||||||
|
|
||||||
return it.readValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
var d byte
|
|
||||||
// read delta-of-delta
|
|
||||||
for i := 0; i < 4; i++ {
|
|
||||||
d <<= 1
|
|
||||||
bit, err := it.br.readBit()
|
|
||||||
if err != nil {
|
|
||||||
it.err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if bit == zero {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
d |= 1
|
|
||||||
}
|
|
||||||
var sz uint8
|
|
||||||
var dod int64
|
|
||||||
switch d {
|
|
||||||
case 0x00:
|
|
||||||
// dod == 0
|
|
||||||
case 0x02:
|
|
||||||
sz = 14
|
|
||||||
case 0x06:
|
|
||||||
sz = 17
|
|
||||||
case 0x0e:
|
|
||||||
sz = 20
|
|
||||||
case 0x0f:
|
|
||||||
bits, err := it.br.readBits(64)
|
|
||||||
if err != nil {
|
|
||||||
it.err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
dod = int64(bits)
|
|
||||||
}
|
|
||||||
|
|
||||||
if sz != 0 {
|
|
||||||
bits, err := it.br.readBits(int(sz))
|
|
||||||
if err != nil {
|
|
||||||
it.err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if bits > (1 << (sz - 1)) {
|
|
||||||
// or something
|
|
||||||
bits = bits - (1 << sz)
|
|
||||||
}
|
|
||||||
dod = int64(bits)
|
|
||||||
}
|
|
||||||
|
|
||||||
it.tDelta = uint64(int64(it.tDelta) + dod)
|
|
||||||
it.t = it.t + int64(it.tDelta)
|
|
||||||
|
|
||||||
return it.readValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *xorIterator) readValue() bool {
|
|
||||||
bit, err := it.br.readBit()
|
|
||||||
if err != nil {
|
|
||||||
it.err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if bit == zero {
|
|
||||||
// it.val = it.val
|
|
||||||
} else {
|
|
||||||
bit, err := it.br.readBit()
|
|
||||||
if err != nil {
|
|
||||||
it.err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if bit == zero {
|
|
||||||
// reuse leading/trailing zero bits
|
|
||||||
// it.leading, it.trailing = it.leading, it.trailing
|
|
||||||
} else {
|
|
||||||
bits, err := it.br.readBits(5)
|
|
||||||
if err != nil {
|
|
||||||
it.err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
it.leading = uint8(bits)
|
|
||||||
|
|
||||||
bits, err = it.br.readBits(6)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
mbits := int(64 - it.leading - it.trailing)
|
|
||||||
bits, err := it.br.readBits(mbits)
|
|
||||||
if err != nil {
|
|
||||||
it.err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
vbits := math.Float64bits(it.val)
|
|
||||||
vbits ^= (bits << it.trailing)
|
|
||||||
it.val = math.Float64frombits(vbits)
|
|
||||||
}
|
|
||||||
|
|
||||||
it.numRead++
|
|
||||||
return true
|
|
||||||
}
|
|
143
vendor/github.com/fabxc/tsdb/labels/labels.go
generated
vendored
143
vendor/github.com/fabxc/tsdb/labels/labels.go
generated
vendored
|
@ -1,143 +0,0 @@
|
||||||
package labels
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/cespare/xxhash"
|
|
||||||
)
|
|
||||||
|
|
||||||
const sep = '\xff'
|
|
||||||
|
|
||||||
// Label is a key/value pair of strings.
|
|
||||||
type Label struct {
|
|
||||||
Name, Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Labels is a sorted set of labels. Order has to be guaranteed upon
|
|
||||||
// instantiation.
|
|
||||||
type Labels []Label
|
|
||||||
|
|
||||||
func (ls Labels) Len() int { return len(ls) }
|
|
||||||
func (ls Labels) Swap(i, j int) { ls[i], ls[j] = ls[j], ls[i] }
|
|
||||||
func (ls Labels) Less(i, j int) bool { return ls[i].Name < ls[j].Name }
|
|
||||||
|
|
||||||
func (ls Labels) String() string {
|
|
||||||
var b bytes.Buffer
|
|
||||||
|
|
||||||
b.WriteByte('{')
|
|
||||||
for i, l := range ls {
|
|
||||||
if i > 0 {
|
|
||||||
b.WriteByte(',')
|
|
||||||
}
|
|
||||||
b.WriteString(l.Name)
|
|
||||||
b.WriteByte('=')
|
|
||||||
b.WriteString(strconv.Quote(l.Value))
|
|
||||||
}
|
|
||||||
b.WriteByte('}')
|
|
||||||
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns a hash value for the label set.
|
|
||||||
func (ls Labels) Hash() uint64 {
|
|
||||||
b := make([]byte, 0, 1024)
|
|
||||||
|
|
||||||
for _, v := range ls {
|
|
||||||
b = append(b, v.Name...)
|
|
||||||
b = append(b, sep)
|
|
||||||
b = append(b, v.Value...)
|
|
||||||
b = append(b, sep)
|
|
||||||
}
|
|
||||||
return xxhash.Sum64(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the value for the label with the given name.
|
|
||||||
// Returns an empty string if the label doesn't exist.
|
|
||||||
func (ls Labels) Get(name string) string {
|
|
||||||
for _, l := range ls {
|
|
||||||
if l.Name == name {
|
|
||||||
return l.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equals returns whether the two label sets are equal.
|
|
||||||
func (ls Labels) Equals(o Labels) bool {
|
|
||||||
if len(ls) != len(o) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i, l := range ls {
|
|
||||||
if l.Name != o[i].Name || l.Value != o[i].Value {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map returns a string map of the labels.
|
|
||||||
func (ls Labels) Map() map[string]string {
|
|
||||||
m := make(map[string]string, len(ls))
|
|
||||||
for _, l := range ls {
|
|
||||||
m[l.Name] = l.Value
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a sorted Labels from the given labels.
|
|
||||||
// The caller has to guarantee that all label names are unique.
|
|
||||||
func New(ls ...Label) Labels {
|
|
||||||
set := make(Labels, 0, len(ls))
|
|
||||||
for _, l := range ls {
|
|
||||||
set = append(set, l)
|
|
||||||
}
|
|
||||||
sort.Sort(set)
|
|
||||||
|
|
||||||
return set
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromMap returns new sorted Labels from the given map.
|
|
||||||
func FromMap(m map[string]string) Labels {
|
|
||||||
l := make([]Label, 0, len(m))
|
|
||||||
for k, v := range m {
|
|
||||||
l = append(l, Label{Name: k, Value: v})
|
|
||||||
}
|
|
||||||
return New(l...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStrings creates new labels from pairs of strings.
|
|
||||||
func FromStrings(ss ...string) Labels {
|
|
||||||
if len(ss)%2 != 0 {
|
|
||||||
panic("invalid number of strings")
|
|
||||||
}
|
|
||||||
var res Labels
|
|
||||||
for i := 0; i < len(ss); i += 2 {
|
|
||||||
res = append(res, Label{Name: ss[i], Value: ss[i+1]})
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Sort(res)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare compares the two label sets.
|
|
||||||
// The result will be 0 if a==b, <0 if a < b, and >0 if a > b.
|
|
||||||
func Compare(a, b Labels) int {
|
|
||||||
l := len(a)
|
|
||||||
if len(b) < l {
|
|
||||||
l = len(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < l; i++ {
|
|
||||||
if d := strings.Compare(a[i].Name, b[i].Name); d != 0 {
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
if d := strings.Compare(a[i].Value, b[i].Value); d != 0 {
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If all labels so far were in common, the set with fewer labels comes first.
|
|
||||||
return len(a) - len(b)
|
|
||||||
}
|
|
66
vendor/github.com/fabxc/tsdb/labels/selector.go
generated
vendored
66
vendor/github.com/fabxc/tsdb/labels/selector.go
generated
vendored
|
@ -1,66 +0,0 @@
|
||||||
package labels
|
|
||||||
|
|
||||||
import "regexp"
|
|
||||||
|
|
||||||
// Selector holds constraints for matching against a label set.
|
|
||||||
type Selector []Matcher
|
|
||||||
|
|
||||||
// Matches returns whether the labels satisfy all matchers.
|
|
||||||
func (s Selector) Matches(labels Labels) bool {
|
|
||||||
for _, m := range s {
|
|
||||||
if v := labels.Get(m.Name()); !m.Matches(v) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Matcher specifies a constraint for the value of a label.
|
|
||||||
type Matcher interface {
|
|
||||||
// Name returns the label name the matcher should apply to.
|
|
||||||
Name() string
|
|
||||||
// Matches checks whether a value fulfills the constraints.
|
|
||||||
Matches(v string) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type EqualMatcher struct {
|
|
||||||
name, value string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *EqualMatcher) Name() string { return m.name }
|
|
||||||
func (m *EqualMatcher) Matches(v string) bool { return v == m.value }
|
|
||||||
|
|
||||||
// NewEqualMatcher returns a new matcher matching an exact label value.
|
|
||||||
func NewEqualMatcher(name, value string) Matcher {
|
|
||||||
return &EqualMatcher{name: name, value: value}
|
|
||||||
}
|
|
||||||
|
|
||||||
type regexpMatcher struct {
|
|
||||||
name string
|
|
||||||
re *regexp.Regexp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *regexpMatcher) Name() string { return m.name }
|
|
||||||
func (m *regexpMatcher) Matches(v string) bool { return m.re.MatchString(v) }
|
|
||||||
|
|
||||||
// NewRegexpMatcher returns a new matcher verifying that a value matches
|
|
||||||
// the regular expression pattern.
|
|
||||||
func NewRegexpMatcher(name, pattern string) (Matcher, error) {
|
|
||||||
re, err := regexp.Compile(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ®expMatcher{name: name, re: re}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// notMatcher inverts the matching result for a matcher.
|
|
||||||
type notMatcher struct {
|
|
||||||
Matcher
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *notMatcher) Matches(v string) bool { return !m.Matcher.Matches(v) }
|
|
||||||
|
|
||||||
// Not inverts the matcher's matching result.
|
|
||||||
func Not(m Matcher) Matcher {
|
|
||||||
return ¬Matcher{m}
|
|
||||||
}
|
|
27
vendor/golang.org/x/time/LICENSE
generated
vendored
27
vendor/golang.org/x/time/LICENSE
generated
vendored
|
@ -1,27 +0,0 @@
|
||||||
Copyright (c) 2009 The Go Authors. 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.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
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
|
|
||||||
OWNER 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.
|
|
22
vendor/golang.org/x/time/PATENTS
generated
vendored
22
vendor/golang.org/x/time/PATENTS
generated
vendored
|
@ -1,22 +0,0 @@
|
||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
371
vendor/golang.org/x/time/rate/rate.go
generated
vendored
371
vendor/golang.org/x/time/rate/rate.go
generated
vendored
|
@ -1,371 +0,0 @@
|
||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package rate provides a rate limiter.
|
|
||||||
package rate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Limit defines the maximum frequency of some events.
|
|
||||||
// Limit is represented as number of events per second.
|
|
||||||
// A zero Limit allows no events.
|
|
||||||
type Limit float64
|
|
||||||
|
|
||||||
// Inf is the infinite rate limit; it allows all events (even if burst is zero).
|
|
||||||
const Inf = Limit(math.MaxFloat64)
|
|
||||||
|
|
||||||
// Every converts a minimum time interval between events to a Limit.
|
|
||||||
func Every(interval time.Duration) Limit {
|
|
||||||
if interval <= 0 {
|
|
||||||
return Inf
|
|
||||||
}
|
|
||||||
return 1 / Limit(interval.Seconds())
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Limiter controls how frequently events are allowed to happen.
|
|
||||||
// It implements a "token bucket" of size b, initially full and refilled
|
|
||||||
// at rate r tokens per second.
|
|
||||||
// Informally, in any large enough time interval, the Limiter limits the
|
|
||||||
// rate to r tokens per second, with a maximum burst size of b events.
|
|
||||||
// As a special case, if r == Inf (the infinite rate), b is ignored.
|
|
||||||
// See https://en.wikipedia.org/wiki/Token_bucket for more about token buckets.
|
|
||||||
//
|
|
||||||
// The zero value is a valid Limiter, but it will reject all events.
|
|
||||||
// Use NewLimiter to create non-zero Limiters.
|
|
||||||
//
|
|
||||||
// Limiter has three main methods, Allow, Reserve, and Wait.
|
|
||||||
// Most callers should use Wait.
|
|
||||||
//
|
|
||||||
// Each of the three methods consumes a single token.
|
|
||||||
// They differ in their behavior when no token is available.
|
|
||||||
// If no token is available, Allow returns false.
|
|
||||||
// If no token is available, Reserve returns a reservation for a future token
|
|
||||||
// and the amount of time the caller must wait before using it.
|
|
||||||
// If no token is available, Wait blocks until one can be obtained
|
|
||||||
// or its associated context.Context is canceled.
|
|
||||||
//
|
|
||||||
// The methods AllowN, ReserveN, and WaitN consume n tokens.
|
|
||||||
type Limiter struct {
|
|
||||||
limit Limit
|
|
||||||
burst int
|
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
tokens float64
|
|
||||||
// last is the last time the limiter's tokens field was updated
|
|
||||||
last time.Time
|
|
||||||
// lastEvent is the latest time of a rate-limited event (past or future)
|
|
||||||
lastEvent time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limit returns the maximum overall event rate.
|
|
||||||
func (lim *Limiter) Limit() Limit {
|
|
||||||
lim.mu.Lock()
|
|
||||||
defer lim.mu.Unlock()
|
|
||||||
return lim.limit
|
|
||||||
}
|
|
||||||
|
|
||||||
// Burst returns the maximum burst size. Burst is the maximum number of tokens
|
|
||||||
// that can be consumed in a single call to Allow, Reserve, or Wait, so higher
|
|
||||||
// Burst values allow more events to happen at once.
|
|
||||||
// A zero Burst allows no events, unless limit == Inf.
|
|
||||||
func (lim *Limiter) Burst() int {
|
|
||||||
return lim.burst
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLimiter returns a new Limiter that allows events up to rate r and permits
|
|
||||||
// bursts of at most b tokens.
|
|
||||||
func NewLimiter(r Limit, b int) *Limiter {
|
|
||||||
return &Limiter{
|
|
||||||
limit: r,
|
|
||||||
burst: b,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow is shorthand for AllowN(time.Now(), 1).
|
|
||||||
func (lim *Limiter) Allow() bool {
|
|
||||||
return lim.AllowN(time.Now(), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowN reports whether n events may happen at time now.
|
|
||||||
// Use this method if you intend to drop / skip events that exceed the rate limit.
|
|
||||||
// Otherwise use Reserve or Wait.
|
|
||||||
func (lim *Limiter) AllowN(now time.Time, n int) bool {
|
|
||||||
return lim.reserveN(now, n, 0).ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Reservation holds information about events that are permitted by a Limiter to happen after a delay.
|
|
||||||
// A Reservation may be canceled, which may enable the Limiter to permit additional events.
|
|
||||||
type Reservation struct {
|
|
||||||
ok bool
|
|
||||||
lim *Limiter
|
|
||||||
tokens int
|
|
||||||
timeToAct time.Time
|
|
||||||
// This is the Limit at reservation time, it can change later.
|
|
||||||
limit Limit
|
|
||||||
}
|
|
||||||
|
|
||||||
// OK returns whether the limiter can provide the requested number of tokens
|
|
||||||
// within the maximum wait time. If OK is false, Delay returns InfDuration, and
|
|
||||||
// Cancel does nothing.
|
|
||||||
func (r *Reservation) OK() bool {
|
|
||||||
return r.ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delay is shorthand for DelayFrom(time.Now()).
|
|
||||||
func (r *Reservation) Delay() time.Duration {
|
|
||||||
return r.DelayFrom(time.Now())
|
|
||||||
}
|
|
||||||
|
|
||||||
// InfDuration is the duration returned by Delay when a Reservation is not OK.
|
|
||||||
const InfDuration = time.Duration(1<<63 - 1)
|
|
||||||
|
|
||||||
// DelayFrom returns the duration for which the reservation holder must wait
|
|
||||||
// before taking the reserved action. Zero duration means act immediately.
|
|
||||||
// InfDuration means the limiter cannot grant the tokens requested in this
|
|
||||||
// Reservation within the maximum wait time.
|
|
||||||
func (r *Reservation) DelayFrom(now time.Time) time.Duration {
|
|
||||||
if !r.ok {
|
|
||||||
return InfDuration
|
|
||||||
}
|
|
||||||
delay := r.timeToAct.Sub(now)
|
|
||||||
if delay < 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return delay
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel is shorthand for CancelAt(time.Now()).
|
|
||||||
func (r *Reservation) Cancel() {
|
|
||||||
r.CancelAt(time.Now())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// CancelAt indicates that the reservation holder will not perform the reserved action
|
|
||||||
// and reverses the effects of this Reservation on the rate limit as much as possible,
|
|
||||||
// considering that other reservations may have already been made.
|
|
||||||
func (r *Reservation) CancelAt(now time.Time) {
|
|
||||||
if !r.ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
r.lim.mu.Lock()
|
|
||||||
defer r.lim.mu.Unlock()
|
|
||||||
|
|
||||||
if r.lim.limit == Inf || r.tokens == 0 || r.timeToAct.Before(now) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate tokens to restore
|
|
||||||
// The duration between lim.lastEvent and r.timeToAct tells us how many tokens were reserved
|
|
||||||
// after r was obtained. These tokens should not be restored.
|
|
||||||
restoreTokens := float64(r.tokens) - r.limit.tokensFromDuration(r.lim.lastEvent.Sub(r.timeToAct))
|
|
||||||
if restoreTokens <= 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// advance time to now
|
|
||||||
now, _, tokens := r.lim.advance(now)
|
|
||||||
// calculate new number of tokens
|
|
||||||
tokens += restoreTokens
|
|
||||||
if burst := float64(r.lim.burst); tokens > burst {
|
|
||||||
tokens = burst
|
|
||||||
}
|
|
||||||
// update state
|
|
||||||
r.lim.last = now
|
|
||||||
r.lim.tokens = tokens
|
|
||||||
if r.timeToAct == r.lim.lastEvent {
|
|
||||||
prevEvent := r.timeToAct.Add(r.limit.durationFromTokens(float64(-r.tokens)))
|
|
||||||
if !prevEvent.Before(now) {
|
|
||||||
r.lim.lastEvent = prevEvent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reserve is shorthand for ReserveN(time.Now(), 1).
|
|
||||||
func (lim *Limiter) Reserve() *Reservation {
|
|
||||||
return lim.ReserveN(time.Now(), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReserveN returns a Reservation that indicates how long the caller must wait before n events happen.
|
|
||||||
// The Limiter takes this Reservation into account when allowing future events.
|
|
||||||
// ReserveN returns false if n exceeds the Limiter's burst size.
|
|
||||||
// Usage example:
|
|
||||||
// r := lim.ReserveN(time.Now(), 1)
|
|
||||||
// if !r.OK() {
|
|
||||||
// // Not allowed to act! Did you remember to set lim.burst to be > 0 ?
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// time.Sleep(r.Delay())
|
|
||||||
// Act()
|
|
||||||
// Use this method if you wish to wait and slow down in accordance with the rate limit without dropping events.
|
|
||||||
// If you need to respect a deadline or cancel the delay, use Wait instead.
|
|
||||||
// To drop or skip events exceeding rate limit, use Allow instead.
|
|
||||||
func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation {
|
|
||||||
r := lim.reserveN(now, n, InfDuration)
|
|
||||||
return &r
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait is shorthand for WaitN(ctx, 1).
|
|
||||||
func (lim *Limiter) Wait(ctx context.Context) (err error) {
|
|
||||||
return lim.WaitN(ctx, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WaitN blocks until lim permits n events to happen.
|
|
||||||
// It returns an error if n exceeds the Limiter's burst size, the Context is
|
|
||||||
// canceled, or the expected wait time exceeds the Context's Deadline.
|
|
||||||
// The burst limit is ignored if the rate limit is Inf.
|
|
||||||
func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) {
|
|
||||||
if n > lim.burst && lim.limit != Inf {
|
|
||||||
return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, lim.burst)
|
|
||||||
}
|
|
||||||
// Check if ctx is already cancelled
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
// Determine wait limit
|
|
||||||
now := time.Now()
|
|
||||||
waitLimit := InfDuration
|
|
||||||
if deadline, ok := ctx.Deadline(); ok {
|
|
||||||
waitLimit = deadline.Sub(now)
|
|
||||||
}
|
|
||||||
// Reserve
|
|
||||||
r := lim.reserveN(now, n, waitLimit)
|
|
||||||
if !r.ok {
|
|
||||||
return fmt.Errorf("rate: Wait(n=%d) would exceed context deadline", n)
|
|
||||||
}
|
|
||||||
// Wait
|
|
||||||
t := time.NewTimer(r.DelayFrom(now))
|
|
||||||
defer t.Stop()
|
|
||||||
select {
|
|
||||||
case <-t.C:
|
|
||||||
// We can proceed.
|
|
||||||
return nil
|
|
||||||
case <-ctx.Done():
|
|
||||||
// Context was canceled before we could proceed. Cancel the
|
|
||||||
// reservation, which may permit other events to proceed sooner.
|
|
||||||
r.Cancel()
|
|
||||||
return ctx.Err()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetLimit is shorthand for SetLimitAt(time.Now(), newLimit).
|
|
||||||
func (lim *Limiter) SetLimit(newLimit Limit) {
|
|
||||||
lim.SetLimitAt(time.Now(), newLimit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetLimitAt sets a new Limit for the limiter. The new Limit, and Burst, may be violated
|
|
||||||
// or underutilized by those which reserved (using Reserve or Wait) but did not yet act
|
|
||||||
// before SetLimitAt was called.
|
|
||||||
func (lim *Limiter) SetLimitAt(now time.Time, newLimit Limit) {
|
|
||||||
lim.mu.Lock()
|
|
||||||
defer lim.mu.Unlock()
|
|
||||||
|
|
||||||
now, _, tokens := lim.advance(now)
|
|
||||||
|
|
||||||
lim.last = now
|
|
||||||
lim.tokens = tokens
|
|
||||||
lim.limit = newLimit
|
|
||||||
}
|
|
||||||
|
|
||||||
// reserveN is a helper method for AllowN, ReserveN, and WaitN.
|
|
||||||
// maxFutureReserve specifies the maximum reservation wait duration allowed.
|
|
||||||
// reserveN returns Reservation, not *Reservation, to avoid allocation in AllowN and WaitN.
|
|
||||||
func (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve time.Duration) Reservation {
|
|
||||||
lim.mu.Lock()
|
|
||||||
|
|
||||||
if lim.limit == Inf {
|
|
||||||
lim.mu.Unlock()
|
|
||||||
return Reservation{
|
|
||||||
ok: true,
|
|
||||||
lim: lim,
|
|
||||||
tokens: n,
|
|
||||||
timeToAct: now,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
now, last, tokens := lim.advance(now)
|
|
||||||
|
|
||||||
// Calculate the remaining number of tokens resulting from the request.
|
|
||||||
tokens -= float64(n)
|
|
||||||
|
|
||||||
// Calculate the wait duration
|
|
||||||
var waitDuration time.Duration
|
|
||||||
if tokens < 0 {
|
|
||||||
waitDuration = lim.limit.durationFromTokens(-tokens)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decide result
|
|
||||||
ok := n <= lim.burst && waitDuration <= maxFutureReserve
|
|
||||||
|
|
||||||
// Prepare reservation
|
|
||||||
r := Reservation{
|
|
||||||
ok: ok,
|
|
||||||
lim: lim,
|
|
||||||
limit: lim.limit,
|
|
||||||
}
|
|
||||||
if ok {
|
|
||||||
r.tokens = n
|
|
||||||
r.timeToAct = now.Add(waitDuration)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update state
|
|
||||||
if ok {
|
|
||||||
lim.last = now
|
|
||||||
lim.tokens = tokens
|
|
||||||
lim.lastEvent = r.timeToAct
|
|
||||||
} else {
|
|
||||||
lim.last = last
|
|
||||||
}
|
|
||||||
|
|
||||||
lim.mu.Unlock()
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// advance calculates and returns an updated state for lim resulting from the passage of time.
|
|
||||||
// lim is not changed.
|
|
||||||
func (lim *Limiter) advance(now time.Time) (newNow time.Time, newLast time.Time, newTokens float64) {
|
|
||||||
last := lim.last
|
|
||||||
if now.Before(last) {
|
|
||||||
last = now
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid making delta overflow below when last is very old.
|
|
||||||
maxElapsed := lim.limit.durationFromTokens(float64(lim.burst) - lim.tokens)
|
|
||||||
elapsed := now.Sub(last)
|
|
||||||
if elapsed > maxElapsed {
|
|
||||||
elapsed = maxElapsed
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the new number of tokens, due to time that passed.
|
|
||||||
delta := lim.limit.tokensFromDuration(elapsed)
|
|
||||||
tokens := lim.tokens + delta
|
|
||||||
if burst := float64(lim.burst); tokens > burst {
|
|
||||||
tokens = burst
|
|
||||||
}
|
|
||||||
|
|
||||||
return now, last, tokens
|
|
||||||
}
|
|
||||||
|
|
||||||
// durationFromTokens is a unit conversion function from the number of tokens to the duration
|
|
||||||
// of time it takes to accumulate them at a rate of limit tokens per second.
|
|
||||||
func (limit Limit) durationFromTokens(tokens float64) time.Duration {
|
|
||||||
seconds := tokens / float64(limit)
|
|
||||||
return time.Nanosecond * time.Duration(1e9*seconds)
|
|
||||||
}
|
|
||||||
|
|
||||||
// tokensFromDuration is a unit conversion function from a time duration to the number of tokens
|
|
||||||
// which could be accumulated during that duration at a rate of limit tokens per second.
|
|
||||||
func (limit Limit) tokensFromDuration(d time.Duration) float64 {
|
|
||||||
return d.Seconds() * float64(limit)
|
|
||||||
}
|
|
18
vendor/vendor.json
vendored
18
vendor/vendor.json
vendored
|
@ -361,18 +361,6 @@
|
||||||
"revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
|
"revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
|
||||||
"revisionTime": "2016-09-30T00:14:02Z"
|
"revisionTime": "2016-09-30T00:14:02Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"checksumSHA1": "uVzWuLvF646YjiKomsc2CR1ua58=",
|
|
||||||
"path": "github.com/fabxc/tsdb/chunks",
|
|
||||||
"revision": "ca1bc920b795cfc670002e7643471b0277e79a9b",
|
|
||||||
"revisionTime": "2017-03-08T15:54:13Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "0Nl+7XBhC+XLpkgkWc6cEtW37aE=",
|
|
||||||
"path": "github.com/fabxc/tsdb/labels",
|
|
||||||
"revision": "ca1bc920b795cfc670002e7643471b0277e79a9b",
|
|
||||||
"revisionTime": "2017-03-08T15:54:13Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"checksumSHA1": "ww7LVo7jNJ1o6sfRcromEHKyY+o=",
|
"checksumSHA1": "ww7LVo7jNJ1o6sfRcromEHKyY+o=",
|
||||||
"origin": "k8s.io/client-go/1.5/vendor/github.com/ghodss/yaml",
|
"origin": "k8s.io/client-go/1.5/vendor/github.com/ghodss/yaml",
|
||||||
|
@ -882,12 +870,6 @@
|
||||||
"revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
|
"revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
|
||||||
"revisionTime": "2016-09-30T00:14:02Z"
|
"revisionTime": "2016-09-30T00:14:02Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"checksumSHA1": "eFQDEix/mGnhwnFu/Hq63zMfrX8=",
|
|
||||||
"path": "golang.org/x/time/rate",
|
|
||||||
"revision": "f51c12702a4d776e4c1fa9b0fabab841babae631",
|
|
||||||
"revisionTime": "2016-10-28T04:02:39Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"checksumSHA1": "AjdmRXf0fiy6Bec9mNlsGsmZi1k=",
|
"checksumSHA1": "AjdmRXf0fiy6Bec9mNlsGsmZi1k=",
|
||||||
"path": "google.golang.org/api/compute/v1",
|
"path": "google.golang.org/api/compute/v1",
|
||||||
|
|
Loading…
Reference in a new issue