Documentation
¶
Overview ¶
Package catalog manages table schema and partition metadata. Metadata is stored in a MetaKV (NATS KV in production, MemKV in tests). Data files remain in object storage (S3/MinIO).
All KV keys are prefixed with a cluster ID to support federation:
<clusterID>.meta → CatalogMeta JSON <clusterID>.table.<name> → TableMeta JSON <clusterID>.manifest.<name> → PartitionManifest JSON
Index ¶
- Constants
- Variables
- func AddValueToHLL(h *HLL, v any, t parquet.TypeID)
- func DecodeSample(r io.Reader) (values []any, totalSeen int64, typeCode uint8, err error)
- func DecodeTableRGMeta(r io.Reader) (map[string][]parquet.RowGroupStats, error)
- func EncodeFileSketches(entries []FileSketchesEntry) []byte
- func EncodeSample(w io.Writer, values []any, totalSeen int64, typeCode uint8) error
- func EncodeTableRGMeta(files []FileRGMeta) []byte
- func IsHLLSupportedType(t parquet.TypeID) bool
- func MergeSamples(files [][]byte) (values []any, totalSeen int64, typeCode uint8)
- func SampleBytes(values []any, totalSeen int64, typeCode uint8) []byte
- func SampleFromBytes(b []byte) (values []any, totalSeen int64, typeCode uint8, ok bool)
- type AlertMeta
- type Catalog
- func (c *Catalog) AddDeleteMarkers(_ context.Context, tableName string, markers []DeleteMarker) error
- func (c *Catalog) AddFiles(_ context.Context, tableName string, partValues map[string]string, ...) error
- func (c *Catalog) AddNewFiles(_ context.Context, tableName string, partValues map[string]string, ...) error
- func (c *Catalog) AggregateColumnStats(_ context.Context, tableName string) (map[string]TableColumnStats, error)
- func (c *Catalog) AnalyzeTable(ctx context.Context, name string) (int, error)
- func (c *Catalog) Bucket() string
- func (c *Catalog) ClusterID() string
- func (c *Catalog) CreateAlert(_ context.Context, m AlertMeta) error
- func (c *Catalog) CreateTable(_ context.Context, name string, schema parquet.Schema, partitionKeys []string) error
- func (c *Catalog) DropAlert(_ context.Context, name string) error
- func (c *Catalog) DropTable(_ context.Context, name string) error
- func (c *Catalog) GCDeleteMarkers(_ context.Context, tableName string, minAge time.Duration) (rewriteTargets map[string][]int64, orphanPaths []string, err error)
- func (c *Catalog) GCSnapshots(ctx context.Context, opts SnapshotOptions, keep int, minAge time.Duration) error
- func (c *Catalog) GetAlert(_ context.Context, name string) (*AlertMeta, error)
- func (c *Catalog) GetManifest(_ context.Context, tableName string) (*PartitionManifest, error)
- func (c *Catalog) GetRemoteManifest(clusterID, tableName string) (*PartitionManifest, error)
- func (c *Catalog) GetRemoteTable(clusterID, tableName string) (*TableMeta, error)
- func (c *Catalog) GetTable(_ context.Context, name string) (*TableMeta, error)
- func (c *Catalog) Init(ctx context.Context) error
- func (c *Catalog) IsKVEmpty(_ context.Context) (bool, error)
- func (c *Catalog) KV() MetaKV
- func (c *Catalog) ListAlerts(_ context.Context) ([]AlertMeta, error)
- func (c *Catalog) ListClusters() ([]RemoteClusterInfo, error)
- func (c *Catalog) ListTables(_ context.Context) ([]string, error)
- func (c *Catalog) LoadUDFs() ([]UDFDef, error)
- func (c *Catalog) PutTableRGMeta(ctx context.Context, table string, files []FileRGMeta) (string, error)
- func (c *Catalog) ReadFile(ctx context.Context, key string) (io.ReadCloser, objstore.ObjectInfo, error)
- func (c *Catalog) RemoveFiles(_ context.Context, tableName string, filePaths []string) error
- func (c *Catalog) Restore(ctx context.Context, opts RestoreOptions) (string, error)
- func (c *Catalog) SaveUDFs(defs []UDFDef) error
- func (c *Catalog) SetAlertEnabled(ctx context.Context, name string, enabled bool) error
- func (c *Catalog) Snapshot(ctx context.Context, opts SnapshotOptions) (string, error)
- func (c *Catalog) Store() objstore.Store
- func (c *Catalog) SwapFileForGC(_ context.Context, tableName string, oldPath string, newFile *FileEntry, ...) error
- func (c *Catalog) TableRGMeta(ctx context.Context, tableName string) (map[string][]parquet.RowGroupStats, error)
- func (c *Catalog) TouchAlertEvaluated(ctx context.Context, name string, at time.Time) error
- func (c *Catalog) UploadFileSketches(ctx context.Context, table, parquetPath string, entries []FileSketchesEntry) (string, error)
- type CatalogMeta
- type DeleteMarker
- type FileColumnStats
- type FileEntry
- type FileRGMeta
- type FileSketchesEntry
- type HLL
- type Histogram
- type Lock
- type LockManager
- type MemKV
- func (m *MemKV) Delete(key string) error
- func (m *MemKV) Get(key string) ([]byte, uint64, error)
- func (m *MemKV) List(prefix string) ([]string, error)
- func (m *MemKV) Put(key string, value []byte) (uint64, error)
- func (m *MemKV) Revision(key string) (uint64, error)
- func (m *MemKV) Update(key string, value []byte, expectedRev uint64) (uint64, error)
- type MetaKV
- type NATSKVAdapter
- func (n *NATSKVAdapter) Delete(key string) error
- func (n *NATSKVAdapter) Get(key string) ([]byte, uint64, error)
- func (n *NATSKVAdapter) List(prefix string) ([]string, error)
- func (n *NATSKVAdapter) Put(key string, value []byte) (uint64, error)
- func (n *NATSKVAdapter) Update(key string, value []byte, expectedRev uint64) (uint64, error)
- type PartitionEntry
- type PartitionManifest
- type RemoteClusterInfo
- type ReservoirSampler
- type RestoreOptions
- type RevisionReader
- type SnapshotKeyEntry
- type SnapshotManifest
- type SnapshotOptions
- type TableColumnStats
- type TableMeta
- type UDFDef
Constants ¶
const (
HistDefaultBuckets = 64
)
Histogram is an equi-depth histogram over a column's values. Each bucket holds boundary values and a count. For numeric columns, the boundaries are int64-encoded; the planner converts to/from float64 for range comparisons.
Equi-depth means each bucket holds approximately the same number of values (1/K of the total). Bucket boundaries adapt to the data distribution: dense regions get narrow buckets, sparse regions wide. This gives accurate selectivity estimates for both common and rare values.
Used in stats.estimatePredSelectivity for range/equality filters when the column has a histogram in the catalog. Replaces hardcoded 0.33 / 0.1 fractions with data-driven estimates.
Wire format (binary, version-1):
[1] version (1) [1] bucket count K (≤ 255) [1] value type code (0=int64, 1=float64, 2=bytes) [1] reserved [8] total values [K+1] boundary values (K buckets → K+1 boundaries) [K*8] per-bucket counts (uint64 LE)
Boundary encoding depends on type code:
- int64: 8 bytes LE per value
- float64: 8 bytes LE (math.Float64bits) per value
- bytes: uint16 length prefix + raw bytes per value
const (
SampleDefaultSize = 256
)
ColumnSample is a fixed-size random sample of a column's values, persisted in FileColumnStats so the catalog can build aggregate histograms across files at query time. The sample is stored sorted so cross-file merge is a sorted-merge of K-way streams; the histogram is built once from the merged sample on AggregateColumnStats.
Storage: ~256 values × 8 bytes for numerics = 2 KB per column per file. Comparable to the per-file Histogram size but mergeable without distribution-assumption hacks.
Type-discriminated wire format mirrors Histogram's encodeValue:
- int64: 8 bytes LE per value
- float64: 8 bytes LE (math.Float64bits) per value
- bytes: uint16 length prefix + raw bytes per value
Variables ¶
var ErrKeyNotFound = errors.New("key not found")
ErrKeyNotFound is returned when a key does not exist in the KV store.
var ErrRevisionMismatch = errors.New("revision mismatch")
ErrRevisionMismatch is returned when a CAS update fails due to a concurrent modification (the key's current revision != expected).
var ErrTableNotFound = errors.New("not found")
ErrTableNotFound marks a GetTable miss: the catalog was reachable and the table is definitely absent. Callers distinguish it (errors.Is) from a transport failure, where the table's existence is unknown — the planner rejects a query on the former (42P01) and stays conservative on the latter.
Functions ¶
func AddValueToHLL ¶
AddValueToHLL hashes a value according to its declared parquet type and inserts the hash into the sketch.
Shared between the ingest path (which receives raw map[string]any rows pre-write) and the ANALYZE path (which decodes parquet rows post-write). Both produce hash-compatible HLLs that the catalog can merge.
Canonical encodings:
- integer/temporal types → 8-byte LE of int64 representation
- float32/float64 → 8-byte LE of math.Float64bits
- bool → single byte 0/1
- string/bytes/network-id types → raw bytes
- timestamp → UnixMilli (time.Time) or int64 (raw)
- duration → nanoseconds
The encoding intentionally normalizes int32 and int64 to the same byte stream so a column widened post-write hashes identically.
func DecodeSample ¶
DecodeSample reads a sample written by EncodeSample.
func DecodeTableRGMeta ¶
DecodeTableRGMeta parses a v1 RG-metadata blob into a by-path map, the shape buildRGUnits consumes.
func EncodeFileSketches ¶
func EncodeFileSketches(entries []FileSketchesEntry) []byte
EncodeFileSketches serializes a per-column sketch map to the v1 wire format. Empty input returns nil (no blob to upload).
func EncodeSample ¶
EncodeSample writes a sorted sample to w in version-1 format.
[1] version (1) [1] type code [2] value count K (uint16 LE) [8] total observed count (uint64 LE, before reservoir downsampling) [K*?] K values, type-discriminated encoding
func EncodeTableRGMeta ¶
func EncodeTableRGMeta(files []FileRGMeta) []byte
EncodeTableRGMeta serializes all files' row-group metadata to the v1 wire format. Empty input returns nil (no blob to upload).
func IsHLLSupportedType ¶
IsHLLSupportedType reports whether the column type is one we collect HLL sketches for. Returns false for nested types whose "value" isn't a single scalar.
func MergeSamples ¶
MergeSamples combines multiple per-file samples into a single sorted sample, weighted by each file's totalSeen so larger files contribute more samples to the merged distribution. Returns combined values, total observed across all files, and the shared type code.
If samples have mixed type codes (shouldn't happen for a valid column), the first sample's type wins; mismatched entries are skipped.
func SampleBytes ¶
SampleBytes serializes a snapshot for catalog persistence.
Types ¶
type AlertMeta ¶
type AlertMeta struct {
Name string `json:"name"`
QueryText string `json:"query"`
IntervalSeconds int64 `json:"interval_seconds"`
WebhookURL string `json:"webhook_url,omitempty"`
WebhookHeaders map[string]string `json:"webhook_headers,omitempty"`
InsertIntoTable string `json:"insert_into_table,omitempty"`
Enabled bool `json:"enabled"`
CreatedAt time.Time `json:"created_at"`
CreatedBy string `json:"created_by,omitempty"`
// Creator identity snapshot for definer's-rights scheduled execution: the
// alert query runs under this identity's ABAC subject on every tick (see
// auth.IdentitySnapshot). Empty on alerts created before this existed —
// the scheduler treats those fail-closed under enabled auth.
CreatedByRole string `json:"created_by_role,omitempty"`
CreatedByMethod string `json:"created_by_method,omitempty"`
CreatedByAttrs map[string]string `json:"created_by_attrs,omitempty"`
LastEvaluatedAt time.Time `json:"last_evaluated_at,omitempty"`
Version int64 `json:"version"`
}
AlertMeta is the catalog entry for a CREATE ALERT definition. Stored at key "<clusterID>.alert.<name>" via MetaKV CAS.
type Catalog ¶
type Catalog struct {
// contains filtered or unexported fields
}
Catalog manages table metadata via KV and data via object storage.
func NewWithCluster ¶
NewWithCluster creates a Catalog with a specific cluster identity.
func NewWithStore ¶
NewWithStore creates a Catalog using an in-memory KV (for tests/embedded use).
func (*Catalog) AddDeleteMarkers ¶
func (c *Catalog) AddDeleteMarkers(_ context.Context, tableName string, markers []DeleteMarker) error
AddDeleteMarkers adds delete markers to a table's manifest using CAS. Merges new markers with existing ones for the same file.
func (*Catalog) AddFiles ¶
func (c *Catalog) AddFiles(_ context.Context, tableName string, partValues map[string]string, partPath string, files []FileEntry) error
AddFiles adds file entries to the manifest for a given partition. Uses compare-and-swap to prevent concurrent flushes from losing updates. Idempotent per file path (mergeFileEntries): duplicate adds replace rather than append. For a writer minting brand-new paths, prefer AddNewFiles, which refuses a collision instead of masking it.
func (*Catalog) AddNewFiles ¶ added in v0.18.2
func (c *Catalog) AddNewFiles(_ context.Context, tableName string, partValues map[string]string, partPath string, files []FileEntry) error
AddNewFiles adds newly-created file entries to the manifest for a given partition — the production write path for ingest, compaction, and delete-marker GC, none of which ever legitimately re-register a path (#494). Uses the same CAS retry as AddFiles, but a Path collision with an existing entry is refused with an error rather than silently replaced; see mergeNewFileEntries.
func (*Catalog) AggregateColumnStats ¶
func (c *Catalog) AggregateColumnStats(_ context.Context, tableName string) (map[string]TableColumnStats, error)
AggregateColumnStats computes table-level column statistics by merging per-file stats across all partitions. Returns nil for columns without stats.
func (*Catalog) AnalyzeTable ¶
AnalyzeTable computes HyperLogLog sketches over every column of every file in the named table and writes them back into the manifest's FileColumnStats.HLL field. Idempotent — re-running ANALYZE replaces existing HLLs with freshly computed ones.
Used when a table's data was pre-staged (e.g., the SF10/SF100 EC2 deploy buckets) without going through the ingest path, so HLL never got collected at write time. The planner's NDV estimator then has real distinct-count data instead of falling back to min/max-range heuristics or FK-naming.
Strategy: for each file, download the parquet bytes, decode row groups via the existing parquet.Reader API, hash every column value into a per-(file, column) HLL. After all files of one table are processed, persist the augmented manifest.
Cost: one full table scan, decompressed but not joined. SF10 lineitem (60 chunks × 1M rows × 16 cols) takes 1-2 minutes serial. Cheap relative to a single query at the same scale; expected to run once per data load.
Returns the count of files analyzed and any error from the first failed file. Files that fail (corrupt, missing) are logged and skipped — partial coverage is better than total failure.
func (*Catalog) CreateAlert ¶
CreateAlert writes a new alert entry; fails if an alert with the same name exists.
func (*Catalog) CreateTable ¶
func (c *Catalog) CreateTable(_ context.Context, name string, schema parquet.Schema, partitionKeys []string) error
CreateTable creates a new table with the given schema and partition keys.
func (*Catalog) GCDeleteMarkers ¶
func (c *Catalog) GCDeleteMarkers(_ context.Context, tableName string, minAge time.Duration) (rewriteTargets map[string][]int64, orphanPaths []string, err error)
GCDeleteMarkers identifies delete markers older than minAge. Returns file paths that need a forced rewrite (marker aged, file still exists) and orphan paths (marker aged, file already gone — orphan markers are removed from the manifest). Rewrite markers are left in the manifest so ForceCompactFile can apply them during the file rewrite; SwapFileForGC removes only the applied markers atomically.
Zero-value CreatedAt markers (pre-existing before the GC feature) are backfilled with the current time so they become eligible for GC in the next cycle rather than being immortal.
func (*Catalog) GCSnapshots ¶
func (c *Catalog) GCSnapshots(ctx context.Context, opts SnapshotOptions, keep int, minAge time.Duration) error
GCSnapshots deletes snapshot timestamps that are older than minAge AND not in the `keep` newest. Never deletes the snapshot currently pointed at by the latest pointer.
func (*Catalog) GetManifest ¶
GetManifest returns the partition manifest for a table.
Freshness is decided by the manifest key's KV REVISION, on every call. The cache only ever skips re-decoding a revision this process already decoded; it is a decode memo, never a staleness window.
It used to be one, and that was #483. A 2-second wall-clock TTL, invalidated only by writes made through the same *Catalog value, is sound only while a process holds exactly one of them. Standalone holds three over the same KV — the coordinator's, the pgwire DB's, and a fresh one per worker pipeline task — and pgwire routes SELECT through the coordinator's catalog while INSERT/UPDATE/DELETE and DDL go through the DB's. Every write therefore invalidated a cache no reader was consulting, and reads answered from a manifest up to two seconds old. Statements issued back to back (a psql script, a SQLancer round, any client driving a session) all land inside that window: writes looked lost, and DROP TABLE + CREATE TABLE of the same name answered out of the previous incarnation's files — silently when the two schemas were encoding-compatible, and as a decode-time type refusal when they were not. A revision is the catalog's own notion of "which version is this", so validating against it cannot drift from what the catalog holds; a clock can.
The returned manifest is SHARED with every other caller holding this revision. Treat it as immutable — mutators inside this package take loadManifest instead.
func (*Catalog) GetRemoteManifest ¶
func (c *Catalog) GetRemoteManifest(clusterID, tableName string) (*PartitionManifest, error)
GetRemoteManifest reads the partition manifest from a remote cluster's catalog.
func (*Catalog) GetRemoteTable ¶
GetRemoteTable reads table metadata from a remote cluster's catalog.
func (*Catalog) Init ¶
Init initializes the catalog. Creates the S3 bucket and seed metadata if needed.
func (*Catalog) IsKVEmpty ¶
IsKVEmpty returns true if no <clusterID>.meta key exists. Used by the coordinator to decide whether startup should restore from a snapshot.
func (*Catalog) ListAlerts ¶
ListAlerts returns all alert entries, sorted by name.
func (*Catalog) ListClusters ¶
func (c *Catalog) ListClusters() ([]RemoteClusterInfo, error)
ListClusters discovers all clusters that have registered in the shared KV. Returns cluster IDs and their table lists.
func (*Catalog) ListTables ¶
ListTables returns the names of all tables in the local catalog.
func (*Catalog) LoadUDFs ¶
LoadUDFs reads persisted UDF definitions from the catalog KV. Returns nil (not error) if no UDFs have been saved.
func (*Catalog) PutTableRGMeta ¶
func (c *Catalog) PutTableRGMeta(ctx context.Context, table string, files []FileRGMeta) (string, error)
PutTableRGMeta uploads the table's RG-metadata blob and returns its object-store key. Empty input returns "" (nothing uploaded).
func (*Catalog) ReadFile ¶
func (c *Catalog) ReadFile(ctx context.Context, key string) (io.ReadCloser, objstore.ObjectInfo, error)
ReadFile reads a file from the catalog's bucket. Convenience helper.
func (*Catalog) RemoveFiles ¶
RemoveFiles removes data files and their delete markers from the manifest. Used after compaction to clean up rewritten files.
func (*Catalog) Restore ¶
Restore reads a snapshot from S3 and populates every KV key it contains. Returns the timestamp restored, or "" if there was nothing to restore (latest pointer absent).
Restore does NOT check whether the KV is already populated — that is the caller's responsibility (see coordinator's startup hook).
func (*Catalog) SetAlertEnabled ¶
SetAlertEnabled toggles the enabled flag via CAS. Retries on revision mismatch.
func (*Catalog) Snapshot ¶
Snapshot writes every <clusterID>.* key to <prefix>/snapshots/<ts>/ and atomically updates <prefix>/latest. Returns the timestamp written.
func (*Catalog) SwapFileForGC ¶
func (c *Catalog) SwapFileForGC(_ context.Context, tableName string, oldPath string, newFile *FileEntry, partValues map[string]string, partPath string, appliedIndices map[int64]bool) error
SwapFileForGC atomically replaces an old file with a rewritten file in the manifest. In a single CAS operation it: (1) removes the old file from the partition, (2) adds the new file entry, and (3) removes only the specific delete marker row indices that were applied during the rewrite. Any row indices added concurrently (by a DELETE after GC started) are preserved.
NOTE: Surviving concurrent markers still reference the old file path after the swap. These become dangling markers since the old file no longer exists. This is by design — the next GC sweep detects them as orphans and cleans them up. The deleted rows they reference will be visible in query results for at most one GC cycle (~5 min default). Remapping marker paths and row indices inside the CAS loop was rejected due to complexity and increased CAS conflict surface (see security review, 2026-04-05).
If newFile is nil, the old file is simply removed (all rows were deleted).
func (*Catalog) TableRGMeta ¶
func (c *Catalog) TableRGMeta(ctx context.Context, tableName string) (map[string][]parquet.RowGroupStats, error)
TableRGMeta returns the table's persisted row-group metadata as a by-path map, or nil when the table has no blob (never analyzed). Best-effort: fetch/decode failures return nil, nil so scans degrade to per-file footer reads instead of failing.
The decoded blob is memoized per table, keyed by the manifest's KV revision — the same invalidation contract as AggregateColumnStats. In the 22-query benchmark process the blob is fetched from the store once per table, not once per query.
func (*Catalog) TouchAlertEvaluated ¶
TouchAlertEvaluated updates LastEvaluatedAt; retries on CAS conflict. Failure to update is non-fatal for the scheduler; callers log and move on.
func (*Catalog) UploadFileSketches ¶
func (c *Catalog) UploadFileSketches(ctx context.Context, table, parquetPath string, entries []FileSketchesEntry) (string, error)
UploadFileSketches is the exported entry point for the ingest path. It bundles per-column sketches into a single object-store blob and returns the canonical key.
type CatalogMeta ¶
type CatalogMeta struct {
Version int `json:"version"`
Tables []string `json:"tables"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
CatalogMeta is the top-level catalog metadata.
type DeleteMarker ¶
type DeleteMarker struct {
FilePath string `json:"file_path"` // path of the data file containing deleted rows
RowIndices []int64 `json:"row_indices"` // 0-based row indices to skip
CreatedAt time.Time `json:"created_at"` // when this marker was created
}
DeleteMarker records rows to skip during scan (merge-on-read). Each marker identifies deleted rows within a specific data file.
type FileColumnStats ¶
type FileColumnStats struct {
MinValue any `json:"min_value,omitempty"`
MaxValue any `json:"max_value,omitempty"`
NullCount int64 `json:"null_count"`
// HLL is a HyperLogLog sketch over the column's distinct values in this
// file. Persisted as 1 byte version + 16384 register bytes (~16 KB).
// Empty if HLL was not collected at write time (e.g., legacy files,
// or for columns where NDV isn't useful — strings of comments). Read
// at plan time via AggregateColumnStats which merges sketches across
// files to estimate table-level NDV.
HLL []byte `json:"hll,omitempty"`
// Sample is a reservoir-sampled snapshot of the column's values in
// this file, encoded by EncodeSample (typically ~256 values, ~2 KB).
// AggregateColumnStats merges samples across files (weighted by
// file row count) and builds an equi-depth Histogram at query time.
// Used by stats.estimatePredSelectivity for range/equality filters.
Sample []byte `json:"sample,omitempty"`
}
FileColumnStats contains per-column min/max/null statistics for a single file. Extracted from Parquet row group metadata at write time.
type FileEntry ¶
type FileEntry struct {
Path string `json:"path"`
SizeBytes int64 `json:"size_bytes"`
NumRows int64 `json:"num_rows"`
CreatedAt time.Time `json:"created_at"`
ColumnStats map[string]FileColumnStats `json:"column_stats,omitempty"`
// SketchesKey points to a bundled per-column HLL+Sample blob in the
// object store (see sketches.go). Externalizing the sketches keeps
// the manifest small enough to fit in the NATS KV per-message
// payload cap (~1 MB) — without it, SF100 lineitem manifests
// (63 files × 16 cols × ~18 KB per sketch) blew past the limit and
// ANALYZE failed to persist the manifest. Empty string when no
// sketches are externalized (legacy inline path still supported via
// FileColumnStats.HLL / .Sample).
SketchesKey string `json:"sketches_key,omitempty"`
}
FileEntry describes a single Parquet file within a partition.
type FileRGMeta ¶
type FileRGMeta struct {
Path string
Groups []parquet.RowGroupStats
}
FileRGMeta is the per-file unit of the table RG-metadata blob.
type FileSketchesEntry ¶
FileSketchesEntry is the in-memory form of one column's sketches.
func DecodeFileSketches ¶
func DecodeFileSketches(r io.Reader) ([]FileSketchesEntry, error)
DecodeFileSketches parses a v1 sketches blob.
type HLL ¶
type HLL struct {
// contains filtered or unexported fields
}
HLL is a fixed-size HyperLogLog++ sketch. Zero value is a valid empty sketch; use Add to insert hashed values.
func HLLFromBytes ¶
HLLFromBytes parses a sketch from its serialized form. Returns nil on any error (corrupt bytes, wrong version) — callers fall back to the heuristic NDV path.
type Histogram ¶
type Histogram struct {
TypeCode uint8
TotalValues int64
// Boundaries has K+1 entries; bucket[i] covers [Boundaries[i], Boundaries[i+1]).
// The last bucket's upper bound is inclusive of the max value.
Boundaries []any
Counts []int64
}
Histogram is the catalog's per-column histogram.
func BuildHistogramFromSamples ¶
BuildHistogramFromSamples constructs an equi-depth histogram from a pre-collected sample of values. Picks K bucket boundaries at sorted 1/K positions of the sample, assigns each sample to a bucket. K caps at 255 to fit the bucket count in one wire byte.
Caller is responsible for typing — pass a []int64, []float64, or [][]byte. Mixed types in the sample slice are rejected (returns nil).
func DecodeHistogram ¶
DecodeHistogram reads a version-1 histogram from r.
func HistogramFromBytes ¶
HistogramFromBytes parses a histogram from its serialized form. Returns nil on any error (corrupt bytes, wrong version).
func HistogramFromMergedSample ¶
HistogramFromMergedSample builds a histogram from the merged sample and the actual total row count. The total drives the histogram's TotalValues so selectivities are reported as fractions of the real table size, not of the sample size.
func (*Histogram) SelectivityEQ ¶
SelectivityEQ returns the estimated fraction of values exactly equal to v. Uniform-distribution assumption within the containing bucket: 1 / (count in that bucket / count of distinct values in bucket). Without per-bucket NDV, falls back to 1 / TotalValues.
func (*Histogram) SelectivityLE ¶
SelectivityLE returns the estimated fraction of values ≤ v.
Cumulates the counts of all buckets fully below v, plus a linear- interpolation fraction of the bucket containing v. For string columns, the partial-bucket fraction defaults to 0.5 (uniform).
Returns 0 (nothing matches) when v < all values, 1 (all match) when v ≥ all values. Clamped to [0, 1].
func (*Histogram) SelectivityLT ¶
SelectivityLT returns the estimated fraction of values < v.
func (*Histogram) SelectivityRange ¶
SelectivityRange returns the estimated fraction of values in [lo, hi]. Inclusive on both ends.
type Lock ¶
type Lock struct {
// contains filtered or unexported fields
}
Lock represents a held distributed lock.
type LockManager ¶
type LockManager struct {
// contains filtered or unexported fields
}
LockManager provides distributed read-write locks via NATS KV.
func NewLockManager ¶
func NewLockManager(js jetstream.JetStream) (*LockManager, error)
NewLockManager creates a lock manager backed by a NATS KV bucket.
func (*LockManager) AcquireReadLock ¶
func (lm *LockManager) AcquireReadLock(ctx context.Context, space, table, readerID string) (*Lock, error)
AcquireReadLock acquires a shared read lock on a table. Multiple readers can hold locks concurrently. Each reader gets a unique key.
func (*LockManager) AcquireWriteLock ¶
AcquireWriteLock acquires an exclusive write lock on a table. Blocks until the lock is acquired or the context is cancelled.
func (*LockManager) HasWriteLock ¶
HasWriteLock checks if a write lock is currently held on a table.
type MemKV ¶
type MemKV struct {
// contains filtered or unexported fields
}
MemKV is an in-memory MetaKV implementation for tests and embedded use.
type MetaKV ¶
type MetaKV interface {
// Get returns the value and revision for a key.
// Returns ErrKeyNotFound if the key does not exist.
Get(key string) (value []byte, revision uint64, err error)
// Put creates or updates a key, returning the new revision.
Put(key string, value []byte) (revision uint64, err error)
// Update performs a compare-and-swap: writes value only if the key's
// current revision matches expectedRev. Returns ErrRevisionMismatch
// if a concurrent write changed the key since it was read.
Update(key string, value []byte, expectedRev uint64) (revision uint64, err error)
// Delete removes a key. No error if the key does not exist.
Delete(key string) error
// List returns all keys matching the given prefix.
// An empty prefix returns all keys.
List(prefix string) ([]string, error)
}
MetaKV abstracts key-value storage for catalog metadata. Production uses NATSKVAdapter; tests/embedded use MemKV.
type NATSKVAdapter ¶
type NATSKVAdapter struct {
// contains filtered or unexported fields
}
NATSKVAdapter wraps a NATS JetStream KeyValue as a MetaKV.
func NewNATSKV ¶
func NewNATSKV(js jetstream.JetStream) (*NATSKVAdapter, error)
NewNATSKV creates a NATS KV-backed MetaKV. Creates or opens the wadjet_catalog KV bucket.
func (*NATSKVAdapter) Delete ¶
func (n *NATSKVAdapter) Delete(key string) error
type PartitionEntry ¶
type PartitionEntry struct {
Path string `json:"path"`
Values map[string]string `json:"values"`
Files []FileEntry `json:"files"`
}
PartitionEntry describes a single partition.
type PartitionManifest ¶
type PartitionManifest struct {
Table string `json:"table"`
Partitions []PartitionEntry `json:"partitions"`
DeleteMarkers []DeleteMarker `json:"delete_markers,omitempty"` // merge-on-read deletes
UpdatedAt time.Time `json:"updated_at"`
// RGMetaKey points to the table's row-group-metadata blob in the
// object store (see rgmeta.go), written by AnalyzeTable. Scans use
// it to enumerate and prune row groups without reading any parquet
// footers. Files added after the blob was written simply aren't in
// it and fall back to footer reads — the key stays valid across
// ingest. Empty until the table is first analyzed.
RGMetaKey string `json:"rg_meta_key,omitempty"`
}
PartitionManifest tracks all partitions and their files for a table.
type RemoteClusterInfo ¶
RemoteClusterInfo describes a remote cluster's catalog.
type ReservoirSampler ¶
type ReservoirSampler struct {
// contains filtered or unexported fields
}
ReservoirSampler holds an in-memory sample using Algorithm L reservoir sampling: O(N) producer cost, uniformly distributed sample of size K from a stream of unknown length. Each Add either replaces a random existing entry or is dropped, weighted to keep all input values equally probable.
func NewReservoirSampler ¶
func NewReservoirSampler(k int) *ReservoirSampler
NewReservoirSampler creates a sampler of the given capacity. K ≤ 0 uses the default (SampleDefaultSize).
func (*ReservoirSampler) Add ¶
func (rs *ReservoirSampler) Add(v any)
Add inserts a value. The sample is updated in O(1) amortized.
type RestoreOptions ¶
type RestoreOptions struct {
SnapshotOptions
// ForceTS, when non-empty, overrides the latest pointer. Use "latest"
// as a sentinel to mean "read the pointer" (equivalent to empty).
ForceTS string
}
RestoreOptions configures where to read a snapshot from.
type RevisionReader ¶ added in v0.18.1
type RevisionReader interface {
// Revision returns the key's current revision, or ErrKeyNotFound.
Revision(key string) (uint64, error)
}
RevisionReader is an OPTIONAL MetaKV capability: report a key's current revision without transferring its value.
Catalog validates every cached manifest against the KV revision on every read (a wall-clock TTL is not a correctness mechanism — see Catalog.GetManifest), so the validation happens on the hottest planner path there is. A store that can answer "what revision is this key at" without shipping back a manifest that is megabytes of JSON at SF100 turns that validation into an O(1) probe. A store that cannot (NATS KV has no value-free get) simply omits the method and pays the full read, which is what the pre-cache code did anyway.
type SnapshotKeyEntry ¶
type SnapshotKeyEntry struct {
KVKey string `json:"kv_key"` // e.g. "local.table.orders"
S3Path string `json:"s3_path"` // relative to <prefix>/snapshots/<ts>/, e.g. "table/orders.json"
SHA256 string `json:"sha256"` // hex-encoded
}
SnapshotKeyEntry records one KV key's location and integrity hash.
type SnapshotManifest ¶
type SnapshotManifest struct {
Version int `json:"version"`
Timestamp string `json:"timestamp"`
ClusterID string `json:"cluster_id"`
KeyCount int `json:"key_count"`
Keys []SnapshotKeyEntry `json:"keys"`
}
SnapshotManifest is the JSON body of <ts>/manifest.json. Lists every KV key included in the snapshot and its SHA256 for integrity.
type SnapshotOptions ¶
type SnapshotOptions struct {
Store objstore.Store
Bucket string
Prefix string // path within bucket, e.g. "wadjet/catalog/". Must end in "/".
}
SnapshotOptions configures where catalog snapshots are written.
type TableColumnStats ¶
type TableColumnStats struct {
MinValue any
MaxValue any
NullCount int64
TotalRows int64
// NDV is the merged HLL estimate of distinct values across all files,
// or 0 when no file had an HLL sketch. When >0 it's preferred over the
// min/max-range heuristic in the optimizer's NDV estimator.
NDV int64
// Histogram is the equi-depth histogram built from merging per-file
// reservoir samples, scaled to TotalRows. Nil when no file had a
// Sample. Used by stats.estimatePredSelectivity for range/equality
// filters — replaces the hardcoded 0.33/0.1 fractions with
// data-driven selectivity.
Histogram *Histogram
}
TableColumnStats holds aggregated per-column statistics across all files. Used by the optimizer for selectivity estimation.
type TableMeta ¶
type TableMeta struct {
Name string `json:"name"`
Schema parquet.Schema `json:"schema"`
PartitionKeys []string `json:"partition_keys"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Version int `json:"version"`
}
TableMeta contains metadata for a single table.