dataobj

package
v3.7.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 26, 2026 License: AGPL-3.0 Imports: 21 Imported by: 1

README

DataObj Package Documentation

Overview

The dataobj package provides a container format for storing and retrieving structured data from object storage. It's designed specifically for Loki's log storage needs, enabling efficient columnar storage and retrieval of log data with support for multiple tenants, metadata indexing, and flexible querying.

Table of Contents


Architecture Overview

The dataobj package provides a hierarchical container format:

┌─────────────────────────────────────┐
│         Data Object File            │
├─────────────────────────────────────┤
│  Header (Magic: "THOR")            │
├─────────────────────────────────────┤
│  Section 1 Data                     │
│  Section 2 Data                     │
│  ...                                │
│  Section N Data                     │
├─────────────────────────────────────┤
│  Section 1 Metadata                 │
│  Section 2 Metadata                 │
│  ...                                │
│  Section N Metadata                 │
├─────────────────────────────────────┤
│  File Metadata (Protobuf)           │
│  - Dictionary                       │
│  - Section Types                    │
│  - Section Layout Info              │
├─────────────────────────────────────┤
│  Footer                             │
│  - File Format Version              │
│  - File Metadata Size (4 bytes)     │
│  - Magic: "THOR"                    │
└─────────────────────────────────────┘
Core Components
  1. Builder - Constructs data objects by accumulating sections
  2. Encoder - Low-level encoding of sections and metadata
  3. Decoder - Low-level decoding of sections from object storage
  4. SectionReader - Interface for reading data/metadata from sections
  5. Section Implementations - Specific section types (logs, streams, pointers, etc.)

Key Concepts

Data Objects

A Data Object is a self-contained file stored in object storage containing:

  • One or more Sections, each holding a specific type of data
  • File Metadata describing all sections and their layout
  • Dictionary for efficient string storage (namespaces, kinds, tenant IDs)
Sections

Sections are the primary organizational unit within a data object:

  • Each section has a type (namespace, kind, version)
  • Sections contain both data and metadata regions
  • Multiple sections of the same type can exist in one object
  • Sections can be tenant-specific
Section Regions

Each section is split into two regions:

  1. Data Region - The actual encoded data (e.g., columnar log data)
  2. Metadata Region - Lightweight metadata to aid in reading the data region

This separation allows reading section metadata without loading the entire data payload.

Columnar Storage

Most section implementations use columnar storage via the internal/dataset package:

  • Data is organized into columns (e.g., timestamp, stream_id, message)
  • Columns are split into pages for efficient random access
  • Pages can be compressed (typically with zstd)
  • Supports predicates for filtering during reads

File Format Structure

File Layout
Offset  | Content
--------|----------------------------------------------------------
0       | Magic bytes: "THOR" (4 bytes)
4       | [Section Data Region - All sections concatenated]
...     | [Section Metadata Region - All sections concatenated]
...     | Format Version (varint)
...     | File Metadata (protobuf-encoded)
-8      | Metadata Size (uint32, little-endian)
-4      | Magic bytes: "THOR" (4 bytes)

File Metadata Structure (Protobuf) can be found in the pkg/dataobj/internal/metadata package.


Encoding Process

High-Level Encoding Flow
┌──────────────┐
│ Log Records  │
└──────┬───────┘
       │
       ▼
┌──────────────────┐
│ Section Builder  │  (e.g., logs.Builder)
│ - Buffer records │
│ - Create stripes │
│ - Merge stripes  │
└──────┬───────────┘
       │
       │ Flush
       ▼
┌──────────────────┐
│ Columnar Encoder │
│ - Encode columns │
│ - Compress pages │
└──────┬───────────┘
       │
       │ WriteSection
       ▼
┌──────────────────┐
│ dataobj.Builder  │
│ - Append section │
│ - Build metadata │
└──────┬───────────┘
       │
       │ Flush
       ▼
┌──────────────────┐
│ Snapshot         │
│ - In-memory/disk │
│ - Ready to upload│
└──────┬───────────┘
       │
       ▼
┌──────────────────┐
│ Object Storage   │
└──────────────────┘
Encoding
1. Section builders

