Documentation
¶
Overview ¶
Package storage is the embeddable entry point for the oteldb storage library.
It is a low-level, distributed, OpenTelemetry-centric storage engine for signals (metrics, logs, traces, profiles), exposed as a small Storage facade. Everything else is an implementation detail behind this package. See the package layout and milestone plan in DESIGN.md at the repository root.
The in-memory engine (InMemory) is the default in tests: a full ingest+query path with WAL and durable flush disabled.
Index ¶
- Variables
- type Accepted
- type Durability
- type Option
- func WithBackend(b backend.Backend) Option
- func WithCluster(c *cluster.Config) Option
- func WithDurability(d Durability) Option
- func WithEncoding(p encoding.Profile) Option
- func WithFlushInterval(ns int64) Option
- func WithFlushThresholdBytes(n int64) Option
- func WithOOOWindow(ns int64) Option
- func WithTenancy(r tenant.Resolver) Option
- func WithTenant(fn func(signal.Resource, signal.Scope) signal.TenantID) Option
- func WithWALDir(dir string) Option
- type Options
- type Storage
- func (s *Storage) Close(ctx context.Context) error
- func (s *Storage) Fetcher(tenants ...signal.TenantID) fetch.Fetcher
- func (s *Storage) Reset(ctx context.Context) error
- func (s *Storage) WriteLogs(_ context.Context, _ log.Logs) (Accepted, error)
- func (s *Storage) WriteMetrics(ctx context.Context, md metric.Metrics) (Accepted, error)
- func (s *Storage) WriteProfiles(_ context.Context, _ profile.Profiles) (Accepted, error)
- func (s *Storage) WriteTraces(_ context.Context, _ trace.Traces) (Accepted, error)
Constants ¶
This section is empty.
Variables ¶
var ErrClosed = errors.New("storage: closed")
ErrClosed is returned by Storage methods after Storage.Close.
var ErrNotEphemeral = errors.New("storage: reset requires an ephemeral backend")
ErrNotEphemeral is returned by Storage.Reset when the backend is durable: Reset wipes all ingested data and is only permitted on an ephemeral (in-memory) store.
var ErrNotImplemented = errors.New("storage: not implemented in this milestone")
ErrNotImplemented is returned by scaffold-stub methods whose end-to-end wiring lands in a later milestone. It is not a fatal error: embedders may compile against the surface and gate on errors.Is(err, ErrNotImplemented).
Functions ¶
This section is empty.
Types ¶
type Accepted ¶
type Accepted struct {
// Accepted is the number of accepted data points (metric points, log records,
// span, profile samples depending on signal).
Accepted int64
// Rejected is the number of rejected data points (e.g. over a tenant limit or
// out of the OOO window). Rejections are reported back to the producer via OTLP
// partial_success so it can retry.
Rejected int64
// RejectedReason is a machine-readable reason for rejections (empty if none).
RejectedReason string
}
Accepted carries per-OTLP partial-success counts (DESIGN.md §5). It implements the OTLP partial-success semantics: accepted/rejected data points + a reason string.
type Durability ¶
type Durability uint8
Durability is the WAL + flush policy (DESIGN.md §5, §8).
const ( // DurabilityDefault is the default durability for a durable backend (WAL on, // flush to backend). For the in-memory engine use [DurabilityEphemeral]. DurabilityDefault Durability = iota // DurabilityEphemeral disables the WAL and durable flush: the head answers all // queries and "flushed" parts live in RAM, dropped on [Storage.Close]. This is // the in-memory engine and the default in tests (DESIGN.md §5). DurabilityEphemeral )
type Option ¶
type Option func(*Options)
Option is a functional option applied to Options by Open/InMemory.
func WithCluster ¶
WithCluster sets the cluster configuration. nil ⇒ single-node.
func WithDurability ¶
func WithDurability(d Durability) Option
WithDurability sets the WAL + flush policy.
func WithEncoding ¶
WithEncoding sets the default encoding profile.
func WithFlushInterval ¶
WithFlushInterval sets the head flush time interval in nanoseconds.
func WithFlushThresholdBytes ¶
WithFlushThresholdBytes sets the head flush size threshold.
func WithOOOWindow ¶
WithOOOWindow sets the out-of-order ingestion window in nanoseconds.
func WithTenancy ¶
WithTenancy sets the tenant policy resolver.
func WithTenant ¶
WithTenant sets the record→tenant routing callback (resource/scope → tenant id).
func WithWALDir ¶
WithWALDir sets the WAL directory (file backend + durability).
type Options ¶
type Options struct {
// Backend is the storage backend (memory/file/s3). If nil, [Open] defaults to
// [backend.Memory] — the in-memory, ephemeral engine (DESIGN.md §5).
Backend backend.Backend
// Cluster is the cluster configuration. nil ⇒ single-node (the cluster layer
// is absent, DESIGN.md §3, §11). Single-node users ignore L0 entirely.
Cluster *cluster.Config
// Tenant derives a record's tenant id from its Resource and Scope (so one OTLP
// batch may fan out to many tenants). If nil, every record routes to "default".
Tenant func(signal.Resource, signal.Scope) signal.TenantID
// Tenancy resolves a tenant id to limits, retention, downsampling, and routing.
// If nil, a permissive default resolver is used.
Tenancy tenant.Resolver
// Encoding is the default codec-chain profile per column kind (DESIGN.md §6).
// If nil, a sensible default is used.
Encoding encoding.Profile
// Durability is the WAL + flush policy. [DurabilityEphemeral] disables both —
// the in-memory engine: the head answers all queries and "flushed" parts are
// kept in RAM and dropped on [Storage.Close] (DESIGN.md §5).
Durability Durability
// WALDir is the WAL directory for the file backend with durability enabled.
// Ignored when [Durability] is [DurabilityEphemeral].
WALDir string
// FlushThresholdBytes is the head size at which a flush to an immutable part is
// triggered. Zero ⇒ default.
FlushThresholdBytes int64
// FlushInterval is the max age of unflushed head data. Zero ⇒ default.
// (Resolved into a duration internally to keep the API import-light.)
FlushInterval int64 // nanoseconds
// OOOWindow is the out-of-order ingestion window in nanoseconds (DESIGN.md §8).
// Samples older than (newest - OOOWindow) are rejected (counted). Zero ⇒ default.
OOOWindow int64 // nanoseconds
}
Options configures a Storage. Use [WithX] functional options to override defaults; Open applies them. The zero value is not valid — call Open (or InMemory) to construct a Storage.
type Storage ¶
type Storage struct {
// contains filtered or unexported fields
}
Storage is the embeddable entry point (DESIGN.md §5). It is safe for concurrent use. Construct with Open or InMemory; never with a literal.
All ingestion is push-based and OTLP-shaped: methods accept the library's internal, []byte-based, zero-alloc ingest batches (e.g. metric.Metrics) and return an Accepted carrying per-OTLP partial-success counts. OTel-Go users convert pdata to these via the optional otlp/pdataconv bridge, which keeps pdata off this hot path. Reads go through the language-agnostic Storage.Fetcher seam; query languages live in the embedder.
This is a scaffold stub: ingestion and query are wired end-to-end at M3 (metrics vertical). The methods currently validate arguments and return ErrNotImplemented so the surface is stable for embedders to compile against.
func InMemory ¶
InMemory returns a fully in-memory, ephemeral Storage (DESIGN.md §5): equivalent to Open with backend.Memory and DurabilityEphemeral. It is the default in tests — a full ingest+query path with no disk or object store.
func Open ¶
Open constructs a Storage from Options (DESIGN.md §5). If Options.Backend is nil it defaults to backend.Memory; if the backend is ephemeral and no durability is chosen, it defaults to DurabilityEphemeral (the in-memory engine).
func (*Storage) Close ¶
Close releases all resources. It is idempotent. After [Close], every method on s returns ErrClosed.
func (*Storage) Fetcher ¶
Fetcher returns the read seam — a fetch.Fetcher over the named tenants' data (head ∪ flushed parts). It is the storage library's query surface: this is a language-agnostic columnar store, so the embedder drives its own query engines (PromQL/LogQL/TraceQL) over the fetch contract. The optional query/promql package bridges this to the Prometheus storage.Queryable for embedders using the Prometheus engine.
Tenant scoping:
- Fetcher(t) — one tenant.
- Fetcher(a, b, …) — a fan-out over several tenants (multi-tenant query): results are merged by series id, so a series with equal labels in more than one tenant is federated into one (see fetch.Merge). Add a tenant label upstream if per-tenant separation is wanted.
- Fetcher() — all tenants that have ingested data (a cross-tenant query).
The returned Fetcher is always usable: with no matching tenant (or after [Close]) it is an empty fetcher that yields no series, so callers need not special-case "no data yet".
func (*Storage) Reset ¶
Reset discards all ingested data, returning every tenant engine to empty (head and flushed parts) without reconstructing the Storage. It is intended for tests and benchmarks that reuse one store across runs instead of rebuilding it. Reset is only valid on an ephemeral (in-memory) backend; on a durable backend it returns ErrNotEphemeral rather than wipe persisted data. The tenant engines themselves are retained (emptied, not dropped), so subsequent writes reuse them.
func (*Storage) WriteMetrics ¶
WriteMetrics ingests a metrics batch. It projects the internal model, derives each point's tenant from its Resource+Scope, and appends to that tenant's engine (indexing labels + buffering samples). Returns per-OTLP partial-success counts: rejected counts out-of-order drops. (Unsupported point kinds and value-less points never reach here: they are filtered and counted by the producer — e.g. the otlp/pdataconv bridge.)
func (*Storage) WriteProfiles ¶
WriteProfiles ingests a profiles batch. Later vertical.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package backend defines the L1 storage seam (DESIGN.md §3, §5): a common Backend interface (Read/Write/List/Delete over whole-object keys) with interchangeable implementations.
|
Package backend defines the L1 storage seam (DESIGN.md §3, §5): a common Backend interface (Read/Write/List/Delete over whole-object keys) with interchangeable implementations. |
|
backendtest
Package backendtest provides a shared conformance suite that every backend.Backend implementation must pass, proving the implementations are interchangeable (DESIGN.md §2: "backends are interchangeable behind backend.Backend").
|
Package backendtest provides a shared conformance suite that every backend.Backend implementation must pass, proving the implementations are interchangeable (DESIGN.md §2: "backends are interchangeable behind backend.Backend"). |
|
bucketindex
Package bucketindex maintains a compact, incremental index of the immutable parts under a key prefix, so a stateless reader enumerates a tenant's parts (and prunes them by time) from a single object instead of a full, expensive bucket LIST (DESIGN.md §11, the object-store-native read path).
|
Package bucketindex maintains a compact, incremental index of the immutable parts under a key prefix, so a stateless reader enumerates a tenant's parts (and prunes them by time) from a single object instead of a full, expensive bucket LIST (DESIGN.md §11, the object-store-native read path). |
|
file
Package file implements a backend.Backend over a local directory tree.
|
Package file implements a backend.Backend over a local directory tree. |
|
s3
Package s3 implements a backend.Backend over an S3-compatible object store.
|
Package s3 implements a backend.Backend over an S3-compatible object store. |
|
Package block implements the L2 immutable columnar part format (DESIGN.md §3, §14 M1): per-column streams with min/max stats and constant-column collapse, a sparse granule mark index, and an atomic manifest written last.
|
Package block implements the L2 immutable columnar part format (DESIGN.md §3, §14 M1): per-column streams with min/max stats and constant-column collapse, a sparse granule mark index, and an atomic manifest written last. |
|
Package cluster implements the L0 distribution layer (DESIGN.md §3, §11, §14 M6–M7): rendezvous (HRW) hashing with spread-minimizing tokens, etcd-backed ring state and leases, RF=3 quorum replication, and rebalancing.
|
Package cluster implements the L0 distribution layer (DESIGN.md §3, §11, §14 M6–M7): rendezvous (HRW) hashing with spread-minimizing tokens, etcd-backed ring state and leases, RF=3 quorum replication, and rebalancing. |
|
etcd
Package etcd backs the L0 cluster ring with etcd: a node registers itself under a lease and watches the member set, so membership is live and self-healing — a crashed node's lease expires and it drops out of every other node's ring within the TTL, with no manual deregistration.
|
Package etcd backs the L0 cluster ring with etcd: a node registers itself under a lease and watches the member set, so membership is live and self-healing — a crashed node's lease expires and it drops out of every other node's ring within the TTL, with no manual deregistration. |
|
rebalance
Package rebalance computes the minimal ownership changes to apply a cluster membership change (DESIGN.md §11).
|
Package rebalance computes the minimal ownership changes to apply a cluster membership change (DESIGN.md §11). |
|
replica
Package replica is the L0 write-replication layer: it fans an opaque write payload out to the ring-owners of a key and returns once a write **quorum** has durably applied it, so the unflushed head survives the loss of a minority of replicas (DESIGN.md §11; RF=3, quorum (RF/2)+1=2).
|
Package replica is the L0 write-replication layer: it fans an opaque write payload out to the ring-owners of a key and returns once a write **quorum** has durably applied it, so the unflushed head survives the loss of a minority of replicas (DESIGN.md §11; RF=3, quorum (RF/2)+1=2). |
|
ring
Package ring implements rendezvous (highest-random-weight, HRW) hashing — the L0 sharding primitive (DESIGN.md §11).
|
Package ring implements rendezvous (highest-random-weight, HRW) hashing — the L0 sharding primitive (DESIGN.md §11). |
|
Package encoding holds the L2 codec layers (DESIGN.md §3, §14 M0):
|
Package encoding holds the L2 codec layers (DESIGN.md §3, §14 M0): |
|
bitstream
Package bitstream implements a zero-alloc, MSB-first bit stream reader and writer.
|
Package bitstream implements a zero-alloc, MSB-first bit stream reader and writer. |
|
chunk
Package chunk implements the zero-alloc value-column codecs (DESIGN.md §14 M0): delta-of-delta timestamps, Gorilla XOR float gauges, T64, dictionary, and scaled-decimal+nearest-delta.
|
Package chunk implements the zero-alloc value-column codecs (DESIGN.md §14 M0): delta-of-delta timestamps, Gorilla XOR float gauges, T64, dictionary, and scaled-decimal+nearest-delta. |
|
compress
Package compress wraps zstd/lz4 block compression and defines the composable codec-chain type (preprocessor → general compressor) used to reach 0.4–0.8 bytes/point (DESIGN.md §3.3, §14 M0).
|
Package compress wraps zstd/lz4 block compression and defines the composable codec-chain type (preprocessor → general compressor) used to reach 0.4–0.8 bytes/point (DESIGN.md §3.3, §14 M0). |
|
Package engine is the L3 single-node storage engine: an in-memory head that absorbs writes (indexing labels and buffering samples) with a bounded out-of-order window, optionally backed by a write-ahead log for crash recovery.
|
Package engine is the L3 single-node storage engine: an in-memory head that absorbs writes (indexing labels and buffering samples) with a bounded out-of-order window, optionally backed by a write-ahead log for crash recovery. |
|
Package index implements the L3 indexing layer (DESIGN.md §3, §14 M2):
|
Package index implements the L3 indexing layer (DESIGN.md §3, §14 M2): |
|
postings
Package postings is the inverted index: for each (name, value) attribute — identified by **interned symbol ids**, not strings — it keeps the sorted list of [signal.SeriesID]s that carry it, and composes those lists with lazy set-op iterators (Intersect/Merge/Without) to resolve label matchers to series.
|
Package postings is the inverted index: for each (name, value) attribute — identified by **interned symbol ids**, not strings — it keeps the sorted list of [signal.SeriesID]s that carry it, and composes those lists with lazy set-op iterators (Intersect/Merge/Without) to resolve label matchers to series. |
|
series
Package series is the series-identity index: it maps a content-addressed signal.SeriesID to its full identity (signal.Series — Resource + Scope + data-point attributes) and back.
|
Package series is the series-identity index: it maps a content-addressed signal.SeriesID to its full identity (signal.Series — Resource + Scope + data-point attributes) and back. |
|
symbols
Package symbols is the string-interning symbol table.
|
Package symbols is the string-interning symbol table. |
|
internal
|
|
|
cmd/fuzz
command
Command fuzz starts a fuzzing campaign for a randomly chosen fuzz target using gosentry (https://github.com/trailofbits/gosentry), Trail of Bits' Go-toolchain fork that runs `go test -fuzz` on top of LibAFL.
|
Command fuzz starts a fuzzing campaign for a randomly chosen fuzz target using gosentry (https://github.com/trailofbits/gosentry), Trail of Bits' Go-toolchain fork that runs `go test -fuzz` on top of LibAFL. |
|
otlp
|
|
|
pdataconv
Package pdataconv is the optional OTel-Go bridge: it converts the collector pdata metrics type (pmetric.Metrics) into the storage library's internal, []byte-based metric.Metrics ingest batch.
|
Package pdataconv is the optional OTel-Go bridge: it converts the collector pdata metrics type (pmetric.Metrics) into the storage library's internal, []byte-based metric.Metrics ingest batch. |
|
Package pool provides cross-cutting sync.Pool helpers, capacity-bucketed byte pools, and arena allocation for same-lifetime batches (DESIGN.md §10).
|
Package pool provides cross-cutting sync.Pool helpers, capacity-bucketed byte pools, and arena allocation for same-lifetime batches (DESIGN.md §10). |
|
Package query groups the storage library's read seam and its language adapters.
|
Package query groups the storage library's read seam and its language adapters. |
|
fetch
Package fetch is the storage seam: the contract every query language compiles to and every data source (head, parts, cluster fan-out) implements.
|
Package fetch is the storage seam: the contract every query language compiles to and every data source (head, parts, cluster fan-out) implements. |
|
promql
Package promql is an optional adapter that bridges the storage fetch contract (query/fetch) to the Prometheus storage.Queryable interface.
|
Package promql is an optional adapter that bridges the storage fetch contract (query/fetch) to the Prometheus storage.Queryable interface. |
|
Package signal holds the OTel data model, signal-neutral types shared across metrics, logs, traces, and profiles: the Signal enum, TenantID, and the typed attribute identity primitives (Value, KeyValue, Attributes, SeriesID).
|
Package signal holds the OTel data model, signal-neutral types shared across metrics, logs, traces, and profiles: the Signal enum, TenantID, and the typed attribute identity primitives (Value, KeyValue, Attributes, SeriesID). |
|
log
Package log holds the logs signal's ingest model.
|
Package log holds the logs signal's ingest model. |
|
metric
Package metric implements the metrics signal: OTLP metric point types, temporality, series identity, and the OTLP → internal projection.
|
Package metric implements the metrics signal: OTLP metric point types, temporality, series identity, and the OTLP → internal projection. |
|
profile
Package profile holds the profiles signal's ingest model.
|
Package profile holds the profiles signal's ingest model. |
|
trace
Package trace holds the traces signal's ingest model.
|
Package trace holds the traces signal's ingest model. |
|
Package tenant provides the cross-cutting policy-callback layer (DESIGN.md §2, §8): a tenant.Resolver maps a tenant id to limits, retention, downsampling, and routing, hot-reloadable by the consumer.
|
Package tenant provides the cross-cutting policy-callback layer (DESIGN.md §2, §8): a tenant.Resolver maps a tenant id to limits, retention, downsampling, and routing, hot-reloadable by the consumer. |
|
Package wal is the write-ahead log: CRC-framed records appended to numbered segment files, replayed in order to reconstruct the in-memory index after a crash.
|
Package wal is the write-ahead log: CRC-framed records appended to numbered segment files, replayed in order to reconstruct the in-memory index after a crash. |