@ -549,8 +549,10 @@ type Reader struct {
// block are always backed by true strings held in here rather than
// strings that are backed by byte slices from the mmap'd index file. This
// prevents memory faults when applications work with read symbols after
// the block has been unmapped.
symbols map [ uint32 ] string
// the block has been unmapped. The older format has sparse indexes so a map
// must be used, but the new format is not so we can use a slice.
symbols map [ uint32 ] string
symbolSlice [ ] string
dec * Decoder
@ -631,11 +633,21 @@ func newReader(b ByteSlice, c io.Closer) (*Reader, error) {
}
var err error
// Use the strings already allocated by symbols, rather than
// re-allocating them again below.
symbols := make ( map [ string ] string , len ( r . symbols ) + len ( r . symbolSlice ) )
for _ , s := range r . symbols {
symbols [ s ] = s
}
for _ , s := range r . symbolSlice {
symbols [ s ] = s
}
err = r . readOffsetTable ( r . toc . labelIndicesTable , func ( key [ ] string , off uint64 ) error {
if len ( key ) != 1 {
return errors . Errorf ( "unexpected key length %d" , len ( key ) )
}
r . labels [ key [ 0 ] ] = off
r . labels [ symbols [ key [ 0 ] ] ] = off
return nil
} )
if err != nil {
@ -645,14 +657,14 @@ func newReader(b ByteSlice, c io.Closer) (*Reader, error) {
if len ( key ) != 2 {
return errors . Errorf ( "unexpected key length %d" , len ( key ) )
}
r . postings [ labels . Label { Name : key [ 0 ] , Value : key [ 1 ] } ] = off
r . postings [ labels . Label { Name : symbols [ key [ 0 ] ] , Value : symbols [ key [ 1 ] ] } ] = off
return nil
} )
if err != nil {
return nil , errors . Wrap ( err , "read postings table" )
}
r . dec = & Decoder { symbols : r . symbols }
r . dec = & Decoder { lookupSymbol : r . lookupSymbol }
return r , nil
}
@ -777,18 +789,17 @@ func (r *Reader) readSymbols(off int) error {
basePos = uint32 ( off ) + 4
nextPos = basePos + uint32 ( origLen - d . len ( ) )
)
if r . version == 2 {
nextPos = 0
r . symbolSlice = make ( [ ] string , 0 , cnt )
}
for d . err ( ) == nil && d . len ( ) > 0 && cnt > 0 {
s := d . uvarintStr ( )
r . symbols [ nextPos ] = s
if r . version == 2 {
nextPos ++
r . symbolSlice = append ( r . symbolSlice , s )
} else {
r . symbols [ nextPos ] = s
nextPos = basePos + uint32 ( origLen - d . len ( ) )
}
cnt --
@ -828,6 +839,9 @@ func (r *Reader) Close() error {
}
func ( r * Reader ) lookupSymbol ( o uint32 ) ( string , error ) {
if int ( o ) < len ( r . symbolSlice ) {
return r . symbolSlice [ o ] , nil
}
s , ok := r . symbols [ o ]
if ! ok {
return "" , errors . Errorf ( "unknown symbol offset %d" , o )
@ -842,12 +856,22 @@ func (r *Reader) Symbols() (map[string]struct{}, error) {
for _ , s := range r . symbols {
res [ s ] = struct { } { }
}
for _ , s := range r . symbolSlice {
res [ s ] = struct { } { }
}
return res , nil
}
// SymbolTable returns the symbol table that is used to resolve symbol references.
func ( r * Reader ) SymbolTable ( ) map [ uint32 ] string {
return r . symbols
func ( r * Reader ) SymbolTableSize ( ) uint64 {
var size int
for _ , s := range r . symbols {
size += len ( s ) + 8
}
for _ , s := range r . symbolSlice {
size += len ( s ) + 8
}
return uint64 ( size )
}
// LabelValues returns value tuples that exist for the given label name tuples.
@ -1031,21 +1055,7 @@ func (t *serializedStringTuples) At(i int) ([]string, error) {
// It currently does not contain decoding methods for all entry types but can be extended
// by them if there's demand.
type Decoder struct {
symbols map [ uint32 ] string
}
func ( dec * Decoder ) lookupSymbol ( o uint32 ) ( string , error ) {
s , ok := dec . symbols [ o ]
if ! ok {
return "" , errors . Errorf ( "unknown symbol offset %d" , o )
}
return s , nil
}
// SetSymbolTable set the symbol table to be used for lookups when decoding series
// and label indices
func ( dec * Decoder ) SetSymbolTable ( t map [ uint32 ] string ) {
dec . symbols = t
lookupSymbol func ( uint32 ) ( string , error )
}
// Postings returns a postings list for b and its number of elements.