A section builder:

  1. Buffers records in memory up to BufferSize
  2. When buffer is full, sorts records and creates a stripe
  3. Stripes are intermediate compressed tables
  4. Multiple stripes are merged when flushing the section
2. Encoding to Columnar Format

When flushing, the builder:

  1. Converts buffered records into columnar format
  2. Creates separate columns for each field (stream_id, timestamp, metadata, message)
  3. Splits columns into pages
  4. Compresses each page independently (zstd)
3. Writing to Data Object

The data object builder:

  1. Collects data and metadata from each section
  2. Builds file metadata with section layout information

Column metadata includes:

  • Page descriptors (offset, size, row count, compression)
  • Column statistics (min/max values)
  • Encoding information
4. Compression Strategy

The encoding uses a multi-level compression strategy:

  • Stripes (intermediate): zstd with SpeedFastest for quick buffering
  • Sections (final): zstd with SpeedDefault for better compression
  • Ordered Appends: When logs arrive pre-sorted, skips stripe creation for better performance

Decoding Process

High-Level Decoding Flow
┌──────────────────┐
│ Object Storage   │
└──────┬───────────┘
       │
       │ Open
       ▼
┌──────────────────┐
│ dataobj.Object   │
│ - Read metadata  │
│ - Parse sections │
└──────┬───────────┘
       │
       │ Open Section
       ▼
┌──────────────────┐
│ Section (e.g.    │
│  logs.Section)   │
│ - Decode metadata│
│ - List columns   │
└──────┬───────────┘
       │
       │ NewReader
       ▼
┌──────────────────┐
│ logs.Reader      │
│ - Read pages     │
│ - Apply filters  │
│ - Decompress     │
└──────┬───────────┘
       │
       │ Read batches
       ▼
┌──────────────────┐
│ Arrow Records    │
└──────────────────┘
Detailed Decoding Steps
1. Opening a Data Object

Opening process:

  1. Reads last 16KB of file in one request (optimistic read for metadata)
  2. Parses footer to find metadata offset and size
  3. Reads and decodes file metadata
  4. Constructs Section objects with SectionReaders
2. Decoding File Metadata

The decoder:

  1. Validates magic bytes ("THOR")
  2. Reads metadata size from last 8 bytes
  3. Seeks to metadata offset
  4. Decodes format version and protobuf metadata
3. Opening a Section

Section opening:

  1. Validates section type and version
  2. Reads extension data for quick access to section metadata
  3. Decodes section metadata (columnar structure)
4. Reading Data

Reading process:

  1. Validates reader options
  2. Maps predicates to internal dataset predicates
  3. Reads pages in batches (with prefetching)
  4. Applies predicates at page and row level
  5. Converts to Arrow record batches

Reader optimizations:

  • Range coalescing: Adjacent pages are read in a single request
  • Parallel reads: Multiple pages can be fetched concurrently
  • Prefetching: Pages are fetched ahead of time while processing current batch
  • Predicate pushdown: Filters applied at page level using statistics
5. Value Encoding Types

Values in pages can use different encodings:

  • Plain: Raw values stored directly
  • Delta: Store deltas between consecutive values (efficient for sorted data)
  • Bitmap: For repetition levels (null/non-null indicators)

Section Types

The package provides several built-in section types:

1. Logs Section

Namespace: github.com/grafana/loki Kind: logs Location: pkg/dataobj/sections/logs/

Stores log records in columnar format.

Columns:

  • stream_id (int64): Stream identifier
  • timestamp (int64): Nanosecond timestamp
  • metadata (binary): Structured metadata key-value pairs, one column per key
  • message (binary): Log line content
2. Streams Section

Namespace: github.com/grafana/loki Kind: streams Location: pkg/dataobj/sections/streams/

Stores stream metadata and statistics.

Columns:

  • stream_id (int64): Unique stream identifier
  • min_timestamp (int64): Earliest timestamp in stream
  • max_timestamp (int64): Latest timestamp in stream
  • labels (binary): Label key-value pairs for the stream, one column per key
  • rows (uint64): Number of log records
  • uncompressed_size (uint64): Uncompressed data size
