Involved Source Files PlanCache: a size-bounded LRU cache of auto-parameterized query plans.
Two layers share one lock. An exact-string fast path (L1) skips parse +
plan on a verbatim repeat; a template index (L2) lets queries differing
only in lifted constants share one compiled plan. L1 entries own the
plans; a template entry dies when its last L1 variant is evicted (the Go
refcount standing in for the Rust engine's Arc/Weak split).
Both layers hold the TEMPLATE plan -- planned after auto-
parameterization, where every cost probe abstains on parameter slots --
so a cached plan is value-independent by construction. It may differ in
SHAPE (never in results) from the literal-probed plan an uncached Run
builds for the same text; this mirrors the Rust engine's query_cached
composition, trading the best-effort literal plan for zero double
planning and cross-literal sharing.
Eviction is least-recently-used past a configurable byte budget. The
byte estimate counts each L1 entry's key, parameters, and a per-plan
estimate; a plan shared by several literal variants is charged once per
variant -- a deliberate over-count, so the true footprint stays under
the bound. The implicit per-snapshot plan cache behind Run/RunWithParams: library
callers get template caching (skip parse + plan on repeats) with no
setup, per the census verdict -- every measured flip is timing-neutral
and the flip-aware bypass routes structurally flipped templates through
sighted planning, so the cached path does no harm. The registry keys
caches by WEAK snapshot pointers with a GC cleanup, so dropping a
snapshot drops its cache; a cache never outlives (or pins) its
snapshot. Callers wanting the literal-planned path explicitly --
benchmarks separating cold from warm, plan-shape experiments that
mutate planner thresholds between runs -- use RunUncached. Package gql is a read-only GQL query engine over an immutable
chickpeas.Snapshot -- the Go port of the rustychickpeas-cypher engine
with an ISO GQL (read subset) surface. Pipeline: parse -> desugar ->
bind -> plan -> execute, returning Rows. The public entry points: Run/RunWithParams execute a GQL query over an
engine snapshot; Explain renders the plan. Pipeline: parse -> desugar ->
plan (cost-based) -> execute, mapping each stage's typed error onto the
package sentinels. Plan-flip detection for the cache: a template planned blind (constants
lifted to parameters) can choose a structurally different operator tree
than value-sighted planning would -- exact scan cardinalities, resolved
anchor degrees, and rewrite gates priced from those exacts all go blind
under auto-parameterization, and a flipped plan can be arbitrarily worse
(the census measured one 17.5x allocation regression). The cache detects
the flip once, when a template is first planned, by also planning the
literal text and comparing the trees value-blind; a flipped template is
marked so execution routes through sighted planning instead of the
cached tree. Non-flipped templates -- the overwhelming majority -- keep
the full cache win. Prepared: a parsed, auto-parameterized, and planned query, ready to
execute repeatedly without re-incurring parse/plan cost -- the unit the
plan cache holds, exposed directly for callers managing their own reuse. The result surface: Rows, an iterator of named-column Row values. The
executor materializes the result set and Rows streams it from the buffer
(same contract as the Rust engine's lazy Rows).
Package-Level Type Names (total 4)
/* sort by: | */
PlanCache is a size-bounded cache of auto-parameterized plans, safe for
concurrent use. Hold one per long-lived snapshot: a cached plan's cost
choices reflect the statistics of the snapshot its template was first
planned against (executing against another snapshot is correct, possibly
suboptimal). Bytes is the approximate resident bytes currently charged. IsEmpty reports whether no live template plan is cached. Len is the number of distinct templates with a live plan. MaxBytes is the current byte budget. Run executes a GQL query through the cache. RunWithParams executes a GQL query through the cache with explicit
$name parameter values. Results are identical to the uncached
RunWithParams. SetMaxBytes changes the budget, evicting immediately if over it.
func DefaultCacheFor(g *chickpeas.Snapshot) *PlanCache
func NewPlanCache(maxBytes int) *PlanCache
Prepared is a compiled query. The plan is auto-parameterized (its
inline constants are lifted and stored), so it is value-independent by
construction; its cost-based choices reflect the statistics of the
snapshot it was prepared against -- executing against another snapshot
is legal and correct, possibly suboptimal. An EXPLAIN/PROFILE query
prepares too: Execute then returns the rendered plan. Columns is the output column names the plan produces, in order. Execute runs the prepared plan against g with explicit $name parameter
values (an unsupplied parameter reads as null); the stored lifted
constants rebind automatically. For an EXPLAIN/PROFILE query this
returns the rendered plan instead. The adaptive anchor choice runs here
exactly as on the cached path: a statement prepared once and executed
many times with different parameter values is the canonical
parameter-sniffing shape, so the value-resolved sibling choice matters
MOST on this path.
func Prepare(g *chickpeas.Snapshot, query string) (*Prepared, error)
Row is one result row: named columns mapped to values. The column slice
is shared across every row of a result. Columns is the output column names, in order. Get returns the value of column name; ok is false when absent. GetAt returns the value at output position i; ok is false out of range. Values is the row's values in output-column order.
func (*Rows).Next() (Row, bool)
func (*Rows).NextBatch(n int) []Row
DefaultCacheFor returns the snapshot's implicit plan cache, creating it
on first use (DefaultCacheBytes budget). Run and RunWithParams route
through it; sharing the same cache with explicit PlanCache calls is
fine but unnecessary.
Explain renders the query's plan (with cardinality estimates and anchor
notes) without executing it.
ExplainCanonical renders the query's plan as a stable, canonical shape string
for golden plan-regression snapshots: operator order, scan sources, hop
patterns, the recognizers that fired, and the chosen anchor -- with the
volatile parts (wall-clock planning time, the numeric estimates, the anchor
note's magnitudes) excluded. Unlike Explain the output is deterministic across
plannings, so a diff between two commits is a review prompt that a planner
change moved the plan, invisible to a row-level differential.
NewPlanCache is an empty cache bounded to maxBytes of approximate
resident memory (LRU eviction past the bound); maxBytes <= 0 means
DefaultCacheBytes.
Prepare parses, desugars, auto-parameterizes, and plans query once
against g's statistics.
Run executes a GQL query over the snapshot, through the snapshot's
implicit plan cache (see DefaultCacheFor): repeats skip parse + plan,
results are identical to the uncached path by the -cached-parity
contract, and structurally flipped templates route through sighted
planning. Use RunUncached for the always-literal-planned path.
RunUncached executes a GQL query with literal-sighted planning on
every call, bypassing the implicit plan cache -- the cold path, for
benchmarks separating cold from warm and for callers that mutate
planner behavior between runs.
RunUncachedWithParams is RunUncached with explicit $name parameter
values.
RunWithParams is Run with explicit $name parameter values. An
unsupplied parameter reads as null.
Package-Level Variables (total 4)
ErrBind marks a semantic error (unknown variable, bad reference).
ErrEval marks a runtime evaluation error.
ErrParse marks a syntax error from the parser.
ErrPlan marks a planning error (unsupported construct, bad plan input).
Package-Level Constants (only one)
DefaultCacheBytes is the default budget: 128 MiB of approximate
resident plan + key + parameter bytes.
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.