Commit Graph
4942 Commits
Author SHA1 Message Date
dennis zhuang 6d86e6ff06 feat: synthesize OTLP resource descriptor for the semantic entity graph (#8904)
* fix(servers): compose OTLP metrics job from service.namespace/service.name

The OTel Prometheus compatibility spec defines job as
"<service.namespace>/<service.name>" when the namespace is present.
The OTLP metrics path only used the bare service.name, so the job tag
diverged from target_info produced by Prometheus-side exporters for the
same resource. Compose the namespace form, and keep not fabricating a
job when service.name is absent.

Behavior change: resources carrying service.namespace now get
"namespace/name" as their job tag value.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* feat(otlp): synthesize otel_resource_info at OTLP metrics ingestion

Ordinary OTLP metrics scatter filtered resource attributes as tags over
every logical metric table, so metrics-only services contribute nothing
to the semantic entity graph. Each request now also projects its
distinct resources into one info-metric-shaped mito table,
otel_resource_info: a fixed allowlist of identity-relevant attributes
under their raw OTel keys (independent of the label translation
strategy and the promote/ignore headers) plus derived job/instance
compatibility columns, value 1.0, and the newest data-point timestamp.

The descriptor is written after the main insert is committed; a failure
there (conflicting pre-existing table, auto-create disabled) degrades
to an OTLP partial_success warning with rejected_data_points = 0
instead of failing the request and triggering client retries of
already-accepted data. A request writing a metric named
otel_resource_info suppresses synthesis. Legacy mode is unchanged.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* feat(operator): otel info-metric conventions with host/container entities

Whitelist the ingestion-synthesized otel_resource_info descriptor via a
new otel_info_metrics conventions map, gated on source=opentelemetry
(the existing gate hardcoded source=prometheus). Its declarations use
explicit descriptive lists instead of descriptive_rest so identifying
attributes of other entities do not leak into service.instance.

Conventions tightened per the Astronomy Shop findings: host identity is
host.id with host.name descriptive only (host.name is not stable across
SDKs and resource detectors), a generic container entity (new entity
type) is declared only when container.id is present, and trace-v1
tables now synthesize host/container from their flattened resource
attributes too. New co-declared edges: service.instance runs_on
container, container runs_on host.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test(otlp): cover the resource descriptor in integration tests

Covers the descriptor's raw-key columns and info-metric options through
the HTTP path, the namespace/name job composition end-to-end, column
names being independent of the translation strategy, the allowlist
excluding unlisted resource attributes, auto-create after a drop, the
metric-name collision suppressing synthesis, and the partial-success
warning (rejected_data_points = 0) when a pre-existing incompatible
table fails the descriptor write while metric data is accepted.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* chore: cargo fmt

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(frontend): degrade descriptor permission denial to a warning

A table-level permission policy denying otel_resource_info would have
failed the whole OTLP metrics request because the descriptor's
permission check ran before the main insert. The descriptor is derived
enrichment: check its permission in the degrade path so a denial skips
the write and surfaces as the partial-success warning, like any other
descriptor write failure.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(otlp): guard descriptor writes with semantic ownership markers

A pre-existing schema-compatible table named otel_resource_info would
silently receive descriptor rows while its missing semantic stamps kept
it out of the entity graph. The descriptor write now requires the
auto-created table's ownership markers (mito engine + signal_type +
source + metric.type=info + metadata_quality=declared) and otherwise
degrades to the partial-success warning; the entity-graph gate for the
otel whitelist likewise requires metric.type=info, so a user table
stamped with only signal/source no longer picks up implicit
declarations.

Also fold the descriptor write cost into the response and surface the
degrade warning through the otel-arrow BatchStatus status_message.
Integration tests pin the full marker set on auto-create and that an
existing owned descriptor keeps accepting writes without degrading —
a missing marker would otherwise silently stop every descriptor write
after the first request.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* perf(otlp): build descriptor rows without the per-resource BTreeMap

Projecting a resource allocated a BTreeMap and then collected it into the
row key, and every attribute was matched against the allowlist by linear
scan. Collect the tags into a Vec and sort once, and match the allowlist
instead of scanning it. Measured on the conversion path: descriptor work
drops 16-18%, from 10.6% to 8.9% of conversion CPU on the worst shape
(1000 resources with 4 data points each), where the cost tracks resource
count rather than data-point count.

Also trims the comments and tests added with the descriptor to what
carries information.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test(otlp): pin the descriptor permission-denial degrade path

A policy denying the descriptor table must not fail the metrics request,
which the fix in 2401b3dd9c does but nothing covered. Verified as a
regression guard by mutation: moving the permission check back before
the main write makes this test fail.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test(otlp): keep legacy mode covered after trimming the unit tests

Trimming the descriptor tests dropped the only assertion that legacy
mode skips the job/instance remap and the promote filter. Both alter
the columns of tables already in use, so fold the check into the legacy
conversion test rather than leaving it uncovered.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(semantic-graph): stop encoding column names into composite entity ids

A composite entity id rendered the identifying columns as sorted
`col=value` pairs, so the same identity split into one entity per
signal: a trace table names its columns service_name and
resource_attributes.service.instance.id where a metric table names them
job and instance. One service instance became two nodes with two
parallel edge sets, breaking the walk from a trace to that instance's
metrics.

Render an id as its values in declared order instead, escaping the
separator so components stay distinguishable, which is what single-column
ids already did by keeping only the value. entity_id_attrs still carries
the structured form.

Values alone are not enough for a namespaced service: the metric side
folds service.namespace into job while traces keep the bare name. Add
qualified_by to the conventions so the trace declarations compose the
namespace the same way, per the OTel rule that job is
<service.namespace>/<service.name> or the bare name when the namespace
is empty. A table without the namespace column keeps the unqualified
identity rather than losing the declaration.

Conventions validation now rejects one entity type declared with a
different number of id columns by two sources, which would silently
produce ids that can never match.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* style(otlp): import the parent module by crate path

check-super-imports.py, part of the CI format gate, rejects a
file-level `use super::`.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* feat(otlp): gate the resource descriptor, and fix what review found

Synthesizing greptime_otel_resource_info creates and writes a table the
user never sent, so it is now off unless
otlp.experimental_enable_resource_info says otherwise. With it off the
request costs exactly what it did before the descriptor existed: nothing
is projected, no table is created, no write and no permission check
happen. Tests run with it on. StandaloneOptions carried no otlp field,
so the whole [otlp] section was silently dropped in standalone mode; map
it through, or the new option (and trace_ingest_chunk_size before it)
would do nothing there.

Renamed from otel_resource_info: the greptime_ prefix marks the table as
engine-managed and makes a collision with a user metric unlikely, which
is what the pre-existing-table ownership check and its per-request
catalog lookup were defending against. Both are gone.

A request may carry data for several graph windows, but the descriptor
folded every data-point time into one row at the newest of them, leaving
the earlier windows with metric rows and no entities. Key the rows by
window as well, and take the times from the data points the encoder
actually writes: it drops exponential histograms, and a resource
carrying nothing else was being described as an entity with no
measurements.