3. Pointers Section

Namespace: github.com/grafana/loki Kind: pointers Location: pkg/dataobj/sections/pointers/

Used in index objects to point to other objects that contain logs, via stream or predicate lookup.

Columns:

  • path (binary): Path to data object in object storage
  • section (int64): The section number within the referenced data object
  • pointer_kind (int64): The type of pointer entry. Determines which fields are set in the section. Either stream or column.

// Fields present for a stream pointer type

  • stream_id (int64): Stream identifier in this index object
  • stream_id_ref (int64): Stream identifier in the target data object's stream section
  • min_timestamp (int64): Min timestamp in the object for this stream
  • max_timestamp (int64): Max timestamp in the object for this stream
  • row_count (int64): Total rows for this stream in the target object
  • uncompressed_size (int64): Total bytes for this stream in the target object

// Fields for a column pointer type

  • column_name (binary): The name of the column in the referenced object
  • column_index (int64): The index number of the column in the referenced object
  • values_bloom_filter (binary): A bloom filter for unique values seen in the referenced column
4. Index Pointers Section

Namespace: github.com/grafana/loki Kind: indexpointers Location: pkg/dataobj/sections/indexpointers/

Used in Table of Contents (toc) objects to point to index objects, via a time range lookup.

Columns:

  • path (binary): Path to the index file
  • min_time (int64): Minimum time covered by the referenced index object
  • max_time (int64): Maximum time covered by the referenced index object

Operational Components

Consumer

Location: pkg/dataobj/consumer/

The consumer reads log data from Kafka and builds data objects.

Key Features:

  • Reads from Kafka partitions
  • Accumulates logs into data objects
  • Flushes based on size or idle timeout
  • Commits offsets after successful upload
  • Emits metadata events containing a reference to each successfully uploaded object.
Metastore

Location: pkg/dataobj/metastore/

Manages an index of data objects and their contents for efficient querying.

The metastore serves queries by the following:

  1. Fetch and scan relevant Table of Contents (toc) files from the query time range to resolve index objects.
  2. Fetches resolved index objects and utilises the contained indexes (stream sections, blooms, etc.) to resolve log objects & metadata such as size and number of log lines.
Index Builder

Location: pkg/dataobj/index/

Creates index objects that contain indexes over data objects containing the logs.

Explorer Service

Location: pkg/dataobj/explorer/

HTTP service for inspecting data objects.


Usage Examples

Example 1: Building and Uploading a Data Object
package main

import (
    "context"
    "time"

    "github.com/grafana/loki/v3/pkg/dataobj"
    "github.com/grafana/loki/v3/pkg/dataobj/sections/logs"
    "github.com/grafana/loki/v3/pkg/dataobj/uploader"
    "github.com/prometheus/prometheus/model/labels"
)

func main() {
    ctx := context.Background()

    // Create logs builder
    logsBuilder := logs.NewBuilder(nil, logs.BuilderOptions{
        PageSizeHint: 256 * 1024,
        BufferSize: 10 * 1024 * 1024,
        AppendStrategy: logs.AppendUnordered,
        SortOrder: logs.SortStreamASC,
    })

    // Append log records
    logsBuilder.Append(logs.Record{
        StreamID:  12345,
        Timestamp: time.Now(),
        Metadata:  labels.Labels{{Name: "level", Value: "error"}},
        Line:      []byte("error occurred"),
    })

    // Create data object
    objBuilder := dataobj.NewBuilder(nil)
    objBuilder.Append(logsBuilder)

    obj, closer, err := objBuilder.Flush()
    if err != nil {
        panic(err)
    }
    defer closer.Close()

    // Upload to object storage
    uploader := uploader.New(uploaderCfg, bucket, logger)
    objectPath, err := uploader.Upload(ctx, obj)
    if err != nil {
        panic(err)
    }

    println("Uploaded to:", objectPath)
}
Example 2: Reading and Querying Logs
package main

import (
    "context"
    "io"

    "github.com/apache/arrow-go/v18/arrow/scalar"
    "github.com/grafana/loki/v3/pkg/dataobj"
    "github.com/grafana/loki/v3/pkg/dataobj/sections/logs"
)

