Like Prometheus, but for logs.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
loki/pkg/dataobj/decoder.go

97 lines
2.7 KiB

package dataobj
import (
"context"
"errors"
"fmt"
"github.com/grafana/loki/v3/pkg/dataobj/internal/metadata/filemd"
"github.com/grafana/loki/v3/pkg/dataobj/internal/util/bufpool"
)
type decoder struct {
rr rangeReader
}
func (d *decoder) Metadata(ctx context.Context) (*filemd.Metadata, error) {
tailer, err := d.tailer(ctx)
if err != nil {
return nil, fmt.Errorf("reading tailer: %w", err)
}
rc, err := d.rr.ReadRange(ctx, int64(tailer.FileSize-tailer.MetadataSize-8), int64(tailer.MetadataSize))
if err != nil {
return nil, fmt.Errorf("getting metadata: %w", err)
}
defer rc.Close()
br := bufpool.GetReader(rc)
defer bufpool.PutReader(br)
return decodeFileMetadata(br)
}
type tailer struct {
MetadataSize uint64
FileSize uint64
}
func (d *decoder) tailer(ctx context.Context) (tailer, error) {
size, err := d.rr.Size(ctx)
if err != nil {
return tailer{}, fmt.Errorf("reading attributes: %w", err)
}
// Read the last 8 bytes of the object to get the metadata size and magic.
rc, err := d.rr.ReadRange(ctx, size-8, 8)
if err != nil {
return tailer{}, fmt.Errorf("getting file tailer: %w", err)
}
defer rc.Close()
br := bufpool.GetReader(rc)
defer bufpool.PutReader(br)
metadataSize, err := decodeTailer(br)
if err != nil {
return tailer{}, fmt.Errorf("scanning tailer: %w", err)
}
return tailer{
MetadataSize: uint64(metadataSize),
FileSize: uint64(size),
}, nil
}
func (d *decoder) SectionReader(metadata *filemd.Metadata, section *filemd.SectionInfo, extensionData []byte) SectionReader {
return &sectionReader{rr: d.rr, md: metadata, sec: section, extensionData: extensionData}
}
var errMissingSectionType = errors.New("missing section type")
// getSectionType returns the [SectionType] for the given section.
func getSectionType(md *filemd.Metadata, section *filemd.SectionInfo) (SectionType, error) {
if section.TypeRef == 0 || section.TypeRef >= uint32(len(md.Types)) {
return SectionType{}, fmt.Errorf("%w: typeRef %d out of bounds [1, %d)", errMissingSectionType, section.TypeRef, len(md.Types))
}
var (
rawType = md.Types[section.TypeRef]
namespaceRef = rawType.NameRef.NamespaceRef
kindRef = rawType.NameRef.KindRef
)
// Validate the namespace and kind references.
if namespaceRef == 0 || namespaceRef >= uint32(len(md.Dictionary)) {
return SectionType{}, fmt.Errorf("%w: namespaceRef %d out of bounds [1, %d)", errMissingSectionType, namespaceRef, len(md.Dictionary))
} else if kindRef == 0 || kindRef >= uint32(len(md.Dictionary)) {
return SectionType{}, fmt.Errorf("%w: kindRef %d out of bounds [1, %d)", errMissingSectionType, kindRef, len(md.Dictionary))
}
return SectionType{
Namespace: md.Dictionary[namespaceRef],
Kind: md.Dictionary[kindRef],
Version: rawType.Version,
}, nil
}