use common::str::ParseBytes;
use surrealdb_cnf as cnf;
const DEFAULT_SCAN_BATCH_SIZE: usize = 1000;
pub(crate) const DEFAULT_SCAN_BATCH_BYTES: usize = 2 << 20;
const DEFAULT_FAN_OUT_ROW_THRESHOLD: usize = 4;
#[derive(Clone, Debug)]
pub(crate) struct ExecConfig {
pub max_computation_depth: u32,
pub idiom_recursion_limit: u32,
pub operator_buffer_size: usize,
pub scan_batch_size: usize,
pub scan_batch_bytes: usize,
pub max_order_limit_priority_queue_size: u32,
pub topk_threshold_pushdown_enabled: bool,
pub gql_max_join_build_rows: usize,
pub gql_max_path_rows: usize,
pub gql_max_output_rows: usize,
pub external_sorting_buffer_limit: usize,
pub generation_allocation_limit: usize,
pub fan_out_row_threshold: usize,
}
impl Default for ExecConfig {
fn default() -> Self {
Self {
max_computation_depth: 120,
idiom_recursion_limit: 256,
operator_buffer_size: 2,
scan_batch_size: DEFAULT_SCAN_BATCH_SIZE,
scan_batch_bytes: DEFAULT_SCAN_BATCH_BYTES,
max_order_limit_priority_queue_size: 1000,
topk_threshold_pushdown_enabled: true,
gql_max_join_build_rows: 1_000_000,
gql_max_path_rows: 1_000_000,
gql_max_output_rows: 1_000_000,
external_sorting_buffer_limit: 50_000,
generation_allocation_limit: 2 << 20,
fan_out_row_threshold: DEFAULT_FAN_OUT_ROW_THRESHOLD,
}
}
}
impl cnf::Config for ExecConfig {
fn parse(&mut self, map: &cnf::ConfigMap) {
map.parse_key("max_computation_depth", &mut self.max_computation_depth)
.parse_key("operator_buffer_size", &mut self.operator_buffer_size)
.parse_key("scan_batch_size", &mut self.scan_batch_size)
.parse_key_with("scan_batch_bytes", &mut self.scan_batch_bytes, |x| {
x.parse_bytes::<usize>().ok().filter(|&n| n > 0)
})
.parse_key(
"max_order_limit_priority_queue_size",
&mut self.max_order_limit_priority_queue_size,
)
.parse_key("topk_threshold_pushdown_enabled", &mut self.topk_threshold_pushdown_enabled)
.parse_key("gql_max_join_build_rows", &mut self.gql_max_join_build_rows)
.parse_key("gql_max_path_rows", &mut self.gql_max_path_rows)
.parse_key("gql_max_output_rows", &mut self.gql_max_output_rows)
.parse_key("external_sorting_buffer_limit", &mut self.external_sorting_buffer_limit)
.parse_key("fan_out_row_threshold", &mut self.fan_out_row_threshold)
.parse_key_with(
"generation_allocation_limit",
&mut self.generation_allocation_limit,
|x| x.parse::<usize>().ok().map(|x| 2 << x.min(28)),
);
}
}
#[cfg(test)]
mod tests {
use surrealdb_cnf::{Config as _, ConfigMap};
use super::*;
#[test]
fn topk_threshold_pushdown_kill_switch_parses() {
let mut config = ExecConfig::default();
assert!(config.topk_threshold_pushdown_enabled, "feature defaults on");
let map = ConfigMap::empty().with_key_value("topk_threshold_pushdown_enabled", "false");
config.parse(&map);
assert!(!config.topk_threshold_pushdown_enabled, "config map disables the feature");
}
#[test]
fn scan_batch_bytes_parses() {
let mut config = ExecConfig::default();
assert_eq!(config.scan_batch_bytes, 2 << 20);
config.parse(&ConfigMap::empty().with_key_value("scan_batch_bytes", "512KiB"));
assert_eq!(config.scan_batch_bytes, 512 << 10);
config.parse(&ConfigMap::empty().with_key_value("scan_batch_bytes", "0"));
assert_eq!(config.scan_batch_bytes, 512 << 10, "zero is ignored");
}
#[test]
fn fan_out_row_threshold_parses() {
let mut config = ExecConfig::default();
assert_eq!(config.fan_out_row_threshold, 4);
let map = ConfigMap::empty().with_key_value("fan_out_row_threshold", "1000000");
config.parse(&map);
assert_eq!(config.fan_out_row_threshold, 1_000_000);
}
#[test]
fn gql_match_limits_parse_from_config_map() {
let mut config = ExecConfig::default();
assert_eq!(config.gql_max_join_build_rows, 1_000_000);
assert_eq!(config.gql_max_path_rows, 1_000_000);
assert_eq!(config.gql_max_output_rows, 1_000_000);
let map = ConfigMap::empty()
.with_key_value("gql_max_join_build_rows", "5")
.with_key_value("gql_max_path_rows", "7")
.with_key_value("gql_max_output_rows", "9");
config.parse(&map);
assert_eq!(config.gql_max_join_build_rows, 5);
assert_eq!(config.gql_max_path_rows, 7);
assert_eq!(config.gql_max_output_rows, 9);
}
}