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
402 changes: 8 additions & 394 deletions Cargo.lock

Large diffs are not rendered by default.

25 changes: 6 additions & 19 deletions data_plane/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,25 +86,12 @@ asap-precompute-rs = { path = "../../ASAPCollector/asap-precompute-rs" }
moka = { version = "0.12", features = ["sync"] }
memmap2 = "0.9"
crc32fast = "1.4"
# Phase 3 — Gorilla-S3 cold engine. `asap-gorilla` (path-dep, mirrors
# the `asap-precompute-rs` sibling-checkout pattern) provides the
# `GORILLA1` block decoder + per-hour `index.json` catalog. `rust-s3`
# (`s3` package on crates.io) is a single-crate S3-compatible client
# with first-class MinIO support; we hold it behind
# `default-features = false` + `tokio-rustls-tls` so it shares the
# rustls backend already pulled in by `reqwest`. `lru` powers the
# Phase 3 `ChunkCache` keyed on chunk object key.
asap-gorilla = { path = "../../ASAPCollector/asap-gorilla-rust" }
# mvp/v5 NOTE FOR REVIEWERS: this PR depends on the matching
# `mvp/v5-postings-compactor` PR in ASAPCollector — specifically the
# `asap_gorilla::Postings` type and the `IndexEntry::byte_offset /
# byte_length / object_key` fields. CI machines that build from a
# `/home/.../ASAPCollector` checkout pinned to `origin/main` will
# fail compilation with `no Postings in the root` until the
# collector PR lands. Local dev: `git fetch && git checkout
# mvp/v5-postings-compactor` in the sibling ASAPCollector repo.
s3 = { version = "0.37", package = "rust-s3", default-features = false, features = ["tokio-rustls-tls"] }
lru = "0.12"
# NOTE: the `asap-gorilla` path-dep + the `s3` (rust-s3) / `lru`
# crates were dropped when the superseded GORILLA1 read side
# (`gorilla_object_store`: GorillaS3Store + decode_block + the
# in-process GorillaQueryEngine) was deleted. The archive tier is
# served by the ThanosQueryEngine (Path A2) over HTTP, which needs
# none of them.

