use std::sync::Arc;
use std::time::{Duration, Instant};
use nodedb_cluster::error::{ClusterError, Result};
use crate::bridge::envelope::{Priority, Request};
use crate::control::state::SharedState;
use crate::event::types::EventSource;
use crate::types::{DatabaseId, ReadConsistency, TenantId, TraceId, VShardId};
use nodedb_physical::physical_plan::PhysicalPlan;
const LOCAL_DISPATCH_TIMEOUT: Duration = Duration::from_secs(30);
pub(super) const LOCAL_DISPATCH_VSHARD: VShardId = VShardId::new(0);
pub struct DataPlaneArrayExecutor {
pub(super) state: Arc<SharedState>,
}
impl DataPlaneArrayExecutor {
pub fn new(state: Arc<SharedState>) -> Self {
Self { state }
}
pub(super) async fn dispatch_and_await(
&self,
plan: PhysicalPlan,
) -> Result<crate::bridge::envelope::Response> {
let request_id = self.state.next_request_id();
let request = Request {
request_id,
tenant_id: TenantId::new(0),
database_id: DatabaseId::DEFAULT,
vshard_id: LOCAL_DISPATCH_VSHARD,
plan,
deadline: Instant::now() + LOCAL_DISPATCH_TIMEOUT,
priority: Priority::Normal,
trace_id: TraceId::generate(),
consistency: ReadConsistency::Strong,
idempotency_key: None,
event_source: EventSource::User,
user_roles: Vec::new(),
user_id: None,
statement_digest: None,
txn_id: None,
wal_lsn: None,
resolved_now_ms: None,
admission: crate::bridge::envelope::Admission::Exempt(
crate::bridge::envelope::ExemptReason::AlreadyOrdered,
),
};
let mut rx = self.state.tracker.register(request_id);
let dispatch_result = match self.state.dispatcher.lock() {
Ok(mut d) => d.dispatch(request),
Err(poisoned) => poisoned.into_inner().dispatch(request),
};
if let Err(e) = dispatch_result {
return Err(ClusterError::Storage {
detail: format!("array executor dispatch: {e}"),
});
}
match tokio::time::timeout(LOCAL_DISPATCH_TIMEOUT, async { rx.recv().await.ok_or(()) })
.await
{
Ok(Ok(resp)) => Ok(resp),
Ok(Err(_)) => Err(ClusterError::Storage {
detail: "array executor: response channel closed".into(),
}),
Err(_) => Err(ClusterError::Storage {
detail: "array executor: local dispatch timed out".into(),
}),
}
}
}