-
Notifications
You must be signed in to change notification settings - Fork 0
1503: feat: (remote) shuffle reader cleanup #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,10 +31,8 @@ use datafusion::{ | |
| pub const BALLISTA_JOB_NAME: &str = "ballista.job.name"; | ||
| /// Configuration key for standalone processing parallelism. | ||
| pub const BALLISTA_STANDALONE_PARALLELISM: &str = "ballista.standalone.parallelism"; | ||
|
|
||
| /// Configuration key for disabling default cache extension node. | ||
| pub const BALLISTA_CACHE_NOOP: &str = "ballista.cache.noop"; | ||
|
|
||
| /// Configuration key for maximum concurrent shuffle read requests. | ||
| pub const BALLISTA_SHUFFLE_READER_MAX_REQUESTS: &str = | ||
| "ballista.shuffle.max_concurrent_read_requests"; | ||
|
|
@@ -44,7 +42,6 @@ pub const BALLISTA_SHUFFLE_READER_FORCE_REMOTE_READ: &str = | |
| /// Configuration key to prefer Flight protocol for remote shuffle reads. | ||
| pub const BALLISTA_SHUFFLE_READER_REMOTE_PREFER_FLIGHT: &str = | ||
| "ballista.shuffle.remote_read_prefer_flight"; | ||
|
|
||
| /// max message size for gRPC clients | ||
| pub const BALLISTA_GRPC_CLIENT_MAX_MESSAGE_SIZE: &str = | ||
| "ballista.grpc_client_max_message_size"; | ||
|
|
@@ -82,6 +79,8 @@ pub const BALLISTA_SHUFFLE_SORT_BASED_BATCH_SIZE: &str = | |
| "ballista.shuffle.sort_based.batch_size"; | ||
| /// Should client employ pull or push job tracking strategy | ||
| pub const BALLISTA_CLIENT_PULL: &str = "ballista.client.pull"; | ||
| /// Should client use tls connection | ||
| pub const BALLISTA_CLIENT_USE_TLS: &str = "ballista.client.use_tls"; | ||
|
|
||
| /// Result type for configuration parsing operations. | ||
| pub type ParseResult<T> = result::Result<T, String>; | ||
|
|
@@ -162,6 +161,10 @@ static CONFIG_ENTRIES: LazyLock<HashMap<String, ConfigEntry>> = LazyLock::new(|| | |
| ConfigEntry::new(BALLISTA_CLIENT_PULL.to_string(), | ||
| "Should client employ pull or push job tracking. In pull mode client will make a request to server in the loop, until job finishes. Pull mode is kept for legacy clients.".to_string(), | ||
| DataType::Boolean, | ||
| Some(false.to_string())), | ||
| ConfigEntry::new(BALLISTA_CLIENT_USE_TLS.to_string(), | ||
| "Should connection between client, scheduler, and executors use TLS.".to_string(), | ||
| DataType::Boolean, | ||
| Some(false.to_string())) | ||
| ]; | ||
| entries | ||
|
|
@@ -274,11 +277,6 @@ impl BallistaConfig { | |
| &self.settings | ||
| } | ||
|
|
||
| /// Returns the maximum message size for gRPC clients in bytes. | ||
| pub fn default_grpc_client_max_message_size(&self) -> usize { | ||
| self.get_usize_setting(BALLISTA_GRPC_CLIENT_MAX_MESSAGE_SIZE) | ||
| } | ||
|
|
||
| /// Returns the standalone processing parallelism level. | ||
| pub fn default_standalone_parallelism(&self) -> usize { | ||
| self.get_usize_setting(BALLISTA_STANDALONE_PARALLELISM) | ||
|
|
@@ -290,25 +288,30 @@ impl BallistaConfig { | |
| } | ||
|
|
||
| /// Returns the gRPC client connection timeout in seconds. | ||
| pub fn default_grpc_client_connect_timeout_seconds(&self) -> usize { | ||
| pub fn grpc_client_connect_timeout_seconds(&self) -> usize { | ||
| self.get_usize_setting(BALLISTA_GRPC_CLIENT_CONNECT_TIMEOUT_SECONDS) | ||
| } | ||
|
|
||
| /// Returns the gRPC client request timeout in seconds. | ||
| pub fn default_grpc_client_timeout_seconds(&self) -> usize { | ||
| pub fn grpc_client_timeout_seconds(&self) -> usize { | ||
| self.get_usize_setting(BALLISTA_GRPC_CLIENT_TIMEOUT_SECONDS) | ||
| } | ||
|
|
||
| /// Returns the TCP keep-alive interval for gRPC clients in seconds. | ||
| pub fn default_grpc_client_tcp_keepalive_seconds(&self) -> usize { | ||
| pub fn grpc_client_tcp_keepalive_seconds(&self) -> usize { | ||
| self.get_usize_setting(BALLISTA_GRPC_CLIENT_TCP_KEEPALIVE_SECONDS) | ||
| } | ||
|
|
||
| /// Returns the HTTP/2 keep-alive interval for gRPC clients in seconds. | ||
| pub fn default_grpc_client_http2_keepalive_interval_seconds(&self) -> usize { | ||
| pub fn grpc_client_http2_keepalive_interval_seconds(&self) -> usize { | ||
| self.get_usize_setting(BALLISTA_GRPC_CLIENT_HTTP2_KEEPALIVE_INTERVAL_SECONDS) | ||
| } | ||
|
|
||
| /// Returns the maximum message size for gRPC clients in bytes. | ||
| pub fn grpc_client_max_message_size(&self) -> usize { | ||
| self.get_usize_setting(BALLISTA_GRPC_CLIENT_MAX_MESSAGE_SIZE) | ||
| } | ||
|
|
||
| /// Returns whether the default cache node extension is disabled. | ||
| pub fn cache_noop(&self) -> bool { | ||
| self.get_bool_setting(BALLISTA_CACHE_NOOP) | ||
|
|
@@ -373,6 +376,11 @@ impl BallistaConfig { | |
| self.get_bool_setting(BALLISTA_CLIENT_PULL) | ||
| } | ||
|
|
||
| /// should client use TLS to communicate with ballista cluster | ||
| pub fn client_use_tls(&self) -> bool { | ||
| self.get_bool_setting(BALLISTA_CLIENT_USE_TLS) | ||
| } | ||
|
|
||
| fn get_usize_setting(&self, key: &str) -> usize { | ||
| if let Some(v) = self.settings.get(key) { | ||
| // infallible because we validate all configs in the constructor | ||
|
|
@@ -419,6 +427,23 @@ impl BallistaConfig { | |
| v.parse::<f64>().unwrap() | ||
| } | ||
| } | ||
| /// sets the configuration value where key starts with ballista | ||
| /// prefix. | ||
| pub fn set_with_prefix( | ||
| &mut self, | ||
| key: &str, | ||
| value: &str, | ||
| ) -> datafusion::error::Result<()> { | ||
| let entries = Self::valid_entries(); | ||
| //let k = format!("{}.{key}", BallistaConfig::PREFIX); | ||
|
|
||
| if entries.contains_key(key) { | ||
| self.settings.insert(key.to_string(), value.to_string()); | ||
| Ok(()) | ||
| } else { | ||
| config_err!("configuration key `{}` does not exist", key) | ||
| } | ||
| } | ||
|
Comment on lines
+430
to
+446
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Unlike Consider adding type validation: 🛡️ Proposed fix to add value validation pub fn set_with_prefix(
&mut self,
key: &str,
value: &str,
) -> datafusion::error::Result<()> {
let entries = Self::valid_entries();
if entries.contains_key(key) {
+ let entry = entries.get(key).unwrap();
+ Self::parse_value(value, entry.data_type.clone())
+ .map_err(|e| datafusion::error::DataFusionError::Configuration(
+ format!("Invalid value '{value}' for key '{key}': {e}")
+ ))?;
self.settings.insert(key.to_string(), value.to_string());
Ok(())
} else {
config_err!("configuration key `{}` does not exist", key)
}
}🤖 Prompt for AI Agents
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. value:useful; category:bug; feedback: The CodeRabbit AI reviewer is correct! The new method does not validate the provided values and this may lead to problems later when these values need to be used. Prevents storing invalid values. |
||
| } | ||
|
|
||
| impl datafusion::config::ExtensionOptions for BallistaConfig { | ||
|
|
@@ -539,7 +564,7 @@ mod tests { | |
| #[test] | ||
| fn default_config() -> Result<()> { | ||
| let config = BallistaConfig::default(); | ||
| assert_eq!(16777216, config.default_grpc_client_max_message_size()); | ||
| assert_eq!(16777216, config.grpc_client_max_message_size()); | ||
| Ok(()) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -253,7 +253,7 @@ impl<T: 'static + AsLogicalPlan> ExecutionPlan for DistributedQueryExec<T> { | |
| self.scheduler_url.clone(), | ||
| self.session_id.clone(), | ||
| query, | ||
| self.config.default_grpc_client_max_message_size(), | ||
| self.config.grpc_client_max_message_size(), | ||
| GrpcClientConfig::from(&self.config), | ||
| Arc::new(self.metrics.clone()), | ||
| partition, | ||
|
|
@@ -280,7 +280,7 @@ impl<T: 'static + AsLogicalPlan> ExecutionPlan for DistributedQueryExec<T> { | |
| execute_query_push( | ||
| self.scheduler_url.clone(), | ||
| query, | ||
| self.config.default_grpc_client_max_message_size(), | ||
| self.config.grpc_client_max_message_size(), | ||
| GrpcClientConfig::from(&self.config), | ||
| Arc::new(self.metrics.clone()), | ||
| partition, | ||
|
|
@@ -701,8 +701,6 @@ async fn fetch_partition( | |
| let partition_id = location.partition_id.ok_or_else(|| { | ||
| DataFusionError::Internal("Received empty partition id".to_owned()) | ||
| })?; | ||
| let host = metadata.host.as_str(); | ||
| let port = metadata.port as u16; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Action contains proxy address instead of executor addressMedium Severity When a flight proxy is configured, Additional Locations (1)
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. value:useful; category:bug; feedback: The Bugbot AI reviewer is correct! The changes in the Pull Request propose to use the flight proxy for some functionalities and still use direct connection to the executor for others. In this particular case the connection should be direct/sticky, because a specific executor is responsible for a given partition. |
||
|
|
||
| let (client_host, client_port) = | ||
| get_client_host_port(&metadata, &scheduler_url, &flight_proxy)?; | ||
|
|
@@ -721,8 +719,6 @@ async fn fetch_partition( | |
| &metadata.id, | ||
| &partition_id.into(), | ||
| &location.path, | ||
| host, | ||
| port, | ||
| flight_transport, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Severity: high Other Locations
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. value:useful; category:bug; feedback: The Augment AI reviewer is correct! The changes in the Pull Request propose to use the flight proxy for some functionalities and still use direct connection to the executor for others. In this particular case the connection should be direct/sticky, because a specific executor is responsible for a given partition. |
||
| ) | ||
| .await | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FetchPartition.host/portare used by the scheduler flight proxy (flight_proxy_service.rs) to connect onward to the executor; usingself.host/self.porthere looks problematic when the client is connected to a proxy/scheduler endpoint. In those cases the ticket may embed the proxy’s host/port and cause the proxy to forward back to itself rather than the executor.Severity: high
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value:useful; category:bug; feedback: The Augment AI reviewer is correct! The changes in the Pull Request propose to use the flight proxy for some functionalities and still use direct connection to the executor for others. In this particular case the connection should be direct/sticky, because a specific executor is responsible for a given partition.