Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
17b209b
Fix spill read profile classification
BohuTANG Dec 8, 2025
ef9efb6
Unify spill I/O profiling by actual location
BohuTANG Dec 8, 2025
caf59e0
Add spill profile unit tests
BohuTANG Dec 8, 2025
1dd02d9
Fix visibility and borrow issues for spill profiling
BohuTANG Dec 8, 2025
f7abcaf
Add spill fallback integration test
BohuTANG Dec 8, 2025
6a7341f
Fix spill metrics: use actual locations and expose helper
BohuTANG Dec 8, 2025
bcc50e7
Carry spill locations through row group writer for profiling
BohuTANG Dec 8, 2025
9a27105
Refine AnyFileWriter to carry paths and fix window writer match
BohuTANG Dec 8, 2025
278a4ad
Hook spill tests into test module
BohuTANG Dec 8, 2025
6980f59
Remove profile unit test and fix imports for spill fallback
BohuTANG Dec 8, 2025
c971944
Guard spill fallback test when local spill is unavailable
BohuTANG Dec 8, 2025
8e43445
Ensure test config enables local spill for fallback test
BohuTANG Dec 8, 2025
a49bbf9
Configure test builder with local spill path via SpillConfig
BohuTANG Dec 8, 2025
3310ffd
Stabilize spill fallback test
BohuTANG Dec 8, 2025
2f3fbe5
Refine spill profiling paths
BohuTANG Dec 8, 2025
3389e5a
Add spill profile tests for local/remote metrics
BohuTANG Dec 8, 2025
132e93e
Refine spill tests and move SpillTarget test to it suite
BohuTANG Dec 8, 2025
cd82c0a
Add spill test config helper and fix spill IT headers
BohuTANG Dec 8, 2025
2a095a3
Fix clippy needless-borrow in spill read profile
BohuTANG Dec 8, 2025
cc934aa
Align spill quota settings and configs
BohuTANG Dec 9, 2025
f9d68fa
Fix spill config mask test ratios
BohuTANG Dec 9, 2025
fc1b541
Refine spill profiling and local writer
BohuTANG Dec 9, 2025
03bd041
Unify spill target and add local path string
BohuTANG Dec 9, 2025
1eb5c59
Add debug logging for spill temp cleanup
BohuTANG Dec 9, 2025
d5885a1
Fix build after removing spill prefix debug
BohuTANG Dec 9, 2025
dcfe940
Adjust spill configs and defaults
BohuTANG Dec 9, 2025
63b69c7
Fix legacy spill config test expectation
BohuTANG Dec 9, 2025
8521f35
Revert HTTP spill cleanups to main behavior
BohuTANG Dec 9, 2025
b5842b0
Fix goldenfile whitespace for configs_table_basic
BohuTANG Dec 9, 2025
baeb117
Adjust configs_table_basic golden trailing lines
BohuTANG Dec 9, 2025
a78813c
Revert vacuum_hook change to main
BohuTANG Dec 9, 2025
1010982
config: disable implicit local spill cache fallback
BohuTANG Dec 10, 2025
4e66e40
Update configs
BohuTANG Dec 10, 2025
91db4a8
Align window spill quota default to 40
BohuTANG Dec 10, 2025
6758b8d
chore: adjust default spill local reserved disk ratio to 10%
BohuTANG Dec 10, 2025
34940cf
chore: align window spill quota ratio default to 60
BohuTANG Dec 10, 2025
25978ae
Update spill adapter and defaults
BohuTANG Dec 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions scripts/ci/deploy/config/databend-query-node-1.toml
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,6 @@ max_bytes = 21474836480

[spill]
spill_local_disk_path = "./.databend/temp/_query_spill"
# Cap local spill to 5GB so window spills keep ~1GB quota with default 20% ratio.
spill_local_disk_max_bytes = 1073741824
window_partition_spilling_disk_quota_ratio = 20
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ path = "_databend_data/cache/query2"
max_bytes = 1073741824 # 1GB

[spill]
spill_local_disk_path = "_databend_data/spill/query2"
spill_local_disk_path = "_databend_data/spill/query2"
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ path = "_databend_data/cache/query3"
max_bytes = 1073741824 # 1GB

[spill]
spill_local_disk_path = "_databend_data/spill/query3"
spill_local_disk_path = "_databend_data/spill/query3"
2 changes: 1 addition & 1 deletion scripts/test-bend-tests/configs/query/query-2.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ path = "_databend_data/cache/query2"
max_bytes = 1073741824 # 1GB

[spill]
spill_local_disk_path = "_databend_data/spill/query2"
spill_local_disk_path = "_databend_data/spill/query2"
2 changes: 1 addition & 1 deletion scripts/test-bend-tests/configs/query/query-3.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ path = "_databend_data/cache/query3"
max_bytes = 1073741824 # 1GB