[dev-dependencies]
tempfile = "3.20.0"
Expand Down
4 changes: 2 additions & 2 deletions data_plane/src/drivers/query/fallback/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
//!
//! * **Hot** = the `ASAPQueryEngine` handled the query from live
//! sketch-backed state.
//! * **Cold** = the query was answered from the Gorilla archive
//! tier ([`crate::storage_engines::gorilla_object_store::GorillaQueryEngine`]).
//! * **Cold** = the query was answered from the archive tier
//! ([`crate::query_engines::thanos_query_engine::ThanosQueryEngine`], Path A2).
//!
//! The "shape" label is the parsed query's root op (`sum`,
//! `count`, `avg`, `selector`, ...) — low-cardinality by design,
Expand Down
22 changes: 0 additions & 22 deletions data_plane/src/drivers/query/servers/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,10 +423,6 @@ impl HttpServer {
.route(runtime_info_path, get(handle_runtime_info))
.route(runtime_info_path, post(handle_runtime_info))
.route("/metrics", get(handle_metrics))
// mvp/v5: dump the S3 cost-tracking counters as CSV.
// The demo's `run_mvp_demo.sh` curls this for each
// baseline; missing counters render as zeros.
.route("/internal/s3_cost.csv", get(handle_s3_cost_csv))
// Control plane integration endpoints
.route("/api/v1/precompute", post(handle_precompute_job))
// Control plane's `PrecomputeClient` (control_plane/src/emit/precompute.rs)
Expand Down Expand Up @@ -1621,11 +1617,6 @@ async fn handle_metrics() -> impl IntoResponse {
let mut buffer = Vec::new();
prometheus::Encoder::encode(&encoder, &metric_families, &mut buffer)
.unwrap_or_else(|e| tracing::error!("Failed to encode metrics: {}", e));
// mvp/v5: append the S3 cost counters in Prometheus text
// exposition. Mirrors `/internal/s3_cost.csv` — the CSV is for
// the demo, this is for live dashboards.
let counters = crate::storage_engines::gorilla_object_store::global_s3_cost_counters();
buffer.extend_from_slice(counters.render_prometheus().as_bytes());
(
[(
axum::http::header::CONTENT_TYPE,
Expand All @@ -1635,19 +1626,6 @@ async fn handle_metrics() -> impl IntoResponse {
)
}

/// mvp/v5: CSV dump of the S3 cost counters.
///
/// Renders ONE header row + ONE data row. Empty when no S3
/// operations have been issued (the counters default to zero, so
/// the CSV is still well-formed).
async fn handle_s3_cost_csv() -> impl IntoResponse {
let counters = crate::storage_engines::gorilla_object_store::global_s3_cost_counters();
(
[(axum::http::header::CONTENT_TYPE, "text/csv; charset=utf-8")],
counters.render_csv(),
)
}

// ============================================================
// Range Query Handlers
// ============================================================
Expand Down
68 changes: 20 additions & 48 deletions data_plane/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ struct Args {
/// (`{metric_name: storage_backend}` map). Loaded at startup and
/// consulted by the HTTP query handler on every PromQL request to
/// pick the right engine (`ASAPQueryEngine` for ASAP-tier sketches,
/// `GorillaQueryEngine` for the cold archive, etc.). Without
/// `ThanosQueryEngine` for the cold archive, etc.). Without
/// this flag the handler falls back to the streaming-config
/// single axis (always `SketchStore`) and the EngineRouter is
/// effectively bypassed — the issue-46 v2 demo's criterion ⑤
Expand Down Expand Up @@ -608,23 +608,21 @@ async fn main() -> Result<()> {
server = server.with_backend_storage_routing(Arc::new(bootstrap_routing));

// Phase-5/6 + Step-2.3: register the Thanos query engine on the
// capability router. Two operating modes, selected at startup:
// capability router. Path A2 is the only archive path now: when
// `ASAP_THANOS_QUERY_URL` is set, the backend forwards
// archive-tier PromQL queries to a `thanos-query` sidecar via the
// [`ThanosQueryEngine`], registered under the single public id
// `thanos_query`.
//
// * **Path A2 mode** — when `ASAP_THANOS_QUERY_URL` is set, the
// backend forwards archive-tier PromQL queries to a
// `thanos-query` sidecar via the
// [`ThanosQueryEngine`], registered under the single public id
// `thanos_query`. The legacy in-process `GorillaQueryEngine`
// is skipped in this mode.
// * **Legacy mode** — when `ASAP_THANOS_QUERY_URL` is unset, the
// in-process `GorillaQueryEngine` answers archive queries
// from per-hour Gorilla chunks landed on S3 / MinIO via the
// `GorillaS3Store`. This is the dev path and is preserved
// verbatim until Phase δ deletes it after Path A2 is verified
// end-to-end.
// The superseded legacy in-process `GorillaQueryEngine` /
// `GorillaS3Store` leg (which read the custom GORILLA1 container
// format from per-hour chunks on S3 / MinIO) has been deleted now
// that Path A2 is verified end-to-end (agents emit XOR-chunk
// fragments → backend gorilla-merger → TSDB blocks → S3 →
// thanos-query).
//
// When neither env-var family is configured the binary registers
// a `NoDataArchiveEngine` stub under `thanos_query`
// When `ASAP_THANOS_QUERY_URL` is not configured the binary
// registers a `NoDataArchiveEngine` stub under `thanos_query`
// so cold queries succeed with an empty result instead of
// surfacing as `503 NoEngineRegistered`. Operators that want the
// original fail-loud behaviour can opt back in by setting
Expand All @@ -635,43 +633,17 @@ async fn main() -> Result<()> {
use data_plane::query_engines::routing::QueryEngine;
info!(
upstream = thanos.base_url(),
"Path A2: registering ThanosQueryEngine for the archive tier (data_source_id=thanos_query); legacy in-process GorillaQueryEngine skipped",
"Path A2: registering ThanosQueryEngine for the archive tier (data_source_id=thanos_query)",
);
let thanos_arc: Arc<dyn QueryEngine> = Arc::new(thanos);
server = server.with_archive_query_engine(thanos_arc);
archive_registered = true;
}
Ok(None) => match data_plane::storage_engines::gorilla_object_store::GorillaS3Config::from_env() {
Ok(s3_cfg) => {
match data_plane::storage_engines::gorilla_object_store::GorillaS3Store::with_default_backend(
s3_cfg,
) {
Ok(store) => {
use data_plane::storage_engines::{GorillaEngineConfig, GorillaQueryEngine};
use data_plane::query_engines::routing::QueryEngine;
let gorilla = Arc::new(GorillaQueryEngine::with_gorilla_s3(
Arc::new(store),
GorillaEngineConfig::default(),
));
info!(
"Registering legacy in-process GorillaQueryEngine on the archive slot (canonical data_source_id=thanos_query); set ASAP_THANOS_QUERY_URL to use the intended Thanos archive path",
);
server = server.with_archive_query_engine(gorilla as Arc<dyn QueryEngine>);
archive_registered = true;
}
Err(e) => {
warn!(
"ASAP_GORILLA_S3_* env vars present but GorillaS3Store failed to build ({e}); router will not have an archive engine",
);
}
}
}
Err(_) => {
info!(
"ASAP_GORILLA_S3_* env vars not configured — router serves ASAP-tier metrics only (set ASAP_GORILLA_S3_BUCKET + ASAP_GORILLA_S3_REGION to enable archive routing, or set ASAP_THANOS_QUERY_URL to enable Path A2 thanos forwarding)",
);
}
},
Ok(None) => {
info!(
"ASAP_THANOS_QUERY_URL not configured — router serves ASAP-tier metrics only (set ASAP_THANOS_QUERY_URL to enable Path A2 thanos archive forwarding)",
);
}
Err(e) => {
warn!(
"ASAP_THANOS_QUERY_URL set but ThanosQueryEngine failed to build ({e}); router will not have an archive engine",
Expand Down
7 changes: 3 additions & 4 deletions data_plane/src/query_engines/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
//!
//! The public query-engine surface is intentionally small:
//! [`asap_query_engine`] answers from ASAP's sketch store, and
//! [`thanos_query_engine`] forwards exact/archive queries to `thanos-query`.
//! Gorilla object storage lives under [`crate::storage_engines::gorilla_object_store`]
//! because it is a storage implementation detail, not a public query-engine
//! family.
//! [`thanos_query_engine`] forwards exact/archive queries to `thanos-query`
//! (Path A2 — the only archive path now that the superseded in-process
//! Gorilla executor / GORILLA1 store has been deleted).
//!
//! ## Public surface
//!
Expand Down
2 changes: 1 addition & 1 deletion data_plane/src/query_engines/routing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! This module is the dispatch boundary between the HTTP query
//! handler and the tier-co-located engines (warm sketch tier in
//! [`crate::query_engines::asap_query_engine`], archive tier in
//! [`crate::storage_engines::gorilla_object_store`]). Two cooperating pieces:
//! [`crate::query_engines::thanos_query_engine`]). Two cooperating pieces:
//!
//! * [`backend_storage_routing`] — config loader + multi-target
//! per-metric lookup (`metric → [(backend, query-shape filter), ...]`).
Expand Down
32 changes: 11 additions & 21 deletions data_plane/src/query_engines/thanos_query_engine/forward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,21 @@
//! Step-2.3 (this file) wires the backend to forward archive-tier
//! PromQL queries to that sidecar over HTTP.
//!
//! Operating modes are selected by the
//! [`ASAP_THANOS_QUERY_URL_ENV`] env var, consulted at backend
//! startup:
//! The engine is selected by the [`ASAP_THANOS_QUERY_URL_ENV`] env
//! var, consulted at backend startup:
//!
//! * **Path A2 mode** (env set) — `ThanosQueryEngine` is
//! registered in the [`crate::query_engines::routing::EngineRouter`]. Archive
//! queries POST to `${ASAP_THANOS_QUERY_URL}/api/v1/query` and
//! the answer is wrapped in ASAP's standard
//! [`crate::query_engines::QueryResult`] shape.
//! * **Legacy mode** (env unset) — the in-process
//! [`crate::storage_engines::gorilla_object_store::GorillaQueryEngine`]
//! handles archive queries from the per-hour Gorilla chunks that
//! [`crate::storage_engines::gorilla_object_store::GorillaS3Store`] streams
//! from S3 / MinIO.
//! Phase δ deletes this leg after Path A2 is verified
//! end-to-end.
//!
//! The two modes are mutually exclusive: when Path A2 is active,
//! both the legacy id (`thanos_query`) and the alias id
//! (`thanos_query`) point at the same `ThanosQueryEngine`
//! instance, so the per-metric `BackendStorageRouting` config can
//! target either name without surprise. See the binary's
//! `register_thanos_or_thanos_query` helper for the
//! registration site.
//! Path A2 is now the only archive path. The superseded legacy
//! in-process Gorilla executor (custom GORILLA1 container format,
//! read from per-hour chunks on S3 / MinIO) has been deleted after
//! Path A2 was verified end-to-end. When the env var is unset, the
//! binary registers a `NoDataArchiveEngine` stub on the archive
//! slot instead.

use std::time::{Duration, Instant};

Expand All @@ -55,8 +46,7 @@ use crate::storage_engines::sketch_db::accuracy::{AccuracyEnvelope, AccuracyProf
/// Env var consulted at backend startup. When set, the binary
/// registers a [`ThanosQueryEngine`] pointing at the URL and the
/// router dispatches archive-tier queries to it. When unset, the
/// legacy in-process [`crate::storage_engines::gorilla_object_store::GorillaQueryEngine`]
/// handles archive queries.
/// binary registers a `NoDataArchiveEngine` stub on the archive slot.
pub const ASAP_THANOS_QUERY_URL_ENV: &str = "ASAP_THANOS_QUERY_URL";

/// Default upstream URL when `ASAP_THANOS_QUERY_URL` is set to the
Expand Down Expand Up @@ -535,8 +525,8 @@ pub enum ThanosQueryError {

/// Convenience combinator the binary uses at startup: try
/// [`ThanosQueryEngine::from_env`]; if it returns `None`, the
/// caller falls through to the legacy in-process
/// [`crate::storage_engines::gorilla_object_store::GorillaQueryEngine`] path.
/// caller registers a `NoDataArchiveEngine` stub on the archive
/// slot (the legacy in-process Gorilla path has been deleted).
///
/// Returning `Result<Option<...>, ...>` instead of unwrapping in
/// `main.rs` keeps the construction failure (bad URL / bad TLS
Expand Down
7 changes: 4 additions & 3 deletions data_plane/src/query_engines/thanos_query_engine/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! Thanos query-engine wrapper.
//!
//! This module owns the public archive query engine, [`ThanosQueryEngine`].
//! Gorilla object storage and the legacy in-process Gorilla executor live
//! under [`crate::storage_engines::gorilla_object_store`].
//! This module owns the public archive query engine, [`ThanosQueryEngine`]
//! (Path A2). The archive tier reuses the `StorageBackend::GorillaObjectStore`
//! routing slot, but the answering engine is Thanos; the superseded
//! in-process Gorilla executor (custom GORILLA1 format) has been deleted.

pub mod forward;

Expand Down
Loading