use parking_lot::RwLock;
use std::collections::HashMap;
use std::sync::Arc;
use super::execution_result::ExecutionResult;
use super::traits::SearchProvider;
use super::MemoryBudget;
use crate::executor::expression::functions::global_registry_ref;
use crate::executor::expression::functions::OwnedFunctionRef;
use crate::executor::streaming::pool::SharedScheduler;
use crate::optimizer::stats::feedback::history::QueryFeedbackHistory;
use crate::optimizer::JoinAlgorithm;
use crate::storage::QueryStorage;
use linkrs_core::metadata::SequenceManager;
use linkrs_core::metadata::{MacroManager, TypeAliasManager};
use linkrs_core::types::expr::expression_context::ExpressionAnalysisContext;
use linkrs_core::Arena;
use linkrs_core::Value;
#[cfg(feature = "fulltext")]
use linkrs_fulltext::manager::FulltextIndexManager;
#[cfg(feature = "vector")]
use linkrs_sync::VectorSyncCoordinator;
#[derive(Debug, Clone, Default)]
pub struct SearchContext {
#[cfg(feature = "fulltext")]
pub fulltext_manager: Option<Arc<FulltextIndexManager>>,
#[cfg(feature = "vector")]
pub vector_coordinator: Option<Arc<VectorSyncCoordinator>>,
pub search_providers: Vec<Arc<dyn SearchProvider>>,
}
#[derive(Debug, Clone)]
pub struct ExecutionContext {
pub results: Arc<RwLock<HashMap<String, ExecutionResult>>>,
pub variables: Arc<RwLock<HashMap<String, linkrs_core::Value>>>,
pub expression_context: Arc<ExpressionAnalysisContext>,
pub search: SearchContext,
pub storage: Option<Arc<RwLock<dyn QueryStorage>>>,
pub bound_snapshot: Option<crate::storage::SnapshotHandle>,
pub space_name: Option<String>,
pub parameters: Arc<HashMap<String, linkrs_core::Value>>,
pub session_variables: Arc<HashMap<String, linkrs_core::Value>>,
pub memory_budget: MemoryBudget,
pub max_workers: usize,
pub query_id: u64,
pub cancel_token: Option<crate::executor::streaming::query_registry::CancelToken>,
pub chunk_size: usize,
pub max_buffered_chunks: usize,
pub shared_scheduler: Option<Arc<SharedScheduler>>,
pub arena: Option<Arc<parking_lot::Mutex<Arena>>>,
pub feedback_history: Option<Arc<QueryFeedbackHistory>>,
pub columnar_policy: Option<Arc<crate::executor::streaming::chunk::ColumnarPolicy>>,
pub join_algorithms: HashMap<i64, JoinAlgorithm>,
pub isolation_level: Option<linkrs_core::types::TransactionIsolationLevel>,
pub ryw_config: Option<linkrs_core::types::ReadYourWritesConfig>,
pub sequence_manager: Option<Arc<SequenceManager>>,
pub macro_manager: Option<Arc<MacroManager>>,
pub type_alias_manager: Option<Arc<TypeAliasManager>>,
}
fn new_base(expression_context: Arc<ExpressionAnalysisContext>) -> ExecutionContext {
ExecutionContext {
results: Arc::new(RwLock::new(HashMap::new())),
variables: Arc::new(RwLock::new(HashMap::new())),
expression_context,
search: SearchContext::default(),
storage: None,
bound_snapshot: None,
space_name: None,
parameters: Arc::new(HashMap::new()),
session_variables: Arc::new(HashMap::new()),
memory_budget: MemoryBudget::default_budget(),
max_workers: 1,
query_id: 0,
cancel_token: None,
chunk_size: ExecutionContext::DEFAULT_CHUNK_SIZE,
max_buffered_chunks: ExecutionContext::DEFAULT_MAX_BUFFERED_CHUNKS,
shared_scheduler: None,
arena: None,
feedback_history: None,
columnar_policy: None,
join_algorithms: HashMap::new(),
isolation_level: None,
ryw_config: None,
sequence_manager: None,
macro_manager: None,
type_alias_manager: None,
}
}
impl ExecutionContext {
pub const DEFAULT_CHUNK_SIZE: usize = 2048;
pub const DEFAULT_MAX_BUFFERED_CHUNKS: usize = 10;
pub fn new(expression_context: Arc<ExpressionAnalysisContext>) -> Self {
new_base(expression_context)
}
pub fn with_parameters(
expression_context: Arc<ExpressionAnalysisContext>,
parameters: HashMap<String, linkrs_core::Value>,
) -> Self {
let mut ctx = new_base(expression_context);
ctx.parameters = Arc::new(parameters);
ctx
}
pub fn with_memory_limit(
expression_context: Arc<ExpressionAnalysisContext>,
max_memory_per_query: u64,
) -> Self {
let budget = if max_memory_per_query > 0 {
MemoryBudget::new(max_memory_per_query as usize)
} else {
MemoryBudget::default_budget()
};
let mut ctx = new_base(expression_context);
ctx.memory_budget = budget;
ctx
}
pub fn set_result(&self, name: String, result: ExecutionResult) {
self.results.write().insert(name, result);
}
pub fn get_result(&self, name: &str) -> Option<ExecutionResult> {
self.results.write().get(name).cloned()
}
pub fn set_variable(&self, name: String, value: linkrs_core::Value) {
self.variables.write().insert(name, value);
}
pub fn get_variable(&self, name: &str) -> Option<linkrs_core::Value> {
self.variables.write().get(name).cloned()
}
pub fn expression_context(&self) -> &Arc<ExpressionAnalysisContext> {
&self.expression_context
}
pub fn get_param(&self, name: &str) -> Option<&linkrs_core::Value> {
self.parameters.get(name)
}
pub fn current_space_id(&self) -> Option<u64> {
self.variables
.write()
.get("space_id")
.and_then(|v| match v {
Value::Int(id) => Some(*id as u64),
_ => None,
})
}
pub fn set_space_id(&self, space_id: u64) {
self.variables
.write()
.insert("space_id".into(), Value::Int(space_id as i32));
}
pub fn sequence_manager(&self) -> Option<&Arc<SequenceManager>> {
self.sequence_manager.as_ref()
}
pub fn set_sequence_manager(&mut self, manager: Arc<SequenceManager>) {
self.sequence_manager = Some(manager);
}
pub fn macro_manager(&self) -> Option<&Arc<MacroManager>> {
self.macro_manager.as_ref()
}
pub fn set_macro_manager(&mut self, manager: Arc<MacroManager>) {
self.macro_manager = Some(manager);
}
pub fn type_alias_manager(&self) -> Option<&Arc<TypeAliasManager>> {
self.type_alias_manager.as_ref()
}
pub fn set_type_alias_manager(&mut self, manager: Arc<TypeAliasManager>) {
self.type_alias_manager = Some(manager);
}
}
impl Default for ExecutionContext {
fn default() -> Self {
let mut ctx = new_base(Arc::new(ExpressionAnalysisContext::new()));
ctx.chunk_size = Self::DEFAULT_CHUNK_SIZE;
ctx.max_buffered_chunks = Self::DEFAULT_MAX_BUFFERED_CHUNKS;
ctx
}
}
impl crate::executor::expression::evaluator::traits::ExpressionContext for ExecutionContext {
fn get_variable(&self, name: &str) -> Option<Value> {
self.variables.write().get(name).cloned()
}
fn set_variable(&mut self, name: String, value: Value) {
self.variables.write().insert(name, value);
}
fn get_function(&self, name: &str) -> Option<OwnedFunctionRef> {
let registry = global_registry_ref();
registry
.get_builtin(name)
.map(|f| OwnedFunctionRef::Builtin(f.clone()))
.or_else(|| {
registry
.get_custom(name)
.map(|f| OwnedFunctionRef::Custom(f.clone()))
})
}
fn get_sequence_manager(&self) -> Option<Arc<SequenceManager>> {
self.sequence_manager.clone()
}
}