mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-11 08:04:04 -08:00
297 lines
6 KiB
Go
297 lines
6 KiB
Go
|
package codec
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding"
|
||
|
"encoding/binary"
|
||
|
"io"
|
||
|
"sync"
|
||
|
|
||
|
clientmodel "github.com/prometheus/client_golang/model"
|
||
|
|
||
|
"github.com/prometheus/prometheus/storage/metric"
|
||
|
)
|
||
|
|
||
|
type codable interface {
|
||
|
encoding.BinaryMarshaler
|
||
|
encoding.BinaryUnmarshaler
|
||
|
}
|
||
|
|
||
|
type byteReader interface {
|
||
|
io.Reader
|
||
|
io.ByteReader
|
||
|
}
|
||
|
|
||
|
var bufPool sync.Pool
|
||
|
|
||
|
func getBuf(l int) []byte {
|
||
|
x := bufPool.Get()
|
||
|
if x == nil {
|
||
|
return make([]byte, l)
|
||
|
}
|
||
|
buf := x.([]byte)
|
||
|
if cap(buf) < l {
|
||
|
return make([]byte, l)
|
||
|
}
|
||
|
return buf[:l]
|
||
|
}
|
||
|
|
||
|
func putBuf(buf []byte) {
|
||
|
bufPool.Put(buf)
|
||
|
}
|
||
|
|
||
|
func EncodeVarint(w io.Writer, i int64) error {
|
||
|
buf := getBuf(binary.MaxVarintLen64)
|
||
|
defer putBuf(buf)
|
||
|
|
||
|
bytesWritten := binary.PutVarint(buf, i)
|
||
|
_, err := w.Write(buf[:bytesWritten])
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func EncodeUint64(w io.Writer, u uint64) error {
|
||
|
buf := getBuf(8)
|
||
|
defer putBuf(buf)
|
||
|
|
||
|
binary.BigEndian.PutUint64(buf, u)
|
||
|
_, err := w.Write(buf)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func DecodeUint64(r io.Reader) (uint64, error) {
|
||
|
buf := getBuf(8)
|
||
|
defer putBuf(buf)
|
||
|
|
||
|
if _, err := io.ReadFull(r, buf); err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
return binary.BigEndian.Uint64(buf), nil
|
||
|
}
|
||
|
|
||
|
func encodeString(b *bytes.Buffer, s string) error {
|
||
|
if err := EncodeVarint(b, int64(len(s))); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if _, err := b.WriteString(s); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func decodeString(b byteReader) (string, error) {
|
||
|
length, err := binary.ReadVarint(b)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
buf := getBuf(int(length))
|
||
|
defer putBuf(buf)
|
||
|
|
||
|
if _, err := io.ReadFull(b, buf); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
return string(buf), nil
|
||
|
}
|
||
|
|
||
|
type CodableMetric clientmodel.Metric
|
||
|
|
||
|
func (m CodableMetric) MarshalBinary() ([]byte, error) {
|
||
|
buf := &bytes.Buffer{}
|
||
|
if err := EncodeVarint(buf, int64(len(m))); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
for l, v := range m {
|
||
|
if err := encodeString(buf, string(l)); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if err := encodeString(buf, string(v)); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
return buf.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
func (m *CodableMetric) UnmarshalBinary(buf []byte) error {
|
||
|
return m.UnmarshalFromReader(bytes.NewReader(buf))
|
||
|
}
|
||
|
|
||
|
func (m *CodableMetric) UnmarshalFromReader(r byteReader) error {
|
||
|
numLabelPairs, err := binary.ReadVarint(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
*m = make(CodableMetric, numLabelPairs)
|
||
|
|
||
|
for ; numLabelPairs > 0; numLabelPairs-- {
|
||
|
ln, err := decodeString(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
lv, err := decodeString(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
(*m)[clientmodel.LabelName(ln)] = clientmodel.LabelValue(lv)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type CodableFingerprint clientmodel.Fingerprint
|
||
|
|
||
|
func (fp CodableFingerprint) MarshalBinary() ([]byte, error) {
|
||
|
b := make([]byte, 8)
|
||
|
binary.BigEndian.PutUint64(b, uint64(fp))
|
||
|
return b, nil
|
||
|
}
|
||
|
|
||
|
func (fp *CodableFingerprint) UnmarshalBinary(buf []byte) error {
|
||
|
*fp = CodableFingerprint(binary.BigEndian.Uint64(buf))
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type CodableFingerprints clientmodel.Fingerprints
|
||
|
|
||
|
func (fps CodableFingerprints) MarshalBinary() ([]byte, error) {
|
||
|
b := bytes.NewBuffer(make([]byte, 0, binary.MaxVarintLen64+len(fps)*8))
|
||
|
if err := EncodeVarint(b, int64(len(fps))); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
buf := getBuf(8)
|
||
|
defer putBuf(buf)
|
||
|
|
||
|
for _, fp := range fps {
|
||
|
binary.BigEndian.PutUint64(buf, uint64(fp))
|
||
|
if _, err := b.Write(buf[:8]); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
return b.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
func (fps *CodableFingerprints) UnmarshalBinary(buf []byte) error {
|
||
|
r := bytes.NewReader(buf)
|
||
|
numFPs, err := binary.ReadVarint(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
*fps = make(CodableFingerprints, numFPs)
|
||
|
|
||
|
offset := len(buf) - r.Len()
|
||
|
for i, _ := range *fps {
|
||
|
(*fps)[i] = clientmodel.Fingerprint(binary.BigEndian.Uint64(buf[offset+i*8:]))
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type CodableLabelPair metric.LabelPair
|
||
|
|
||
|
func (lp CodableLabelPair) MarshalBinary() ([]byte, error) {
|
||
|
buf := &bytes.Buffer{}
|
||
|
if err := encodeString(buf, string(lp.Name)); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if err := encodeString(buf, string(lp.Value)); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return buf.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
func (lp *CodableLabelPair) UnmarshalBinary(buf []byte) error {
|
||
|
r := bytes.NewReader(buf)
|
||
|
n, err := decodeString(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v, err := decodeString(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
lp.Name = clientmodel.LabelName(n)
|
||
|
lp.Value = clientmodel.LabelValue(v)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type CodableLabelName clientmodel.LabelName
|
||
|
|
||
|
func (l CodableLabelName) MarshalBinary() ([]byte, error) {
|
||
|
buf := &bytes.Buffer{}
|
||
|
if err := encodeString(buf, string(l)); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return buf.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
func (l *CodableLabelName) UnmarshalBinary(buf []byte) error {
|
||
|
r := bytes.NewReader(buf)
|
||
|
n, err := decodeString(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
*l = CodableLabelName(n)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type CodableLabelValues clientmodel.LabelValues
|
||
|
|
||
|
func (vs CodableLabelValues) MarshalBinary() ([]byte, error) {
|
||
|
buf := &bytes.Buffer{}
|
||
|
if err := EncodeVarint(buf, int64(len(vs))); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
for _, v := range vs {
|
||
|
if err := encodeString(buf, string(v)); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
return buf.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
func (vs *CodableLabelValues) UnmarshalBinary(buf []byte) error {
|
||
|
r := bytes.NewReader(buf)
|
||
|
numValues, err := binary.ReadVarint(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
*vs = make(CodableLabelValues, numValues)
|
||
|
|
||
|
for i, _ := range *vs {
|
||
|
v, err := decodeString(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
(*vs)[i] = clientmodel.LabelValue(v)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type CodableTimeRange struct {
|
||
|
first, last clientmodel.Timestamp
|
||
|
}
|
||
|
|
||
|
func (tr CodableTimeRange) MarshalBinary() ([]byte, error) {
|
||
|
buf := &bytes.Buffer{}
|
||
|
if err := EncodeVarint(buf, int64(tr.first)); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if err := EncodeVarint(buf, int64(tr.last)); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return buf.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
func (tr *CodableTimeRange) UnmarshalBinary(buf []byte) error {
|
||
|
r := bytes.NewReader(buf)
|
||
|
first, err := binary.ReadVarint(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
last, err := binary.ReadVarint(r)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
tr.first = clientmodel.Timestamp(first)
|
||
|
tr.last = clientmodel.Timestamp(last)
|
||
|
return nil
|
||
|
}
|