| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | package tsdb | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-01-20 14:58:19 +08:00
										 |  |  | 	"bufio" | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | 	"encoding/binary" | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2017-02-16 07:24:53 +08:00
										 |  |  | 	"hash" | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | 	"hash/crc32" | 
					
						
							|  |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2017-02-23 17:50:22 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2016-12-12 18:38:43 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-23 17:50:22 +08:00
										 |  |  | 	"github.com/coreos/etcd/pkg/fileutil" | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 	"github.com/pkg/errors" | 
					
						
							| 
									
										
										
										
											2017-04-04 17:27:26 +08:00
										 |  |  | 	"github.com/prometheus/tsdb/labels" | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	// MagicIndex 4 bytes at the head of an index file.
 | 
					
						
							|  |  |  | 	MagicIndex = 0xBAAAD700 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 	indexFormatV1 = 1 | 
					
						
							| 
									
										
										
										
											2017-02-23 17:50:22 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | const compactionPageBytes = minSectorSize * 64 | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // IndexWriter serialized the index for a block of series data.
 | 
					
						
							|  |  |  | // The methods must generally be called in order they are specified.
 | 
					
						
							|  |  |  | type IndexWriter interface { | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 	// AddSeries populates the index writer witha series and its offsets
 | 
					
						
							|  |  |  | 	// of chunks that the index can reference.
 | 
					
						
							|  |  |  | 	// The reference number is used to resolve a series against the postings
 | 
					
						
							|  |  |  | 	// list iterator. It only has to be available during the write processing.
 | 
					
						
							| 
									
										
										
										
											2017-03-14 22:40:16 +08:00
										 |  |  | 	AddSeries(ref uint32, l labels.Labels, chunks ...*ChunkMeta) error | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// WriteLabelIndex serializes an index from label names to values.
 | 
					
						
							|  |  |  | 	// The passed in values chained tuples of strings of the length of names.
 | 
					
						
							|  |  |  | 	WriteLabelIndex(names []string, values []string) error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// WritePostings writes a postings list for a single label pair.
 | 
					
						
							| 
									
										
										
										
											2017-03-30 07:18:41 +08:00
										 |  |  | 	// The Postings here contain refs to the series that were added.
 | 
					
						
							| 
									
										
										
										
											2016-12-15 04:58:29 +08:00
										 |  |  | 	WritePostings(name, value string, it Postings) error | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-30 07:18:41 +08:00
										 |  |  | 	// Close writes any finalization and closes the resources associated with
 | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | 	// the underlying writer.
 | 
					
						
							|  |  |  | 	Close() error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | type indexWriterSeries struct { | 
					
						
							| 
									
										
										
										
											2016-12-21 16:39:01 +08:00
										 |  |  | 	labels labels.Labels | 
					
						
							| 
									
										
										
										
											2017-03-14 22:40:16 +08:00
										 |  |  | 	chunks []*ChunkMeta // series file offset of chunks
 | 
					
						
							|  |  |  | 	offset uint32       // index file offset of series reference
 | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | // indexWriter implements the IndexWriter interface for the standard
 | 
					
						
							|  |  |  | // serialization format.
 | 
					
						
							|  |  |  | type indexWriter struct { | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	f       *os.File | 
					
						
							|  |  |  | 	bufw    *bufio.Writer | 
					
						
							| 
									
										
										
										
											2017-01-19 18:22:47 +08:00
										 |  |  | 	n       int64 | 
					
						
							|  |  |  | 	started bool | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	// Reusable memory.
 | 
					
						
							|  |  |  | 	b       []byte | 
					
						
							|  |  |  | 	uint32s []uint32 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	series       map[uint32]*indexWriterSeries | 
					
						
							| 
									
										
										
										
											2016-12-10 04:40:38 +08:00
										 |  |  | 	symbols      map[string]uint32 // symbol offsets
 | 
					
						
							| 
									
										
										
										
											2016-12-10 05:12:16 +08:00
										 |  |  | 	labelIndexes []hashEntry       // label index offsets
 | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 	postings     []hashEntry       // postings lists offsets
 | 
					
						
							| 
									
										
										
										
											2017-02-16 07:24:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	crc32 hash.Hash | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | func newIndexWriter(dir string) (*indexWriter, error) { | 
					
						
							|  |  |  | 	df, err := fileutil.OpenDir(dir) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	f, err := os.OpenFile(filepath.Join(dir, "index"), os.O_CREATE|os.O_WRONLY, 0666) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := fileutil.Fsync(df); err != nil { | 
					
						
							|  |  |  | 		return nil, errors.Wrap(err, "sync dir") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	iw := &indexWriter{ | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 		f:    f, | 
					
						
							|  |  |  | 		bufw: bufio.NewWriterSize(f, 1<<22), | 
					
						
							|  |  |  | 		n:    0, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Reusable memory.
 | 
					
						
							|  |  |  | 		b:       make([]byte, 0, 1<<23), | 
					
						
							|  |  |  | 		uint32s: make([]uint32, 0, 1<<15), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Caches.
 | 
					
						
							|  |  |  | 		symbols: make(map[string]uint32, 1<<13), | 
					
						
							|  |  |  | 		series:  make(map[uint32]*indexWriterSeries, 1<<16), | 
					
						
							| 
									
										
										
										
											2017-02-16 07:24:53 +08:00
										 |  |  | 		crc32:   crc32.New(crc32.MakeTable(crc32.Castagnoli)), | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	if err := iw.writeMeta(); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return iw, nil | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (w *indexWriter) write(wr io.Writer, b []byte) error { | 
					
						
							|  |  |  | 	n, err := wr.Write(b) | 
					
						
							|  |  |  | 	w.n += int64(n) | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | // section writes a CRC32 checksummed section of length l and guarded by flag.
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | func (w *indexWriter) section(l int, flag byte, f func(w io.Writer) error) error { | 
					
						
							| 
									
										
										
										
											2017-02-16 07:24:53 +08:00
										 |  |  | 	w.crc32.Reset() | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	wr := io.MultiWriter(w.crc32, w.bufw) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 18:24:20 +08:00
										 |  |  | 	b := [5]byte{flag, 0, 0, 0, 0} | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	binary.BigEndian.PutUint32(b[1:], uint32(l)) | 
					
						
							| 
									
										
										
										
											2016-12-11 01:08:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if err := w.write(wr, b[:]); err != nil { | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 		return errors.Wrap(err, "writing header") | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := f(wr); err != nil { | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 		return errors.Wrap(err, "write contents") | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	if err := w.write(w.bufw, w.crc32.Sum(nil)); err != nil { | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 		return errors.Wrap(err, "writing checksum") | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | func (w *indexWriter) writeMeta() error { | 
					
						
							| 
									
										
										
										
											2016-12-11 22:49:24 +08:00
										 |  |  | 	b := [8]byte{} | 
					
						
							| 
									
										
										
										
											2016-12-11 01:08:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	binary.BigEndian.PutUint32(b[:4], MagicIndex) | 
					
						
							|  |  |  | 	b[4] = flagStd | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	return w.write(w.bufw, b[:]) | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-14 22:40:16 +08:00
										 |  |  | func (w *indexWriter) AddSeries(ref uint32, lset labels.Labels, chunks ...*ChunkMeta) error { | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	if _, ok := w.series[ref]; ok { | 
					
						
							|  |  |  | 		return errors.Errorf("series with reference %d already added", ref) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | 	// Populate the symbol table from all label sets we have to reference.
 | 
					
						
							|  |  |  | 	for _, l := range lset { | 
					
						
							|  |  |  | 		w.symbols[l.Name] = 0 | 
					
						
							|  |  |  | 		w.symbols[l.Value] = 0 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	w.series[ref] = &indexWriterSeries{ | 
					
						
							|  |  |  | 		labels: lset, | 
					
						
							| 
									
										
										
										
											2016-12-16 19:13:17 +08:00
										 |  |  | 		chunks: chunks, | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | func (w *indexWriter) writeSymbols() error { | 
					
						
							|  |  |  | 	// Generate sorted list of strings we will store as reference table.
 | 
					
						
							|  |  |  | 	symbols := make([]string, 0, len(w.symbols)) | 
					
						
							|  |  |  | 	for s := range w.symbols { | 
					
						
							|  |  |  | 		symbols = append(symbols, s) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sort.Strings(symbols) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 	// The start of the section plus a 5 byte section header are our base.
 | 
					
						
							|  |  |  | 	// TODO(fabxc): switch to relative offsets and hold sections in a TOC.
 | 
					
						
							|  |  |  | 	base := uint32(w.n) + 5 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 05:27:43 +08:00
										 |  |  | 	buf := [binary.MaxVarintLen32]byte{} | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	w.b = append(w.b[:0], flagStd) | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, s := range symbols { | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 		w.symbols[s] = base + uint32(len(w.b)) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:12:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 05:27:43 +08:00
										 |  |  | 		n := binary.PutUvarint(buf[:], uint64(len(s))) | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 		w.b = append(w.b, buf[:n]...) | 
					
						
							|  |  |  | 		w.b = append(w.b, s...) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:12:16 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-10 04:23:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	return w.section(len(w.b), flagStd, func(wr io.Writer) error { | 
					
						
							|  |  |  | 		return w.write(wr, w.b) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:27:43 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | type indexWriterSeriesSlice []*indexWriterSeries | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s indexWriterSeriesSlice) Len() int      { return len(s) } | 
					
						
							|  |  |  | func (s indexWriterSeriesSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s indexWriterSeriesSlice) Less(i, j int) bool { | 
					
						
							|  |  |  | 	return labels.Compare(s[i].labels, s[j].labels) < 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 05:27:43 +08:00
										 |  |  | func (w *indexWriter) writeSeries() error { | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 	// Series must be stored sorted along their labels.
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	series := make(indexWriterSeriesSlice, 0, len(w.series)) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:27:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 	for _, s := range w.series { | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 		series = append(series, s) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	sort.Sort(series) | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Current end of file plus 5 bytes for section header.
 | 
					
						
							|  |  |  | 	// TODO(fabxc): switch to relative offsets.
 | 
					
						
							|  |  |  | 	base := uint32(w.n) + 5 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	w.b = w.b[:0] | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 	buf := make([]byte, binary.MaxVarintLen64) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, s := range series { | 
					
						
							| 
									
										
										
										
											2016-12-12 22:39:55 +08:00
										 |  |  | 		// Write label set symbol references.
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 		s.offset = base + uint32(len(w.b)) | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-12 22:39:55 +08:00
										 |  |  | 		n := binary.PutUvarint(buf, uint64(len(s.labels))) | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 		w.b = append(w.b, buf[:n]...) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:27:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 		for _, l := range s.labels { | 
					
						
							| 
									
										
										
										
											2016-12-12 22:39:55 +08:00
										 |  |  | 			n = binary.PutUvarint(buf, uint64(w.symbols[l.Name])) | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 			w.b = append(w.b, buf[:n]...) | 
					
						
							| 
									
										
										
										
											2016-12-12 22:39:55 +08:00
										 |  |  | 			n = binary.PutUvarint(buf, uint64(w.symbols[l.Value])) | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 			w.b = append(w.b, buf[:n]...) | 
					
						
							| 
									
										
										
										
											2016-12-12 22:39:55 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-16 19:13:17 +08:00
										 |  |  | 		// Write chunks meta data including reference into chunk file.
 | 
					
						
							| 
									
										
										
										
											2016-12-12 22:39:55 +08:00
										 |  |  | 		n = binary.PutUvarint(buf, uint64(len(s.chunks))) | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 		w.b = append(w.b, buf[:n]...) | 
					
						
							| 
									
										
										
										
											2016-12-12 22:39:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		for _, c := range s.chunks { | 
					
						
							| 
									
										
										
										
											2016-12-16 19:13:17 +08:00
										 |  |  | 			n = binary.PutVarint(buf, c.MinTime) | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 			w.b = append(w.b, buf[:n]...) | 
					
						
							| 
									
										
										
										
											2016-12-16 19:13:17 +08:00
										 |  |  | 			n = binary.PutVarint(buf, c.MaxTime) | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 			w.b = append(w.b, buf[:n]...) | 
					
						
							| 
									
										
										
										
											2016-12-12 22:39:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-16 19:13:17 +08:00
										 |  |  | 			n = binary.PutUvarint(buf, uint64(c.Ref)) | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 			w.b = append(w.b, buf[:n]...) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:27:43 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	return w.section(len(w.b), flagStd, func(wr io.Writer) error { | 
					
						
							|  |  |  | 		return w.write(wr, w.b) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 14:58:54 +08:00
										 |  |  | func (w *indexWriter) init() error { | 
					
						
							|  |  |  | 	if err := w.writeSymbols(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := w.writeSeries(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	w.started = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | func (w *indexWriter) WriteLabelIndex(names []string, values []string) error { | 
					
						
							| 
									
										
										
										
											2017-01-19 21:01:38 +08:00
										 |  |  | 	if !w.started { | 
					
						
							| 
									
										
										
										
											2017-02-02 14:58:54 +08:00
										 |  |  | 		if err := w.init(); err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-19 21:01:38 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-12 18:38:43 +08:00
										 |  |  | 	valt, err := newStringTuples(values, len(names)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2016-12-10 04:40:38 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-12 18:38:43 +08:00
										 |  |  | 	sort.Sort(valt) | 
					
						
							| 
									
										
										
										
											2016-12-10 04:40:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 05:12:16 +08:00
										 |  |  | 	w.labelIndexes = append(w.labelIndexes, hashEntry{ | 
					
						
							| 
									
										
										
										
											2016-12-12 18:38:43 +08:00
										 |  |  | 		name:   strings.Join(names, string(sep)), | 
					
						
							| 
									
										
										
										
											2016-12-10 05:12:16 +08:00
										 |  |  | 		offset: uint32(w.n), | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-12 22:39:55 +08:00
										 |  |  | 	buf := make([]byte, binary.MaxVarintLen32) | 
					
						
							|  |  |  | 	n := binary.PutUvarint(buf, uint64(len(names))) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	l := n + len(values)*4 | 
					
						
							| 
									
										
										
										
											2016-12-10 05:12:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | 	return w.section(l, flagStd, func(wr io.Writer) error { | 
					
						
							| 
									
										
										
										
											2016-12-12 18:38:43 +08:00
										 |  |  | 		// First byte indicates tuple size for index.
 | 
					
						
							| 
									
										
										
										
											2016-12-12 22:39:55 +08:00
										 |  |  | 		if err := w.write(wr, buf[:n]); err != nil { | 
					
						
							| 
									
										
										
										
											2016-12-12 18:38:43 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for _, v := range valt.s { | 
					
						
							|  |  |  | 			binary.BigEndian.PutUint32(buf, w.symbols[v]) | 
					
						
							| 
									
										
										
										
											2016-12-10 04:40:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 18:24:20 +08:00
										 |  |  | 			if err := w.write(wr, buf[:4]); err != nil { | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-12-10 04:40:38 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 04:58:29 +08:00
										 |  |  | func (w *indexWriter) WritePostings(name, value string, it Postings) error { | 
					
						
							| 
									
										
										
										
											2017-02-02 14:58:54 +08:00
										 |  |  | 	if !w.started { | 
					
						
							|  |  |  | 		if err := w.init(); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 	key := name + string(sep) + value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.postings = append(w.postings, hashEntry{ | 
					
						
							|  |  |  | 		name:   key, | 
					
						
							|  |  |  | 		offset: uint32(w.n), | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 	// Order of the references in the postings list does not imply order
 | 
					
						
							|  |  |  | 	// of the series references within the persisted block they are mapped to.
 | 
					
						
							|  |  |  | 	// We have to sort the new references again.
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	refs := w.uint32s[:0] | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 	for it.Next() { | 
					
						
							| 
									
										
										
										
											2017-01-02 20:27:52 +08:00
										 |  |  | 		s, ok := w.series[it.At()] | 
					
						
							| 
									
										
										
										
											2017-01-02 17:34:55 +08:00
										 |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2017-01-02 20:27:52 +08:00
										 |  |  | 			return errors.Errorf("series for reference %d not found", it.At()) | 
					
						
							| 
									
										
										
										
											2017-01-02 17:34:55 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		refs = append(refs, s.offset) | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if err := it.Err(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	sort.Sort(uint32slice(refs)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.b = w.b[:0] | 
					
						
							|  |  |  | 	buf := make([]byte, 4) | 
					
						
							| 
									
										
										
										
											2016-12-11 01:08:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-20 20:10:37 +08:00
										 |  |  | 	for _, r := range refs { | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 		binary.BigEndian.PutUint32(buf, r) | 
					
						
							|  |  |  | 		w.b = append(w.b, buf...) | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	w.uint32s = refs[:0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return w.section(len(w.b), flagStd, func(wr io.Writer) error { | 
					
						
							|  |  |  | 		return w.write(wr, w.b) | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | type uint32slice []uint32 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s uint32slice) Len() int           { return len(s) } | 
					
						
							|  |  |  | func (s uint32slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] } | 
					
						
							|  |  |  | func (s uint32slice) Less(i, j int) bool { return s[i] < s[j] } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 05:12:16 +08:00
										 |  |  | type hashEntry struct { | 
					
						
							|  |  |  | 	name   string | 
					
						
							|  |  |  | 	offset uint32 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 17:13:54 +08:00
										 |  |  | func (w *indexWriter) writeHashmap(h []hashEntry) error { | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	w.b = w.b[:0] | 
					
						
							| 
									
										
										
										
											2016-12-12 15:12:19 +08:00
										 |  |  | 	buf := [binary.MaxVarintLen32]byte{} | 
					
						
							| 
									
										
										
										
											2016-12-10 05:12:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-11 01:08:50 +08:00
										 |  |  | 	for _, e := range h { | 
					
						
							| 
									
										
										
										
											2016-12-12 15:12:19 +08:00
										 |  |  | 		n := binary.PutUvarint(buf[:], uint64(len(e.name))) | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 		w.b = append(w.b, buf[:n]...) | 
					
						
							|  |  |  | 		w.b = append(w.b, e.name...) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:12:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-12 15:12:19 +08:00
										 |  |  | 		n = binary.PutUvarint(buf[:], uint64(e.offset)) | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 		w.b = append(w.b, buf[:n]...) | 
					
						
							| 
									
										
										
										
											2016-12-11 01:08:50 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 06:35:02 +08:00
										 |  |  | 	return w.section(len(w.b), flagStd, func(wr io.Writer) error { | 
					
						
							|  |  |  | 		return w.write(wr, w.b) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:36:31 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2016-12-10 17:13:54 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 17:13:54 +08:00
										 |  |  | func (w *indexWriter) finalize() error { | 
					
						
							|  |  |  | 	// Write out hash maps to jump to correct label index and postings sections.
 | 
					
						
							|  |  |  | 	lo := uint32(w.n) | 
					
						
							|  |  |  | 	if err := w.writeHashmap(w.labelIndexes); err != nil { | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 17:13:54 +08:00
										 |  |  | 	po := uint32(w.n) | 
					
						
							|  |  |  | 	if err := w.writeHashmap(w.postings); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 17:13:54 +08:00
										 |  |  | 	// Terminate index file with offsets to hashmaps. This is the entry Pointer
 | 
					
						
							|  |  |  | 	// for any index query.
 | 
					
						
							|  |  |  | 	// TODO(fabxc): also store offset to series section to allow plain
 | 
					
						
							|  |  |  | 	// iteration over all existing series?
 | 
					
						
							| 
									
										
										
										
											2016-12-11 01:08:50 +08:00
										 |  |  | 	b := [8]byte{} | 
					
						
							|  |  |  | 	binary.BigEndian.PutUint32(b[:4], lo) | 
					
						
							|  |  |  | 	binary.BigEndian.PutUint32(b[4:], po) | 
					
						
							| 
									
										
										
										
											2016-12-10 16:44:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	return w.write(w.bufw, b[:]) | 
					
						
							| 
									
										
										
										
											2016-12-10 05:12:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | func (w *indexWriter) Close() error { | 
					
						
							| 
									
										
										
										
											2017-01-10 01:34:29 +08:00
										 |  |  | 	if err := w.finalize(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-25 14:24:20 +08:00
										 |  |  | 	if err := w.bufw.Flush(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := fileutil.Fsync(w.f); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return w.f.Close() | 
					
						
							| 
									
										
										
										
											2016-12-10 03:45:46 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // IndexReader provides reading access of serialized index data.
 | 
					
						
							|  |  |  | type IndexReader interface { | 
					
						
							|  |  |  | 	// LabelValues returns the possible label values
 | 
					
						
							|  |  |  | 	LabelValues(names ...string) (StringTuples, error) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Postings returns the postings list iterator for the label pair.
 | 
					
						
							| 
									
										
										
										
											2017-03-30 07:18:41 +08:00
										 |  |  | 	// The Postings here contain the offsets to the series inside the index.
 | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 	Postings(name, value string) (Postings, error) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Series returns the series for the given reference.
 | 
					
						
							| 
									
										
										
										
											2017-03-14 22:40:16 +08:00
										 |  |  | 	Series(ref uint32) (labels.Labels, []*ChunkMeta, error) | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// LabelIndices returns the label pairs for which indices exist.
 | 
					
						
							|  |  |  | 	LabelIndices() ([][]string, error) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Close released the underlying resources of the reader.
 | 
					
						
							|  |  |  | 	Close() error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StringTuples provides access to a sorted list of string tuples.
 | 
					
						
							|  |  |  | type StringTuples interface { | 
					
						
							|  |  |  | 	// Total number of tuples in the list.
 | 
					
						
							|  |  |  | 	Len() int | 
					
						
							|  |  |  | 	// At returns the tuple at position i.
 | 
					
						
							|  |  |  | 	At(i int) ([]string, error) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type indexReader struct { | 
					
						
							|  |  |  | 	// The underlying byte slice holding the encoded series data.
 | 
					
						
							|  |  |  | 	b []byte | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Close that releases the underlying resources of the byte slice.
 | 
					
						
							|  |  |  | 	c io.Closer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Cached hashmaps of section offsets.
 | 
					
						
							|  |  |  | 	labels   map[string]uint32 | 
					
						
							|  |  |  | 	postings map[string]uint32 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	errInvalidSize = fmt.Errorf("invalid size") | 
					
						
							|  |  |  | 	errInvalidFlag = fmt.Errorf("invalid flag") | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newIndexReader returns a new indexReader on the given directory.
 | 
					
						
							|  |  |  | func newIndexReader(dir string) (*indexReader, error) { | 
					
						
							|  |  |  | 	f, err := openMmapFile(filepath.Join(dir, "index")) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	r := &indexReader{b: f.b, c: f} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Verify magic number.
 | 
					
						
							|  |  |  | 	if len(f.b) < 4 { | 
					
						
							|  |  |  | 		return nil, errors.Wrap(errInvalidSize, "index header") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if m := binary.BigEndian.Uint32(r.b[:4]); m != MagicIndex { | 
					
						
							|  |  |  | 		return nil, errors.Errorf("invalid magic number %x", m) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The last two 4 bytes hold the pointers to the hashmaps.
 | 
					
						
							|  |  |  | 	loff := binary.BigEndian.Uint32(r.b[len(r.b)-8 : len(r.b)-4]) | 
					
						
							|  |  |  | 	poff := binary.BigEndian.Uint32(r.b[len(r.b)-4:]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	flag, b, err := r.section(loff) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, errors.Wrapf(err, "label index hashmap section at %d", loff) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if r.labels, err = readHashmap(flag, b); err != nil { | 
					
						
							|  |  |  | 		return nil, errors.Wrap(err, "read label index hashmap") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	flag, b, err = r.section(poff) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, errors.Wrapf(err, "postings hashmap section at %d", loff) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if r.postings, err = readHashmap(flag, b); err != nil { | 
					
						
							|  |  |  | 		return nil, errors.Wrap(err, "read postings hashmap") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return r, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func readHashmap(flag byte, b []byte) (map[string]uint32, error) { | 
					
						
							|  |  |  | 	if flag != flagStd { | 
					
						
							|  |  |  | 		return nil, errInvalidFlag | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	h := make(map[string]uint32, 512) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for len(b) > 0 { | 
					
						
							|  |  |  | 		l, n := binary.Uvarint(b) | 
					
						
							|  |  |  | 		if n < 1 { | 
					
						
							|  |  |  | 			return nil, errors.Wrap(errInvalidSize, "read key length") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b = b[n:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if len(b) < int(l) { | 
					
						
							|  |  |  | 			return nil, errors.Wrap(errInvalidSize, "read key") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		s := string(b[:l]) | 
					
						
							|  |  |  | 		b = b[l:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		o, n := binary.Uvarint(b) | 
					
						
							|  |  |  | 		if n < 1 { | 
					
						
							|  |  |  | 			return nil, errors.Wrap(errInvalidSize, "read offset value") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b = b[n:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		h[s] = uint32(o) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return h, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r *indexReader) Close() error { | 
					
						
							|  |  |  | 	return r.c.Close() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r *indexReader) section(o uint32) (byte, []byte, error) { | 
					
						
							|  |  |  | 	b := r.b[o:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(b) < 5 { | 
					
						
							|  |  |  | 		return 0, nil, errors.Wrap(errInvalidSize, "read header") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	flag := b[0] | 
					
						
							|  |  |  | 	l := binary.BigEndian.Uint32(b[1:5]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b = b[5:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// b must have the given length plus 4 bytes for the CRC32 checksum.
 | 
					
						
							|  |  |  | 	if len(b) < int(l)+4 { | 
					
						
							|  |  |  | 		return 0, nil, errors.Wrap(errInvalidSize, "section content") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return flag, b[:l], nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r *indexReader) lookupSymbol(o uint32) (string, error) { | 
					
						
							|  |  |  | 	if int(o) > len(r.b) { | 
					
						
							|  |  |  | 		return "", errors.Errorf("invalid symbol offset %d", o) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	l, n := binary.Uvarint(r.b[o:]) | 
					
						
							|  |  |  | 	if n < 0 { | 
					
						
							|  |  |  | 		return "", errors.New("reading symbol length failed") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	end := int(o) + n + int(l) | 
					
						
							|  |  |  | 	if end > len(r.b) { | 
					
						
							|  |  |  | 		return "", errors.New("invalid length") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	b := r.b[int(o)+n : end] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return yoloString(b), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r *indexReader) LabelValues(names ...string) (StringTuples, error) { | 
					
						
							|  |  |  | 	key := strings.Join(names, string(sep)) | 
					
						
							|  |  |  | 	off, ok := r.labels[key] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2017-03-20 18:37:06 +08:00
										 |  |  | 		// XXX(fabxc): hot fix. Should return a partial data error and handle cases
 | 
					
						
							|  |  |  | 		// where the entire block has no data gracefully.
 | 
					
						
							|  |  |  | 		return emptyStringTuples{}, nil | 
					
						
							|  |  |  | 		//return nil, fmt.Errorf("label index doesn't exist")
 | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	flag, b, err := r.section(off) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, errors.Wrapf(err, "section at %d", off) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if flag != flagStd { | 
					
						
							|  |  |  | 		return nil, errInvalidFlag | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	l, n := binary.Uvarint(b) | 
					
						
							|  |  |  | 	if n < 1 { | 
					
						
							|  |  |  | 		return nil, errors.Wrap(errInvalidSize, "read label index size") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	st := &serializedStringTuples{ | 
					
						
							|  |  |  | 		l:      int(l), | 
					
						
							|  |  |  | 		b:      b[n:], | 
					
						
							|  |  |  | 		lookup: r.lookupSymbol, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return st, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-20 18:37:06 +08:00
										 |  |  | type emptyStringTuples struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (emptyStringTuples) At(i int) ([]string, error) { return nil, nil } | 
					
						
							|  |  |  | func (emptyStringTuples) Len() int                   { return 0 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | func (r *indexReader) LabelIndices() ([][]string, error) { | 
					
						
							|  |  |  | 	res := [][]string{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for s := range r.labels { | 
					
						
							|  |  |  | 		res = append(res, strings.Split(s, string(sep))) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return res, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-14 22:40:16 +08:00
										 |  |  | func (r *indexReader) Series(ref uint32) (labels.Labels, []*ChunkMeta, error) { | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 	k, n := binary.Uvarint(r.b[ref:]) | 
					
						
							|  |  |  | 	if n < 1 { | 
					
						
							|  |  |  | 		return nil, nil, errors.Wrap(errInvalidSize, "number of labels") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b := r.b[int(ref)+n:] | 
					
						
							|  |  |  | 	lbls := make(labels.Labels, 0, k) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := 0; i < 2*int(k); i += 2 { | 
					
						
							|  |  |  | 		o, m := binary.Uvarint(b) | 
					
						
							|  |  |  | 		if m < 1 { | 
					
						
							|  |  |  | 			return nil, nil, errors.Wrap(errInvalidSize, "symbol offset") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		n, err := r.lookupSymbol(uint32(o)) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, nil, errors.Wrap(err, "symbol lookup") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b = b[m:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		o, m = binary.Uvarint(b) | 
					
						
							|  |  |  | 		if m < 1 { | 
					
						
							|  |  |  | 			return nil, nil, errors.Wrap(errInvalidSize, "symbol offset") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		v, err := r.lookupSymbol(uint32(o)) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, nil, errors.Wrap(err, "symbol lookup") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b = b[m:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		lbls = append(lbls, labels.Label{ | 
					
						
							|  |  |  | 			Name:  n, | 
					
						
							|  |  |  | 			Value: v, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Read the chunks meta data.
 | 
					
						
							|  |  |  | 	k, n = binary.Uvarint(b) | 
					
						
							|  |  |  | 	if n < 1 { | 
					
						
							|  |  |  | 		return nil, nil, errors.Wrap(errInvalidSize, "number of chunks") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b = b[n:] | 
					
						
							| 
									
										
										
										
											2017-03-14 22:40:16 +08:00
										 |  |  | 	chunks := make([]*ChunkMeta, 0, k) | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for i := 0; i < int(k); i++ { | 
					
						
							|  |  |  | 		firstTime, n := binary.Varint(b) | 
					
						
							|  |  |  | 		if n < 1 { | 
					
						
							|  |  |  | 			return nil, nil, errors.Wrap(errInvalidSize, "first time") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b = b[n:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		lastTime, n := binary.Varint(b) | 
					
						
							|  |  |  | 		if n < 1 { | 
					
						
							|  |  |  | 			return nil, nil, errors.Wrap(errInvalidSize, "last time") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b = b[n:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		o, n := binary.Uvarint(b) | 
					
						
							|  |  |  | 		if n < 1 { | 
					
						
							|  |  |  | 			return nil, nil, errors.Wrap(errInvalidSize, "chunk offset") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b = b[n:] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-14 22:40:16 +08:00
										 |  |  | 		chunks = append(chunks, &ChunkMeta{ | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 			Ref:     o, | 
					
						
							|  |  |  | 			MinTime: firstTime, | 
					
						
							|  |  |  | 			MaxTime: lastTime, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return lbls, chunks, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r *indexReader) Postings(name, value string) (Postings, error) { | 
					
						
							|  |  |  | 	key := name + string(sep) + value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	off, ok := r.postings[key] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2017-04-05 20:14:30 +08:00
										 |  |  | 		return emptyPostings, nil | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	flag, b, err := r.section(off) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, errors.Wrapf(err, "section at %d", off) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if flag != flagStd { | 
					
						
							|  |  |  | 		return nil, errors.Wrapf(errInvalidFlag, "section at %d", off) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 02:10:12 +08:00
										 |  |  | 	// Add iterator over the bytes.
 | 
					
						
							|  |  |  | 	if len(b)%4 != 0 { | 
					
						
							|  |  |  | 		return nil, errors.Wrap(errInvalidSize, "plain postings entry") | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-27 16:34:42 +08:00
										 |  |  | 	return newBigEndianPostings(b), nil | 
					
						
							| 
									
										
										
										
											2017-03-07 19:47:49 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type stringTuples struct { | 
					
						
							|  |  |  | 	l int      // tuple length
 | 
					
						
							|  |  |  | 	s []string // flattened tuple entries
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newStringTuples(s []string, l int) (*stringTuples, error) { | 
					
						
							|  |  |  | 	if len(s)%l != 0 { | 
					
						
							|  |  |  | 		return nil, errors.Wrap(errInvalidSize, "string tuple list") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return &stringTuples{s: s, l: l}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (t *stringTuples) Len() int                   { return len(t.s) / t.l } | 
					
						
							|  |  |  | func (t *stringTuples) At(i int) ([]string, error) { return t.s[i : i+t.l], nil } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (t *stringTuples) Swap(i, j int) { | 
					
						
							|  |  |  | 	c := make([]string, t.l) | 
					
						
							|  |  |  | 	copy(c, t.s[i:i+t.l]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for k := 0; k < t.l; k++ { | 
					
						
							|  |  |  | 		t.s[i+k] = t.s[j+k] | 
					
						
							|  |  |  | 		t.s[j+k] = c[k] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (t *stringTuples) Less(i, j int) bool { | 
					
						
							|  |  |  | 	for k := 0; k < t.l; k++ { | 
					
						
							|  |  |  | 		d := strings.Compare(t.s[i+k], t.s[j+k]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if d < 0 { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if d > 0 { | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type serializedStringTuples struct { | 
					
						
							|  |  |  | 	l      int | 
					
						
							|  |  |  | 	b      []byte | 
					
						
							|  |  |  | 	lookup func(uint32) (string, error) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (t *serializedStringTuples) Len() int { | 
					
						
							|  |  |  | 	// TODO(fabxc): Cache this?
 | 
					
						
							|  |  |  | 	return len(t.b) / (4 * t.l) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (t *serializedStringTuples) At(i int) ([]string, error) { | 
					
						
							|  |  |  | 	if len(t.b) < (i+t.l)*4 { | 
					
						
							|  |  |  | 		return nil, errInvalidSize | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	res := make([]string, 0, t.l) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for k := 0; k < t.l; k++ { | 
					
						
							|  |  |  | 		offset := binary.BigEndian.Uint32(t.b[(i+k)*4:]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		s, err := t.lookup(offset) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, errors.Wrap(err, "symbol lookup") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		res = append(res, s) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res, nil | 
					
						
							|  |  |  | } |