func main() {
    ctx := context.Background()

    // Open data object
    obj, err := dataobj.FromBucket(ctx, bucket, "objects/ab/cd123...", 0)
    if err != nil {
        panic(err)
    }

    // Find logs sections
    var logsSection *dataobj.Section
    for _, sec := range obj.Sections() {
        if logs.CheckSection(sec) {
            logsSection = sec
            break
        }
    }

    // Open logs section
    section, err := logs.Open(ctx, logsSection)
    if err != nil {
        panic(err)
    }

    // Find columns
    var timestampCol, messageCol *logs.Column
    for _, col := range section.Columns() {
        switch col.Type {
        case logs.ColumnTypeTimestamp:
            timestampCol = col
        case logs.ColumnTypeMessage:
            messageCol = col
        }
    }

    // Create reader with predicate
    reader := logs.NewReader(logs.ReaderOptions{
        Columns: []*logs.Column{timestampCol, messageCol},
        Predicates: []logs.Predicate{
            logs.GreaterThanPredicate{
                Column: timestampCol,
                Value:  scalar.NewInt64Scalar(startTime.UnixNano()),
            },
        },
    })
    defer reader.Close()
    
    if err := reader.Open(ctx); err != nil {
        panic(err)
    }

    // Read batches
    for {
        batch, err := reader.Read(ctx, 1000)
        if err == io.EOF {
            break
        }
        if err != nil {
            panic(err)
        }

        // Process batch (Arrow record)
        for i := 0; i < int(batch.NumRows()); i++ {
            timestamp := batch.Column(0).(*array.Timestamp).Value(i)
            message := batch.Column(1).(*array.String).Value(i)
            println(timestamp, message)
        }

        batch.Release()
    }
}

Testing and Tools

Inspect Tool
# Inspect data object structure
go run ./pkg/dataobj/tools/inspect.go -path objects/ab/cd123...

# Show statistics
go run ./pkg/dataobj/tools/stats.go -path objects/ab/cd123...
Explorer Service

The explorer provides a web UI for browsing data objects:

# Start explorer
./loki -target=dataobj-explorer

# Access UI
curl http://localhost:3100/dataobj/api/v1/list

Documentation

Overview

Package dataobj holds utilities for working with data objects.

Data objects are a container format for storing data intended to be retrieved from object storage. Each data object is composed of one or more "sections," each of which contains a specific type of data, such as logs stored in a columnar format.

Sections are further split into two "regions": the section data and the section metadata. Section metadata is intended to be a lightweight payload per section (usually protobuf) which aids in reading smaller portions of the data region.

Each section has a type indicating what kind of data was encoded in that section. A data object may have multiple sections of the same type.

The dataobj package provides a low-level Builder interface for composing sections into a dataobj, and a SectionReader interface for reading encoded sections.

Section implementations are stored in their own packages and provide higher-level utilities for writing and reading those sections. See github.com/grafana/loki/v3/pkg/dataobj/sections/logs for an example.

Creating a new section implementation

To create a new section implementation:

  1. Create a new package for your section.

  2. Create a new SectionType for your section. Pick a combination of namespace and kind that avoids collisions with other sections that may be written to a file.

  3. Create a "Builder" type which implmeents SectionBuilder. Your builder type should have methods for buffering data to be appended. Encode buffered data on a call to Flush.

  4. Create higher-level reading APIs on top of SectionReader, decoding the data encoded from your builder.

Then, callers can create an instance of your Builder and store it in a data object using Builder.Append, and read it back using your higher-level APIs.

While not required, it is typical for section packages to additionally implement:

  • A package-level CheckSection function to check if a Section was built with your package.

  • A package-specific Section type that wraps Section to use in your reading APIs.

  • A function which returns the estimated size of something to be appended to your builder, so callers can flush the section once it gets big enough.

  • A method on your builder to report the estimated size of the section, both before and after compression.

## Encoding and decoding

