Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/en/changes/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@
* LAL: support full arithmetic (`+`, `-`, `*`, `/`) on numeric operands and fix the original bug where `(tag("x") as Integer) + (tag("y") as Integer)` was treated as string concatenation — expressions like `input_tokens + output_tokens < 10000` produced the concatenated string `"2589115"` rather than the integer sum `2704`, so token-threshold conditions never triggered `abort {}`. Operand types are now inferred from explicit casts (`as Integer` / `as Long` / `as Float` / `as Double`), typed proto fields, or numeric literal shape (with `L` / `F` / `D` suffix support, e.g. `1000L`). The compiler honours JLS-style binary numeric promotion and emits Java arithmetic in the declared primitive type — `(x as Integer) + (y as Integer)` compiles to `int + int` (not widened to `long`). `+` with any String operand falls back to string concatenation; `-` / `*` / `/` against non-numeric operands produces a compile-time error. The `as Double` and `as Float` casts are accepted in `typeCast` clauses, including in `def` declarations. Numeric comparisons honour declared casts on both sides (no more universal `h.toLong()` wrapper).
* Fix: `avgHistogramPercentile` / `sumHistogramPercentile` meter functions reported the smallest finite bucket boundary (e.g. `10` for OTel `gen_ai_server_request_duration` whose `le` is rewritten from `0.01s` → `10ms`) for every rank when no samples were observed in any bucket. The percentile loop's `count >= roof` check matched on the first sorted bucket because both sides were `0`. `calculate()` now short-circuits to `0` for every rank when the windowed total is `0`.
* Fix: MAL `expPrefix` now applies to every metric source in `exp`, not just the leading one. Previously the prefix was spliced after the first `.`, so secondary metrics inside arguments (e.g. the divisor in `a.sum(['s']).safeDiv(b.sum(['s']))`) silently skipped the prefix — a rule like envoy-ai-gateway's `request_latency_avg` (`sum / count`) would tag-rewrite only the dividend. The injection is now AST-aware: every bare-IDENTIFIER metric source is wrapped, while downsampling-type constants (`SUM`, `AVG`, `LATEST`, `SUM_PER_MIN`, `MAX`, `MIN`) are skipped.
* Add `@Stream(allowBootReshape = true)` opt-in for additive boot-time reshape of BanyanDB streams / measures. Code-defined stream classes (e.g. `AlarmRecord`) can now annotate their schema as eligible for in-place additive update at OAP boot — a new `@Column` is appended to the live tag-family / fields via `client.update` instead of being silently rejected with `SKIPPED_SHAPE_MISMATCH` (which previously forced operators to drop the measure / stream and lose historical rows). The opt-in is per-stream and gated by an `isPurelyAdditive` shape diff: type changes, drops, kind flips, entity / interval / sharding-key changes, and field re-typing still skip with `SKIPPED_SHAPE_MISMATCH`, so identity-breaking edits remain explicit operator actions. Only the init / standalone OAP performs the reshape; non-init peers continue through the existing poll-and-wait loop so a single node drives DDL. `AlarmRecord` is opted in. Default remains `false` for all other models — boot-time reshape stays off unless the annotation is explicitly set.
* Add `@Stream(allowBootReshape = true)` opt-in for additive boot-time reshape of BanyanDB streams / measures. Code-defined stream classes (e.g. `AlarmRecord`) can now annotate their schema as eligible for in-place additive update at OAP boot — a new `@Column` is appended to the live tag-family / fields via `client.update` instead of being silently rejected with `SKIPPED_SHAPE_MISMATCH` (which previously forced operators to drop the measure / stream and lose historical rows). Additive includes both new tags / fields **and** relocating an existing tag between families when a `@Column`'s `storageOnly` flag flips (e.g. `id1` moving from `storage-only` → `searchable` when it becomes indexed). The opt-in is per-stream and gated by an `isPurelyAdditive` shape diff: tag type changes, tag drops, kind flips (tag↔field), entity / interval / sharding-key changes, and field re-typing still skip with `SKIPPED_SHAPE_MISMATCH`, so identity-breaking edits remain explicit operator actions. Only the init / standalone OAP performs the reshape; non-init peers continue through the existing poll-and-wait loop so a single node drives DDL. When a `check*` records `SKIPPED_SHAPE_MISMATCH` the dependent `IndexRule` / `IndexRuleBinding` reconciliation is also skipped — preventing the previous gap where the binding silently updated to a tag list that diverged from the live tag-family layout. `AlarmRecord` is opted in. Default remains `false` for all other models — boot-time reshape stays off unless the annotation is explicitly set. **Operator caveat:** BanyanDB does not physically migrate existing rows when a tag's family changes; pre-existing data stays in its original on-disk location while new writes go to the declared family — expect a backfill window for queries that route through new IndexRules on relocated tags.

#### UI
* Add mobile menu icon and i18n labels for the iOS layer.
Expand Down
39 changes: 32 additions & 7 deletions docs/en/concepts-and-designs/runtime-rule-hot-update.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,18 +169,43 @@ backing schema needs to change.
Streams whose schema lives in OAP source code (e.g. `AlarmRecord`) can opt in
to **additive** boot-time reshape via
`@Stream(allowBootReshape = true)`. When the flag is on and the diff is
purely additive (new tag / new field; no type changes, no drops, no entity /
interval / sharding-key flips), the installer calls `client.update` at boot
to append the new column to the live measure / stream; non-additive
divergences still record `SKIPPED_SHAPE_MISMATCH` and require an operator
drop+recreate. Only the init / standalone OAP performs the reshape; non-init
peers continue through the existing poll-and-wait loop so a single node
drives DDL during a rolling restart.
purely additive, the installer calls `client.update` at boot to extend the
live measure / stream; non-additive divergences still record
`SKIPPED_SHAPE_MISMATCH` and require an operator drop+recreate. Only the
init / standalone OAP performs the reshape; non-init peers continue through
the existing poll-and-wait loop so a single node drives DDL during a rolling
restart.

"Additive" includes two cases:

1. **New tag / new field** — a brand-new `@Column` is appended to the live
tag family (or fields list, for measures).
2. **Tag relocation between families** — a `@Column`'s `storageOnly` flag
flips, moving the tag between the `storage-only` and `searchable`
families. The tag identity and type are preserved; only its on-disk
family location changes.

Drops, tag-type changes, kind flips (tag↔field), and entity / interval /
sharding-key changes are still rejected with `SKIPPED_SHAPE_MISMATCH`.

When the primary `check*` records `SKIPPED_SHAPE_MISMATCH`, the dependent
`IndexRule` and `IndexRuleBinding` reconciliation is **also skipped**. This
preserves coherence between the stream / measure tag layout and the binding
that points into it — without the gate, the binding would silently update to
reference the new declared tag list while the live tag families still carry
the old shape, leaving operators with a binding routing to tags that don't
exist in the live family layout.

This opt-in is **BanyanDB-only**. JDBC and Elasticsearch are append-only on
the data path and already accept additive column / mapping additions at boot
without operator intervention, so the flag is unread on those backends.

> **Operator caveat:** BanyanDB does not physically migrate existing rows
> when a tag's family changes. Pre-existing data for the relocated tag stays
> in its original on-disk family location; new writes go to the declared
> family. Queries that route through a new IndexRule on the relocated tag
> will only see post-reshape rows until historical data ages out via TTL.

## On-demand workflow

Triggered by an HTTP call to one of the admin endpoints. A request arriving at any
Expand Down
Loading
Loading