func (f *LogFile) TagValueIterator(name, key []byte) TagValueIterator {
	f.mu.RLock()
	defer f.mu.RUnlock()
	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}
	tk, ok := mm.tagSet[string(key)]
	if !ok {
		return nil
	}
	return tk.TagValueIterator()
}
TagValueIterator returns a value iterator for a tag key.
package tsi1
import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"hash/crc32"
	"io"
	"os"
	"sort"
	"sync"
	"time"
	"github.com/influxdata/influxdb/models"
	"github.com/influxdata/influxdb/pkg/bloom"
	"github.com/influxdata/influxdb/pkg/estimator"
	"github.com/influxdata/influxdb/pkg/estimator/hll"
	"github.com/influxdata/influxdb/pkg/mmap"
	"github.com/influxdata/influxdb/tsdb"
)
var (
	ErrLogEntryChecksumMismatch = errors.New("log entry checksum mismatch")
)
const (
	LogEntrySeriesTombstoneFlag      = 0x01
	LogEntryMeasurementTombstoneFlag = 0x02
	LogEntryTagKeyTombstoneFlag      = 0x04
	LogEntryTagValueTombstoneFlag    = 0x08
)
type LogFile struct {
	mu     sync.RWMutex
	wg     sync.WaitGroup  
	id     int             
	data   []byte          
	file   *os.File        
	w      *bufio.Writer   
	buf    []byte          
	keyBuf []byte
	sfile   *tsdb.SeriesFile  
	size    int64             
	modTime time.Time         
	mSketch, mTSketch estimator.Sketch  
	sSketch, sTSketch estimator.Sketch  
	seriesIDSet, tombstoneSeriesIDSet *tsdb.SeriesIDSet
	mms logMeasurements
	path string
}
func NewLogFile(sfile *tsdb.SeriesFile, path string) *LogFile {
	return &LogFile{
		sfile:    sfile,
		path:     path,
		mms:      make(logMeasurements),
		mSketch:  hll.NewDefaultPlus(),
		mTSketch: hll.NewDefaultPlus(),
		sSketch:  hll.NewDefaultPlus(),
		sTSketch: hll.NewDefaultPlus(),
		seriesIDSet:          tsdb.NewSeriesIDSet(),
		tombstoneSeriesIDSet: tsdb.NewSeriesIDSet(),
	}
}
func (f *LogFile) Open() error {
	if err := f.open(); err != nil {
		f.Close()
		return err
	}
	return nil
}
func (f *LogFile) open() error {
	f.id, _ = ParseFilename(f.path)
	file, err := os.OpenFile(f.Path(), os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return err
	}
	f.file = file
	f.w = bufio.NewWriter(f.file)
	fi, err := file.Stat()
	if err != nil {
		return err
	} else if fi.Size() == 0 {
		return nil
	}
	f.size = fi.Size()
	f.modTime = fi.ModTime()
	data, err := mmap.Map(f.Path(), 0)
	if err != nil {
		return err
	}
	f.data = data
	var n int64
	for buf := f.data; len(buf) > 0; {
		var e LogEntry
		if err := e.UnmarshalBinary(buf); err == io.ErrShortBuffer || err == ErrLogEntryChecksumMismatch {
			break
		} else if err != nil {
			return err
		}
		f.execEntry(&e)
		n += int64(e.Size)
		buf = buf[e.Size:]
	}
	f.size = n
	if _, err := file.Seek(n, io.SeekStart); err != nil {
		return err
	}
	return nil
}
func (f *LogFile) Close() error {
	f.wg.Wait()
	if f.w != nil {
		f.w.Flush()
		f.w = nil
	}
	if f.file != nil {
		f.file.Close()
		f.file = nil
	}
	if f.data != nil {
		mmap.Unmap(f.data)
	}
	f.mms = make(logMeasurements)
	return nil
}
func (f *LogFile) Flush() error {
	if f.w != nil {
		return f.w.Flush()
	}
	return nil
}
func (f *LogFile) ID() int { return f.id }
func (f *LogFile) Path() string { return f.path }
func (f *LogFile) SetPath(path string) { f.path = path }
func (f *LogFile) Level() int { return 0 }
func (f *LogFile) Filter() *bloom.Filter { return nil }
func (f *LogFile) Retain() { f.wg.Add(1) }
func (f *LogFile) Release() { f.wg.Done() }
func (f *LogFile) Stat() (int64, time.Time) {
	f.mu.RLock()
	size, modTime := f.size, f.modTime
	f.mu.RUnlock()
	return size, modTime
}
func (f *LogFile) SeriesIDSet() (*tsdb.SeriesIDSet, error) {
	return f.seriesIDSet, nil
}
func (f *LogFile) TombstoneSeriesIDSet() (*tsdb.SeriesIDSet, error) {
	return f.tombstoneSeriesIDSet, nil
}
func (f *LogFile) Size() int64 {
	f.mu.RLock()
	v := f.size
	f.mu.RUnlock()
	return v
}
func (f *LogFile) Measurement(name []byte) MeasurementElem {
	f.mu.RLock()
	defer f.mu.RUnlock()
	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}
	return mm
}
func (f *LogFile) MeasurementHasSeries(ss *tsdb.SeriesIDSet, name []byte) bool {
	f.mu.RLock()
	defer f.mu.RUnlock()
	mm, ok := f.mms[string(name)]
	if !ok {
		return false
	}
	for id := range mm.series {
		if ss.Contains(id) {
			return true
		}
	}
	return false
}
func (f *LogFile) MeasurementNames() []string {
	f.mu.RLock()
	defer f.mu.RUnlock()
	return f.measurementNames()
}
func (f *LogFile) measurementNames() []string {
	a := make([]string, 0, len(f.mms))
	for name := range f.mms {
		a = append(a, name)
	}
	sort.Strings(a)
	return a
}
func (f *LogFile) DeleteMeasurement(name []byte) error {
	f.mu.Lock()
	defer f.mu.Unlock()
	e := LogEntry{Flag: LogEntryMeasurementTombstoneFlag, Name: name}
	if err := f.appendEntry(&e); err != nil {
		return err
	}
	f.execEntry(&e)
	return nil
}
func (f *LogFile) TagKeySeriesIDIterator(name, key []byte) tsdb.SeriesIDIterator {
	f.mu.RLock()
	defer f.mu.RUnlock()
	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}
	tk, ok := mm.tagSet[string(key)]
	if !ok {
		return nil
	}
	itrs := make([]tsdb.SeriesIDIterator, 0, len(tk.tagValues))
	for _, tv := range tk.tagValues {
		if len(tv.series) == 0 {
			continue
		}
		itrs = append(itrs, newLogSeriesIDIterator(tv.series))
	}
	return tsdb.MergeSeriesIDIterators(itrs...)
}
func (f *LogFile) TagKeyIterator(name []byte) TagKeyIterator {
	f.mu.RLock()
	defer f.mu.RUnlock()
	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}
	a := make([]logTagKey, 0, len(mm.tagSet))
	for _, k := range mm.tagSet {
		a = append(a, k)
	}
	return newLogTagKeyIterator(a)
}
func (f *LogFile) TagKey(name, key []byte) TagKeyElem {
	f.mu.RLock()
	defer f.mu.RUnlock()
	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}
	tk, ok := mm.tagSet[string(key)]
	if !ok {
		return nil
	}
	return &tk
}
func (f *LogFile) TagValue(name, key, value []byte) TagValueElem {
	f.mu.RLock()
	defer f.mu.RUnlock()
	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}
	tk, ok := mm.tagSet[string(key)]
	if !ok {
		return nil
	}
	tv, ok := tk.tagValues[string(value)]
	if !ok {
		return nil
	}
	return &tv
}