There are no requirements on how to encode or decode a section, but there are recommendations:

  • Use protobuf for representing the metadata of the section.

  • Write section data so that it can be read in smaller units. For example, columnar data is split into pages, each of which can be read independently.

[SectionReader]s cannot access data outside of their section. Calling DataRange with an offset of 0 reads data from the beginning of that section's data region, not from the start of the dataobj.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

A Builder builds data objects from a set of incoming log data. Log data is appended to a builder by calling Builder.Append. Buffered log data is flushed manually by calling Builder.Flush.

Methods on Builder are not goroutine-safe; callers are responsible for synchronizing calls.

func NewBuilder

func NewBuilder(scratchStore scratch.Store) *Builder

A Builder accumulates data from a set of in-progress sections. A Builder can be flushed into a data object by calling Builder.Flush.

If provided, completed sections will be written to sectionScratchPath to reduce the peak memory usage of a builder to the peak memory usage of in-progress sections.

NewBuilder returns an error if sectionScratchPath specifies an invalid path on disk.

func (*Builder) Append

func (b *Builder) Append(sec SectionBuilder) error

Append flushes a SectionBuilder, buffering its data and metadata into b. Append does not enforce ordering; sections may be flushed to the dataobj in any order.

Append returns an error if the section failed to flush.

After successfully calling Append, sec is reset and can be reused.

func (*Builder) Bytes added in v3.6.0

func (b *Builder) Bytes() int

Bytes returns the current number of bytes buffered in b for all appended sections.

func (*Builder) Flush

func (b *Builder) Flush() (*Object, io.Closer, error)

Flush constructs a new Object from the accumulated sections. Allocated resources for the Object must be released by calling Close on the returned io.Closer. After closing, the returned Object must no longer be read.

Flush returns an error if the object could not be constructed. Builder.Reset is called after a successful flush to discard any pending data, allowing new data to be appended.

func (*Builder) Reset

func (b *Builder) Reset()

Reset discards pending data and resets the builder to an empty state.

type Metrics added in v3.6.0

type Metrics struct {
	// contains filtered or unexported fields
}

Metrics instruments encoded data objects.

func NewMetrics added in v3.6.0

func NewMetrics() *Metrics

NewMetrics creates a new set of metrics for encoding.

func (*Metrics) Observe added in v3.6.0

func (m *Metrics) Observe(obj *Object) error

Observe updates metrics with statistics about the given Object.

func (*Metrics) Register added in v3.6.0

func (m *Metrics) Register(reg prometheus.Registerer) error

Register registers metrics to report to reg.

func (*Metrics) Unregister added in v3.6.0

func (m *Metrics) Unregister(reg prometheus.Registerer)

Unregister unregisters metrics from the provided Registerer.

type Object added in v3.5.0

type Object struct {
	// contains filtered or unexported fields
}

An Object is a representation of a data object.

func FromBucket added in v3.5.0

func FromBucket(ctx context.Context, bucket objstore.BucketReader, path string, prefetchBytes int64) (*Object, error)

FromBucket opens an Object from the given storage bucket and path. FromBucket returns an error if the metadata of the Object cannot be read or if the provided ctx times out.

func FromReaderAt added in v3.5.0

func FromReaderAt(r io.ReaderAt, size int64) (*Object, error)

FromReadSeeker opens an Object from the given ReaderAt. The size argument specifies the size of the data object in bytes. FromReaderAt returns an error if the metadata of the Object cannot be read.

func (*Object) Reader added in v3.6.0

func (o *Object) Reader(ctx context.Context) (io.ReadCloser, error)

Reader returns a reader for the entire raw data object.

func (*Object) Sections added in v3.6.0

func (o *Object) Sections() Sections

Sections returns the list of sections available in the Object. The slice of returned sections must not be mutated.

func (*Object) Size added in v3.6.0

func (o *Object) Size() int64

Size returns the size of the data object in bytes.

func (*Object) Tenants added in v3.6.0

func (o *Object) Tenants() []string

Tenant returns the list of tenant that have sections in the Object. The slice of returned tenants must not be mutated.

type Section added in v3.6.0

