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
}
ReadTagBlockTrailer returns the tag block trailer from data.
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
}