[spill]
spill_local_disk_path = "_databend_data/spill/query3"
spill_local_disk_path = "_databend_data/spill/query3"
2 changes: 1 addition & 1 deletion scripts/test-bend-tests/configs/query/query-4.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ path = "_databend_data/cache/query4"
max_bytes = 1073741824 # 1GB

[spill]
spill_local_disk_path = "_databend_data/spill/query4"
spill_local_disk_path = "_databend_data/spill/query4"
2 changes: 1 addition & 1 deletion scripts/test-bend-tests/configs/query/query-5.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ path = "_databend_data/cache/query5"
max_bytes = 1073741824 # 1GB

[spill]
spill_local_disk_path = "_databend_data/spill/query5"
spill_local_disk_path = "_databend_data/spill/query5"
63 changes: 43 additions & 20 deletions src/query/config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ pub struct FsStorageConfig {

impl FsStorageConfig {
fn default_reserved_space_percentage() -> Option<OrderedFloat<f64>> {
None // Use None as default, will use system default (30.0) if not specified
None // Use None as default, will use system default (10.0) if not specified
}
}

Expand Down Expand Up @@ -3585,13 +3585,32 @@ pub struct SpillConfig {
#[clap(long, value_name = "VALUE", default_value = "")]
pub spill_local_disk_path: String,

#[clap(long, value_name = "VALUE", default_value = "30")]
#[clap(long, value_name = "VALUE", default_value = "10")]
/// Percentage of reserve disk space that won't be used for spill to local disk.
pub spill_local_disk_reserved_space_percentage: OrderedFloat<f64>,

#[clap(long, value_name = "VALUE", default_value = "18446744073709551615")]
/// Allow space in bytes to spill to local disk.
pub spill_local_disk_max_bytes: u64,

/// Maximum percentage of the global local spill quota that a single sort
/// operator may use for one query.
///
/// Value range: 0-100. Effective only when local spill is enabled (there is
/// a valid local spill path and non-zero `spill_local_disk_max_bytes`).
#[clap(long, value_name = "PERCENT", default_value = "60")]
pub sort_spilling_disk_quota_ratio: u64,

/// Maximum percentage of the global local spill quota that window
/// partitioners may use for one query.
#[clap(long, value_name = "PERCENT", default_value = "60")]
pub window_partition_spilling_disk_quota_ratio: u64,

/// Maximum percentage of the global local spill quota that HTTP
/// result-set spilling may use for one query.
/// TODO: keep 0 to avoid deleting local result-set spill dir before HTTP pagination finishes.
#[clap(long, value_name = "PERCENT", default_value = "0")]
pub result_set_spilling_disk_quota_ratio: u64,
}

impl SpillConfig {
Expand Down Expand Up @@ -3630,8 +3649,12 @@ impl Default for SpillConfig {
Self {
storage: None,
spill_local_disk_path: String::new(),
spill_local_disk_reserved_space_percentage: OrderedFloat(30.0),
spill_local_disk_reserved_space_percentage: OrderedFloat(10.0),
spill_local_disk_max_bytes: u64::MAX,
sort_spilling_disk_quota_ratio: 60,
window_partition_spilling_disk_quota_ratio: 60,
// TODO: keep 0 to avoid deleting local result-set spill dir before HTTP pagination finishes.
result_set_spilling_disk_quota_ratio: 0,
}
}
}
Expand Down Expand Up @@ -3706,7 +3729,7 @@ mod cache_config_converters {
catalogs.insert(CATALOG_HIVE.to_string(), catalog);
}

let spill = convert_local_spill_config(spill, &cache.disk_cache_config)?;
let spill = convert_local_spill_config(spill)?;

Ok(InnerConfig {
query: query.try_into()?,
Expand Down Expand Up @@ -3803,10 +3826,7 @@ mod cache_config_converters {
}
}

fn convert_local_spill_config(
spill: SpillConfig,
cache: &DiskCacheConfig,
) -> Result<inner::SpillConfig> {
fn convert_local_spill_config(spill: SpillConfig) -> Result<inner::SpillConfig> {
// Determine configuration based on auto-detected spill type
let spill_type = spill.get_spill_type();
let (local_writeable_root, path, reserved_disk_ratio, global_bytes_limit, storage_params) =
Expand All @@ -3818,7 +3838,7 @@ mod cache_config_converters {
let reserved_ratio = storage
.fs
.reserved_space_percentage
.unwrap_or(OrderedFloat(30.0))
.unwrap_or(OrderedFloat(10.0))
/ 100.0;
let max_bytes = storage.fs.max_bytes.unwrap_or(u64::MAX);

Expand Down Expand Up @@ -3864,16 +3884,11 @@ mod cache_config_converters {
)
}
_ => {
// Default behavior for "default" type and any unrecognized types
// Default behavior with backward compatibility
let local_writeable_root = if cache.path != DiskCacheConfig::default().path
&& spill.spill_local_disk_path.is_empty()
{
Some(cache.path.clone())
} else {
None
};

// Default behavior for "default" type and any unrecognized types:
// do NOT implicitly reuse the data cache disk. Local spill is
// enabled only when explicitly configured via either
// - [spill.storage] with type = "fs", or
// - legacy spill_local_disk_path.
let storage_params = spill
.storage
.map(|storage| {
Expand All @@ -3883,7 +3898,7 @@ mod cache_config_converters {
.transpose()?;

(
local_writeable_root,
None,
spill.spill_local_disk_path,
spill.spill_local_disk_reserved_space_percentage / 100.0,
spill.spill_local_disk_max_bytes,
Expand All @@ -3898,6 +3913,10 @@ mod cache_config_converters {
reserved_disk_ratio,
global_bytes_limit,
storage_params,
sort_spilling_disk_quota_ratio: spill.sort_spilling_disk_quota_ratio,
window_partition_spilling_disk_quota_ratio: spill
.window_partition_spilling_disk_quota_ratio,
result_set_spilling_disk_quota_ratio: spill.result_set_spilling_disk_quota_ratio,
})
}

Expand All @@ -3916,6 +3935,10 @@ mod cache_config_converters {
spill_local_disk_path: value.path,
spill_local_disk_reserved_space_percentage: value.reserved_disk_ratio * 100.0,
spill_local_disk_max_bytes: value.global_bytes_limit,
sort_spilling_disk_quota_ratio: value.sort_spilling_disk_quota_ratio,
window_partition_spilling_disk_quota_ratio: value
.window_partition_spilling_disk_quota_ratio,
result_set_spilling_disk_quota_ratio: value.result_set_spilling_disk_quota_ratio,
}
}
}
Expand Down
65 changes: 64 additions & 1 deletion src/query/config/src/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,22 @@ pub struct SpillConfig {
pub global_bytes_limit: u64,

pub storage_params: Option<StorageParams>,

/// Maximum percentage of the global local spill quota that a single
/// sort operator may use for one query.
///
/// Value range: 0-100. Effective only when local spill is enabled
/// (i.e. there is a valid local spill path and non-zero global
/// bytes limit).
pub sort_spilling_disk_quota_ratio: u64,

/// Maximum percentage of the global local spill quota that window
/// partitioners may use for one query.
pub window_partition_spilling_disk_quota_ratio: u64,

/// Maximum percentage of the global local spill quota that HTTP
/// result-set spilling may use for one query.
pub result_set_spilling_disk_quota_ratio: u64,
}

impl SpillConfig {
Expand All @@ -807,13 +823,56 @@ impl SpillConfig {
None
}

/// Helper to compute a per-query local spill quota (in bytes) from a
/// percentage of the global local spill limit.
///
/// - If local spill is disabled (no local path or zero global
/// limit), returns 0.
/// - `ratio` is clamped into [0, 100].
pub fn quota_bytes_from_ratio(&self, ratio: u64) -> usize {
// Only effective when local spill is enabled.
if self.local_path().is_none() {
return 0;
}

let ratio = std::cmp::min(ratio, 100);
if ratio == 0 {
return 0;
}

let bytes = self.global_bytes_limit.saturating_mul(ratio) / 100;

// TempDirManager works with `usize` limits.
std::cmp::min(bytes, usize::MAX as u64) as usize
}

/// Per-query quota for sort operators.
pub fn sort_spill_bytes_limit(&self) -> usize {
self.quota_bytes_from_ratio(self.sort_spilling_disk_quota_ratio)
}

/// Per-query quota for window partitioners.
pub fn window_partition_spill_bytes_limit(&self) -> usize {
self.quota_bytes_from_ratio(self.window_partition_spilling_disk_quota_ratio)
}

/// Per-query quota for HTTP result-set spilling.
pub fn result_set_spill_bytes_limit(&self) -> usize {
self.quota_bytes_from_ratio(self.result_set_spilling_disk_quota_ratio)
}

pub fn new_for_test(path: String, reserved_disk_ratio: f64, global_bytes_limit: u64) -> Self {
Self {
local_writeable_root: None,
path,
reserved_disk_ratio: OrderedFloat(reserved_disk_ratio),
global_bytes_limit,
storage_params: None,
// Use the same defaults as the external config.
sort_spilling_disk_quota_ratio: 60,
window_partition_spilling_disk_quota_ratio: 60,
// TODO: keep 0 to avoid deleting local result-set spill dir before HTTP pagination finishes.
result_set_spilling_disk_quota_ratio: 0,
}
}
}
Expand All @@ -823,9 +882,13 @@ impl Default for SpillConfig {
Self {
local_writeable_root: None,
path: "".to_string(),
reserved_disk_ratio: OrderedFloat(0.3),
reserved_disk_ratio: OrderedFloat(0.1),
global_bytes_limit: u64::MAX,
storage_params: None,
sort_spilling_disk_quota_ratio: 60,
window_partition_spilling_disk_quota_ratio: 60,
// TODO: keep 0 to avoid deleting local result-set spill dir before HTTP pagination finishes.
result_set_spilling_disk_quota_ratio: 0,
}
}
}
11 changes: 11 additions & 0 deletions src/query/config/src/mask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,20 @@ impl SpillConfig {
ref spill_local_disk_path,
spill_local_disk_reserved_space_percentage,
spill_local_disk_max_bytes,
sort_spilling_disk_quota_ratio,
window_partition_spilling_disk_quota_ratio,
result_set_spilling_disk_quota_ratio,
} = *self;

Self {
storage: storage.as_ref().map(|storage| storage.mask_display()),
spill_local_disk_path: spill_local_disk_path.clone(),
spill_local_disk_reserved_space_percentage,
spill_local_disk_max_bytes,
sort_spilling_disk_quota_ratio,
window_partition_spilling_disk_quota_ratio,
// TODO: keep 0 to avoid deleting local result-set spill dir before HTTP pagination finishes.
result_set_spilling_disk_quota_ratio,
}
}
}
Expand Down Expand Up @@ -375,6 +382,10 @@ mod tests {
spill_local_disk_path: "".to_string(),
spill_local_disk_reserved_space_percentage: 30.0.into(),
spill_local_disk_max_bytes: 10,
sort_spilling_disk_quota_ratio: 60,
window_partition_spilling_disk_quota_ratio: 30,
// TODO: keep 0 to avoid deleting local result-set spill dir before HTTP pagination finishes.
result_set_spilling_disk_quota_ratio: 0,
storage: Some(StorageConfig {
typ: "s3".to_string(),
s3: S3StorageConfig {
Expand Down
6 changes: 5 additions & 1 deletion src/query/service/src/physical_plans/physical_recluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use databend_common_catalog::plan::DataSourcePlan;
use databend_common_catalog::plan::ReclusterTask;
use databend_common_catalog::table::Table;
use databend_common_catalog::table_context::TableContext;
use databend_common_config::GlobalConfig;
use databend_common_exception::ErrorCode;
use databend_common_exception::Result;
use databend_common_expression::DataSchemaRef;
Expand Down Expand Up @@ -319,9 +320,12 @@ impl IPhysicalPlan for HilbertPartition {
)?;

let settings = builder.settings.clone();
let disk_bytes_limit = settings.get_window_partition_spilling_to_disk_bytes_limit()?;
let temp_dir_manager = TempDirManager::instance();

let disk_bytes_limit = GlobalConfig::instance()
.spill
.window_partition_spill_bytes_limit();

let enable_dio = settings.get_enable_dio()?;
let disk_spill = temp_dir_manager
.get_disk_spill_dir(disk_bytes_limit, &builder.ctx.get_id())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::sync::atomic::AtomicUsize;

use databend_common_catalog::plan::DataSourcePlan;
use databend_common_catalog::table_context::TableContext;
use databend_common_config::GlobalConfig;
use databend_common_exception::Result;
use databend_common_expression::SortColumnDescription;
use databend_common_pipeline::core::ProcessorPtr;
Expand Down Expand Up @@ -148,7 +149,9 @@ impl IPhysicalPlan for WindowPartition {
}

let temp_dir_manager = TempDirManager::instance();
let disk_bytes_limit = settings.get_window_partition_spilling_to_disk_bytes_limit()?;
let disk_bytes_limit = GlobalConfig::instance()
.spill
.window_partition_spill_bytes_limit();
let enable_dio = settings.get_enable_dio()?;
let disk_spill = temp_dir_manager
.get_disk_spill_dir(disk_bytes_limit, &builder.ctx.get_id())
Expand Down
3 changes: 2 additions & 1 deletion src/query/service/src/pipelines/builders/builder_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

use std::sync::Arc;

use databend_common_config::GlobalConfig;
use databend_common_exception::Result;
use databend_common_expression::DataSchemaRef;
use databend_common_expression::LimitType;
Expand Down Expand Up @@ -132,7 +133,7 @@ impl SortPipelineBuilder {

let spiller = {
let temp_dir_manager = TempDirManager::instance();
let disk_bytes_limit = settings.get_sort_spilling_to_disk_bytes_limit()?;
let disk_bytes_limit = GlobalConfig::instance().spill.sort_spill_bytes_limit();
let enable_dio = settings.get_enable_dio()?;
let disk_spill = temp_dir_manager
.get_disk_spill_dir(disk_bytes_limit, &self.ctx.get_id())
Expand Down
Loading
Loading