type Section struct {
	Type   SectionType   // The type denoting the kind of data held in a section.
	Reader SectionReader // The low-level reader for a Section.

	// Tenant specifies the tenant that owns this section. Tenant is required
	// for sections which wholly contain tenant-specific data.
	Tenant string
}

A Section is a subset of an Object that holds a specific type of data. Use section packages for higher-level abstractions around sections.

type SectionBuilder added in v3.6.0

type SectionBuilder interface {
	// Type returns the SectionType representing the section being built.
	// Implementations are responsible for guaranteeing that two no
	// SectionBuilders return the same SectionType for different encodings.
	//
	// The returned Type is encoded directly into data objects. Implementations
	// that change SectionType values should be careful to continue supporting
	// old values for backwards compatibility.
	Type() SectionType

	// Flush encodes and flushes the section to w. Encodings that rely on byte
	// offsets should be relative to the first byte of the section's data.
	//
	// Flush returns the number of bytes written to w, and any error encountered
	// while encoding or flushing.
	//
	// After Flush is called, the SectionBuilder is reset to a fresh state and
	// can be reused.
	Flush(w SectionWriter) (n int64, err error)

	// Reset resets the SectionBuilder to a fresh state.
	Reset()
}

A SectionBuilder accumulates data for a single in-progress section.

Each section package provides an implementation of SectionBuilder that includes utilities to buffer data into that section. Callers should use Bytes or EstimatedSize to determine when enough data has been accumulated into a section.

type SectionReader added in v3.6.0

type SectionReader interface {
	// ExtensionData returns optional encoded information about the section
	// stored at the file level, provided through the [SectionWriter]. Sections
	// can use this for retrieving critical information that must be known
	// without needing to read the metadata first.
	//
	// ExtensionData will be nil if no extension data is available.
	ExtensionData() []byte

	// DataRange opens a reader of length bytes from the data region of a
	// section. The offset argument determines where in the data region reading
	// should start.
	//
	// DataRange returns an error if the read fails or if offset+length goes
	// beyond the readable data region. The returned reader is only valid as long
	// as the provided ctx is not canceled.
	DataRange(ctx context.Context, offset, length int64) (io.ReadCloser, error)

	// MetadataRange opens a reader of length bytes from the metadata region of
	// a section. The offset argument determines where in the metadata region
	// reading should start.
	//
	// MetadataRange returns an error if the read fails or if offset+length goes
	// beyond the readable metadata region. The returned reader is only valid as long
	// as the provided ctx is not canceled.
	MetadataRange(ctx context.Context, offset, length int64) (io.ReadCloser, error)

	// DataSize returns the total size of the data region of a section. DataSize
	// returns 0 for sections with no data region.
	DataSize() int64

	// MetadataSize returns the total size of the metadata region of a section.
	// MetadataSize returns 0 for sections with no metadata region.
	MetadataSize() int64
}

SectionReader is a low-level interface to read data ranges and metadata from a section.

Section packages provider higher-level abstractions around Section using this interface.

type SectionType added in v3.6.0

type SectionType struct {
	Namespace string // A namesapce for the section (e.g., "github.com/grafana/loki").
	Kind      string // The kind of section, scoped to the namespace (e.g., "logs").

	// Version is an optional section-specified value denoting an encoding
	// version of the section.
	Version uint32
}

SectionType uniquely identifies a Section type.

func (SectionType) Equals added in v3.6.0

func (ty SectionType) Equals(o SectionType) bool

Equals returns true if o has the same namespace and kind as ty. The Version field is not checked.

func (SectionType) String added in v3.6.0

func (ty SectionType) String() string

type SectionWriter added in v3.6.0

type SectionWriter interface {
	// WriteSection writes a section to the underlying data stream, partitioned
	// by section data and section metadata. It returns the sum of bytes written
	// from both input slices (0 <= n <= len(data)+len(metadata)) and any error
	// encountered that caused the write to stop early.
	//
	// The opts argument provides additional information about the section being
	// written. If opts is nil, the section is written without any additional
	// context.
	//
	// Implementations of WriteSection:
	//
	//   - Must return an error if the write stops early.
	//   - Must not modify the slices passed to it, even temporarily.
	//   - Must not retain references to slices after WriteSection returns.
	//
	// The physical layout of data and metadata is not defined: they may be
	// written non-contiguously, interleaved, or in any order.
	WriteSection(opts *WriteSectionOptions, data, metadata []byte) (n int64, err error)
}

