use crate::metrics::LoggingMetricsCollector;
use crate::{execution_loop, executor::Executor, flight_service::BallistaFlightService};
use arrow_flight::flight_service_server::FlightServiceServer;
use ballista_core::extension::SessionConfigExt;
use ballista_core::registry::BallistaFunctionRegistry;
use ballista_core::utils::{GrpcServerConfig, default_config_producer};
use ballista_core::{
BALLISTA_VERSION,
error::Result,
serde::BallistaCodec,
serde::protobuf::{ExecutorRegistration, scheduler_grpc_client::SchedulerGrpcClient},
serde::scheduler::{ExecutorOperatingSystemSpecification, ExecutorSpecification},
utils::create_grpc_server,
};
use ballista_core::{ConfigProducer, RuntimeProducer};
use datafusion::execution::{SessionState, SessionStateBuilder};
use log::info;
use std::sync::Arc;
use tempfile::TempDir;
use tokio::net::TcpListener;
use tonic::transport::Channel;
use uuid::Uuid;
pub async fn new_standalone_executor_from_state(
scheduler: SchedulerGrpcClient<Channel>,
concurrent_tasks: usize,
session_state: &SessionState,
) -> Result<()> {
let logical = session_state.config().ballista_logical_extension_codec();
let physical = session_state.config().ballista_physical_extension_codec();
let codec: BallistaCodec<
datafusion_proto::protobuf::LogicalPlanNode,
datafusion_proto::protobuf::PhysicalPlanNode,
> = BallistaCodec::new(logical, physical);
let config = session_state.config().clone().upgrade_for_ballista();
let runtime = session_state.runtime_env().clone();
let config_producer: ConfigProducer = Arc::new(move || config.clone());
let runtime_producer: RuntimeProducer = Arc::new(move |_| Ok(runtime.clone()));
new_standalone_executor_from_builder(
scheduler,
concurrent_tasks,
config_producer,
runtime_producer,
codec,
session_state.into(),
)
.await
}
pub async fn new_standalone_executor_from_builder(
scheduler: SchedulerGrpcClient<Channel>,
concurrent_tasks: usize,
config_producer: ConfigProducer,
runtime_producer: RuntimeProducer,
codec: BallistaCodec,
function_registry: BallistaFunctionRegistry,
) -> Result<()> {
let listener = TcpListener::bind("localhost:0").await?;
let address = listener.local_addr()?;
info!("Ballista v{BALLISTA_VERSION} Rust Executor listening on {address:?}");
let executor_meta = ExecutorRegistration {
id: Uuid::new_v4().to_string(), host: Some("localhost".to_string()),
port: address.port() as u32,
grpc_port: 50020,
specification: Some(
ExecutorSpecification::default()
.with_task_slots(concurrent_tasks as u32)
.into(),
),
os_info: Some(ExecutorOperatingSystemSpecification::default().into()),
};
let config = config_producer();
let max_message_size = config.ballista_grpc_client_max_message_size();
let work_dir = TempDir::new()?.path().to_str().unwrap().to_string();
info!("work_dir: {work_dir}");
let executor = Arc::new(Executor::with_default_execution_engine(
executor_meta,
&work_dir,
runtime_producer,
config_producer,
Arc::new(function_registry),
Arc::new(LoggingMetricsCollector::default()),
concurrent_tasks,
));
let service = BallistaFlightService::new(work_dir);
let server = FlightServiceServer::new(service)
.max_decoding_message_size(max_message_size)
.max_encoding_message_size(max_message_size);
tokio::spawn(
create_grpc_server(&GrpcServerConfig::default())
.add_service(server)
.serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(
listener,
)),
);
tokio::spawn(execution_loop::poll_loop(scheduler, executor, codec));
Ok(())
}
pub async fn new_standalone_executor(
scheduler: SchedulerGrpcClient<Channel>,
concurrent_tasks: usize,
codec: BallistaCodec,
) -> Result<()> {
use ballista_core::extension::{
ballista_aggregate_functions, ballista_scalar_functions,
ballista_window_functions,
};
let session_state = SessionStateBuilder::new()
.with_default_features()
.with_scalar_functions(ballista_scalar_functions())
.with_aggregate_functions(ballista_aggregate_functions())
.with_window_functions(ballista_window_functions())
.build();
let runtime = session_state.runtime_env().clone();
let runtime_producer: RuntimeProducer = Arc::new(move |_| Ok(runtime.clone()));
new_standalone_executor_from_builder(
scheduler,
concurrent_tasks,
Arc::new(default_config_producer),
runtime_producer,
codec,
(&session_state).into(),
)
.await
}