Documentation
¶
Overview ¶
Package scale provides fetch-seam scale-out primitives: [Fetcher → Fetcher] decorators that any embedder's query engine composes over fetch.Fetcher (a per-tenant engine, a cluster fan-out, a cross-tenant fetch.Merge) without the library owning a query language.
- SplitFetcher splits a wide time window into aligned sub-intervals fetched in parallel, the query-frontend "split by interval" technique applied to the fetch contract.
- CacheFetcher memoizes results of fully-pushable (serializable-equality) requests.
Both implement fetch.Fetcher, so they nest freely — e.g. a SplitFetcher over a CacheFetcher over a cluster fetcher caches each aligned sub-window independently.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Cache ¶
type Cache interface {
Get(key string) ([]*fetch.Batch, bool)
Put(key string, batches []*fetch.Batch)
}
Cache stores fetch results keyed by an opaque string (built by the CacheFetcher from the request's tenant, window, and equality specs). Implementations must be safe for concurrent use. MemoryCache is the built-in bounded-LRU implementation.
Stored batches are treated as immutable snapshots: a CacheFetcher hands the cache an independent copy on Put, and callers of Get must not mutate the returned batches' sample columns in place (they may freely reslice/reorder the returned slice).
type CacheFetcher ¶
type CacheFetcher struct {
Inner fetch.Fetcher
Cache Cache
// Freshness is the recent-window guard in nanoseconds: a request whose End is within
// Freshness of now is not cached. 0 ⇒ no guard (every cacheable request is cached).
Freshness int64
// Now returns the current time as unix nanoseconds, for the Freshness guard. nil ⇒
// [time.Now]. Tests inject a fixed clock.
Now func() int64
}
CacheFetcher memoizes the results of **fully-pushable** requests: a request is cacheable only when every matcher carries a serializable equality fetch.EqualMatcher spec, so the cache key is exact and a hit can never drop a matching series. Requests with a non-equality matcher (an opaque predicate that cannot be keyed) bypass the cache and hit Inner directly.
The results cache does not auto-invalidate, so a request touching the **recent** window — where new samples may still arrive — must not be cached. The Freshness guard enforces that: a request whose window ends within Freshness of now bypasses the cache. Composed under a SplitFetcher, this caches the settled sub-windows and always re-fetches the most recent one (the standard query-frontend behavior).
func (CacheFetcher) Fetch ¶
Fetch returns the cached batches for r when present, otherwise fetches from Inner and stores the result. A non-cacheable request (or a nil Cache) is a transparent pass-through to Inner.
func (CacheFetcher) Unwrap ¶ added in v0.17.0
func (f CacheFetcher) Unwrap() fetch.Fetcher
Unwrap exposes the cached fetcher so fetch.CounterOf can reach the engine's Count for the count() pushdown (count is not cached — it reads through to Inner).
type MemoryCache ¶
type MemoryCache struct {
// contains filtered or unexported fields
}
MemoryCache is a bounded, LRU Cache held entirely in memory. It is safe for concurrent use. On Put it stores a deep copy of the batches (independent of the producer's reused buffers); on Get it returns a fresh slice of those snapshots so a caller's reslicing never disturbs the cache's order.
func NewMemoryCache ¶
func NewMemoryCache(maxEntries int) *MemoryCache
NewMemoryCache returns an LRU cache holding at most maxEntries results (≤ 0 ⇒ unbounded).
func (*MemoryCache) Get ¶
func (c *MemoryCache) Get(key string) ([]*fetch.Batch, bool)
Get returns a fresh slice of the cached batches and marks the entry most-recently-used.
func (*MemoryCache) Len ¶
func (c *MemoryCache) Len() int
Len returns the number of cached entries (testing/introspection).
type SplitFetcher ¶
type SplitFetcher struct {
Inner fetch.Fetcher
Interval int64 // sub-window width in nanos; ≤ 0 disables splitting (transparent pass-through)
}
SplitFetcher fetches a fetch.Request as a set of aligned sub-windows of width Interval, run concurrently against Inner and merged by series. Splitting on a fixed grid (aligned to multiples of Interval) makes each sub-window's bounds independent of the overall request, so overlapping queries reuse the same sub-windows — the property a downstream CacheFetcher relies on for hits across shifting ranges.
func (SplitFetcher) Fetch ¶
Fetch splits r's window into aligned sub-windows, fetches them concurrently from Inner, and returns their merged batches. A request spanning a single sub-window (or with Interval ≤ 0) passes straight through, so splitting never adds overhead to a narrow query.
func (SplitFetcher) Unwrap ¶ added in v0.17.0
func (f SplitFetcher) Unwrap() fetch.Fetcher
Unwrap exposes the split fetcher's inner so fetch.CounterOf can reach the engine's Count for the count() pushdown: count is evaluated over the full [Start, End] on Inner directly (a count is not a split-friendly aggregate — a series active in two sub-windows counts once for the whole range, so summing per-window counts would over-count).