SectionWriter writes data object sections to an underlying stream, such as a data object.

type Sections added in v3.6.0

type Sections []*Section

A Sections is a slice of Section.

func (Sections) Count added in v3.6.0

func (s Sections) Count(predicate func(*Section) bool) int

Count returns the number of sections that pass some predicate.

func (Sections) Filter added in v3.6.0

func (s Sections) Filter(predicate func(*Section) bool) iter.Seq2[int, *Section]

Filter returns an iterator over sections that pass some predicate. The index field is the number of the section that passed the predicate.

type WriteSectionOptions added in v3.6.0

type WriteSectionOptions struct {
	// Tenant that owns the written data and metadata. Tenant must be set for
	// sections that are wholly owned by a single tenant.
	Tenant string

	// ExtensionData is an optional field for section information to store at
	// the file level. To minimize the cost of opening data objects, sections
	// should only use this field for information that's required to start
	// reading section metadata and to keep the payload as small as possible.
	//
	// ExtensionData does not impact the return value of n in
	// [SectionWriter.WriteSection].
	//
	// Implementations of [SectionWriter] must not retain references to this
	// slice after WriteSection returns.
	ExtensionData []byte
}

WriteSectionOptions provides additional options when writing sections.

Directories

Path Synopsis
logsobj
Package logsobj provides tooling for creating logs-oriented data objects.
Package logsobj provides tooling for creating logs-oriented data objects.
indexobj
Package indexobj provides tooling for creating index-oriented data objects.
Package indexobj provides tooling for creating index-oriented data objects.
internal
arrowconv
Package arrowconv provides helper utilities for converting between Arrow and dataset values.
Package arrowconv provides helper utilities for converting between Arrow and dataset values.
dataset
Package dataset contains utilities for working with datasets.
Package dataset contains utilities for working with datasets.
result
Package result provides utilities for dealing with iterators that can fail during iteration.
Package result provides utilities for dealing with iterators that can fail during iteration.
streamio
Package streamio defines interfaces shared by other packages for streaming binary data.
Package streamio defines interfaces shared by other packages for streaming binary data.
util/bitmask
Package bitmask provides an API for creating and manipulating bitmasks of arbitrary length.
Package bitmask provides an API for creating and manipulating bitmasks of arbitrary length.
util/bufpool
Package bufpool offers a pool of *bytes.Buffer objects that are placed into exponentially sized buckets.
Package bufpool offers a pool of *bytes.Buffer objects that are placed into exponentially sized buckets.
util/protocodec
Package protocodec provides utilities for encoding and decoding protobuf messages into files.
Package protocodec provides utilities for encoding and decoding protobuf messages into files.
util/rangeset
Package rangeset implements a half-open interval set [start, end).
Package rangeset implements a half-open interval set [start, end).
util/sliceclear
Package sliceclear provides a way to clear and truncate the length of a slice.
Package sliceclear provides a way to clear and truncate the length of a slice.
util/symbolizer
Package symbolizer provides a string interning mechanism to reduce memory usage by reusing identical strings.
Package symbolizer provides a string interning mechanism to reduce memory usage by reusing identical strings.
sections
internal/columnar
Package columnar provides a base implementation for sections which store columnar data using github.com/grafana/loki/v3/pkg/dataobj/internal/dataset.
Package columnar provides a base implementation for sections which store columnar data using github.com/grafana/loki/v3/pkg/dataobj/internal/dataset.
logs
Package logs defines types used for the data object logs section.
Package logs defines types used for the data object logs section.
pointers
Package pointers defines types used for the data object pointers section.
Package pointers defines types used for the data object pointers section.
streams
Package streams defines types used for the data object streams section.
Package streams defines types used for the data object streams section.
TODO(grobinson): Find a way to move this file into the dataobj package.
TODO(grobinson): Find a way to move this file into the dataobj package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL