func (enc *TagBlockEncoder) encodeTagKeyBlock() error {
	offsets := rhh.NewHashMap(rhh.Options{Capacity: int64(len(enc.keys)), LoadFactor: LoadFactor})
	enc.trailer.KeyData.Offset = enc.n
	for i := range enc.keys {
		entry := &enc.keys[i]
		offsets.Put(entry.key, enc.n)
		if err := writeUint8To(enc.w, encodeTagKeyFlag(entry.deleted), &enc.n); err != nil {
			return err
		}
		if err := writeUint64To(enc.w, uint64(entry.data.offset), &enc.n); err != nil {
			return err
		} else if err := writeUint64To(enc.w, uint64(entry.data.size), &enc.n); err != nil {
			return err
		}
		if err := writeUint64To(enc.w, uint64(entry.hashIndex.offset), &enc.n); err != nil {
			return err
		} else if err := writeUint64To(enc.w, uint64(entry.hashIndex.size), &enc.n); err != nil {
			return err
		}
		if err := writeUvarintTo(enc.w, uint64(len(entry.key)), &enc.n); err != nil {
			return err
		} else if err := writeTo(enc.w, entry.key, &enc.n); err != nil {
			return err
		}
	}
	enc.trailer.KeyData.Size = enc.n - enc.trailer.KeyData.Offset
	enc.trailer.HashIndex.Offset = enc.n
	if err := writeUint64To(enc.w, uint64(offsets.Cap()), &enc.n); err != nil {
		return err
	}
	for i := int64(0); i < offsets.Cap(); i++ {
		_, v := offsets.Elem(i)
		offset, _ := v.(int64)
		if err := writeUint64To(enc.w, uint64(offset), &enc.n); err != nil {
			return err
		}
	}
	enc.trailer.HashIndex.Size = enc.n - enc.trailer.HashIndex.Offset
	return nil
}
encodeTagKeyBlock encodes the keys section to the writer.
package tsi1
import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"github.com/influxdata/influxdb/pkg/rhh"
)
const TagBlockVersion = 1
const (
	TagKeyTombstoneFlag = 0x01
)
const (
	TagValueTombstoneFlag = 0x01
)
const (
	TagKeyNSize      = 8
	TagKeyOffsetSize = 8
	TagValueNSize      = 8
	TagValueOffsetSize = 8
)
var (
	ErrUnsupportedTagBlockVersion = errors.New("unsupported tag block version")
	ErrTagBlockSizeMismatch       = errors.New("tag block size mismatch")
)
type TagBlock struct {
	data []byte
	valueData []byte
	keyData   []byte
	hashData  []byte
	version int  
}
func (blk *TagBlock) Version() int { return blk.version }
func (blk *TagBlock) UnmarshalBinary(data []byte) error {
	t, err := ReadTagBlockTrailer(data)
	if err != nil {
		return err
	}
	if int64(len(data)) != t.Size {
		return ErrTagBlockSizeMismatch
	}
	blk.valueData = data[t.ValueData.Offset:]
	blk.valueData = blk.valueData[:t.ValueData.Size]
	blk.keyData = data[t.KeyData.Offset:]
	blk.keyData = blk.keyData[:t.KeyData.Size]
	blk.hashData = data[t.HashIndex.Offset:]
	blk.hashData = blk.hashData[:t.HashIndex.Size]
	blk.data = data
	return nil
}
func (blk *TagBlock) TagKeyElem(key []byte) TagKeyElem {
	var elem TagBlockKeyElem
	if !blk.DecodeTagKeyElem(key, &elem) {
		return nil
	}
	return &elem
}
func (blk *TagBlock) DecodeTagKeyElem(key []byte, elem *TagBlockKeyElem) bool {
	keyN := int64(binary.BigEndian.Uint64(blk.hashData[:TagKeyNSize]))
	hash := rhh.HashKey(key)
	pos := hash % keyN
	var d int64
	for {
		offset := binary.BigEndian.Uint64(blk.hashData[TagKeyNSize+(pos*TagKeyOffsetSize):])
		if offset == 0 {
			return false
		}
		elem.unmarshal(blk.data[offset:], blk.data)
		if bytes.Equal(elem.key, key) {
			return true
		}
		if d > rhh.Dist(rhh.HashKey(elem.key), pos, keyN) {
			return false
		}
		pos = (pos + 1) % keyN
		d++
		if d > keyN {
			return false
		}
	}
}
func (blk *TagBlock) TagValueElem(key, value []byte) TagValueElem {
	var valueElem TagBlockValueElem
	if !blk.DecodeTagValueElem(key, value, &valueElem) {
		return nil
	}
	return &valueElem
}
func (blk *TagBlock) TagValueSeriesData(key, value []byte) (uint64, []byte) {
	var valueElem TagBlockValueElem
	if !blk.DecodeTagValueElem(key, value, &valueElem) {
		return 0, nil
	}
	return valueElem.series.n, valueElem.series.data
}
func (blk *TagBlock) DecodeTagValueElem(key, value []byte, valueElem *TagBlockValueElem) bool {
	var keyElem TagBlockKeyElem
	if !blk.DecodeTagKeyElem(key, &keyElem) {
		return false
	}
	hashData := keyElem.hashIndex.buf
	valueN := int64(binary.BigEndian.Uint64(hashData[:TagValueNSize]))
	hash := rhh.HashKey(value)
	pos := hash % valueN
	var d int64
	for {
		offset := binary.BigEndian.Uint64(hashData[TagValueNSize+(pos*TagValueOffsetSize):])
		if offset == 0 {
			return false
		}
		valueElem.unmarshal(blk.data[offset:])
		if bytes.Equal(valueElem.value, value) {
			return true
		}
		max := rhh.Dist(rhh.HashKey(valueElem.value), pos, valueN)
		if d > max {
			return false
		}
		pos = (pos + 1) % valueN
		d++
		if d > valueN {
			return false
		}
	}
}
func (blk *TagBlock) TagKeyIterator() TagKeyIterator {
	return &tagBlockKeyIterator{
		blk:     blk,
		keyData: blk.keyData,
	}
}
type tagBlockKeyIterator struct {
	blk     *TagBlock
	keyData []byte
	e       TagBlockKeyElem
}
func (itr *tagBlockKeyIterator) Next() TagKeyElem {
	if len(itr.keyData) == 0 {
		return nil
	}
	itr.e.unmarshal(itr.keyData, itr.blk.data)
	itr.keyData = itr.keyData[itr.e.size:]
	assert(len(itr.e.Key()) > 0, "invalid zero-length tag key")
	return &itr.e
}
type tagBlockValueIterator struct {
	data []byte
	e    TagBlockValueElem
}
func (itr *tagBlockValueIterator) Next() TagValueElem {
	if len(itr.data) == 0 {
		return nil
	}
	itr.e.unmarshal(itr.data)
	itr.data = itr.data[itr.e.size:]
	assert(len(itr.e.Value()) > 0, "invalid zero-length tag value")
	return &itr.e
}
type TagBlockKeyElem struct {
	flag byte
	key  []byte
	data struct {
		offset uint64
		size   uint64
		buf    []byte
	}
	hashIndex struct {
		offset uint64
		size   uint64
		buf    []byte
	}
	size int
}
func (e *TagBlockKeyElem) Deleted() bool { return (e.flag & TagKeyTombstoneFlag) != 0 }
func (e *TagBlockKeyElem) Key() []byte { return e.key }
func (e *TagBlockKeyElem) TagValueIterator() TagValueIterator {
	return &tagBlockValueIterator{data: e.data.buf}
}
func (e *TagBlockKeyElem) unmarshal(buf, data []byte) {
	start := len(buf)
	e.flag, buf = buf[0], buf[1:]
	e.data.offset, buf = binary.BigEndian.Uint64(buf), buf[8:]
	e.data.size, buf = binary.BigEndian.Uint64(buf), buf[8:]
	e.data.buf = data[e.data.offset:]
	e.data.buf = e.data.buf[:e.data.size]
	e.hashIndex.offset, buf = binary.BigEndian.Uint64(buf), buf[8:]
	e.hashIndex.size, buf = binary.BigEndian.Uint64(buf), buf[8:]
	e.hashIndex.buf = data[e.hashIndex.offset:]
	e.hashIndex.buf = e.hashIndex.buf[:e.hashIndex.size]
	n, sz := binary.Uvarint(buf)
	e.key, buf = buf[sz:sz+int(n)], buf[int(n)+sz:]
	e.size = start - len(buf)
}
type TagBlockValueElem struct {
	flag   byte
	value  []byte
	series struct {
		n    uint64  
		data []byte  
	}
	size int
}
func (e *TagBlockValueElem) Deleted() bool { return (e.flag & TagValueTombstoneFlag) != 0 }
func (e *TagBlockValueElem) Value() []byte { return e.value }
func (e *TagBlockValueElem) SeriesN() uint64 { return e.series.n }
func (e *TagBlockValueElem) SeriesData() []byte { return e.series.data }
func (e *TagBlockValueElem) SeriesID(i int) uint64 {
	return binary.BigEndian.Uint64(e.series.data[i*SeriesIDSize:])
}
func (e *TagBlockValueElem) SeriesIDs() []uint64 {
	a := make([]uint64, 0, e.series.n)
	var prev uint64
	for data := e.series.data; len(data) > 0; {
		delta, n := binary.Uvarint(data)
		data = data[n:]
		seriesID := prev + uint64(delta)
		a = append(a, seriesID)
		prev = seriesID
	}
	return a
}
func (e *TagBlockValueElem) Size() int { return e.size }
func (e *TagBlockValueElem) unmarshal(buf []byte) {
	start := len(buf)
	e.flag, buf = buf[0], buf[1:]
	sz, n := binary.Uvarint(buf)
	e.value, buf = buf[n:n+int(sz)], buf[n+int(sz):]
	v, n := binary.Uvarint(buf)
	e.series.n = uint64(v)
	buf = buf[n:]
	sz, n = binary.Uvarint(buf)
	buf = buf[n:]
	e.series.data = buf[:sz]
	buf = buf[sz:]
	e.size = start - len(buf)
}
const TagBlockTrailerSize = 0 +
	8 + 8 +  
	8 + 8 +  
	8 + 8 +  
	8 +  
	2  
