blob: 63d32e20be1dcb226fc0b1726733413f2d6b44ab [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use std::path::{Path, PathBuf};
use std::sync::Arc;
use datafusion::error::Result as DataFusionResult;
use datafusion::execution::runtime_env::RuntimeEnvBuilder;
use datafusion::execution::SessionStateBuilder;
use paimon::{CatalogOptions, FileSystemCatalog, Options};
use paimon_datafusion::SQLContext;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BenchmarkRuntimeConfig {
pub target_partitions: usize,
#[serde(default = "default_batch_size")]
pub batch_size: usize,
#[serde(default)]
pub parquet_pushdown_filters: bool,
pub memory_limit_bytes: Option<usize>,
pub spill_dir: Option<PathBuf>,
pub max_spill_bytes: Option<u64>,
}
impl Default for BenchmarkRuntimeConfig {
fn default() -> Self {
Self {
target_partitions: std::thread::available_parallelism()
.map(usize::from)
.unwrap_or(1),
batch_size: default_batch_size(),
parquet_pushdown_filters: false,
memory_limit_bytes: None,
spill_dir: None,
max_spill_bytes: None,
}
}
}
fn default_batch_size() -> usize {
8192
}
pub fn build_sql_context(config: &BenchmarkRuntimeConfig) -> DataFusionResult<SQLContext> {
let mut runtime = RuntimeEnvBuilder::new();
if let Some(memory_limit) = config.memory_limit_bytes {
runtime = runtime.with_memory_limit(memory_limit, 1.0);
}
if let Some(spill_dir) = &config.spill_dir {
runtime = runtime.with_temp_file_path(spill_dir);
}
if let Some(max_spill_bytes) = config.max_spill_bytes {
runtime = runtime.with_max_temp_directory_size(max_spill_bytes);
}
let sql = SQLContext::new();
let state_ref = sql.ctx().state_ref();
let current_state = state_ref.read().clone();
let mut session_config = current_state
.config()
.clone()
.with_target_partitions(config.target_partitions.max(1))
.with_batch_size(config.batch_size.max(1));
session_config
.options_mut()
.execution
.parquet
.pushdown_filters = config.parquet_pushdown_filters;
let state = SessionStateBuilder::from(current_state)
.with_config(session_config)
.with_runtime_env(Arc::new(runtime.build()?))
.build();
*state_ref.write() = state;
drop(state_ref);
Ok(sql)
}
pub struct CatalogSession {
pub sql: SQLContext,
pub catalog: Arc<FileSystemCatalog>,
pub catalog_name: String,
pub database: String,
}
pub async fn open_catalog_session(
runtime_config: &BenchmarkRuntimeConfig,
warehouse: &Path,
database: &str,
) -> Result<CatalogSession, Box<dyn std::error::Error + Send + Sync>> {
std::fs::create_dir_all(warehouse)?;
let mut options = Options::new();
options.set(CatalogOptions::WAREHOUSE, warehouse.display().to_string());
let catalog = Arc::new(FileSystemCatalog::new(options)?);
let mut sql = build_sql_context(runtime_config)?;
sql.register_catalog_with_default_db("paimon", catalog.clone(), Some(database))
.await?;
// Keep decoder batch boundaries identical for Parquet and Paimon. Paimon
// retains Java's table default, so use its supported session override.
sql.sql(&format!(
"SET 'paimon.read.batch-size' = '{}'",
runtime_config.batch_size
))
.await?;
Ok(CatalogSession {
sql,
catalog,
catalog_name: "paimon".to_string(),
database: database.to_string(),
})
}