Projecting a resource cloned its attributes once per data point. Nest
the windows under the attributes instead, so they are moved once per
resource, and walk the data-point times through a visitor rather than
collecting a Vec per metric.

Also documents what the two maps key and hold, and lifts the projected
attribute names to constants beside KEY_SERVICE_NAME.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(otlp): skip the descriptor's work entirely when it is disabled

The collision scan over the request's output tables ran even with the
feature off. Short-circuit on the option instead, and update the config
snapshot the new [otlp] section changed.

Also drops the doc comment orphaned by the deleted ownership check: it
had attached itself to the trait impl and described a check that no
longer exists.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* refactor(semantic-graph): drop the expect and name the service identity

The CASE is built through Case directly rather than the fallible
when().otherwise() builder, so the non-test path no longer carries an
expect (architecture-invariants $4).

service_identity returned two same-typed Options that both call sites
destructured positionally; a named struct makes a swap fail to compile.

Also records that id-column order is part of the identity, where the
option docs and the conventions authors will read it.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* chore(semantic-graph): drop comments that narrate the code

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(semantic-graph): cast duration_nano before the trace-table union

Trace tables written before the signed-integer ingest change hold
duration_nano as UInt64 and later ones as Int64. The calls derivation
unions the per-table selects, and the two have no common integer type,
so a deployment holding both shapes could not build the plan. The
cross-table test now spans both.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* refactor(semantic-graph): drop the redundant duration_nano casts

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(otlp): decide exponential histogram acceptance in one place