type TagBlockTrailer struct {
	Version int    
	Size    int64  
	ValueData struct {
		Offset int64
		Size   int64
	}
	KeyData struct {
		Offset int64
		Size   int64
	}
	HashIndex struct {
		Offset int64
		Size   int64
	}
}
func (t *TagBlockTrailer) WriteTo(w io.Writer) (n int64, err error) {
	if err := writeUint64To(w, uint64(t.ValueData.Offset), &n); err != nil {
		return n, err
	} else if err := writeUint64To(w, uint64(t.ValueData.Size), &n); err != nil {
		return n, err
	}
	if err := writeUint64To(w, uint64(t.KeyData.Offset), &n); err != nil {
		return n, err
	} else if err := writeUint64To(w, uint64(t.KeyData.Size), &n); err != nil {
		return n, err
	}
	if err := writeUint64To(w, uint64(t.HashIndex.Offset), &n); err != nil {
		return n, err
	} else if err := writeUint64To(w, uint64(t.HashIndex.Size), &n); err != nil {
		return n, err
	}
	if err := writeUint64To(w, uint64(t.Size), &n); err != nil {
		return n, err
	} else if err := writeUint16To(w, IndexFileVersion, &n); err != nil {
		return n, err
	}
	return n, nil
}
func ReadTagBlockTrailer(data []byte) (TagBlockTrailer, error) {
	var t TagBlockTrailer
	t.Version = int(binary.BigEndian.Uint16(data[len(data)-2:]))
	if t.Version != TagBlockVersion {
		return t, ErrUnsupportedTagBlockVersion
	}
	buf := data[len(data)-TagBlockTrailerSize:]
	t.ValueData.Offset, buf = int64(binary.BigEndian.Uint64(buf[0:8])), buf[8:]
	t.ValueData.Size, buf = int64(binary.BigEndian.Uint64(buf[0:8])), buf[8:]
	t.KeyData.Offset, buf = int64(binary.BigEndian.Uint64(buf[0:8])), buf[8:]
	t.KeyData.Size, buf = int64(binary.BigEndian.Uint64(buf[0:8])), buf[8:]
	t.HashIndex.Offset, buf = int64(binary.BigEndian.Uint64(buf[0:8])), buf[8:]
	t.HashIndex.Size, buf = int64(binary.BigEndian.Uint64(buf[0:8])), buf[8:]
	t.Size = int64(binary.BigEndian.Uint64(buf[0:8]))
	return t, nil
}
type TagBlockEncoder struct {
	w   io.Writer
	buf bytes.Buffer
	offsets *rhh.HashMap
	n       int64
	trailer TagBlockTrailer
	keys      []tagKeyEncodeEntry
	prevValue []byte
}
func NewTagBlockEncoder(w io.Writer) *TagBlockEncoder {
	return &TagBlockEncoder{
		w:       w,
		offsets: rhh.NewHashMap(rhh.Options{LoadFactor: LoadFactor}),
		trailer: TagBlockTrailer{
			Version: TagBlockVersion,
		},
	}
}
func (enc *TagBlockEncoder) N() int64 { return enc.n }
func (enc *TagBlockEncoder) EncodeKey(key []byte, deleted bool) error {
	if err := enc.ensureHeaderWritten(); err != nil {
		return err
	}
	if len(enc.keys) > 0 {
		prev := enc.keys[len(enc.keys)-1].key
		if cmp := bytes.Compare(prev, key); cmp == 1 {
			return fmt.Errorf("tag key out of order: prev=%s, new=%s", prev, key)
		} else if cmp == 0 {
			return fmt.Errorf("tag key already encoded: %s", key)
		}
	}
	if err := enc.flushValueHashIndex(); err != nil {
		return err
	}
	entry := tagKeyEncodeEntry{
		key:     key,
		deleted: deleted,
	}
	entry.data.offset = enc.n
	enc.keys = append(enc.keys, entry)
	enc.prevValue = nil
	return nil
}
func (enc *TagBlockEncoder) EncodeValue(value []byte, deleted bool, seriesIDs []uint64) error {
	if len(enc.keys) == 0 {
		return fmt.Errorf("tag key must be encoded before encoding values")
	} else if len(value) == 0 {
		return fmt.Errorf("zero length tag value not allowed")
	}
	if cmp := bytes.Compare(enc.prevValue, value); cmp == 1 {
		return fmt.Errorf("tag value out of order: prev=%s, new=%s", enc.prevValue, value)
	} else if cmp == 0 {
		return fmt.Errorf("tag value already encoded: %s", value)
	}
	enc.offsets.Put(value, enc.n)
	if err := writeUint8To(enc.w, encodeTagValueFlag(deleted), &enc.n); err != nil {
		return err
	}
	if err := writeUvarintTo(enc.w, uint64(len(value)), &enc.n); err != nil {
		return err
	} else if err := writeTo(enc.w, value, &enc.n); err != nil {
		return err
	}
	enc.buf.Reset()
	var prev uint64
	for _, seriesID := range seriesIDs {
		delta := seriesID - prev
		var buf [binary.MaxVarintLen32]byte
		i := binary.PutUvarint(buf[:], uint64(delta))
		if _, err := enc.buf.Write(buf[:i]); err != nil {
			return err
		}
		prev = seriesID
	}
	if err := writeUvarintTo(enc.w, uint64(len(seriesIDs)), &enc.n); err != nil {
		return err
	}
	if err := writeUvarintTo(enc.w, uint64(enc.buf.Len()), &enc.n); err != nil {
		return err
	}
	nn, err := enc.buf.WriteTo(enc.w)
	if enc.n += nn; err != nil {
		return err
	}
	enc.prevValue = value
	return nil
}
func (enc *TagBlockEncoder) Close() error {
	if err := enc.ensureHeaderWritten(); err != nil {
		return err
	} else if err := enc.flushValueHashIndex(); err != nil {
		return err
	}
	enc.trailer.ValueData.Size = enc.n - enc.trailer.ValueData.Offset
	if err := enc.encodeTagKeyBlock(); err != nil {
		return err
	}
	enc.trailer.Size = enc.n + TagBlockTrailerSize
	nn, err := enc.trailer.WriteTo(enc.w)
	enc.n += nn
	return err
}
func (enc *TagBlockEncoder) ensureHeaderWritten() error {
	if enc.n > 0 {
		return nil
	} else if _, err := enc.w.Write([]byte{0}); err != nil {
		return err
	}
	enc.n++
	enc.trailer.ValueData.Offset = enc.n
	return nil
}
func (enc *TagBlockEncoder) flushValueHashIndex() error {
	if len(enc.keys) == 0 {
		return nil
	}
	key := &enc.keys[len(enc.keys)-1]
	key.data.size = enc.n - key.data.offset
	key.hashIndex.offset = enc.n
	if err := writeUint64To(enc.w, uint64(enc.offsets.Cap()), &enc.n); err != nil {
		return err
	}
	for i := int64(0); i < enc.offsets.Cap(); i++ {
		_, v := enc.offsets.Elem(i)
		offset, _ := v.(int64)
		if err := writeUint64To(enc.w, uint64(offset), &enc.n); err != nil {
			return err
		}
	}
	key.hashIndex.size = enc.n - key.hashIndex.offset
	enc.offsets = rhh.NewHashMap(rhh.Options{LoadFactor: LoadFactor})
	return nil
}