use crate::ClientError;
use crate::ClientResult;
use crate::base::client_config::ClientConfig;
pub struct ClientConfigValidator;
impl ClientConfigValidator {
pub const MIN_POLL_NAME_SERVER_INTERVAL: u32 = 10_000;
pub const MAX_POLL_NAME_SERVER_INTERVAL: u32 = 600_000;
pub const MIN_HEARTBEAT_BROKER_INTERVAL: u32 = 10_000;
pub const MAX_HEARTBEAT_BROKER_INTERVAL: u32 = 600_000;
pub const MIN_PERSIST_CONSUMER_OFFSET_INTERVAL: u32 = 1_000;
pub const MAX_PERSIST_CONSUMER_OFFSET_INTERVAL: u32 = 60_000;
pub const MIN_TRACE_MSG_BATCH_NUM: usize = 1;
pub const MAX_TRACE_MSG_BATCH_NUM: usize = 10_000;
pub const MIN_MAX_PAGE_SIZE_IN_GET_METADATA: usize = 1;
pub const MAX_MAX_PAGE_SIZE_IN_GET_METADATA: usize = 100_000;
pub const MIN_MQ_CLIENT_API_TIMEOUT: u64 = 100;
pub const MAX_MQ_CLIENT_API_TIMEOUT: u64 = 60_000;
pub const MAX_PULL_MESSAGE_SERVICE_SHARDS_PER_CPU: usize = 8;
pub fn validate_config(config: &ClientConfig) -> ClientResult<()> {
Self::validate_poll_name_server_interval(config.poll_name_server_interval)?;
Self::validate_heartbeat_broker_interval(config.heartbeat_broker_interval)?;
Self::validate_persist_consumer_offset_interval(config.persist_consumer_offset_interval)?;
Self::validate_mq_client_api_timeout(config.mq_client_api_timeout)?;
Self::validate_trace_msg_batch_num(config.trace_msg_batch_num)?;
Self::validate_max_page_size_in_get_metadata(config.max_page_size_in_get_metadata)?;
Self::validate_client_callback_executor_threads(config.client_callback_executor_threads)?;
Self::validate_pull_message_service_shards(config.pull_message_service_shards)?;
if config.enable_concurrent_heartbeat {
Self::validate_concurrent_heartbeat_thread_pool_size(config.concurrent_heartbeat_thread_pool_size)?;
}
Ok(())
}
pub fn validate_poll_name_server_interval(interval: u32) -> ClientResult<()> {
if !(Self::MIN_POLL_NAME_SERVER_INTERVAL..=Self::MAX_POLL_NAME_SERVER_INTERVAL).contains(&interval) {
return Err(ClientError::config_invalid(
"poll_name_server_interval",
interval.to_string(),
format!(
"must be between {} and {} milliseconds",
Self::MIN_POLL_NAME_SERVER_INTERVAL,
Self::MAX_POLL_NAME_SERVER_INTERVAL
),
));
}
Ok(())
}
pub fn validate_heartbeat_broker_interval(interval: u32) -> ClientResult<()> {
if !(Self::MIN_HEARTBEAT_BROKER_INTERVAL..=Self::MAX_HEARTBEAT_BROKER_INTERVAL).contains(&interval) {
return Err(ClientError::config_invalid(
"heartbeat_broker_interval",
interval.to_string(),
format!(
"must be between {} and {} milliseconds",
Self::MIN_HEARTBEAT_BROKER_INTERVAL,
Self::MAX_HEARTBEAT_BROKER_INTERVAL
),
));
}
Ok(())
}
pub fn validate_persist_consumer_offset_interval(interval: u32) -> ClientResult<()> {
if !(Self::MIN_PERSIST_CONSUMER_OFFSET_INTERVAL..=Self::MAX_PERSIST_CONSUMER_OFFSET_INTERVAL)
.contains(&interval)
{
return Err(ClientError::config_invalid(
"persist_consumer_offset_interval",
interval.to_string(),
format!(
"must be between {} and {} milliseconds",
Self::MIN_PERSIST_CONSUMER_OFFSET_INTERVAL,
Self::MAX_PERSIST_CONSUMER_OFFSET_INTERVAL
),
));
}
Ok(())
}
pub fn validate_trace_msg_batch_num(num: usize) -> ClientResult<()> {
if !(Self::MIN_TRACE_MSG_BATCH_NUM..=Self::MAX_TRACE_MSG_BATCH_NUM).contains(&num) {
return Err(ClientError::config_invalid(
"trace_msg_batch_num",
num.to_string(),
format!(
"must be between {} and {}",
Self::MIN_TRACE_MSG_BATCH_NUM,
Self::MAX_TRACE_MSG_BATCH_NUM
),
));
}
Ok(())
}
pub fn validate_max_page_size_in_get_metadata(size: usize) -> ClientResult<()> {
if !(Self::MIN_MAX_PAGE_SIZE_IN_GET_METADATA..=Self::MAX_MAX_PAGE_SIZE_IN_GET_METADATA).contains(&size) {
return Err(ClientError::config_invalid(
"max_page_size_in_get_metadata",
size.to_string(),
format!(
"must be between {} and {}",
Self::MIN_MAX_PAGE_SIZE_IN_GET_METADATA,
Self::MAX_MAX_PAGE_SIZE_IN_GET_METADATA
),
));
}
Ok(())
}
pub fn validate_mq_client_api_timeout(timeout: u64) -> ClientResult<()> {
if !(Self::MIN_MQ_CLIENT_API_TIMEOUT..=Self::MAX_MQ_CLIENT_API_TIMEOUT).contains(&timeout) {
return Err(ClientError::config_invalid(
"mq_client_api_timeout",
timeout.to_string(),
format!(
"must be between {} and {} milliseconds",
Self::MIN_MQ_CLIENT_API_TIMEOUT,
Self::MAX_MQ_CLIENT_API_TIMEOUT
),
));
}
Ok(())
}
pub fn validate_concurrent_heartbeat_thread_pool_size(size: usize) -> ClientResult<()> {
if size == 0 {
return Err(ClientError::config_invalid(
"concurrent_heartbeat_thread_pool_size",
size.to_string(),
"must be greater than 0",
));
}
#[allow(clippy::redundant_closure)]
let cpu_count = std::panic::catch_unwind(|| num_cpus::get()).unwrap_or(4);
let max_size = cpu_count * 4;
if size > max_size {
return Err(ClientError::config_invalid(
"concurrent_heartbeat_thread_pool_size",
size.to_string(),
format!("should not exceed {} (CPU cores * 4)", max_size),
));
}
Ok(())
}
pub fn validate_client_callback_executor_threads(threads: usize) -> ClientResult<()> {
if threads == 0 {
return Err(ClientError::config_invalid(
"client_callback_executor_threads",
threads.to_string(),
"must be greater than 0",
));
}
#[allow(clippy::redundant_closure)]
let cpu_count = std::panic::catch_unwind(|| num_cpus::get()).unwrap_or(4);
let max_threads = cpu_count * 8;
if threads > max_threads {
return Err(ClientError::config_invalid(
"client_callback_executor_threads",
threads.to_string(),
format!("should not exceed {} (CPU cores * 8)", max_threads),
));
}
Ok(())
}
pub fn validate_pull_message_service_shards(shards: usize) -> ClientResult<()> {
if shards == 0 {
return Err(ClientError::config_invalid(
"pull_message_service_shards",
shards.to_string(),
"must be greater than 0",
));
}
#[allow(clippy::redundant_closure)]
let cpu_count = std::panic::catch_unwind(|| num_cpus::get()).unwrap_or(4);
let max_shards = cpu_count * Self::MAX_PULL_MESSAGE_SERVICE_SHARDS_PER_CPU;
if shards > max_shards {
return Err(ClientError::config_invalid(
"pull_message_service_shards",
shards.to_string(),
format!("should not exceed {} (CPU cores * 8)", max_shards),
));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_poll_name_server_interval_valid() {
assert!(ClientConfigValidator::validate_poll_name_server_interval(30_000).is_ok());
assert!(ClientConfigValidator::validate_poll_name_server_interval(10_000).is_ok());
assert!(ClientConfigValidator::validate_poll_name_server_interval(600_000).is_ok());
}
#[test]
fn test_validate_poll_name_server_interval_invalid() {
assert!(ClientConfigValidator::validate_poll_name_server_interval(1_000).is_err());
assert!(ClientConfigValidator::validate_poll_name_server_interval(700_000).is_err());
}
#[test]
fn test_validate_heartbeat_broker_interval_valid() {
assert!(ClientConfigValidator::validate_heartbeat_broker_interval(30_000).is_ok());
assert!(ClientConfigValidator::validate_heartbeat_broker_interval(10_000).is_ok());
assert!(ClientConfigValidator::validate_heartbeat_broker_interval(600_000).is_ok());
}
#[test]
fn test_validate_heartbeat_broker_interval_invalid() {
assert!(ClientConfigValidator::validate_heartbeat_broker_interval(1_000).is_err());
assert!(ClientConfigValidator::validate_heartbeat_broker_interval(700_000).is_err());
}
#[test]
fn test_validate_trace_msg_batch_num_valid() {
assert!(ClientConfigValidator::validate_trace_msg_batch_num(1).is_ok());
assert!(ClientConfigValidator::validate_trace_msg_batch_num(10).is_ok());
assert!(ClientConfigValidator::validate_trace_msg_batch_num(10_000).is_ok());
}
#[test]
fn test_validate_trace_msg_batch_num_invalid() {
assert!(ClientConfigValidator::validate_trace_msg_batch_num(0).is_err());
assert!(ClientConfigValidator::validate_trace_msg_batch_num(10_001).is_err());
}
#[test]
fn test_validate_concurrent_heartbeat_thread_pool_size_valid() {
assert!(ClientConfigValidator::validate_concurrent_heartbeat_thread_pool_size(1).is_ok());
assert!(ClientConfigValidator::validate_concurrent_heartbeat_thread_pool_size(4).is_ok());
}
#[test]
fn test_validate_pull_message_service_shards() {
assert!(ClientConfigValidator::validate_pull_message_service_shards(1).is_ok());
assert!(ClientConfigValidator::validate_pull_message_service_shards(4).is_ok());
assert!(ClientConfigValidator::validate_pull_message_service_shards(0).is_err());
}
#[test]
fn test_validate_mq_client_api_timeout_valid() {
assert!(ClientConfigValidator::validate_mq_client_api_timeout(3_000).is_ok());
assert!(ClientConfigValidator::validate_mq_client_api_timeout(100).is_ok());
assert!(ClientConfigValidator::validate_mq_client_api_timeout(60_000).is_ok());
}
#[test]
fn test_validate_mq_client_api_timeout_invalid() {
assert!(ClientConfigValidator::validate_mq_client_api_timeout(50).is_err());
assert!(ClientConfigValidator::validate_mq_client_api_timeout(70_000).is_err());
}
}