The resource descriptor mirrored only the experimental gate, so with both
experimental flags on a resource whose only metric is a delta exponential
histogram was described as an entity with no measurements. The encoder's
whole-metric rules move into exponential_histogram_gate, which both call,
and the descriptor takes its timestamps through exponential_histogram_value
so per-point rejections drop out too.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
2026-08-25 13:08:44 +00:00
dennis zhuang 1851f6bf4d fix(query): keep INSERT timestamp conversion out of the source query (#8911)
* fix(query): keep INSERT timestamp conversion out of the source query

Interpreting an INSERT's string timestamps used to work by pushing the
conversion down into the source query, which changed what that query
means. Two consequences:

- Pushing through a UNION's DISTINCT moved the dedup key from the raw
  strings to parsed instants, so rows spelling the same instant
  differently collapsed into one. On an append-only table that is a
  silently dropped row.
- A UNION branch that needed no conversion (a NULL, or an explicit cast)
  made the whole column give up, leaving sibling branches on UTC while
  the rest of the row used the session timezone.

Convert at the assignment instead, by routing its cast through a
timezone-carrying timestamp type and back. Arrow applies the timezone
when a cast target carries one, and stripping it afterwards preserves
the value. The source query is no longer touched, so both cases go away
and the tree-walking rewrite (roughly 160 lines) is deleted.

The rewrite reads source types, so it now runs TypeCoercion first: a
UNION still carries its loose per-branch schema before coercion, and
retargeting a cast whose input later becomes a timestamp would shift the
value rather than reinterpret it.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(query): address review on INSERT assignment rewrite

- Clone the input `Arc` instead of the whole subtree, and only rebuild it
  when a `Values` row actually changes.
- Defer cloning the cast source until the literal-folding path has been
  ruled out.
- Move the UTC check onto `Timezone::is_utc`, replacing a bare string
  compare.
- Cover a prepared `INSERT ... VALUES (?)`: an untyped placeholder types
  as `Null`, so the assignment cast is left for parameter substitution.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
2026-08-25 12:34:53 +00:00
Lei, HUANG 73c4140938 feat(function): expose uddsketch rank (#8929)
* feat(function): expose uddsketch rank

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* test(function): cover uddsketch rank in sqlness

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* fix(function): support legacy uddsketch rank

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* docs(function): document uddsketch rank behavior

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

---------

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>
2026-08-25 11:31:47 +00:00
LFC 932f87f7a8 refactor(json2): support querying v2 storage layout (#8940)
* feat(json2): support querying v2 storage layout

- route missing JSON2 paths to the v2 remainder field
- reconstruct complete values from explicit fields and remainder data
- preserve root JSON2 columns across projections and filters
- support nested JSON values in json_get string results
- add and reorganize JSON2 sqlness coverage

Signed-off-by: luofucong <luofc@foxmail.com>

* resolve PR comments

Signed-off-by: luofucong <luofc@foxmail.com>

---------

Signed-off-by: luofucong <luofc@foxmail.com>
2026-08-25 11:11:06 +00:00
Weny Xu 28398138ec fix(flight): bound DoGet response wait (#8943)
* fix(flight): defer datanode query initialization

Signed-off-by: WenyXu <wenymedia@gmail.com>

* fix(client): retain Flight stream peer context

Signed-off-by: WenyXu <wenymedia@gmail.com>

* fix(client): improve Flight stream diagnostics

Signed-off-by: WenyXu <wenymedia@gmail.com>

---------

Signed-off-by: WenyXu <wenymedia@gmail.com>
2026-08-25 10:31:06 +00:00
Weny Xu 8a473c5bf0 fix(meta): allow manual migration from offline datanodes (#8934)
* fix(meta): allow migration from offline datanodes

Signed-off-by: WenyXu <wenymedia@gmail.com>

* test: fix offline migration event actor

Signed-off-by: WenyXu <wenymedia@gmail.com>

* test: read migration routes from metadata

Signed-off-by: WenyXu <wenymedia@gmail.com>

---------

Signed-off-by: WenyXu <wenymedia@gmail.com>
2026-08-25 10:30:59 +00:00
Yingwen 046862f067 feat(cmd): improve parquet rewrite fidelity and scanbench output (#8947)
* feat(cmd): preserve parquet rewrite metadata settings

Signed-off-by: evenyag <realevenyag@gmail.com>

* feat(cmd): print scanner metrics in verbose scanbench

Signed-off-by: evenyag <realevenyag@gmail.com>

* fix(cmd): preserve SST truncation settings in property dumps

Signed-off-by: evenyag <realevenyag@gmail.com>

---------

Signed-off-by: evenyag <realevenyag@gmail.com>
2026-08-25 09:22:53 +00:00
Yingwen a3a0db63b8 feat(mito2): add series index searcher (#8926)
* feat(mito2): add series index searcher

Signed-off-by: evenyag <realevenyag@gmail.com>

* refactor(mito2): use parquet push decoder for series index

Signed-off-by: evenyag <realevenyag@gmail.com>

* fix(mito2): handle evolved series index schemas

Signed-off-by: evenyag <realevenyag@gmail.com>

---------

Signed-off-by: evenyag <realevenyag@gmail.com>
2026-08-25 07:01:10 +00:00
shuiyisong 04614175fe refactor: centralize native histogram encoding in common-query (#8945)
* refactor: centralize native histogram encoding in common-query

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: fmt

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

---------

Signed-off-by: shuiyisong <xixing.sys@gmail.com>
2026-08-25 06:26:09 +00:00
discord9 3493d2d0fb perf(servers)!: speed up Prometheus JSON response building with ryu and per-series entry reuse (#8815)
* fix(perf): align direct-SST CREATE TABLE with baked index metadata

The offline fixture generator (query_perf_fixture::direct_sst::
build_region_metadata) bakes greptime:inverted_index /
greptime:skipping_index field metadata into the region manifest for
tag/field columns, but create_table_sql emitted a bare CREATE TABLE
without those declarations. MergeScan's remote-schema validation then
failed on any tag/field projection (HTTP 500 'advertised remote stream
schema field mismatch'), breaking direct_readable_sst perf cases.

CREATE TABLE now declares the matching SKIPPING INDEX WITH
(granularity='1') / INVERTED INDEX column options. A round-trip test
proves the emitted SQL is parser-valid and yields the exact catalog
metadata.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* perf(servers): speed up Prometheus JSON response building with ryu and per-series entry reuse

PrometheusJsonResponse::record_batches_to_data spends ~47% of its CPU
in f64::to_string() per sample and ~32% in IndexMap::entry() per row
(60s profile of concurrent query_range workloads, ~800k series).

- Replace f64::to_string() with ryu::Buffer::format_finite for finite
  values (shortest round-trip, 3-5x faster); NaN/+Inf/-Inf keep the
  previous std formatting so wire output is unchanged.
- Remember the previous row's label vector and entry index; query output
  is clustered by series, so consecutive rows reuse the same IndexMap
  entry via get_index_mut instead of rebuilding and hashing the label
  vector (worst case adds one Vec comparison per series transition).

Also adds a query-regression case (prom_json_response) that measures the
real Prometheus HTTP range API path (/v1/prometheus/api/v1/query_range),
which is the only frontend path that builds the Prometheus JSON response
(TQL ANALYZE formats the SQL JSON shape instead), plus a prom_http query
kind in the regression runner.

Perf (aligned base d90cca4b75, 256 series x 481 points):
- prom_range_2h (JSON response path): 29.31ms -> 21.46ms (-26.8%)
- tql_range_2h_control (non-JSON path): +1.87% (noise)

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* fix(servers): keep Prometheus wire format for integral floats with ryu

ryu::Buffer::format_finite prints integral values as "1.0", but the
Prometheus JSON wire format (matching std f64::to_string) expects "1".
Strip the trailing ".0" that ryu only emits for integral values; extreme
values keep ryu scientific notation, and NaN/Inf keep std output. Adds
wire-format tests covering 1.0, 0.0, -0.0, 1.5, 0.1, 1e21, 1e30, 1e-7,
f64::MAX, NaN, ±Inf.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* fix(servers): address Prometheus response review feedback

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* perf(servers)!: use ryu for Prometheus sample values

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* fix(cmd): skip Prometheus execution time extraction

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

---------

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
2026-08-25 05:16:50 +00:00
Yingwen 0cc83c4570 feat(cmd): add parquet development tools (#8939)
* feat(cmd): add parquet metadata development tool

Signed-off-by: evenyag <realevenyag@gmail.com>

* feat(cmd): add parquet rewrite development tool

Signed-off-by: evenyag <realevenyag@gmail.com>

* feat(cmd): add SST replacement development tool

Signed-off-by: evenyag <realevenyag@gmail.com>

* feat(cmd): support local parquet files in parquetbench

Signed-off-by: evenyag <realevenyag@gmail.com>

* fix(cmd): clean up parquet development tools

Signed-off-by: evenyag <realevenyag@gmail.com>

* refactor(cmd): share datanode tool utilities

Signed-off-by: evenyag <realevenyag@gmail.com>

* fix(cmd): satisfy parquet tool lints

Signed-off-by: evenyag <realevenyag@gmail.com>

* docs: document parquet development tools

Signed-off-by: evenyag <realevenyag@gmail.com>

* refactor(cmd): rename SST replacement module

Signed-off-by: evenyag <realevenyag@gmail.com>

* fix(cmd): validate parquet rewrite options

Signed-off-by: evenyag <realevenyag@gmail.com>

---------

Signed-off-by: evenyag <realevenyag@gmail.com>
2026-08-24 13:34:30 +00:00
shuiyisong 1c5eabcbbf feat(otlp): support cumulative exponential histograms (#8900)
* feat: implement exponential histogram

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* chore: remove duplicate tests

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix(otlp): enforce exponential histogram ingestion safety

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* chore: update rfc

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: test

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix(otlp): remove protocol-coupled histogram checks

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* perf(otlp): reuse native histogram schema across data points

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: merge repeated OTLP histogram fragments

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix(otlp): build rejection messages lazily

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: add doc

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

---------

Signed-off-by: shuiyisong <xixing.sys@gmail.com>
2026-08-24 12:59:44 +00:00
shuiyisong 82444635f5 feat: support quantile and fraction queries on mixed histograms (#8874)
* fix: test

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: remove try_build_float_literal

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: remove NonCommutative

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: NaN

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* chore: add comments

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* test(query): cover frontend-only histogram fold planning

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix(promql): ignore unparseable histogram bucket labels

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: typo

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: sqlness

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

---------

Signed-off-by: shuiyisong <xixing.sys@gmail.com>
2026-08-24 12:45:35 +00:00
Lei, HUANGandYingwen 4ac3423261 fix(mito2): split SSTs at primary key series boundaries (#8888)
* fix(mito2): split SSTs at series boundaries

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* test(mito2): cover SST splitting without primary key

Also document the sortedness precondition and the series boundary
split semantics on write_all_flat/write_all_flat_as_primary_key and
the new split helpers.

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* test(mito2): avoid per-row Vec allocation for empty primary key

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* Update src/mito2/src/sst/parquet/writer.rs

Co-authored-by: Yingwen <realevenyag@gmail.com>

---------

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>
Co-authored-by: Yingwen <realevenyag@gmail.com>
2026-08-24 10:02:32 +00:00
Ning Sun 174577164a feat: otlp duration_nano and trace_flag signed integer coercion (#8816)
* feat(servers): add signed→unsigned int coercion to OTLP ingest path

Phase 0 of transitioning built-in data models from unsigned to signed
integers (#8793): add lossless Int64→UInt64 and Int32→UInt32 coercion
arms so existing UInt64/UInt32 columns (e.g. trace `duration_nano`, log
`trace_flags`) keep accepting new signed ingest without an ALTER TABLE.

The OTLP ingest path already reconciles every incoming column against the
existing table schema and treats it as authoritative. With these arms,
`choose_trace_reconcile_decision` returns `UseExisting(UInt64/Uint32)`
for an existing unsigned column receiving signed data: the table keeps
its type byte-for-byte and the request value is coerced. No persisted
format is mutated; existing data stays readable as-is. This is the safety
net that makes the actual schema flip (Phase 1) safe.

Only the signed→unsigned direction is supported — the reverse would be
lossy for values above the signed range and is intentionally rejected.

Tests cover both new arms plus an end-to-end log test proving an existing
UInt64 column coerces an incoming Int64 value while keeping its type.

Signed-off-by: Ning Sun <sunning@greptime.com>

* feat: add compatibility layer for uint trace/log fields

Signed-off-by: Ning Sun <sunning@greptime.com>

* fix: jaeger test

Signed-off-by: Ning Sun <sunning@greptime.com>

* fix: keep trace v0 unsigned, reject negative span durations

- Keep the frozen v0 data model on UInt64 duration_nano: the signed
  ingest compatibility layer only runs on the v1 path, so flipping v0
  would break writes into every pre-existing v0 table at mito's schema
  check. Pin the schema with unit and integration tests.
- Reject spans whose end precedes their start (or whose duration does
  not fit i64) on the v1 path instead of wrapping: new Int64 tables and
  existing UInt64 tables now fail identically, rather than storing
  negative durations that break the Jaeger query API.
- Extract is_supported_signed_to_unsigned_coercion so the trace and log
  ingest paths share one supported-pair predicate and cannot drift.

Signed-off-by: Ning Sun <sunning@greptime.com>

* fix: clamp negative span durations to zero, revert semantic_graph comment

- Record duration 0 for spans whose end precedes their start instead of
  erroring: a malformed span no longer fails the request, and the value
  written is always a non-negative, in-range i64 so new Int64 tables and
  existing UInt64 tables (via the checked coercion) behave identically.
  Durations above i64::MAX saturate rather than wrap.
- Revert the doc-comment tweak on the semantic_graph test fixture; the
  file is untouched by this PR again.

Signed-off-by: Ning Sun <sunning@greptime.com>

---------

Signed-off-by: Ning Sun <sunning@greptime.com>
2026-08-24 09:28:49 +00:00
Weny Xu a502dfdefd fix(mito2): fence checkpoints during region transitions (#8847)
* fix: fence checkpoints during region transitions

Signed-off-by: WenyXu <wenymedia@gmail.com>

* test(datanode): fix transient downgrade setup

Signed-off-by: WenyXu <wenymedia@gmail.com>

* test(mito2): fix checkpoint lifecycle test setup

Signed-off-by: WenyXu <wenymedia@gmail.com>

* test(mito2): cover cancelled downgrade waiter retry

Signed-off-by: WenyXu <wenymedia@gmail.com>

* fix(mito2): fence direct follower transitions

Signed-off-by: WenyXu <wenymedia@gmail.com>

* test: trim checkpoint transition coverage

Signed-off-by: WenyXu <wenymedia@gmail.com>

* refactor(mito2): clarify checkpoint task lifecycle

Signed-off-by: WenyXu <wenymedia@gmail.com>

---------

Signed-off-by: WenyXu <wenymedia@gmail.com>
2026-08-24 06:09:44 +00:00
LFC 7fd0a7bb98 refactor(json2): optimize JSON2 building without auto-expanded paths (#8928)
* refactor(json2): optimize JSON2 building without auto-expanded paths

Signed-off-by: luofucong <luofc@foxmail.com>

* resolve PR comments

Signed-off-by: luofucong <luofc@foxmail.com>

* avoid panicking memtable write

Signed-off-by: luofucong <luofc@foxmail.com>

---------

Signed-off-by: luofucong <luofc@foxmail.com>
2026-08-21 12:14:47 +00:00
LFC 76f08d2b3f refactor(json2): add bounded auto-expansion to the JSON2 vector builder (#8909)
* refactor(json2): add bounded auto-expansion to the JSON2 vector builder

Signed-off-by: luofucong <luofc@foxmail.com>

* resolve PR comments

Signed-off-by: luofucong <luofc@foxmail.com>

* fix ci

Signed-off-by: luofucong <luofc@foxmail.com>

---------

Signed-off-by: luofucong <luofc@foxmail.com>
2026-08-21 03:28:39 +00:00
Weny Xu 8fac712870 fix(meta): avoid blocking runtime on stats cache lock (#8910)
Signed-off-by: WenyXu <wenymedia@gmail.com>
2026-08-19 12:43:42 +00:00
Lei, HUANG 2182dccd9b fix: cap default runtime sizes to a minimum of 2 threads (#8908)
* fix: cap default runtime sizes to a minimum of 2 threads

RuntimeOptions derived its default sizes directly from num_cpus. On
single-core machines every runtime (global, compact, query, ingest)
ended up with one worker thread, which can easily deadlock async code
(e.g. block_on combined with spawn).

Clamp all CPU-derived runtime sizes to at least 2 threads.

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* fix: init logging before runtimes so runtime options are logged

The global runtimes were initialized before the global logging
subscriber, so the "Creating runtime ..." info logs that carry the
runtime sizes were silently dropped. Initialize logging first in all
node start paths; common-telemetry has no dependency on
common-runtime, so the reorder is safe.

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

---------

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>
2026-08-19 10:04:50 +00:00
dennis zhuang 3de4feddd5 feat(otlp): report the cause of rejected trace spans (#8897)
* feat(otlp): report the cause of rejected trace spans

When trace-v1 ingestion cannot coerce an attribute value, it falls back to
single-span writes and rejects the bad span. That behavior is correct, but the
OTLP partial-success message only carried `Rejected span <trace_id>:<span_id>
(InvalidArguments)`: the column, the source value, the source type and the
target type were all dropped, so locating the bad attribute required adding a
detailed exporter on the collector side and replaying traffic.

Two places lost the information. `prepare_trace_column_rewrites` built a message
without the failing value, and the span rejection path kept only the status code
from the error.

Coercion errors now name the failing value, e.g.

    failed to coerce trace column 'span_attributes.http.response.body.size'
    in table 'opentelemetry_traces' from String("") to Int64

and the rejection detail carries that cause. Values are user data, so a string
keeps at most 16 characters, is escaped, and binary payloads report only their
length; the cause itself is bounded at 256 characters. Both truncations cut on a
char boundary.

Failure details now deduplicate: repeats of the same (site, cause) collapse into
one entry with an occurrence count, keyed on the untruncated cause so two
failures that differ past the display limit stay separate. Only four distinct
entries are retained and the rest are counted, which keeps the state bounded no
matter how many distinct bad values a request carries. A fully rejected request
is logged at warn level and a partial success at debug level, since the latter
repeats every export interval; the detail goes out as a Debug field so a newline
in an attribute key cannot forge log lines.

Rejection semantics are unchanged: partial success, same accepted and rejected
counts, same HTTP status mapping.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* refactor(otlp): compare failure keys directly instead of hashing

The dedup identity was a DefaultHasher fingerprint of `(label, key)`, which
bought a fixed 8 bytes per entry at the cost of an import, four lines, and a
collision argument the reader has to make. Entries are capped at four and a
cause runs a couple of hundred characters, so the saving is about a kilobyte
per in-flight request while the column name it avoids retaining is already held
several times over by the request itself.

Compare the strings instead, keeping the untruncated cause as the key so
failures differing past the display limit still stay apart. Labels are metric
label values and always static, so the entry borrows them.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
2026-08-19 04:32:23 +00:00
Ning Sun 8dbfbee611 refactor: remove open metrics parser (#8905) 2026-08-19 03:47:44 +00:00
LFC b96ea86a62 refactor(json2): add JSON2 v2 physical layout primitives (#8901)
* refactor(json2): add JSON2 v2 physical layout primitives

Signed-off-by: luofucong <luofc@foxmail.com>

* resolve PR comments

Signed-off-by: luofucong <luofc@foxmail.com>

* fix ci

Signed-off-by: luofucong <luofc@foxmail.com>

---------

Signed-off-by: luofucong <luofc@foxmail.com>
2026-08-19 02:27:06 +00:00
sun b882e393df feat: update dashboard to v0.13.13 (#8898) 2026-08-18 03:47:58 +00:00
LFC d7f1233f77 refactor(json2): support JSON2 storage layout settings in DDL (#8895)
* refactor(json2): add JSON2 storage layout settings

Signed-off-by: luofucong <luofc@foxmail.com>

* resolve PR comments

Signed-off-by: luofucong <luofc@foxmail.com>

---------

Signed-off-by: luofucong <luofc@foxmail.com>
2026-08-17 11:24:44 +00:00
dennis zhuang 10f587bc30 fix(query): preserve timestamp literal semantics in inserts (#8889)
* fix(query): follow timestamp insert assignment lineage

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(query): fold constant insert timestamp literals at the assignment

Following lineage by retyping the source column changed every output
column that reads it: a string column sharing the literal was silently
rewritten to a formatted timestamp, and a nanosecond column was
truncated to the precision of whichever column was converted first.

Resolve the constant read-only and fold it into the assignment
expression instead, which leaves the source query untouched and also
covers literals behind WHERE, ORDER BY and DISTINCT. VALUES rows and
UNION branches carry per-row values, so they keep the in-place rewrite,
now guarded against columns with more than one consumer.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test(query): strengthen insert lineage regression

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test(query): trim redundant insert coverage

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(query): rebuild insert unions loosely and cover UNION distinct

Per review: rebuilding a rewritten union with the strict constructor
rejected legal pre-coercion plans whose untouched columns still differ
across branches. Use try_new_with_loose_types, matching the SQL planner.

Distinct::All joins the rewrite passthrough so UNION (distinct) literals
get session-timezone parsing like UNION ALL; deduplication then keys on
parsed instants instead of raw strings. The top-level rewrite path gains
the same single-consumer guard as rewrite_projection for hand-built DML
plans that share a source column between targets.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* style(query): tighten insert assignment comments

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
2026-08-17 10:19:08 +00:00
dennis zhuang 09c0b23a23 feat: manage semantic table options via ALTER TABLE SET/UNSET (#8880)
* fix(meta): actually acquire logical table locks in alter-logical-tables procedure

The procedure listed its logical table locks from table_info_values,
which is only filled during Prepare, while procedure lock keys are
fixed at submission — so the logical locks were never acquired. Today
every writer of a logical table's info is serialized by the physical
table lock, which hides the problem; a metadata-only alter procedure
targeting a single logical table would race it.

Resolve the logical table ids at submission, persist them in the
procedure state (serde(default): state dumped by older versions keeps
the previous behavior), lock physical + logical tables, and re-check
the resolved ids against the locked set at Prepare so a table dropped
and recreated after submission cannot be mutated without a lock.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* feat: manage semantic table options via ALTER TABLE SET/UNSET

CREATE TABLE accepts greptime.semantic.* options, but ALTER TABLE SET
routed every option through SetRegionOption, whose closed match
rejects them — tables auto-created by ingestion could never receive
semantic declarations after the fact.

Semantic options are pure metadata markers no region consumes, so
they now take a metadata-only alter, following the repartition-hint
precedent:

- New AlterKind::SetAnnotations/UnsetAnnotations carrying an
  AnnotationFamily (currently only Semantic), so future marker-style
  option families reuse the same machinery. The converter classifies
  a SET/UNSET batch by key prefix and rejects batches that mix
  annotation keys with regular options.
- The procedure reuses the MetadataOnly flow: no region dispatch,
  table-info update plus cache invalidation only.
- Validation lives in the table-meta mutation layer, so it runs at
  frontend verification and again in the procedure's prepare step
  under the table lock: SET is strict (known key, value domain,
  entity columns exist and render as strings); UNSET is lenient
  inside the namespace so stale keys can be cleaned up.
  ModifyColumnTypes re-checks columns referenced by entity
  declarations at the same layer, closing a verify-then-execute race.
- Logical metric tables are supported: an annotation alter submits a
  regular alter-table task locking only the logical table, and the
  DDL manager's physical-route guard admits it.
- create_table_info re-checks semantic value domains for gRPC-built
  expressions that bypass the SQL parser.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* refactor(table): centralize annotation option classification and validation

Address review feedback on the AnnotationFamily abstraction: with only
one variant that every consumer immediately destructured, the
generality was fake. Make it real and exhaustive instead:

- AnnotationFamily gains RepartitionHint: repartition.column.hint is
  the same kind of marker option (pure metadata, no region consumes
  it) and previously had a hand-rolled special case in the converter,
  the metadata-only classifier, and a dedicated AlterKind pair — all
  deleted, one classification API remains. Per-family logical-table
  eligibility (allows_logical_tables) replaces the hard-coded
  Semantic check in the DDL manager guard.
- One validation core in the table crate (check_annotation) serves
  both DDL entry points. CREATE and ALTER previously duplicated the
  rules; each keeps its existing error variants, status codes and
  messages via thin adapters over a typed error (ALTER missing column
  stays 4002 TableColumnNotFound, CREATE stays InvalidArguments).
- The batch classifier returns Result instead of swallowing the
  mixed-batch error: a mixed SET on a logical table now reports the
  actual problem instead of UnexpectedLogicalRouteTable, and the flow
  classifiers propagate instead of guessing. The converter also moves
  its owned payloads instead of cloning them.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test(meta): cover logical-table annotation alter routing

The route-guard branch admitting metadata-only annotation alters on
logical tables was only exercised end to end by sqlness. Pin it at the
DDL manager level: a semantic SET on a logical table succeeds, updates
only the logical table's metadata and dispatches nothing to datanodes;
a mixed batch reports its own error instead of the route guard's; the
repartition hint stays rejected on logical routes.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(table): keep entity guard on ADD COLUMN and report missing columns first

Review follow-ups: the old verify_alter loop scanned the post-alter
schema, so it also caught DROP COLUMN followed by re-adding the
declared column with a non-string type — the mutation-layer move only
kept the MODIFY path. Guard add_columns the same way (this also covers
ingestion auto-alter). And run the MODIFY drift check after the
existence lookup, so altering a dropped-but-still-declared column
reports ColumnNotExists (4002) like every other MODIFY on a missing
column.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* style(grpc-expr): drop a test comment restating the classifier doc

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* refactor(table): rename annotation validation helpers per review

check_annotation* validated and normalized; align the names with the
validate_and_normalize_* convention nearby, and spell out
AnnotationContext (Cx is not used in this repo).

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
2026-08-17 09:53:59 +00:00
Yingwen 4126cf99b6 refactor(mito2): rename pk index to series index (#8893)
Signed-off-by: evenyag <realevenyag@gmail.com>
2026-08-17 07:21:29 +00:00
Lei, HUANG a8924bb95c refactor(udaf): replace uddsketch implementation (#8867)
* refactor(function): replace uddsketch implementation

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* bench(function): compare uddsketch batch ingestion

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* perf(function): avoid copying non-null uddsketch batches

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* fix(function): decode legacy uddsketch states

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* fix(function): harden legacy uddsketch validation

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* format: taplo

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* test: add compatibility tests for uddsketch functions

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

---------

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>
2026-08-14 12:20:04 +00:00
Yingwen cb30837cd5 feat: add incremental primary key index writer (#8788)
* feat: initial implementation of the pk index writer

Signed-off-by: evenyag <realevenyag@gmail.com>

* perf: optimize primary key index writer

Signed-off-by: evenyag <realevenyag@gmail.com>

* chore: add todo

Signed-off-by: evenyag <realevenyag@gmail.com>

* feat(mito2): track series count in pk index metrics

Signed-off-by: evenyag <realevenyag@gmail.com>

* refactor(mito2): simplify pk index writer cleanup

Signed-off-by: evenyag <realevenyag@gmail.com>

* fix(mito2): clean up aborted pk index writers

Signed-off-by: evenyag <realevenyag@gmail.com>

---------

Signed-off-by: evenyag <realevenyag@gmail.com>
2026-08-14 12:06:27 +00:00
shuiyisong 072810159a chore: add v2 version label to prom metrics (#8885)
Signed-off-by: shuiyisong <xixing.sys@gmail.com>
2026-08-14 09:40:50 +00:00
Weny Xu ed4271af40 feat(procedure): record event actor (#8849)
* feat(event): record procedure actor

Signed-off-by: WenyXu <wenymedia@gmail.com>

* test: handle streamed region migration output

Signed-off-by: WenyXu <wenymedia@gmail.com>

* test: cover procedure actors across SQL protocols

Signed-off-by: WenyXu <wenymedia@gmail.com>

---------

Signed-off-by: WenyXu <wenymedia@gmail.com>
2026-08-14 09:36:01 +00:00
sun 2eb5f593f8 feat: update dashboard to v0.13.12 (#8882) 2026-08-14 08:45:02 +00:00
dennis zhuang 4dd92c774e feat: add json_object function and use it in the entity-graph derivation (#8870)
* feat: add json_object scalar function

Builds a JSONB object from interleaved (key, value, ...) arguments, like
MySQL's JSON_OBJECT. Values are written into the binary directly, so
JSON-hostile characters (quotes, backslashes, control characters) need no
text-level escaping. Keys must be non-NULL strings; values may be strings,
numbers, booleans, or NULL (JSON null).

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix: build entity-graph JSON objects with json_object

The derivation assembled entity_id_attrs and descriptive by concatenating a
JSON text and parsing it, escaping only backslash and double quote in runtime
values. A label containing a control character (e.g. a newline) produced
unparseable text and failed the whole semantic_entities scan instead of one
attribute. json_object assembles the JSONB binary directly from the value
columns, so no text escaping is involved; NULL-to-'' stays at the call site.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* chore: trim comments and fold duplicate test coverage

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix: json_object() returns an empty object; narrow values to integers and floats

MySQL's JSON_OBJECT allows an empty pair list, so the signature accepts zero
arguments and the row count falls back to number_rows. Decimals stay rejected
instead of casting to Float64: JSONB numbers (i64/u64/f64) cannot represent
them exactly and a silent precision loss is worse than an explicit cast.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* chore: document key-to-string conversion and align test naming

Keys follow MySQL JSON_OBJECT: any castable type is converted to string.
Rustdoc and the cast-failure message now say so, with a numeric-key test.
Test names take the module-conventional test_ prefix.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
2026-08-14 08:24:50 +00:00
Morax c3cd186997 fix(query): respect query timezone in timestamp casts (#8859)
* fix(query): respect timezone in insert values

Signed-off-by: Morax <james20081204@gmail.com>

* fix(query): normalize timestamp casts with query timezone

Signed-off-by: Morax <james20081204@gmail.com>

* fix(query): scope timestamp conversion to insert assignments

Signed-off-by: Morax <james20081204@gmail.com>

* style(query): simplify Arc usage

Signed-off-by: Morax <james20081204@gmail.com>

---------

Signed-off-by: Morax <james20081204@gmail.com>
2026-08-14 07:04:51 +00:00
Yingwen 76924c2d36 feat(mito2): introduce two-phase metric series scans (#8826)
* feat(mito2): add two-phase series scan

Signed-off-by: evenyag <realevenyag@gmail.com>

* docs: regenerate configuration reference

Signed-off-by: evenyag <realevenyag@gmail.com>

* test(sqlness): update series scan explain results

Signed-off-by: evenyag <realevenyag@gmail.com>

* test: update config API expectation

Signed-off-by: evenyag <realevenyag@gmail.com>

* fix(mito2): bound two-phase series discovery

Signed-off-by: evenyag <realevenyag@gmail.com>

* fix(mito2): avoid candidate distribution deadlock

Signed-off-by: evenyag <realevenyag@gmail.com>

* chore(mito2): remove obsolete dead code allowances

Signed-off-by: evenyag <realevenyag@gmail.com>

* fix(mito2): share series scan memory pool

Signed-off-by: evenyag <realevenyag@gmail.com>

---------

Signed-off-by: evenyag <realevenyag@gmail.com>
2026-08-14 06:32:17 +00:00
fys 6538db6d61 refactor(json2): push down json2 type hints to parquet reads (#8833)
* refactor(mito): push down json2 type hints to parquet reads

Signed-off-by: fys <fengys1996@gmail.com>

* refactor(mito): share json2 target types with arc

Signed-off-by: fys <fengys1996@gmail.com>

* refactor(mito): derive json2 output schema from target types

Signed-off-by: fys <fengys1996@gmail.com>

* refactor(mito): simplify read columns construction

Signed-off-by: fys <fengys1996@gmail.com>

* fix: cargo check

Signed-off-by: fys <fengys1996@gmail.com>

* fix(mito): reject JSON hints for non-JSON2 read columns

Signed-off-by: fys <fengys1996@gmail.com>

* fix: do not pushdown json type hint of non-json2-col

Signed-off-by: fys <fengys1996@gmail.com>

* fix: unit test

Signed-off-by: fys <fengys1996@gmail.com>

* refactor(query): simplify JSON type hint application

Signed-off-by: fys <fengys1996@gmail.com>

* refactor: clean up JSON2 type hint handling

Signed-off-by: fys <fengys1996@gmail.com>

* refactor(mito2): keep JSON2 hints with flat read format

Signed-off-by: fys <fengys1996@gmail.com>

* fix(mito): use raw parquet projection for output schema

Signed-off-by: fys <fengys1996@gmail.com>

* fix(query): note JSON2 hint scope limitation

Signed-off-by: fys <fengys1996@gmail.com>

* refactor(mito): store JSON target types as native types

Signed-off-by: fys <fengys1996@gmail.com>

* test(json2): cover join hint qualifier limitation

Signed-off-by: fys <fengys1996@gmail.com>

* refactor(mito): remove JSON2 fallback from compat cast

Signed-off-by: fys <fengys1996@gmail.com>

* docs(mito): document ReadColumns ordering contract

Signed-off-by: fys <fengys1996@gmail.com>

* fix: cargo clippy

Signed-off-by: fys <fengys1996@gmail.com>

---------

Signed-off-by: fys <fengys1996@gmail.com>
2026-08-14 06:21:17 +00:00
shuiyisong b1263fc65f perf: optimize Prometheus remote write v2 decoding (#8873)
* test: add bench for prom decode

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* chore: merge v2 decode manually and add to bench

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* refactor: update v2 path

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* refactor: update v2 path

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix: use constant

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

---------

Signed-off-by: shuiyisong <xixing.sys@gmail.com>
2026-08-14 06:15:42 +00:00
discord9 f692ac32f3 test(mito2): isolate sequence publication barrier (#8876)
* test(mito2): isolate sequence publication barrier

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* test(mito2): trim sequence barrier test noise

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

---------

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
2026-08-14 04:21:46 +00:00
jeremyhi 3c80df043a fix(mito2): keep deletion markers when compacting part of a window (#8872)
`TwcsPicker::find_inputs` decides `filter_deleted` from the shape of the whole
time window, but the compaction inputs are only a subset of it: `reduce_runs`
and `merge_seq_files` narrow the selection down and the max input file num limit
narrows it further. When a deletion marker lands in the compacted set while the
file holding the row it masks stays behind, the marker is dropped from the
output and the old row becomes visible again.

Re-check the final selection against the rest of the window and stop filtering
deleted rows whenever something left behind still overlaps the inputs. The check
compares ranges inclusively, so it also covers files that share only a boundary
timestamp: run detection treats those as non-overlapping, which is how a single
timestamp delete file ends up in the same run as the file it deletes rows from.

Signed-off-by: jeremyhi <fengjiachun@gmail.com>
2026-08-13 14:17:09 +00:00
Lei, HUANG 7539e60139 refactor: remove trivial tests (#8877)
* refactor: remove trivial tests

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

* fix: remove unused trace test import

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>

---------

Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>
2026-08-13 12:10:49 +00:00
Ning Sun 354921c80e chore: update mysql test drivers and lru (#8868)
* chore: update mysql test drivers and lru

* fix: test
2026-08-13 10:58:29 +00:00
jeremyhi 764c93bf43 perf(query): choose bounded CTE as hash join build side (#8807)
* fix(query): choose bounded CTE as hash join build side

Signed-off-by: jeremyhi <fengjiachun@gmail.com>

* perf(query): remove join estimate cap

* test(compat): accept repartition in analyze plan

Signed-off-by: jeremyhi <fengjiachun@gmail.com>

---------

Signed-off-by: jeremyhi <fengjiachun@gmail.com>
2026-08-13 10:51:53 +00:00
Lanqing Yang 0e28916695 perf(mito2): optimize dictionary primary key sorting (#8767)
Signed-off-by: lyang24 <lanqingy93@gmail.com>
2026-08-13 07:52:44 +00:00
Weny Xu 1af4c33524 refactor(event): separate procedure submission context (#8856)
* refactor(event): separate procedure submission context

Signed-off-by: WenyXu <wenymedia@gmail.com>

* fix(event): map extensions and forward GC context

Signed-off-by: WenyXu <wenymedia@gmail.com>

* fix(gc): initialize integration test context

Signed-off-by: WenyXu <wenymedia@gmail.com>

* fix(test): pass procedure context to DDL helpers

Signed-off-by: WenyXu <wenymedia@gmail.com>

* refactor: simplify procedure submission contexts

Signed-off-by: WenyXu <wenymedia@gmail.com>

* refactor(event): separate procedure and query contexts

Signed-off-by: WenyXu <wenymedia@gmail.com>

* fix(event): clarify procedure context propagation

Signed-off-by: WenyXu <wenymedia@gmail.com>

* fix(event): preserve procedure submission context

Signed-off-by: WenyXu <wenymedia@gmail.com>

* refactor(event): move DDL context by value

Signed-off-by: WenyXu <wenymedia@gmail.com>

* fix(test): retain manual GC event context

Signed-off-by: WenyXu <wenymedia@gmail.com>

* refactor(event): tighten procedure context API

Signed-off-by: WenyXu <wenymedia@gmail.com>

* chore: update greptime-proto

Signed-off-by: WenyXu <wenymedia@gmail.com>

---------

Signed-off-by: WenyXu <wenymedia@gmail.com>
2026-08-13 07:29:00 +00:00
discord9 d0fecdd6b0 fix(mito2): publish committed sequence only after rows are installed (#8862)
The committed-sequence watermark must never cover rows that are not yet
physically visible. Previously write_memtable() published next_sequence - 1
before bulk parts were installed, so a scan opening a snapshot could bind H
to invisible sequences and permanently miss rows after checkpoint advance.

Publish once, after both ordinary and bulk memtable writes complete, in
the single-region fast path, the multi-region spawned tasks, and WAL
replay; skip publication for contexts whose WAL entry could not be built.
Add a deterministic worker-level race test using a cfg(test) bulk-install
barrier proving the committed sequence stays put until installation.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
2026-08-13 06:57:46 +00:00
dennis zhuang 546625c45a feat: embedded convention pack for the entity graph (prom/k8s, gen_ai naming) (#8854)
* feat: embed the derivation conventions as data and adopt gen_ai entity naming

Move the co-declared edge vocabulary, the agent-edge vocabulary and the
virtual-destination candidates from Rust consts into an embedded
conventions.yaml (include_str!), parsed once behind a LazyLock and
validated against the entity-type grammar and the closed rel_type set; a
broken file propagates as a plan error instead of panicking. The agent
vocabulary entity types follow the GenAI semantic-convention namespace
as written: gen_ai.agent / gen_ai.model / gen_ai.tool.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* feat: drop the tag requirement for entity identity columns

Entity declarations no longer require id columns to be tag/primary-key
columns; only column existence is validated. Trace pipelines flatten the
identifying attributes (span_attributes.gen_ai.agent.id, ...) into field
columns, so the tag rule locked real trace tables out of declaring
entities while buying no correctness — the read-time derivation works on
any column.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* feat: implicit declarations for well-known prometheus info metrics

Tables stamped signal_type=metric + source=prometheus whose name matches
the conventions.yaml whitelist (kube_pod_info, kube_node_info,
kube_pod_owner, target_info) get implicit entity declarations: k8s.pod /
k8s.node / k8s.workload with name-based identity and target_info's
service / service.instance with the remaining tags as the descriptive
snapshot. The existing co-declared vocabulary then derives runs_on and
part_of from the same rows, so no new edge branch is needed. Explicit
declarations of a type always suppress the implicit one, and the metric
engine's physical table is excluded (it aggregates every logical
table's columns).

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test: cover the prometheus conventions in sqlness and compact the graph cases

Add the whitelisted-info-metric scenario (kube_pod_info, kube_pod_owner,
target_info deriving runs_on / part_of, a non-whitelisted metric
contributing nothing), fold the single-table calls, cross-table pairing
and virtual-node cases into one trace scenario (they exercise the same
union-before-join path), merge the two declaring-metric-table cases, and
reuse one rename probe for both reserved names.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix: reject entity id columns without a stable string form

Review follow-ups: the DDL check now validates against the schema and
rejects binary-backed and nested types for identity columns (the
derivation renders ids via CAST to Utf8, so the failure used to surface
only when the graph was scanned); the agent sqlness case keeps its
identity columns as fields to cover the relaxed tag rule end to end;
stale tag-rule comments and a dangling const reference are cleaned up.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix: type-check every entity column role, not only ids

The registry renders scope and descriptive values through the same
CAST-to-string path as ids, so a binary-backed column in any role fails
at scan time; the DDL check is now role-independent (and simpler).

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* refactor: name the code-anchored vocabulary constants

Entity types and edge attributes the derivation code itself anchors on
(service, gen_ai.agent, calls, trace/attribute provenance) become
constants in the conventions module; the rest of the vocabulary stays
YAML-only data. ImplicitEntity is renamed PromImplicitEntity, and the
implicit-declaration path logs each skip of a whitelisted info metric
(wrong stamps, suppressed by an explicit declaration, missing id
column) so a missing graph entity is diagnosable.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* refactor: single-source the graph constants

The graph tables' column names move to common-catalog (the schemas
catalog exposes and the plans operator builds must match column by
column), and the conventions module now carries the complete built-in
vocabulary — entity types, rel_types, provenances and connection types —
with the embedded YAML validated by membership against it, so an edit
drifting outside the vocabulary fails the conventions test instead of
deriving nothing.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix: treat empty identity components as absent

kube-state-metrics emits empty-string labels an entity id must not be
built from: an unscheduled pod's node and an owner-less pod's owner_kind
/ owner_name. Standard Prometheus drops empty labels (they arrive as
NULL and the existing predicate handles them), but other remote-write
agents may keep them, which produced ghost entities with empty ids and
false runs_on / part_of edges. Every identity predicate (registry,
co-declared edges, span endpoints) now requires non-NULL and non-empty
components through one shared helper.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* refactor: tighten the conventions DSL semantics

Rename the co-declaration rule lists to what they are (co_declared_edges
/ trace_co_declared_edges — derivation rules, not a relation
vocabulary), stop overstating the GenAI entity types (Greptime types
derived from GenAI attributes; OTel defines no model/tool entities),
move target_info's descriptive snapshot to service.instance (the
remaining labels are the target's resource attributes, and instances
would write conflicting snapshots onto the logical service), and extend
the descriptor whitelist with the stable KSM sources: container info
metrics (closing the k8s.pod contains k8s.container rule),
kube_service_info (new k8s.service entity type) and the fuller
descriptive label sets.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix: guard entity column types on ALTER as well

ALTER MODIFY COLUMN could change a declared entity column to a type
without a stable string form, deferring the failure to graph scan time;
verify_alter now checks the post-alter schema. Dropping a declared
column stays allowed — the read-time derivation skips the stale
declaration, and semantic options cannot be altered off yet.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* feat: bridge traces and kube-state-metrics on the pod UID

Trace-v1 tables now get implicit declarations from their flattened
resource attributes (otlp_trace_entities in conventions.yaml): the
service identity — replacing the hardcoded fallback — plus
service.instance and k8s.pod, each applied only when its columns exist.
A new co-declared rule derives service.instance runs_on k8s.pod, and
the whitelisted kube-state-metrics pod identity switches from
namespace+pod names to the UID, so the trace-side pod and every KSM
descriptor land on one entity while names stay descriptive. This also
removes pod identity from the multi-cluster same-name collision.

The conventions rejection tests were passing for the wrong reason (a
half-renamed fixture key failed deserialization before reaching any
validation rule); they now assert the specific error each case targets.
Sqlness covers the UID merge across descriptor tables, pod-contains-
container, the k8s.service node, and the empty-uid/empty-node rows
deriving nothing.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test: cover the OTLP-to-graph chain end to end

One real OTLP export must come out of semantic_relationships as the
zero-configuration chain: service calls service, instance part_of
service, instance runs_on pod (bridged by k8s.pod.uid). Resources
without service.instance.id or k8s.pod.uid derive nothing extra.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix: identify k8s.service by UID

Same reasoning as pods: a recreated same-name service must not merge
into the old entity and same-named services across clusters must not
collide; kube_service_info carries a stable uid and nothing joins on the
service's name. Also drop a stale tag-rule mention from the option
validation docs.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* chore: cut duplicated test coverage and redundant comments

The trace service-fallback test collapsed into the resource-entities
test (same synthesis path since the fallback moved to YAML; only the
invalid-explicit-no-fallback case was distinct), role-duplicate and
subsumed DDL cases are gone, the embedded-conventions test is just the
parse (its assertions were decorative), and the YAML section comments no
longer restate the struct docs.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
2026-08-13 02:31:56 +00:00
shuiyisong 6249623cfb chore: remove iceberg read (#8858)
Signed-off-by: shuiyisong <xixing.sys@gmail.com>
2026-08-12 08:15:12 +00:00
shuiyisong 6493435bee feat(promql): support native histogram aggregations (#8848)
* feat(promql): support native histogram aggregations

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix(promql): correct mixed native histogram aggregations

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix(promql): format mixed count_values labels consistently

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* fix(promql): preserve reset hint warnings for incompatible histograms

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

---------

Signed-off-by: shuiyisong <xixing.sys@gmail.com>
2026-08-12 07:50:54 +00:00
discord9 9241e96fa2 fix(metric-engine): handle Utf8View tag/label columns without panicking (#8772)
* fix(metric-engine): handle Utf8View tag/label columns without panicking

label_replace (planned as DataFusion regexp_replace) coerces to Utf8View,
so label columns materialize as StringViewArray; build_tag_arrays'
StringArray downcast then panicked ('tag column must be utf8') — e.g. for
OTLP/json2 ingest. TSID computation, sparse-PK encoding and tag
extraction now accept generic ArrayRef tag columns (Utf8/LargeUtf8/
Utf8View/Dictionary) via string_array_value_at_index, and build_tag_arrays
errors instead of panicking on non-string columns. The mito2 time-series
memtable string-field paths are hardened the same way.

Adds label_replace_with_utf8view_labels_does_not_panic (issue #8732).

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* refactor(metric-engine): add is_string_null_at helper for tag null checks

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* fix(datatypes): use is_none_or to satisfy clippy unnecessary-map-or

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* fix: reject oversized string batches before memtable append

Distinguish a full active string builder from a batch that cannot fit an
empty Arrow string builder at all. Scan every string field so a later
intrinsically oversized field cannot be skipped after an earlier field
requests a freeze. Return InvalidBatch instead of reaching Arrow's offset
overflow panic.

Also cover Utf8View tags with nulls through the metric-engine tag, TSID,
and sparse-primary-key path.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

---------

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
2026-08-12 07:49:46 +00:00