use crate::control::state::SharedState;
use crate::types::{DatabaseId, Lsn, TenantId, TraceId, TxnId};
use nodedb_physical::physical_plan::{GraphOp, MetaOp, PhysicalPlan};
use super::bsp::fan_bsp_all_cores;
use super::fanout::gather_graph_op_all_cores;
use super::snapshot::fan_tenant_snapshot_all_cores;
use super::wcc::fan_wcc_all_cores;
pub struct NodeLevelResult {
pub payload: Vec<u8>,
pub watermark_lsn: Lsn,
pub read_version_lsn: Lsn,
}
pub async fn execute_plan_all_local_cores(
state: &SharedState,
tenant_id: TenantId,
database_id: DatabaseId,
plan: PhysicalPlan,
trace_id: TraceId,
txn_id: Option<TxnId>,
) -> crate::Result<NodeLevelResult> {
match &plan {
PhysicalPlan::Graph(g) => match g {
GraphOp::Match { .. }
| GraphOp::MatchContinuation { .. }
| GraphOp::MatchVarLenResume { .. } => {
use crate::control::server::graph_dispatch::match_broadcast::broadcast_match_to_all_cores;
use crate::data::executor::handlers::graph_match::encode_match_envelope_raw;
let outcome = broadcast_match_to_all_cores(
state,
tenant_id,
database_id,
plan,
trace_id,
txn_id,
)
.await?;
let envelope = encode_match_envelope_raw(
outcome.rows_payload.as_ref(),
&outcome.frontier,
&outcome.resume,
)?;
Ok(NodeLevelResult {
payload: envelope,
watermark_lsn: Lsn::ZERO,
read_version_lsn: Lsn::ZERO,
})
}
GraphOp::BspSuperstep(_) => {
fan_bsp_all_cores(state, tenant_id, database_id, plan, trace_id).await
}
GraphOp::WccSuperstep(_) => {
fan_wcc_all_cores(state, tenant_id, database_id, plan, trace_id).await
}
GraphOp::EdgePut { .. }
| GraphOp::EdgePutBatch { .. }
| GraphOp::EdgeDelete { .. }
| GraphOp::EdgeDeleteBatch { .. }
| GraphOp::Hop { .. }
| GraphOp::Neighbors { .. }
| GraphOp::NeighborsMulti { .. }
| GraphOp::Path { .. }
| GraphOp::Subgraph { .. }
| GraphOp::RagFusion { .. }
| GraphOp::Algo { .. }
| GraphOp::SetNodeLabels { .. }
| GraphOp::RemoveNodeLabels { .. }
| GraphOp::TemporalNeighbors { .. }
| GraphOp::TemporalAlgorithm { .. }
| GraphOp::Stats { .. } => {
generic_gather(state, tenant_id, database_id, plan, trace_id, txn_id).await
}
},
PhysicalPlan::Meta(meta) => match meta {
MetaOp::CreateTenantSnapshot { .. } => {
fan_tenant_snapshot_all_cores(state, tenant_id, database_id, plan, trace_id).await
}
MetaOp::RestoreTenantSnapshot { .. } => {
single_blob_gather(state, tenant_id, database_id, plan, trace_id, None).await
}
MetaOp::ResolveTxn { .. } => {
single_blob_gather(state, tenant_id, database_id, plan, trace_id, None).await
}
MetaOp::CalvinResolve { .. } => {
single_blob_gather(state, tenant_id, database_id, plan, trace_id, None).await
}
MetaOp::StageWrite { .. } | MetaOp::DropTxnOverlay { .. } => {
single_blob_gather(state, tenant_id, database_id, plan, trace_id, txn_id).await
}
MetaOp::WalAppend { .. }
| MetaOp::Cancel { .. }
| MetaOp::TransactionBatch { .. }
| MetaOp::CreateSnapshot
| MetaOp::Compact
| MetaOp::Checkpoint
| MetaOp::RegisterContinuousAggregate { .. }
| MetaOp::UnregisterContinuousAggregate { .. }
| MetaOp::ListContinuousAggregates
| MetaOp::ConvertCollection { .. }
| MetaOp::PurgeTenant { .. }
| MetaOp::UnregisterCollection { .. }
| MetaOp::UnregisterMaterializedView { .. }
| MetaOp::QueryCollectionSize { .. }
| MetaOp::EnforceTimeseriesRetention { .. }
| MetaOp::TemporalPurgeEdgeStore { .. }
| MetaOp::TemporalPurgeDocumentStrict { .. }
| MetaOp::TemporalPurgeColumnar { .. }
| MetaOp::TemporalPurgeCrdt { .. }
| MetaOp::TemporalPurgeArray { .. }
| MetaOp::AlterArray { .. }
| MetaOp::ApplyContinuousAggRetention
| MetaOp::QueryAggregateWatermark { .. }
| MetaOp::QueryLastValues { .. }
| MetaOp::QueryLastValue { .. }
| MetaOp::CalvinExecuteStatic { .. }
| MetaOp::CalvinExecutePassive { .. }
| MetaOp::CalvinExecuteActive { .. }
| MetaOp::RebuildIndex { .. }
| MetaOp::PutSynonymGroup { .. }
| MetaOp::DeleteSynonymGroup { .. }
| MetaOp::RenameCollection { .. }
| MetaOp::MarkSavepoint { .. }
| MetaOp::RollbackToSavepoint { .. }
| MetaOp::RecordCalvinWriteVersions { .. }
| MetaOp::CalvinFlush { .. }
| MetaOp::CalvinDrop { .. } => {
generic_gather(state, tenant_id, database_id, plan, trace_id, txn_id).await
}
},
PhysicalPlan::Vector(_)
| PhysicalPlan::Document(_)
| PhysicalPlan::Kv(_)
| PhysicalPlan::Text(_)
| PhysicalPlan::Columnar(_)
| PhysicalPlan::Timeseries(_)
| PhysicalPlan::Spatial(_)
| PhysicalPlan::Crdt(_)
| PhysicalPlan::Query(_)
| PhysicalPlan::Array(_)
| PhysicalPlan::ClusterArray(_) => {
generic_gather(state, tenant_id, database_id, plan, trace_id, txn_id).await
}
}
}
async fn generic_gather(
state: &SharedState,
tenant_id: TenantId,
database_id: DatabaseId,
plan: PhysicalPlan,
trace_id: TraceId,
txn_id: Option<TxnId>,
) -> crate::Result<NodeLevelResult> {
use crate::control::server::exchange::gather::gather_all_cores;
let outcome = gather_all_cores(state, tenant_id, database_id, plan, trace_id, txn_id).await?;
Ok(NodeLevelResult {
payload: outcome.merged_array,
watermark_lsn: outcome.watermark_lsn,
read_version_lsn: outcome.read_version_lsn,
})
}
async fn single_blob_gather(
state: &SharedState,
tenant_id: TenantId,
database_id: DatabaseId,
plan: PhysicalPlan,
trace_id: TraceId,
txn_id: Option<TxnId>,
) -> crate::Result<NodeLevelResult> {
let responses = gather_graph_op_all_cores(
state,
tenant_id,
database_id,
plan,
trace_id,
txn_id,
"single-blob",
)
.await?;
let mut watermark_lsn = Lsn::ZERO;
let mut read_version_lsn = Lsn::ZERO;
let mut payload: Option<Vec<u8>> = None;
for resp in responses {
if resp.watermark_lsn > watermark_lsn {
watermark_lsn = resp.watermark_lsn;
}
if resp.read_version_lsn > read_version_lsn {
read_version_lsn = resp.read_version_lsn;
}
if payload.is_none() && !resp.payload.is_empty() {
payload = Some(resp.payload.as_ref().to_vec());
}
}
Ok(NodeLevelResult {
payload: payload.unwrap_or_default(),
watermark_lsn,
read_version_lsn,
})
}