func (pb *Block) Chunks() (ChunkReader, error) {
	if err := pb.startRead(); err != nil {
		return nil, err
	}
	return blockChunkReader{ChunkReader: pb.chunkr, b: pb}, nil
}
Chunks returns a new ChunkReader against the block data.
package tsdb
import (
	"encoding/json"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/oklog/ulid"
	"github.com/pkg/errors"
	"github.com/prometheus/prometheus/tsdb/chunkenc"
	"github.com/prometheus/prometheus/tsdb/chunks"
	tsdb_errors "github.com/prometheus/prometheus/tsdb/errors"
	"github.com/prometheus/prometheus/tsdb/fileutil"
	"github.com/prometheus/prometheus/tsdb/index"
	"github.com/prometheus/prometheus/tsdb/labels"
	"github.com/prometheus/prometheus/tsdb/tombstones"
)
type IndexWriter interface {
	AddSymbols(sym map[string]struct{}) error
	AddSeries(ref uint64, l labels.Labels, chunks ...chunks.Meta) error
	WriteLabelIndex(names []string, values []string) error
	WritePostings(name, value string, it index.Postings) error
	Close() error
}
type IndexReader interface {
	Symbols() (map[string]struct{}, error)
	LabelValues(names ...string) (index.StringTuples, error)
	Postings(name, value string) (index.Postings, error)
	SortedPostings(index.Postings) index.Postings
	Series(ref uint64, lset *labels.Labels, chks *[]chunks.Meta) error
	LabelIndices() ([][]string, error)
	LabelNames() ([]string, error)
	Close() error
}
type StringTuples interface {
	Len() int
	At(i int) ([]string, error)
}
type ChunkWriter interface {
	WriteChunks(chunks ...chunks.Meta) error
	Close() error
}
type ChunkReader interface {
	Chunk(ref uint64) (chunkenc.Chunk, error)
	Close() error
}
type BlockReader interface {
	Index() (IndexReader, error)
	Chunks() (ChunkReader, error)
	Tombstones() (tombstones.Reader, error)
	Meta() BlockMeta
}
type Appendable interface {
	Appender() Appender
}
type BlockMeta struct {
	ULID ulid.ULID `json:"ulid"`
	MinTime int64 `json:"minTime"`
	MaxTime int64 `json:"maxTime"`
	Stats BlockStats `json:"stats,omitempty"`
	Compaction BlockMetaCompaction `json:"compaction"`
	Version int `json:"version"`
}
type BlockStats struct {
	NumSamples    uint64 `json:"numSamples,omitempty"`
	NumSeries     uint64 `json:"numSeries,omitempty"`
	NumChunks     uint64 `json:"numChunks,omitempty"`
	NumTombstones uint64 `json:"numTombstones,omitempty"`
}
type BlockDesc struct {
	ULID    ulid.ULID `json:"ulid"`
	MinTime int64     `json:"minTime"`
	MaxTime int64     `json:"maxTime"`
}
type BlockMetaCompaction struct {
	Level int `json:"level"`
	Sources []ulid.ULID `json:"sources,omitempty"`
	Deletable bool `json:"deletable,omitempty"`
	Parents []BlockDesc `json:"parents,omitempty"`
	Failed  bool        `json:"failed,omitempty"`
}
const indexFilename = "index"
const metaFilename = "meta.json"
const metaVersion1 = 1
func chunkDir(dir string) string { return filepath.Join(dir, "chunks") }
func readMetaFile(dir string) (*BlockMeta, int64, error) {
	b, err := ioutil.ReadFile(filepath.Join(dir, metaFilename))
	if err != nil {
		return nil, 0, err
	}
	var m BlockMeta
	if err := json.Unmarshal(b, &m); err != nil {
		return nil, 0, err
	}
	if m.Version != metaVersion1 {
		return nil, 0, errors.Errorf("unexpected meta file version %d", m.Version)
	}
	return &m, int64(len(b)), nil
}
func writeMetaFile(logger log.Logger, dir string, meta *BlockMeta) (int64, error) {
	meta.Version = metaVersion1
	path := filepath.Join(dir, metaFilename)
	tmp := path + ".tmp"
	defer func() {
		if err := os.RemoveAll(tmp); err != nil {
			level.Error(logger).Log("msg", "remove tmp file", "err", err.Error())
		}
	}()
	f, err := os.Create(tmp)
	if err != nil {
		return 0, err
	}
	jsonMeta, err := json.MarshalIndent(meta, "", "\t")
	if err != nil {
		return 0, err
	}
	var merr tsdb_errors.MultiError
	n, err := f.Write(jsonMeta)
	if err != nil {
		merr.Add(err)
		merr.Add(f.Close())
		return 0, merr.Err()
	}
	if err := f.Sync(); err != nil {
		merr.Add(err)
		merr.Add(f.Close())
		return 0, merr.Err()
	}
	if err := f.Close(); err != nil {
		return 0, err
	}
	return int64(n), fileutil.Replace(tmp, path)
}
type Block struct {
	mtx            sync.RWMutex
	closing        bool
	pendingReaders sync.WaitGroup
	dir  string
	meta BlockMeta
	symbolTableSize uint64
	chunkr     ChunkReader
	indexr     IndexReader
	tombstones tombstones.Reader
	logger log.Logger
	numBytesChunks    int64
	numBytesIndex     int64
	numBytesTombstone int64
	numBytesMeta      int64
}
func OpenBlock(logger log.Logger, dir string, pool chunkenc.Pool) (pb *Block, err error) {
	if logger == nil {
		logger = log.NewNopLogger()
	}
	var closers []io.Closer
	defer func() {
		if err != nil {
			var merr tsdb_errors.MultiError
			merr.Add(err)
			merr.Add(closeAll(closers))
			err = merr.Err()
		}
	}()
	meta, sizeMeta, err := readMetaFile(dir)
	if err != nil {
		return nil, err
	}
	cr, err := chunks.NewDirReader(chunkDir(dir), pool)
	if err != nil {
		return nil, err
	}
	closers = append(closers, cr)
	ir, err := index.NewFileReader(filepath.Join(dir, indexFilename))
	if err != nil {
		return nil, err
	}
	closers = append(closers, ir)
	tr, sizeTomb, err := tombstones.ReadTombstones(dir)
	if err != nil {
		return nil, err
	}
	closers = append(closers, tr)
	pb = &Block{
		dir:               dir,
		meta:              *meta,
		chunkr:            cr,
		indexr:            ir,
		tombstones:        tr,
		symbolTableSize:   ir.SymbolTableSize(),
		logger:            logger,
		numBytesChunks:    cr.Size(),
		numBytesIndex:     ir.Size(),
		numBytesTombstone: sizeTomb,
		numBytesMeta:      sizeMeta,
	}
	return pb, nil
}
func (pb *Block) Close() error {
	pb.mtx.Lock()
	pb.closing = true
	pb.mtx.Unlock()
	pb.pendingReaders.Wait()
	var merr tsdb_errors.MultiError
	merr.Add(pb.chunkr.Close())
	merr.Add(pb.indexr.Close())
	merr.Add(pb.tombstones.Close())
	return merr.Err()
}
func (pb *Block) String() string {
	return pb.meta.ULID.String()
}
func (pb *Block) Dir() string { return pb.dir }
func (pb *Block) Meta() BlockMeta { return pb.meta }
func (pb *Block) MinTime() int64 { return pb.meta.MinTime }
func (pb *Block) MaxTime() int64 { return pb.meta.MaxTime }
func (pb *Block) Size() int64 {
	return pb.numBytesChunks + pb.numBytesIndex + pb.numBytesTombstone + pb.numBytesMeta
}
var ErrClosing = errors.New("block is closing")
func (pb *Block) startRead() error {
	pb.mtx.RLock()
	defer pb.mtx.RUnlock()
	if pb.closing {
		return ErrClosing
	}
	pb.pendingReaders.Add(1)
	return nil
}
func (pb *Block) Index() (IndexReader, error) {
	if err := pb.startRead(); err != nil {
		return nil, err
	}
	return blockIndexReader{ir: pb.indexr, b: pb}, nil
}