From fb99f77088b73a04d5ca227f2bef01771701e400 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Tue, 21 Jan 2025 14:58:08 +0100 Subject: [PATCH 01/26] [#429] Request response service builder skeleton --- iceoryx2/src/service/builder/mod.rs | 21 +++ .../src/service/builder/request_response.rs | 176 ++++++++++++++++++ iceoryx2/src/service/messaging_pattern.rs | 2 + 3 files changed, 199 insertions(+) create mode 100644 iceoryx2/src/service/builder/request_response.rs diff --git a/iceoryx2/src/service/builder/mod.rs b/iceoryx2/src/service/builder/mod.rs index 3340776ed..96f92d944 100644 --- a/iceoryx2/src/service/builder/mod.rs +++ b/iceoryx2/src/service/builder/mod.rs @@ -20,6 +20,8 @@ pub mod event; /// Builder for [`MessagingPattern::PublishSubscribe`](crate::service::messaging_pattern::MessagingPattern::PublishSubscribe) pub mod publish_subscribe; +pub mod request_response; + use crate::node::SharedNode; use crate::service; use crate::service::dynamic_config::DynamicConfig; @@ -112,6 +114,19 @@ impl Builder { } } + pub fn request( + self, + ) -> request_response::BuilderRequest { + BuilderWithServiceType::new( + StaticConfig::new_publish_subscribe::( + &self.name, + self.shared_node.config(), + ), + self.shared_node, + ) + .request::() + } + /// Create a new builder to create a /// [`MessagingPattern::PublishSubscribe`](crate::service::messaging_pattern::MessagingPattern::PublishSubscribe) [`Service`]. pub fn publish_subscribe( @@ -155,6 +170,12 @@ impl BuilderWithServiceType { } } + fn request( + self, + ) -> request_response::BuilderRequest { + request_response::BuilderRequest::new(self) + } + fn publish_subscribe( self, ) -> publish_subscribe::Builder { diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs new file mode 100644 index 000000000..83d1196b3 --- /dev/null +++ b/iceoryx2/src/service/builder/request_response.rs @@ -0,0 +1,176 @@ +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use std::fmt::Debug; +use std::marker::PhantomData; + +use crate::service; +use crate::service::builder; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum RequestResponseOpenError {} + +impl core::fmt::Display for RequestResponseOpenError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + std::write!(f, "RequestResponseOpenError::{:?}", self) + } +} + +impl std::error::Error for RequestResponseOpenError {} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum RequestResponseCreateError {} + +impl core::fmt::Display for RequestResponseCreateError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + std::write!(f, "RequestResponseCreateError::{:?}", self) + } +} + +impl std::error::Error for RequestResponseCreateError {} + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum RequestResponseOpenOrCreateError { + RequestResponseOpenError(RequestResponseOpenError), + RequestResponseCreateError(RequestResponseCreateError), +} + +impl From for RequestResponseOpenOrCreateError { + fn from(value: RequestResponseOpenError) -> Self { + RequestResponseOpenOrCreateError::RequestResponseOpenError(value) + } +} + +impl From for RequestResponseOpenOrCreateError { + fn from(value: RequestResponseCreateError) -> Self { + RequestResponseOpenOrCreateError::RequestResponseCreateError(value) + } +} + +impl core::fmt::Display for RequestResponseOpenOrCreateError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + std::write!(f, "RequestResponseOpenOrCreateError::{:?}", self) + } +} + +impl std::error::Error for RequestResponseOpenOrCreateError {} + +#[derive(Debug)] +pub struct BuilderRequest { + base: builder::BuilderWithServiceType, + _request_payload: PhantomData, +} + +impl + BuilderRequest +{ + pub(crate) fn new(base: builder::BuilderWithServiceType) -> Self { + Self { + base, + _request_payload: PhantomData, + } + } + + pub fn response( + self, + ) -> Builder { + Builder::new(self.base) + } +} + +#[derive(Debug)] +pub struct Builder< + RequestPayload: Debug, + RequestHeader: Debug, + ResponsePayload: Debug, + ResponseHeader: Debug, + ServiceType: service::Service, +> { + base: builder::BuilderWithServiceType, + _request_payload: PhantomData, + _request_header: PhantomData, + _response_payload: PhantomData, + _response_header: PhantomData, +} + +impl< + RequestPayload: Debug, + RequestHeader: Debug, + ResponsePayload: Debug, + ResponseHeader: Debug, + ServiceType: service::Service, + > Builder +{ + fn new(base: builder::BuilderWithServiceType) -> Self { + Self { + base, + _request_payload: PhantomData, + _request_header: PhantomData, + _response_payload: PhantomData, + _response_header: PhantomData, + } + } + + pub fn request_header( + self, + ) -> Builder { + unsafe { + core::mem::transmute::< + Self, + Builder, + >(self) + } + } + + pub fn response_header( + self, + ) -> Builder { + unsafe { + core::mem::transmute::< + Self, + Builder, + >(self) + } + } + + pub fn enable_safe_overflow_for_requests(mut self, value: bool) -> Self { + todo!() + } + + pub fn enable_safe_overflow_for_responses(mut self, value: bool) -> Self { + todo!() + } + + pub fn max_active_requests(mut self, value: usize) -> Self { + todo!() + } + + pub fn max_borrowed_responses(mut self, value: usize) -> Self { + todo!() + } + + pub fn response_buffer_size(mut self, value: usize) -> Self { + todo!() + } + + pub fn max_servers(mut self, value: usize) -> Self { + todo!() + } + + pub fn max_clients(mut self, value: usize) -> Self { + todo!() + } + + pub fn max_nodes(mut self, value: usize) -> Self { + todo!() + } +} diff --git a/iceoryx2/src/service/messaging_pattern.rs b/iceoryx2/src/service/messaging_pattern.rs index 4aaef4012..df23c7cd6 100644 --- a/iceoryx2/src/service/messaging_pattern.rs +++ b/iceoryx2/src/service/messaging_pattern.rs @@ -46,4 +46,6 @@ pub enum MessagingPattern { /// ability to sleep until a signal/event arrives. /// Building block to realize push-notifications. Event, + + RequestResponse, } From e17a9a1a1169ca45cdcf60f4771cb5489faf6329 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Tue, 21 Jan 2025 17:07:18 +0100 Subject: [PATCH 02/26] [#429] Add request response static config --- config/iceoryx2.toml | 10 +++ iceoryx2-ffi/ffi/src/api/config.rs | 2 +- iceoryx2/src/config.rs | 26 ++++++ .../static_config/messaging_pattern.rs | 6 ++ iceoryx2/src/service/static_config/mod.rs | 46 +++++++++- .../service/static_config/request_response.rs | 86 +++++++++++++++++++ 6 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 iceoryx2/src/service/static_config/request_response.rs diff --git a/config/iceoryx2.toml b/config/iceoryx2.toml index 70d0fa9f9..e6df9c693 100644 --- a/config/iceoryx2.toml +++ b/config/iceoryx2.toml @@ -21,6 +21,16 @@ connection-suffix = '.connection' creation-timeout.secs = 0 creation-timeout.nanos = 500000000 +[defaults.request-response] +enable-safe-overflow-for-requests = true +enable-safe-overflow-for-responses = true +max-active-requests = 2 +max-borrowed-responses = 2 +response-buffer-size = 2 +max-servers = 2 +max-clients = 8 +max-nodes = 20 + [defaults.publish-subscribe] max-subscribers = 8 max-publishers = 2 diff --git a/iceoryx2-ffi/ffi/src/api/config.rs b/iceoryx2-ffi/ffi/src/api/config.rs index 20081b2ab..b926f53ef 100644 --- a/iceoryx2-ffi/ffi/src/api/config.rs +++ b/iceoryx2-ffi/ffi/src/api/config.rs @@ -76,7 +76,7 @@ pub(super) struct ConfigOwner { #[repr(C)] #[repr(align(8))] // align_of() pub struct iox2_config_storage_t { - internal: [u8; 3624], // size_of() + internal: [u8; 3680], // size_of() } /// Contains the iceoryx2 config diff --git a/iceoryx2/src/config.rs b/iceoryx2/src/config.rs index fc5cdf4aa..637198651 100644 --- a/iceoryx2/src/config.rs +++ b/iceoryx2/src/config.rs @@ -215,6 +215,8 @@ pub struct Defaults { pub publish_subscribe: PublishSubscribe, /// Default settings for the messaging pattern event pub event: Event, + + pub request_response: RequestResonse, } /// Default settings for the publish-subscribe messaging pattern. These settings are used unless @@ -284,6 +286,20 @@ pub struct Event { pub notifier_dead_event: Option, } +#[non_exhaustive] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub struct RequestResonse { + pub enable_safe_overflow_for_requests: bool, + pub enable_safe_overflow_for_responses: bool, + pub max_active_requests: usize, + pub max_borrowed_responses: usize, + pub response_buffer_size: usize, + pub max_servers: usize, + pub max_clients: usize, + pub max_nodes: usize, +} + /// Represents the configuration that iceoryx2 will utilize. It is divided into two sections: /// the [Global] settings, which must align with the iceoryx2 instance the application intends to /// join, and the [Defaults] for communication within that iceoryx2 instance. The user has the @@ -326,6 +342,16 @@ impl Default for Config { }, }, defaults: Defaults { + request_response: RequestResonse { + enable_safe_overflow_for_requests: true, + enable_safe_overflow_for_responses: true, + max_active_requests: 2, + max_borrowed_responses: 2, + response_buffer_size: 2, + max_servers: 2, + max_clients: 8, + max_nodes: 20, + }, publish_subscribe: PublishSubscribe { max_subscribers: 8, max_publishers: 2, diff --git a/iceoryx2/src/service/static_config/messaging_pattern.rs b/iceoryx2/src/service/static_config/messaging_pattern.rs index f63977ea7..b2e4ff4e9 100644 --- a/iceoryx2/src/service/static_config/messaging_pattern.rs +++ b/iceoryx2/src/service/static_config/messaging_pattern.rs @@ -17,12 +17,16 @@ use crate::service::static_config::event; use crate::service::static_config::publish_subscribe; use serde::{Deserialize, Serialize}; +use super::request_response; + /// Contains the static config of the corresponding /// [`service::MessagingPattern`](crate::service::messaging_pattern::MessagingPattern). #[non_exhaustive] #[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] #[serde(tag = "messaging_pattern")] pub enum MessagingPattern { + RequestResponse(request_response::StaticConfig), + /// Stores the static config of the /// [`service::MessagingPattern::PublishSubscribe`](crate::service::messaging_pattern::MessagingPattern::PublishSubscribe) PublishSubscribe(publish_subscribe::StaticConfig), @@ -35,6 +39,7 @@ pub enum MessagingPattern { impl Display for MessagingPattern { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { + MessagingPattern::RequestResponse(_) => write!(f, "RequestResponse"), MessagingPattern::Event(_) => write!(f, "Event"), MessagingPattern::PublishSubscribe(_) => write!(f, "PublishSubscribe"), } @@ -81,6 +86,7 @@ mod tests { assert_that!(p2.is_same_pattern(&p1), eq true); let mut new_defaults = config::Defaults { + request_response: cfg.defaults.request_response.clone(), publish_subscribe: cfg.defaults.publish_subscribe.clone(), event: cfg.defaults.event.clone(), }; diff --git a/iceoryx2/src/service/static_config/mod.rs b/iceoryx2/src/service/static_config/mod.rs index 3ef98fbe5..3f8b10fbe 100644 --- a/iceoryx2/src/service/static_config/mod.rs +++ b/iceoryx2/src/service/static_config/mod.rs @@ -24,6 +24,8 @@ pub mod publish_subscribe; /// and the type variant pub mod message_type_details; +pub mod request_response; + pub mod messaging_pattern; use iceoryx2_bb_log::fatal_panic; @@ -46,6 +48,23 @@ pub struct StaticConfig { } impl StaticConfig { + pub(crate) fn new_request_response( + service_name: &ServiceName, + config: &config::Config, + ) -> Self { + let messaging_pattern = + MessagingPattern::RequestResponse(request_response::StaticConfig::new(config)); + Self { + service_id: ServiceId::new::( + service_name, + crate::service::messaging_pattern::MessagingPattern::RequestResponse, + ), + service_name: service_name.clone(), + messaging_pattern, + attributes: AttributeSet::new(), + } + } + pub(crate) fn new_event( service_name: &ServiceName, config: &config::Config, @@ -104,11 +123,30 @@ impl StaticConfig { .is_same_pattern(&rhs.messaging_pattern) } + pub(crate) fn request_response(&self) -> &request_response::StaticConfig { + match &self.messaging_pattern { + MessagingPattern::RequestResponse(ref v) => v, + m => { + fatal_panic!(from self, "This should never happen! Trying to access request_response::StaticConfig when the messaging pattern is actually {:?}!", m) + } + } + } + + pub(crate) fn request_response_mut(&mut self) -> &mut request_response::StaticConfig { + let origin = format!("{:?}", self); + match &mut self.messaging_pattern { + MessagingPattern::RequestResponse(ref mut v) => v, + m => { + fatal_panic!(from origin, "This should never happen! Trying to access request_response::StaticConfig when the messaging pattern is actually {:?}!", m) + } + } + } + pub(crate) fn event(&self) -> &event::StaticConfig { match &self.messaging_pattern { MessagingPattern::Event(ref v) => v, m => { - fatal_panic!(from self, "This should never happen. Trying to access event::StaticConfig when the messaging pattern is actually {:?}!", m) + fatal_panic!(from self, "This should never happen! Trying to access event::StaticConfig when the messaging pattern is actually {:?}!", m) } } } @@ -118,7 +156,7 @@ impl StaticConfig { match &mut self.messaging_pattern { MessagingPattern::Event(ref mut v) => v, m => { - fatal_panic!(from origin, "This should never happen. Trying to access event::StaticConfig when the messaging pattern is actually {:?}!", m) + fatal_panic!(from origin, "This should never happen! Trying to access event::StaticConfig when the messaging pattern is actually {:?}!", m) } } } @@ -127,7 +165,7 @@ impl StaticConfig { match &self.messaging_pattern { MessagingPattern::PublishSubscribe(ref v) => v, m => { - fatal_panic!(from self, "This should never happen. Trying to access publish_subscribe::StaticConfig when the messaging pattern is actually {:?}!", m) + fatal_panic!(from self, "This should never happen! Trying to access publish_subscribe::StaticConfig when the messaging pattern is actually {:?}!", m) } } } @@ -137,7 +175,7 @@ impl StaticConfig { match &mut self.messaging_pattern { MessagingPattern::PublishSubscribe(ref mut v) => v, m => { - fatal_panic!(from origin, "This should never happen. Trying to access publish_subscribe::StaticConfig when the messaging pattern is actually {:?}!", m) + fatal_panic!(from origin, "This should never happen! Trying to access publish_subscribe::StaticConfig when the messaging pattern is actually {:?}!", m) } } } diff --git a/iceoryx2/src/service/static_config/request_response.rs b/iceoryx2/src/service/static_config/request_response.rs new file mode 100644 index 000000000..228292b83 --- /dev/null +++ b/iceoryx2/src/service/static_config/request_response.rs @@ -0,0 +1,86 @@ +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use serde::{Deserialize, Serialize}; + +use crate::config; + +use super::message_type_details::MessageTypeDetails; + +#[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct StaticConfig { + pub(crate) enable_safe_overflow_for_requests: bool, + pub(crate) enable_safe_overflow_for_responses: bool, + pub(crate) max_active_requests: usize, + pub(crate) max_borrowed_responses: usize, + pub(crate) response_buffer_size: usize, + pub(crate) max_servers: usize, + pub(crate) max_clients: usize, + pub(crate) max_nodes: usize, + pub(crate) request_message_type_details: MessageTypeDetails, + pub(crate) response_message_type_details: MessageTypeDetails, +} + +impl StaticConfig { + pub(crate) fn new(config: &config::Config) -> Self { + Self { + enable_safe_overflow_for_requests: config + .defaults + .request_response + .enable_safe_overflow_for_requests, + enable_safe_overflow_for_responses: config + .defaults + .request_response + .enable_safe_overflow_for_responses, + max_active_requests: config.defaults.request_response.max_active_requests, + max_borrowed_responses: config.defaults.request_response.max_borrowed_responses, + response_buffer_size: config.defaults.request_response.response_buffer_size, + max_servers: config.defaults.request_response.max_servers, + max_clients: config.defaults.request_response.max_clients, + max_nodes: config.defaults.request_response.max_nodes, + request_message_type_details: MessageTypeDetails::default(), + response_message_type_details: MessageTypeDetails::default(), + } + } + + pub fn enable_safe_overflow_for_requests(&self) -> bool { + self.enable_safe_overflow_for_requests + } + + pub fn enable_safe_overflow_for_responses(&self) -> bool { + self.enable_safe_overflow_for_responses + } + + pub fn max_active_requests(&self) -> usize { + self.max_active_requests + } + + pub fn max_borrowed_responses(&self) -> usize { + self.max_borrowed_responses + } + + pub fn response_buffer_size(&self) -> usize { + self.response_buffer_size + } + + pub fn max_servers(&self) -> usize { + self.max_servers + } + + pub fn max_clients(&self) -> usize { + self.max_clients + } + + pub fn max_nodes(&self) -> usize { + self.max_nodes + } +} From 625b023ade1aa319665f0777ab48c0e8714d3c9d Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Tue, 21 Jan 2025 17:30:09 +0100 Subject: [PATCH 03/26] [#429] Add dynamic config for request response --- iceoryx2-ffi/ffi/src/api/service_builder.rs | 2 +- iceoryx2-ffi/ffi/src/api/subscriber.rs | 2 +- iceoryx2/src/service/dynamic_config/mod.rs | 20 ++- .../dynamic_config/request_response.rs | 123 ++++++++++++++++++ iceoryx2/src/service/header/mod.rs | 2 + .../src/service/header/request_response.rs | 19 +++ 6 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 iceoryx2/src/service/dynamic_config/request_response.rs create mode 100644 iceoryx2/src/service/header/request_response.rs diff --git a/iceoryx2-ffi/ffi/src/api/service_builder.rs b/iceoryx2-ffi/ffi/src/api/service_builder.rs index b60a00b86..1b600ab45 100644 --- a/iceoryx2-ffi/ffi/src/api/service_builder.rs +++ b/iceoryx2-ffi/ffi/src/api/service_builder.rs @@ -100,7 +100,7 @@ impl ServiceBuilderUnion { #[repr(C)] #[repr(align(8))] // alignment of Option pub struct iox2_service_builder_storage_t { - internal: [u8; 464], // magic number obtained with size_of::>() + internal: [u8; 608], // magic number obtained with size_of::>() } #[repr(C)] diff --git a/iceoryx2-ffi/ffi/src/api/subscriber.rs b/iceoryx2-ffi/ffi/src/api/subscriber.rs index 3dcb7c293..06e782760 100644 --- a/iceoryx2-ffi/ffi/src/api/subscriber.rs +++ b/iceoryx2-ffi/ffi/src/api/subscriber.rs @@ -98,7 +98,7 @@ impl SubscriberUnion { #[repr(C)] #[repr(align(16))] // alignment of Option pub struct iox2_subscriber_storage_t { - internal: [u8; 816], // magic number obtained with size_of::>() + internal: [u8; 960], // magic number obtained with size_of::>() } #[repr(C)] diff --git a/iceoryx2/src/service/dynamic_config/mod.rs b/iceoryx2/src/service/dynamic_config/mod.rs index 3f80a01e1..0a0551e71 100644 --- a/iceoryx2/src/service/dynamic_config/mod.rs +++ b/iceoryx2/src/service/dynamic_config/mod.rs @@ -20,6 +20,8 @@ pub mod event; /// based service. pub mod publish_subscribe; +pub mod request_response; + use core::fmt::Display; use iceoryx2_bb_container::queue::RelocatableContainer; use iceoryx2_bb_elementary::CallbackProgression; @@ -56,6 +58,7 @@ pub(crate) enum RemoveDeadNodeResult { #[derive(Debug)] pub(crate) enum MessagingPattern { + RequestResonse(request_response::DynamicConfig), PublishSubscribe(publish_subscribe::DynamicConfig), Event(event::DynamicConfig), } @@ -98,6 +101,7 @@ impl DynamicConfig { match &mut self.messaging_pattern { MessagingPattern::PublishSubscribe(ref mut v) => v.init(allocator), MessagingPattern::Event(ref mut v) => v.init(allocator), + MessagingPattern::RequestResonse(ref mut v) => v.init(allocator), } } @@ -113,6 +117,9 @@ impl DynamicConfig { v.remove_dead_node_id(node_id, port_cleanup_callback) } MessagingPattern::Event(ref v) => v.remove_dead_node_id(node_id, port_cleanup_callback), + MessagingPattern::RequestResonse(ref v) => { + v.remove_dead_node_id(node_id, port_cleanup_callback) + } }; let mut ret_val = Err(RemoveDeadNodeResult::NodeNotRegistered); @@ -167,11 +174,20 @@ impl DynamicConfig { } } + pub(crate) fn request_response(&self) -> &request_response::DynamicConfig { + match &self.messaging_pattern { + MessagingPattern::RequestResonse(ref v) => v, + m => { + fatal_panic!(from self, "This should never happen! Trying to access request_response::DynamicConfig when the messaging pattern is actually {:?}.", m); + } + } + } + pub(crate) fn publish_subscribe(&self) -> &publish_subscribe::DynamicConfig { match &self.messaging_pattern { MessagingPattern::PublishSubscribe(ref v) => v, m => { - fatal_panic!(from self, "This should never happen! Try to access publish_subscribe::DynamicConfig when the messaging pattern is actually {:?}.", m); + fatal_panic!(from self, "This should never happen! Trying to access publish_subscribe::DynamicConfig when the messaging pattern is actually {:?}.", m); } } } @@ -180,7 +196,7 @@ impl DynamicConfig { match &self.messaging_pattern { MessagingPattern::Event(ref v) => v, m => { - fatal_panic!(from self, "This should never happen! Try to access event::DynamicConfig when the messaging pattern is actually {:?}.", m); + fatal_panic!(from self, "This should never happen! Trying to access event::DynamicConfig when the messaging pattern is actually {:?}.", m); } } } diff --git a/iceoryx2/src/service/dynamic_config/request_response.rs b/iceoryx2/src/service/dynamic_config/request_response.rs new file mode 100644 index 000000000..9fc119d3e --- /dev/null +++ b/iceoryx2/src/service/dynamic_config/request_response.rs @@ -0,0 +1,123 @@ +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use iceoryx2_bb_container::queue::RelocatableContainer; +use iceoryx2_bb_elementary::CallbackProgression; +use iceoryx2_bb_lock_free::mpmc::container::{Container, ContainerHandle, ReleaseMode}; +use iceoryx2_bb_log::fatal_panic; +use iceoryx2_bb_memory::bump_allocator::BumpAllocator; + +use crate::{node::NodeId, port::port_identifiers::UniquePortId}; + +use super::PortCleanupAction; + +#[doc(hidden)] +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct ServerDetails {} + +#[doc(hidden)] +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct ClientDetails {} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub(crate) struct DynamicConfigSettings { + pub number_of_servers: usize, + pub number_of_clients: usize, +} + +#[repr(C)] +#[derive(Debug)] +pub struct DynamicConfig { + pub(crate) servers: Container, + pub(crate) clients: Container, +} + +impl DynamicConfig { + pub(crate) fn new(config: &DynamicConfigSettings) -> Self { + Self { + servers: unsafe { Container::new_uninit(config.number_of_servers) }, + clients: unsafe { Container::new_uninit(config.number_of_clients) }, + } + } + + pub(crate) unsafe fn init(&mut self, allocator: &BumpAllocator) { + fatal_panic!(from self, + when self.servers.init(allocator), + "This should never happen! Unable to initialize servers port id container."); + fatal_panic!(from self, + when self.clients.init(allocator), + "This should never happen! Unable to initialize clients port id container."); + } + + pub(crate) fn memory_size(config: &DynamicConfigSettings) -> usize { + Container::::memory_size(config.number_of_servers) + + Container::::memory_size(config.number_of_clients) + } + + pub fn number_of_clients(&self) -> usize { + self.clients.len() + } + + /// Returns how many [`crate::port::subscriber::Subscriber`] ports are currently connected. + pub fn number_of_servers(&self) -> usize { + self.servers.len() + } + + pub(crate) unsafe fn remove_dead_node_id< + PortCleanup: FnMut(UniquePortId) -> PortCleanupAction, + >( + &self, + node_id: &NodeId, + mut port_cleanup_callback: PortCleanup, + ) { + todo!() + } + + #[doc(hidden)] + pub fn __internal_list_servers(&self, mut callback: F) { + let state = unsafe { self.servers.get_state() }; + + state.for_each(|_, details| { + callback(details); + CallbackProgression::Continue + }); + } + + #[doc(hidden)] + pub fn __internal_list_publishers(&self, mut callback: F) { + let state = unsafe { self.clients.get_state() }; + + state.for_each(|_, details| { + callback(details); + CallbackProgression::Continue + }); + } + + pub(crate) fn add_server(&self, details: ServerDetails) -> Option { + unsafe { self.servers.add(details).ok() } + } + + pub(crate) fn release_server_handle(&self, handle: ContainerHandle) { + unsafe { self.servers.remove(handle, ReleaseMode::Default) }; + } + + pub(crate) fn add_client(&self, details: ClientDetails) -> Option { + unsafe { self.clients.add(details).ok() } + } + + pub(crate) fn release_publisher_handle(&self, handle: ContainerHandle) { + unsafe { self.clients.remove(handle, ReleaseMode::Default) }; + } +} diff --git a/iceoryx2/src/service/header/mod.rs b/iceoryx2/src/service/header/mod.rs index 9ebf37ed4..060419b75 100644 --- a/iceoryx2/src/service/header/mod.rs +++ b/iceoryx2/src/service/header/mod.rs @@ -13,3 +13,5 @@ /// Sample header used by /// [`MessagingPattern::PublishSubscribe`](crate::service::messaging_pattern::MessagingPattern::PublishSubscribe) pub mod publish_subscribe; + +pub mod request_response; diff --git a/iceoryx2/src/service/header/request_response.rs b/iceoryx2/src/service/header/request_response.rs new file mode 100644 index 000000000..e799c59ea --- /dev/null +++ b/iceoryx2/src/service/header/request_response.rs @@ -0,0 +1,19 @@ +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct RequestHeader {} + +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct ResponseHeader {} From 80766cdfb8e89ee5c533a896a009dc0b5567a115 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Tue, 21 Jan 2025 17:42:35 +0100 Subject: [PATCH 04/26] [#429] Make builder configurable --- config/iceoryx2.toml | 2 +- iceoryx2/src/config.rs | 4 +- .../src/service/builder/request_response.rs | 70 +++++++++++++++++-- .../service/static_config/request_response.rs | 8 +-- 4 files changed, 70 insertions(+), 14 deletions(-) diff --git a/config/iceoryx2.toml b/config/iceoryx2.toml index e6df9c693..1e3f7b12a 100644 --- a/config/iceoryx2.toml +++ b/config/iceoryx2.toml @@ -26,7 +26,7 @@ enable-safe-overflow-for-requests = true enable-safe-overflow-for-responses = true max-active-requests = 2 max-borrowed-responses = 2 -response-buffer-size = 2 +max-response-buffer-size = 2 max-servers = 2 max-clients = 8 max-nodes = 20 diff --git a/iceoryx2/src/config.rs b/iceoryx2/src/config.rs index 637198651..1814b3504 100644 --- a/iceoryx2/src/config.rs +++ b/iceoryx2/src/config.rs @@ -294,7 +294,7 @@ pub struct RequestResonse { pub enable_safe_overflow_for_responses: bool, pub max_active_requests: usize, pub max_borrowed_responses: usize, - pub response_buffer_size: usize, + pub max_response_buffer_size: usize, pub max_servers: usize, pub max_clients: usize, pub max_nodes: usize, @@ -347,7 +347,7 @@ impl Default for Config { enable_safe_overflow_for_responses: true, max_active_requests: 2, max_borrowed_responses: 2, - response_buffer_size: 2, + max_response_buffer_size: 2, max_servers: 2, max_clients: 8, max_nodes: 20, diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index 83d1196b3..8cb7ceb2a 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -13,8 +13,11 @@ use std::fmt::Debug; use std::marker::PhantomData; -use crate::service; +use iceoryx2_bb_elementary::alignment::Alignment; +use iceoryx2_bb_log::fatal_panic; + use crate::service::builder; +use crate::service::{self, static_config}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum RequestResponseOpenError {} @@ -96,6 +99,14 @@ pub struct Builder< ServiceType: service::Service, > { base: builder::BuilderWithServiceType, + override_request_alignment: Option, + override_response_alignment: Option, + verify_enable_safe_overflow_for_requests: bool, + verify_enable_safe_overflow_for_responses: bool, + verify_max_active_requests: bool, + verify_max_borrowed_responses: bool, + verify_max_response_buffer_size: bool, + _request_payload: PhantomData, _request_header: PhantomData, _response_payload: PhantomData, @@ -113,6 +124,13 @@ impl< fn new(base: builder::BuilderWithServiceType) -> Self { Self { base, + override_request_alignment: None, + override_response_alignment: None, + verify_enable_safe_overflow_for_requests: false, + verify_enable_safe_overflow_for_responses: false, + verify_max_active_requests: false, + verify_max_borrowed_responses: false, + verify_max_response_buffer_size: false, _request_payload: PhantomData, _request_header: PhantomData, _response_payload: PhantomData, @@ -120,6 +138,24 @@ impl< } } + fn config_details_mut(&mut self) -> &mut static_config::request_response::StaticConfig { + match self.base.service_config.messaging_pattern { + static_config::messaging_pattern::MessagingPattern::RequestResponse(ref mut v) => v, + _ => { + fatal_panic!(from self, "This should never happen! Accessing wrong messaging pattern in RequestResponse builder!"); + } + } + } + + fn config_details(&self) -> &static_config::request_response::StaticConfig { + match self.base.service_config.messaging_pattern { + static_config::messaging_pattern::MessagingPattern::RequestResponse(ref v) => v, + _ => { + fatal_panic!(from self, "This should never happen! Accessing wrong messaging pattern in RequestResponse builder!"); + } + } + } + pub fn request_header( self, ) -> Builder { @@ -142,24 +178,44 @@ impl< } } + pub fn request_payload_alignment(mut self, alignment: Alignment) -> Self { + self.override_request_alignment = Some(alignment.value()); + self + } + + pub fn response_payload_alignment(mut self, alignment: Alignment) -> Self { + self.override_response_alignment = Some(alignment.value()); + self + } + pub fn enable_safe_overflow_for_requests(mut self, value: bool) -> Self { - todo!() + self.config_details_mut().enable_safe_overflow_for_requests = value; + self.verify_enable_safe_overflow_for_requests = true; + self } pub fn enable_safe_overflow_for_responses(mut self, value: bool) -> Self { - todo!() + self.config_details_mut().enable_safe_overflow_for_responses = value; + self.verify_enable_safe_overflow_for_responses = true; + self } pub fn max_active_requests(mut self, value: usize) -> Self { - todo!() + self.config_details_mut().max_active_requests = value; + self.verify_max_active_requests = true; + self } pub fn max_borrowed_responses(mut self, value: usize) -> Self { - todo!() + self.config_details_mut().max_borrowed_responses = value; + self.verify_max_borrowed_responses = true; + self } - pub fn response_buffer_size(mut self, value: usize) -> Self { - todo!() + pub fn max_response_buffer_size(mut self, value: usize) -> Self { + self.config_details_mut().max_response_buffer_size = value; + self.verify_max_response_buffer_size = true; + self } pub fn max_servers(mut self, value: usize) -> Self { diff --git a/iceoryx2/src/service/static_config/request_response.rs b/iceoryx2/src/service/static_config/request_response.rs index 228292b83..5baac1005 100644 --- a/iceoryx2/src/service/static_config/request_response.rs +++ b/iceoryx2/src/service/static_config/request_response.rs @@ -22,7 +22,7 @@ pub struct StaticConfig { pub(crate) enable_safe_overflow_for_responses: bool, pub(crate) max_active_requests: usize, pub(crate) max_borrowed_responses: usize, - pub(crate) response_buffer_size: usize, + pub(crate) max_response_buffer_size: usize, pub(crate) max_servers: usize, pub(crate) max_clients: usize, pub(crate) max_nodes: usize, @@ -43,7 +43,7 @@ impl StaticConfig { .enable_safe_overflow_for_responses, max_active_requests: config.defaults.request_response.max_active_requests, max_borrowed_responses: config.defaults.request_response.max_borrowed_responses, - response_buffer_size: config.defaults.request_response.response_buffer_size, + max_response_buffer_size: config.defaults.request_response.max_response_buffer_size, max_servers: config.defaults.request_response.max_servers, max_clients: config.defaults.request_response.max_clients, max_nodes: config.defaults.request_response.max_nodes, @@ -68,8 +68,8 @@ impl StaticConfig { self.max_borrowed_responses } - pub fn response_buffer_size(&self) -> usize { - self.response_buffer_size + pub fn max_response_buffer_size(&self) -> usize { + self.max_response_buffer_size } pub fn max_servers(&self) -> usize { From e414b82f2d6b00115553185fe18ee7ff59de5b39 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Tue, 21 Jan 2025 19:14:37 +0100 Subject: [PATCH 05/26] [#429] Add service management functionality --- iceoryx2/src/service/builder/event.rs | 4 +- .../src/service/builder/publish_subscribe.rs | 8 +- .../src/service/builder/request_response.rs | 213 +++++++++++++++++- 3 files changed, 214 insertions(+), 11 deletions(-) diff --git a/iceoryx2/src/service/builder/event.rs b/iceoryx2/src/service/builder/event.rs index 5d1b01881..d1a834803 100644 --- a/iceoryx2/src/service/builder/event.rs +++ b/iceoryx2/src/service/builder/event.rs @@ -378,7 +378,7 @@ impl Builder { } Some((static_config, static_storage)) => { let event_static_config = - self.verify_service_attributes(&static_config, required_attributes)?; + self.verify_service_configuration(&static_config, required_attributes)?; let service_tag = self .base @@ -570,7 +570,7 @@ impl Builder { } } - fn verify_service_attributes( + fn verify_service_configuration( &self, existing_settings: &static_config::StaticConfig, required_attributes: &AttributeVerifier, diff --git a/iceoryx2/src/service/builder/publish_subscribe.rs b/iceoryx2/src/service/builder/publish_subscribe.rs index 09ddb920b..6335642f6 100644 --- a/iceoryx2/src/service/builder/publish_subscribe.rs +++ b/iceoryx2/src/service/builder/publish_subscribe.rs @@ -377,7 +377,7 @@ impl } /// Validates configuration and overrides the invalid setting with meaningful values. - fn adjust_attributes_to_meaningful_values(&mut self) { + fn adjust_configuration_to_meaningful_values(&mut self) { let origin = format!("{:?}", self); let settings = self.base.service_config.publish_subscribe_mut(); @@ -412,7 +412,7 @@ impl } } - fn verify_service_attributes( + fn verify_service_configuration( &self, existing_settings: &static_config::StaticConfig, required_attributes: &AttributeVerifier, @@ -502,7 +502,7 @@ impl publish_subscribe::PortFactory, PublishSubscribeCreateError, > { - self.adjust_attributes_to_meaningful_values(); + self.adjust_configuration_to_meaningful_values(); let msg = "Unable to create publish subscribe service"; @@ -622,7 +622,7 @@ impl } Some((static_config, static_storage)) => { let pub_sub_static_config = - self.verify_service_attributes(&static_config, attributes)?; + self.verify_service_configuration(&static_config, attributes)?; let service_tag = self .base diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index 8cb7ceb2a..42106c0ba 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -14,13 +14,27 @@ use std::fmt::Debug; use std::marker::PhantomData; use iceoryx2_bb_elementary::alignment::Alignment; -use iceoryx2_bb_log::fatal_panic; +use iceoryx2_bb_log::{fail, fatal_panic, warn}; +use crate::prelude::AttributeVerifier; use crate::service::builder; use crate::service::{self, static_config}; +use super::ServiceState; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum RequestResponseOpenError {} +pub enum RequestResponseOpenError { + IncompatibleAttributes, + IncompatibleMessagingPattern, + IncompatibleOverflowBehaviorForRequests, + IncompatibleOverflowBehaviorForResponses, + DoesNotSupportRequestedAmountOfActiveRequests, + DoesNotSupportRequestedAmountOfBorrowedResponses, + DoesNotSupportRequestedResponseBufferSize, + DoesNotSupportRequestedAmountOfServers, + DoesNotSupportRequestedAmountOfClients, + DoesNotSupportRequestedAmountOfNodes, +} impl core::fmt::Display for RequestResponseOpenError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -67,6 +81,13 @@ impl core::fmt::Display for RequestResponseOpenOrCreateError { impl std::error::Error for RequestResponseOpenOrCreateError {} +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] +enum ServiceAvailabilityState { + ServiceState(ServiceState), + IncompatibleRequestType, + IncompatibleResponseType, +} + #[derive(Debug)] pub struct BuilderRequest { base: builder::BuilderWithServiceType, @@ -106,6 +127,9 @@ pub struct Builder< verify_max_active_requests: bool, verify_max_borrowed_responses: bool, verify_max_response_buffer_size: bool, + verify_max_servers: bool, + verify_max_clients: bool, + verify_max_nodes: bool, _request_payload: PhantomData, _request_header: PhantomData, @@ -131,6 +155,9 @@ impl< verify_max_active_requests: false, verify_max_borrowed_responses: false, verify_max_response_buffer_size: false, + verify_max_servers: false, + verify_max_clients: false, + verify_max_nodes: false, _request_payload: PhantomData, _request_header: PhantomData, _response_payload: PhantomData, @@ -219,14 +246,190 @@ impl< } pub fn max_servers(mut self, value: usize) -> Self { - todo!() + self.config_details_mut().max_servers = value; + self.verify_max_servers = true; + self } pub fn max_clients(mut self, value: usize) -> Self { - todo!() + self.config_details_mut().max_clients = value; + self.verify_max_clients = true; + self } pub fn max_nodes(mut self, value: usize) -> Self { - todo!() + self.config_details_mut().max_nodes = value; + self.verify_max_nodes = true; + self + } + + fn adjust_configuration_to_meaningful_values(&mut self) { + let origin = format!("{:?}", self); + let settings = self.base.service_config.request_response_mut(); + + if settings.max_active_requests == 0 { + warn!(from origin, + "Setting the maximum number of active requests to 0 is not supported. Adjust it to 1, the smallest supported value."); + settings.max_active_requests = 1; + } + + if settings.max_borrowed_responses == 0 { + warn!(from origin, + "Setting the maximum number of borrowed responses to 0 is not supported. Adjust it to 1, the smallest supported value."); + settings.max_borrowed_responses = 1; + } + + if settings.max_servers == 0 { + warn!(from origin, + "Setting the maximum number of servers to 0 is not supported. Adjust it to 1, the smallest supported value."); + settings.max_servers = 1; + } + + if settings.max_clients == 0 { + warn!(from origin, + "Setting the maximum number of clients to 0 is not supported. Adjust it to 1, the smallest supported value."); + settings.max_clients = 1; + } + + if settings.max_nodes == 0 { + warn!(from origin, + "Setting the maximum number of nodes to 0 is not supported. Adjust it to 1, the smallest supported value."); + settings.max_nodes = 1; + } + } + + fn verify_service_configuration( + &self, + existing_settings: &static_config::StaticConfig, + required_attributes: &AttributeVerifier, + ) -> Result { + let msg = "Unable to open request response service"; + + let existing_attributes = existing_settings.attributes(); + if let Err(incompatible_key) = required_attributes.verify_requirements(existing_attributes) + { + fail!(from self, with RequestResponseOpenError::IncompatibleAttributes, + "{} due to incompatible service attribute key \"{}\". The following attributes {:?} are required but the service has the attributes {:?}.", + msg, incompatible_key, required_attributes, existing_attributes); + } + + let required_configuration = self.base.service_config.request_response(); + let existing_configuration = match &existing_settings.messaging_pattern { + static_config::messaging_pattern::MessagingPattern::RequestResponse(ref v) => v, + p => { + fail!(from self, with RequestResponseOpenError::IncompatibleMessagingPattern, + "{} since a service with the messaging pattern {:?} exists but MessagingPattern::RequestResponse is required.", + msg, p); + } + }; + + if self.verify_enable_safe_overflow_for_requests + && existing_configuration.enable_safe_overflow_for_requests + != required_configuration.enable_safe_overflow_for_requests + { + fail!(from self, with RequestResponseOpenError::IncompatibleOverflowBehaviorForRequests, + "{} since the service has an incompatible safe overflow behavior for requests.", + msg); + } + + if self.verify_enable_safe_overflow_for_responses + && existing_configuration.enable_safe_overflow_for_responses + != required_configuration.enable_safe_overflow_for_responses + { + fail!(from self, with RequestResponseOpenError::IncompatibleOverflowBehaviorForResponses, + "{} since the service has an incompatible safe overflow behavior for responses.", + msg); + } + + if self.verify_max_active_requests + && existing_configuration.max_active_requests + < required_configuration.max_active_requests + { + fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfActiveRequests, + "{} since the service supports only {} active requests but {} are required.", + msg, existing_configuration.max_active_requests, required_configuration.max_active_requests); + } + + if self.verify_max_borrowed_responses + && existing_configuration.max_borrowed_responses + < required_configuration.max_borrowed_responses + { + fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedResponses, + "{} since the service supports only {} borrowed responses but {} are required.", + msg, existing_configuration.max_borrowed_responses, required_configuration.max_borrowed_responses); + } + + if self.verify_max_response_buffer_size + && existing_configuration.max_response_buffer_size + < required_configuration.max_response_buffer_size + { + fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedResponseBufferSize, + "{} since the service supports a maximum response buffer size of {} but a size of {} is required.", + msg, existing_configuration.max_response_buffer_size, required_configuration.max_response_buffer_size); + } + + if self.verify_max_servers + && existing_configuration.max_servers < required_configuration.max_servers + { + fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfServers, + "{} since the service supports at most {} servers but {} are required.", + msg, existing_configuration.max_servers, required_configuration.max_servers); + } + + if self.verify_max_clients + && existing_configuration.max_clients < required_configuration.max_clients + { + fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfClients, + "{} since the service supports at most {} clients but {} are required.", + msg, existing_configuration.max_clients, required_configuration.max_clients); + } + + if self.verify_max_nodes + && existing_configuration.max_nodes < required_configuration.max_nodes + { + fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfClients, + "{} since the service supports at most {} nodes but {} are required.", + msg, existing_configuration.max_nodes, required_configuration.max_nodes); + } + + Ok(existing_configuration.clone()) + } + + fn is_service_available( + &mut self, + error_msg: &str, + ) -> Result< + Option<(static_config::StaticConfig, ServiceType::StaticStorage)>, + ServiceAvailabilityState, + > { + match self.base.is_service_available(error_msg) { + Ok(Some((config, storage))) => { + if !self + .config_details() + .request_message_type_details + .is_compatible_to(&config.request_response().request_message_type_details) + { + fail!(from self, with ServiceAvailabilityState::IncompatibleRequestType, + "{} since the services uses the request type \"{:?}\" which is not compatible to the requested type \"{:?}\".", + error_msg, &config.request_response().request_message_type_details, + self.config_details().request_message_type_details); + } + + if !self + .config_details() + .response_message_type_details + .is_compatible_to(&config.request_response().response_message_type_details) + { + fail!(from self, with ServiceAvailabilityState::IncompatibleResponseType, + "{} since the services uses the response type \"{:?}\" which is not compatible to the requested type \"{:?}\".", + error_msg, &config.request_response().response_message_type_details, + self.config_details().response_message_type_details); + } + + Ok(Some((config, storage))) + } + Ok(None) => Ok(None), + Err(e) => Err(ServiceAvailabilityState::ServiceState(e)), + } } } From c78ca04bade1d972cd0e1c0e9dcffb9bb0c886df Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Tue, 21 Jan 2025 19:34:55 +0100 Subject: [PATCH 06/26] [#429] Add request response port factory skeleton --- .../src/service/builder/request_response.rs | 2 +- iceoryx2/src/service/port_factory/mod.rs | 2 + .../service/port_factory/request_response.rs | 82 +++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 iceoryx2/src/service/port_factory/request_response.rs diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index 42106c0ba..ad7b9f7c1 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -16,7 +16,7 @@ use std::marker::PhantomData; use iceoryx2_bb_elementary::alignment::Alignment; use iceoryx2_bb_log::{fail, fatal_panic, warn}; -use crate::prelude::AttributeVerifier; +use crate::prelude::{AttributeSpecifier, AttributeVerifier}; use crate::service::builder; use crate::service::{self, static_config}; diff --git a/iceoryx2/src/service/port_factory/mod.rs b/iceoryx2/src/service/port_factory/mod.rs index 51c138f0e..4f141f068 100644 --- a/iceoryx2/src/service/port_factory/mod.rs +++ b/iceoryx2/src/service/port_factory/mod.rs @@ -19,6 +19,8 @@ use super::dynamic_config::DynamicConfig; use super::service_id::ServiceId; use super::{attribute::AttributeSet, service_name::ServiceName}; +pub mod request_response; + /// Factory to create the endpoints of /// [`MessagingPattern::Event`](crate::service::messaging_pattern::MessagingPattern::Event) based /// communication and to acquire static and dynamic service information diff --git a/iceoryx2/src/service/port_factory/request_response.rs b/iceoryx2/src/service/port_factory/request_response.rs new file mode 100644 index 000000000..e74ee756e --- /dev/null +++ b/iceoryx2/src/service/port_factory/request_response.rs @@ -0,0 +1,82 @@ +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use iceoryx2_bb_elementary::CallbackProgression; +use iceoryx2_cal::dynamic_storage::DynamicStorage; + +use crate::{ + node::NodeListFailure, + prelude::AttributeSet, + service::{ + self, dynamic_config, service_id::ServiceId, service_name::ServiceName, static_config, + }, +}; + +use super::nodes; + +#[derive(Debug)] +pub struct PortFactory { + pub(crate) service: Service, +} + +unsafe impl Send for PortFactory {} +unsafe impl Sync for PortFactory {} + +impl crate::service::port_factory::PortFactory for PortFactory { + type Service = Service; + type StaticConfig = static_config::request_response::StaticConfig; + type DynamicConfig = dynamic_config::request_response::DynamicConfig; + + fn name(&self) -> &ServiceName { + self.service.__internal_state().static_config.name() + } + + fn service_id(&self) -> &ServiceId { + self.service.__internal_state().static_config.service_id() + } + + fn attributes(&self) -> &AttributeSet { + self.service.__internal_state().static_config.attributes() + } + + fn static_config(&self) -> &Self::StaticConfig { + self.service + .__internal_state() + .static_config + .request_response() + } + + fn dynamic_config(&self) -> &Self::DynamicConfig { + self.service + .__internal_state() + .dynamic_storage + .get() + .request_response() + } + + fn nodes) -> CallbackProgression>( + &self, + callback: F, + ) -> Result<(), NodeListFailure> { + nodes( + self.service.__internal_state().dynamic_storage.get(), + self.service.__internal_state().shared_node.config(), + callback, + ) + } +} + +impl PortFactory { + pub(crate) fn new(service: Service) -> Self { + Self { service } + } +} From 3965504d1ecb1b28ff4ae1f1cf8b00438598b750 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Wed, 22 Jan 2025 11:21:53 +0100 Subject: [PATCH 07/26] [#429] Request response service creation --- .../src/service/builder/request_response.rs | 175 +++++++++++++++++- 1 file changed, 169 insertions(+), 6 deletions(-) diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index ad7b9f7c1..5612e10ee 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -15,25 +15,35 @@ use std::marker::PhantomData; use iceoryx2_bb_elementary::alignment::Alignment; use iceoryx2_bb_log::{fail, fatal_panic, warn}; +use iceoryx2_cal::dynamic_storage::DynamicStorageCreateError; +use iceoryx2_cal::serialize::Serialize; +use iceoryx2_cal::static_storage::{StaticStorage, StaticStorageCreateError, StaticStorageLocked}; use crate::prelude::{AttributeSpecifier, AttributeVerifier}; -use crate::service::builder; +use crate::service::dynamic_config::request_response::DynamicConfigSettings; +use crate::service::port_factory::request_response; use crate::service::{self, static_config}; +use crate::service::{builder, dynamic_config}; use super::ServiceState; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum RequestResponseOpenError { - IncompatibleAttributes, - IncompatibleMessagingPattern, - IncompatibleOverflowBehaviorForRequests, - IncompatibleOverflowBehaviorForResponses, DoesNotSupportRequestedAmountOfActiveRequests, DoesNotSupportRequestedAmountOfBorrowedResponses, DoesNotSupportRequestedResponseBufferSize, DoesNotSupportRequestedAmountOfServers, DoesNotSupportRequestedAmountOfClients, DoesNotSupportRequestedAmountOfNodes, + HangsInCreation, + IncompatibleRequestType, + IncompatibleResponseType, + IncompatibleAttributes, + IncompatibleMessagingPattern, + IncompatibleOverflowBehaviorForRequests, + IncompatibleOverflowBehaviorForResponses, + InsufficientPermissions, + ServiceInCorruptedState, } impl core::fmt::Display for RequestResponseOpenError { @@ -44,8 +54,40 @@ impl core::fmt::Display for RequestResponseOpenError { impl std::error::Error for RequestResponseOpenError {} +impl From for RequestResponseOpenError { + fn from(value: ServiceAvailabilityState) -> Self { + match value { + ServiceAvailabilityState::IncompatibleRequestType => { + RequestResponseOpenError::IncompatibleRequestType + } + ServiceAvailabilityState::IncompatibleResponseType => { + RequestResponseOpenError::IncompatibleResponseType + } + ServiceAvailabilityState::ServiceState(ServiceState::IncompatibleMessagingPattern) => { + RequestResponseOpenError::IncompatibleMessagingPattern + } + ServiceAvailabilityState::ServiceState(ServiceState::InsufficientPermissions) => { + RequestResponseOpenError::InsufficientPermissions + } + ServiceAvailabilityState::ServiceState(ServiceState::HangsInCreation) => { + RequestResponseOpenError::HangsInCreation + } + ServiceAvailabilityState::ServiceState(ServiceState::Corrupted) => { + RequestResponseOpenError::ServiceInCorruptedState + } + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum RequestResponseCreateError {} +pub enum RequestResponseCreateError { + AlreadyExists, + InternalFailure, + IsBeingCreatedByAnotherInstance, + InsufficientPermissions, + HangsInCreation, + ServiceInCorruptedState, +} impl core::fmt::Display for RequestResponseCreateError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -55,6 +97,27 @@ impl core::fmt::Display for RequestResponseCreateError { impl std::error::Error for RequestResponseCreateError {} +impl From for RequestResponseCreateError { + fn from(value: ServiceAvailabilityState) -> Self { + match value { + ServiceAvailabilityState::IncompatibleRequestType + | ServiceAvailabilityState::IncompatibleResponseType + | ServiceAvailabilityState::ServiceState(ServiceState::IncompatibleMessagingPattern) => { + RequestResponseCreateError::AlreadyExists + } + ServiceAvailabilityState::ServiceState(ServiceState::InsufficientPermissions) => { + RequestResponseCreateError::InsufficientPermissions + } + ServiceAvailabilityState::ServiceState(ServiceState::HangsInCreation) => { + RequestResponseCreateError::HangsInCreation + } + ServiceAvailabilityState::ServiceState(ServiceState::Corrupted) => { + RequestResponseCreateError::ServiceInCorruptedState + } + } + } +} + #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum RequestResponseOpenOrCreateError { RequestResponseOpenError(RequestResponseOpenError), @@ -432,4 +495,104 @@ impl< Err(e) => Err(ServiceAvailabilityState::ServiceState(e)), } } + + fn create_impl( + &mut self, + attributes: &AttributeSpecifier, + ) -> Result, RequestResponseCreateError> { + let msg = "Unable to create request response service"; + self.adjust_configuration_to_meaningful_values(); + + match self.is_service_available(msg)? { + Some(_) => { + fail!(from self, with RequestResponseCreateError::AlreadyExists, + "{} since the service already exists.", + msg); + } + None => { + let service_tag = self + .base + .create_node_service_tag(msg, RequestResponseCreateError::InternalFailure)?; + + let static_config = match self.base.create_static_config_storage() { + Ok(static_config) => static_config, + Err(StaticStorageCreateError::AlreadyExists) => { + fail!(from self, with RequestResponseCreateError::AlreadyExists, + "{} since the service already exists.", msg); + } + Err(StaticStorageCreateError::Creation) => { + fail!(from self, with RequestResponseCreateError::IsBeingCreatedByAnotherInstance, + "{} since the service is being created by another instance.", msg); + } + Err(StaticStorageCreateError::InsufficientPermissions) => { + fail!(from self, with RequestResponseCreateError::InsufficientPermissions, + "{} since the static service information could not be created due to insufficient permissions.", + msg); + } + Err(e) => { + fail!(from self, with RequestResponseCreateError::InternalFailure, + "{} since the static service information could not be created due to an internal failure ({:?}).", + msg, e); + } + }; + + let request_response_config = self.base.service_config.request_response(); + let dynamic_config_setting = DynamicConfigSettings { + number_of_servers: request_response_config.max_servers, + number_of_clients: request_response_config.max_clients, + }; + + let dynamic_config = match self.base.create_dynamic_config_storage( + dynamic_config::MessagingPattern::RequestResonse( + dynamic_config::request_response::DynamicConfig::new( + &dynamic_config_setting, + ), + ), + dynamic_config::request_response::DynamicConfig::memory_size( + &dynamic_config_setting, + ), + request_response_config.max_nodes, + ) { + Ok(dynamic_config) => dynamic_config, + Err(DynamicStorageCreateError::AlreadyExists) => { + fail!(from self, with RequestResponseCreateError::ServiceInCorruptedState, + "{} since the dynamic config of a previous instance of the service still exists.", + msg); + } + Err(e) => { + fail!(from self, with RequestResponseCreateError::InternalFailure, + "{} since the dynamic service segment could not be created ({:?}).", + msg, e); + } + }; + + self.base.service_config.attributes = attributes.0.clone(); + let serialized_service_config = fail!(from self, + when ServiceType::ConfigSerializer::serialize(&self.base.service_config), + with RequestResponseCreateError::ServiceInCorruptedState, + "{} since the configuration could not be serialized.", + msg); + + let mut unlocked_static_details = fail!(from self, + when static_config.unlock(serialized_service_config.as_slice()), + with RequestResponseCreateError::ServiceInCorruptedState, + "{} since the configuration could not be written into the static storage.", + msg); + + unlocked_static_details.release_ownership(); + if let Some(mut service_tag) = service_tag { + service_tag.release_ownership(); + } + + Ok(request_response::PortFactory::new( + ServiceType::__internal_from_state(service::ServiceState::new( + self.base.service_config.clone(), + self.base.shared_node.clone(), + dynamic_config, + unlocked_static_details, + )), + )) + } + } + } } From ae3801295d63072be83c8d18a4eac559d6b94ebc Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Wed, 22 Jan 2025 11:48:11 +0100 Subject: [PATCH 08/26] [#429] Request response service open --- .../src/service/builder/request_response.rs | 89 ++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index 5612e10ee..41534e86f 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -15,11 +15,12 @@ use std::marker::PhantomData; use iceoryx2_bb_elementary::alignment::Alignment; use iceoryx2_bb_log::{fail, fatal_panic, warn}; -use iceoryx2_cal::dynamic_storage::DynamicStorageCreateError; +use iceoryx2_cal::dynamic_storage::{DynamicStorageCreateError, DynamicStorageOpenError}; use iceoryx2_cal::serialize::Serialize; use iceoryx2_cal::static_storage::{StaticStorage, StaticStorageCreateError, StaticStorageLocked}; use crate::prelude::{AttributeSpecifier, AttributeVerifier}; +use crate::service::builder::OpenDynamicStorageFailure; use crate::service::dynamic_config::request_response::DynamicConfigSettings; use crate::service::port_factory::request_response; use crate::service::{self, static_config}; @@ -29,12 +30,14 @@ use super::ServiceState; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum RequestResponseOpenError { + DoesNotExist, DoesNotSupportRequestedAmountOfActiveRequests, DoesNotSupportRequestedAmountOfBorrowedResponses, DoesNotSupportRequestedResponseBufferSize, DoesNotSupportRequestedAmountOfServers, DoesNotSupportRequestedAmountOfClients, DoesNotSupportRequestedAmountOfNodes, + ExceedsMaxNumberOfNodes, HangsInCreation, IncompatibleRequestType, IncompatibleResponseType, @@ -43,6 +46,8 @@ pub enum RequestResponseOpenError { IncompatibleOverflowBehaviorForRequests, IncompatibleOverflowBehaviorForResponses, InsufficientPermissions, + InternalFailure, + IsMarkedForDestruction, ServiceInCorruptedState, } @@ -595,4 +600,86 @@ impl< } } } + + fn open_impl( + &mut self, + attributes: &AttributeVerifier, + ) -> Result, RequestResponseOpenError> { + const OPEN_RETRY_LIMIT: usize = 5; + let msg = "Unable to open request response service"; + + let mut service_open_retry_count = 0; + loop { + match self.is_service_available(msg)? { + None => { + fail!(from self, with RequestResponseOpenError::DoesNotExist, + "{} since the service does not exist.", + msg); + } + Some((static_config, static_storage)) => { + let request_response_static_config = + self.verify_service_configuration(&static_config, attributes)?; + + let service_tag = self + .base + .create_node_service_tag(msg, RequestResponseOpenError::InternalFailure)?; + + let dynamic_config = match self.base.open_dynamic_config_storage() { + Ok(v) => v, + Err(OpenDynamicStorageFailure::IsMarkedForDestruction) => { + fail!(from self, with RequestResponseOpenError::IsMarkedForDestruction, + "{} since the service is marked for destruction.", + msg); + } + Err(OpenDynamicStorageFailure::ExceedsMaxNumberOfNodes) => { + fail!(from self, with RequestResponseOpenError::ExceedsMaxNumberOfNodes, + "{} since it would exceed the maximum number of supported nodes.", + msg); + } + Err(OpenDynamicStorageFailure::DynamicStorageOpenError( + DynamicStorageOpenError::DoesNotExist, + )) => { + fail!(from self, with RequestResponseOpenError::ServiceInCorruptedState, + "{} since the dynamic segment of the service is missing.", + msg); + } + Err(e) => { + if self.is_service_available(msg)?.is_none() { + fail!(from self, with RequestResponseOpenError::DoesNotExist, + "{} since the service does not exist.", msg); + } + + service_open_retry_count += 1; + + if OPEN_RETRY_LIMIT < service_open_retry_count { + fail!(from self, with RequestResponseOpenError::ServiceInCorruptedState, + "{} since the dynamic service information could not be opened ({:?}).", + msg, e); + } + + continue; + } + }; + + self.base.service_config.messaging_pattern = + static_config::messaging_pattern::MessagingPattern::RequestResponse( + request_response_static_config.clone(), + ); + + if let Some(mut service_tag) = service_tag { + service_tag.release_ownership(); + } + + return Ok(request_response::PortFactory::new( + ServiceType::__internal_from_state(service::ServiceState::new( + static_config, + self.base.shared_node.clone(), + dynamic_config, + static_storage, + )), + )); + } + } + } + } } From 2ae087377cef559ce1d6e13aabb9ffc0eebbe97a Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Wed, 22 Jan 2025 19:11:55 +0100 Subject: [PATCH 09/26] [#429] Fix infinite loop possibility in open_or_create for services --- iceoryx2-ffi/ffi/src/api/service_builder_event.rs | 3 +++ .../ffi/src/api/service_builder_pub_sub.rs | 3 +++ iceoryx2/src/service/builder/event.rs | 14 ++++++++++++-- iceoryx2/src/service/builder/mod.rs | 2 ++ iceoryx2/src/service/builder/publish_subscribe.rs | 14 ++++++++++++-- 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/iceoryx2-ffi/ffi/src/api/service_builder_event.rs b/iceoryx2-ffi/ffi/src/api/service_builder_event.rs index 5fe582192..7ead475bd 100644 --- a/iceoryx2-ffi/ffi/src/api/service_builder_event.rs +++ b/iceoryx2-ffi/ffi/src/api/service_builder_event.rs @@ -85,6 +85,8 @@ pub enum iox2_event_open_or_create_error_e { C_INSUFFICIENT_PERMISSIONS, #[CStr = "old connection still active"] C_OLD_CONNECTION_STILL_ACTIVE, + #[CStr = "same service is created and removed repeatedly"] + SERVICE_IN_FLUX, } impl IntoCInt for EventOpenError { @@ -172,6 +174,7 @@ impl IntoCInt for EventOpenOrCreateError { match self { EventOpenOrCreateError::EventOpenError(error) => error.into_c_int(), EventOpenOrCreateError::EventCreateError(error) => error.into_c_int(), + e => e.into_c_int(), } } } diff --git a/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs b/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs index c19be4037..c83d452b4 100644 --- a/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs +++ b/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs @@ -92,6 +92,8 @@ pub enum iox2_pub_sub_open_or_create_error_e { C_OLD_CONNECTION_STILL_ACTIVE, #[CStr = "hangs in creation"] C_HANGS_IN_CREATION, + #[CStr = "same service is created and removed repeatedly"] + SERVICE_IN_FLUX, } impl IntoCInt for PublishSubscribeOpenError { @@ -185,6 +187,7 @@ impl IntoCInt for PublishSubscribeOpenOrCreateError { PublishSubscribeOpenOrCreateError::PublishSubscribeCreateError(error) => { error.into_c_int() } + e => e.into_c_int(), } } } diff --git a/iceoryx2/src/service/builder/event.rs b/iceoryx2/src/service/builder/event.rs index d1a834803..eea9fb284 100644 --- a/iceoryx2/src/service/builder/event.rs +++ b/iceoryx2/src/service/builder/event.rs @@ -20,6 +20,7 @@ use crate::service::port_factory::event; use crate::service::static_config::messaging_pattern::MessagingPattern; use crate::service::*; use crate::service::{self, dynamic_config::event::DynamicConfigSettings}; +use builder::RETRY_LIMIT; use iceoryx2_bb_log::{fail, fatal_panic}; use iceoryx2_bb_posix::clock::Time; use iceoryx2_cal::dynamic_storage::DynamicStorageCreateError; @@ -141,6 +142,7 @@ pub enum EventOpenOrCreateError { EventOpenError(EventOpenError), /// Failures that can occur when an event [`Service`] is created. EventCreateError(EventCreateError), + SystemInFlux, } impl From for EventOpenOrCreateError { @@ -336,7 +338,16 @@ impl Builder { ) -> Result, EventOpenOrCreateError> { let msg = "Unable to open or create event service"; + let mut retry_count = 0; loop { + if RETRY_LIMIT < retry_count { + fail!(from self, + with EventOpenOrCreateError::SystemInFlux, + "{} since an instance is creating and removing the same service repeatedly.", + msg); + } + retry_count += 1; + match self.base.is_service_available(msg)? { Some(_) => return Ok(self.open_with_attributes(required_attributes)?), None => { @@ -366,7 +377,6 @@ impl Builder { mut self, required_attributes: &AttributeVerifier, ) -> Result, EventOpenError> { - const OPEN_RETRY_LIMIT: usize = 5; let msg = "Unable to open event service"; let mut service_open_retry_count = 0; @@ -408,7 +418,7 @@ impl Builder { service_open_retry_count += 1; - if OPEN_RETRY_LIMIT < service_open_retry_count { + if RETRY_LIMIT < service_open_retry_count { fail!(from self, with EventOpenError::ServiceInCorruptedState, "{} since the dynamic service information could not be opened ({:?}). This could indicate a corrupted system or a misconfigured system where services are created/removed with a high frequency.", msg, e); diff --git a/iceoryx2/src/service/builder/mod.rs b/iceoryx2/src/service/builder/mod.rs index 96f92d944..a987ee359 100644 --- a/iceoryx2/src/service/builder/mod.rs +++ b/iceoryx2/src/service/builder/mod.rs @@ -51,6 +51,8 @@ use super::config_scheme::static_config_storage_config; use super::service_name::ServiceName; use super::Service; +const RETRY_LIMIT: usize = 5; + #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] enum ServiceState { IncompatibleMessagingPattern, diff --git a/iceoryx2/src/service/builder/publish_subscribe.rs b/iceoryx2/src/service/builder/publish_subscribe.rs index 6335642f6..91e096dc7 100644 --- a/iceoryx2/src/service/builder/publish_subscribe.rs +++ b/iceoryx2/src/service/builder/publish_subscribe.rs @@ -22,6 +22,7 @@ use crate::service::header::publish_subscribe::Header; use crate::service::port_factory::publish_subscribe; use crate::service::static_config::messaging_pattern::MessagingPattern; use crate::service::*; +use builder::RETRY_LIMIT; use iceoryx2_bb_elementary::alignment::Alignment; use iceoryx2_bb_log::{fail, fatal_panic, warn}; use iceoryx2_cal::dynamic_storage::DynamicStorageCreateError; @@ -181,6 +182,7 @@ pub enum PublishSubscribeOpenOrCreateError { PublishSubscribeOpenError(PublishSubscribeOpenError), /// Failures that can occur when a [`Service`] could not be created. PublishSubscribeCreateError(PublishSubscribeCreateError), + SystemInFlux, } impl From for PublishSubscribeOpenOrCreateError { @@ -610,7 +612,6 @@ impl publish_subscribe::PortFactory, PublishSubscribeOpenError, > { - const OPEN_RETRY_LIMIT: usize = 5; let msg = "Unable to open publish subscribe service"; let mut service_open_retry_count = 0; @@ -652,7 +653,7 @@ impl service_open_retry_count += 1; - if OPEN_RETRY_LIMIT < service_open_retry_count { + if RETRY_LIMIT < service_open_retry_count { fail!(from self, with PublishSubscribeOpenError::ServiceInCorruptedState, "{} since the dynamic service information could not be opened ({:?}). This could indicate a corrupted system or a misconfigured system where services are created/removed with a high frequency.", msg, e); @@ -691,7 +692,16 @@ impl > { let msg = "Unable to open or create publish subscribe service"; + let mut retry_count = 0; loop { + if RETRY_LIMIT < retry_count { + fail!(from self, + with PublishSubscribeOpenOrCreateError::SystemInFlux, + "{} since an instance is creating and removing the same service repeatedly.", + msg); + } + retry_count += 1; + match self.is_service_available(msg)? { Some(_) => match self.open_impl(attributes) { Ok(factory) => return Ok(factory), From 754cb5f5b92b49c3d14328dfb05c6ff1f5c9a638 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Wed, 22 Jan 2025 19:12:12 +0100 Subject: [PATCH 10/26] [#429] Finalize implementation of request response service builder --- .../src/service/builder/request_response.rs | 128 +++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index 41534e86f..d561c84f2 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -23,10 +23,11 @@ use crate::prelude::{AttributeSpecifier, AttributeVerifier}; use crate::service::builder::OpenDynamicStorageFailure; use crate::service::dynamic_config::request_response::DynamicConfigSettings; use crate::service::port_factory::request_response; -use crate::service::{self, static_config}; +use crate::service::{self, header, static_config}; use crate::service::{builder, dynamic_config}; -use super::ServiceState; +use super::message_type_details::{MessageTypeDetails, TypeVariant}; +use super::{ServiceState, RETRY_LIMIT}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum RequestResponseOpenError { @@ -127,6 +128,13 @@ impl From for RequestResponseCreateError { pub enum RequestResponseOpenOrCreateError { RequestResponseOpenError(RequestResponseOpenError), RequestResponseCreateError(RequestResponseCreateError), + SystemInFlux, +} + +impl From for RequestResponseOpenOrCreateError { + fn from(value: ServiceAvailabilityState) -> Self { + RequestResponseOpenOrCreateError::RequestResponseOpenError(value.into()) + } } impl From for RequestResponseOpenOrCreateError { @@ -682,4 +690,120 @@ impl< } } } + + fn open_or_create_impl( + mut self, + attributes: &AttributeVerifier, + ) -> Result, RequestResponseOpenOrCreateError> { + let msg = "Unable to open or create request response service"; + + let mut retry_count = 0; + loop { + if RETRY_LIMIT < retry_count { + fail!(from self, + with RequestResponseOpenOrCreateError::SystemInFlux, + "{} since an instance is creating and removing the same service repeatedly.", + msg); + } + retry_count += 1; + + match self.is_service_available(msg)? { + Some(_) => match self.open_impl(attributes) { + Ok(factory) => return Ok(factory), + Err(RequestResponseOpenError::DoesNotExist) => continue, + Err(e) => return Err(e.into()), + }, + None => { + match self.create_impl(&AttributeSpecifier(attributes.attributes().clone())) { + Ok(factory) => return Ok(factory), + Err(RequestResponseCreateError::AlreadyExists) + | Err(RequestResponseCreateError::IsBeingCreatedByAnotherInstance) => { + continue; + } + Err(e) => return Err(e.into()), + } + } + } + } + } + + fn prepare_message_type_details(&mut self) { + self.config_details_mut().request_message_type_details = MessageTypeDetails::from::< + header::request_response::RequestHeader, + RequestHeader, + RequestPayload, + >(TypeVariant::FixedSize); + + self.config_details_mut().response_message_type_details = MessageTypeDetails::from::< + header::request_response::ResponseHeader, + ResponseHeader, + ResponsePayload, + >(TypeVariant::FixedSize); + + if let Some(alignment) = self.override_request_alignment { + self.config_details_mut() + .request_message_type_details + .payload + .alignment = self + .config_details() + .request_message_type_details + .payload + .alignment + .max(alignment); + } + + if let Some(alignment) = self.override_response_alignment { + self.config_details_mut() + .response_message_type_details + .payload + .alignment = self + .config_details() + .response_message_type_details + .payload + .alignment + .max(alignment); + } + } + + pub fn open_or_create( + self, + ) -> Result, RequestResponseOpenOrCreateError> { + self.open_or_create_with_attributes(&AttributeVerifier::new()) + } + + pub fn open_or_create_with_attributes( + mut self, + required_attributes: &AttributeVerifier, + ) -> Result, RequestResponseOpenOrCreateError> { + self.prepare_message_type_details(); + self.open_or_create_impl(required_attributes) + } + + pub fn open( + self, + ) -> Result, RequestResponseOpenError> { + self.open_with_attributes(&AttributeVerifier::new()) + } + + pub fn open_with_attributes( + mut self, + required_attributes: &AttributeVerifier, + ) -> Result, RequestResponseOpenError> { + self.prepare_message_type_details(); + self.open_impl(required_attributes) + } + + pub fn create( + self, + ) -> Result, RequestResponseCreateError> { + self.create_with_attributes(&AttributeSpecifier::new()) + } + + pub fn create_with_attributes( + mut self, + attributes: &AttributeSpecifier, + ) -> Result, RequestResponseCreateError> { + self.prepare_message_type_details(); + self.create_impl(attributes) + } } From e33e1368b9d4a0959401f7716b9ee3881b59791b Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Wed, 22 Jan 2025 19:44:20 +0100 Subject: [PATCH 11/26] [#429] Add simple request response example that just creates a request response service --- examples/Cargo.toml | 10 ++++++ examples/rust/request_response/BUILD.bazel | 35 +++++++++++++++++++ examples/rust/request_response/README.md | 2 ++ examples/rust/request_response/client.rs | 30 ++++++++++++++++ examples/rust/request_response/server.rs | 28 +++++++++++++++ iceoryx2/src/service/builder/mod.rs | 14 ++++---- .../src/service/builder/request_response.rs | 25 +------------ .../dynamic_config/request_response.rs | 8 +++-- 8 files changed, 119 insertions(+), 33 deletions(-) create mode 100644 examples/rust/request_response/BUILD.bazel create mode 100644 examples/rust/request_response/README.md create mode 100644 examples/rust/request_response/client.rs create mode 100644 examples/rust/request_response/server.rs diff --git a/examples/Cargo.toml b/examples/Cargo.toml index c5973f1fd..678dd3749 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -113,6 +113,16 @@ path = "rust/publish_subscribe_with_user_header/publisher.rs" name = "publish_subscribe_user_header_subscriber" path = "rust/publish_subscribe_with_user_header/subscriber.rs" +# request_response + +[[example]] +name = "request_response_server" +path = "rust/request_response/server.rs" + +[[example]] +name = "request_response_client" +path = "rust/request_response/client.rs" + # service attributes [[example]] diff --git a/examples/rust/request_response/BUILD.bazel b/examples/rust/request_response/BUILD.bazel new file mode 100644 index 000000000..ac064f398 --- /dev/null +++ b/examples/rust/request_response/BUILD.bazel @@ -0,0 +1,35 @@ +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache Software License 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +# which is available at https://opensource.org/licenses/MIT. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT + +load("@rules_rust//rust:defs.bzl", "rust_binary") + +rust_binary( + name = "server", + srcs = [ + "server.rs", + ], + deps = [ + "//iceoryx2:iceoryx2", + "//examples/rust:examples-common", + ], +) + +rust_binary( + name = "client", + srcs = [ + "client.rs", + ], + deps = [ + "//iceoryx2:iceoryx2", + "//examples/rust:examples-common", + ], +) diff --git a/examples/rust/request_response/README.md b/examples/rust/request_response/README.md new file mode 100644 index 000000000..2eef01b8c --- /dev/null +++ b/examples/rust/request_response/README.md @@ -0,0 +1,2 @@ +# Request-Response + diff --git a/examples/rust/request_response/client.rs b/examples/rust/request_response/client.rs new file mode 100644 index 000000000..84870a0be --- /dev/null +++ b/examples/rust/request_response/client.rs @@ -0,0 +1,30 @@ +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use std::time::Duration; + +use examples_common::TransmissionData; +use iceoryx2::prelude::*; + +fn main() -> Result<(), Box> { + let node = NodeBuilder::new().create::()?; + + let service = node + .service_builder(&"My/Funk/ServiceName".try_into()?) + .request_response::() + .open_or_create()?; + + drop(service); + println!("exit"); + + Ok(()) +} diff --git a/examples/rust/request_response/server.rs b/examples/rust/request_response/server.rs new file mode 100644 index 000000000..a541e8b54 --- /dev/null +++ b/examples/rust/request_response/server.rs @@ -0,0 +1,28 @@ +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use examples_common::TransmissionData; +use iceoryx2::prelude::*; + +fn main() -> Result<(), Box> { + let node = NodeBuilder::new().create::()?; + + let service = node + .service_builder(&"My/Funk/ServiceName".try_into()?) + .request_response::() + .open_or_create()?; + + drop(service); + println!("exit"); + + Ok(()) +} diff --git a/iceoryx2/src/service/builder/mod.rs b/iceoryx2/src/service/builder/mod.rs index a987ee359..5e0b3e1f8 100644 --- a/iceoryx2/src/service/builder/mod.rs +++ b/iceoryx2/src/service/builder/mod.rs @@ -116,17 +116,17 @@ impl Builder { } } - pub fn request( + pub fn request_response( self, - ) -> request_response::BuilderRequest { + ) -> request_response::Builder { BuilderWithServiceType::new( - StaticConfig::new_publish_subscribe::( + StaticConfig::new_request_response::( &self.name, self.shared_node.config(), ), self.shared_node, ) - .request::() + .request_response::() } /// Create a new builder to create a @@ -172,10 +172,10 @@ impl BuilderWithServiceType { } } - fn request( + fn request_response( self, - ) -> request_response::BuilderRequest { - request_response::BuilderRequest::new(self) + ) -> request_response::Builder { + request_response::Builder::new(self) } fn publish_subscribe( diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index d561c84f2..ab7f2eb59 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -164,29 +164,6 @@ enum ServiceAvailabilityState { IncompatibleResponseType, } -#[derive(Debug)] -pub struct BuilderRequest { - base: builder::BuilderWithServiceType, - _request_payload: PhantomData, -} - -impl - BuilderRequest -{ - pub(crate) fn new(base: builder::BuilderWithServiceType) -> Self { - Self { - base, - _request_payload: PhantomData, - } - } - - pub fn response( - self, - ) -> Builder { - Builder::new(self.base) - } -} - #[derive(Debug)] pub struct Builder< RequestPayload: Debug, @@ -221,7 +198,7 @@ impl< ServiceType: service::Service, > Builder { - fn new(base: builder::BuilderWithServiceType) -> Self { + pub(crate) fn new(base: builder::BuilderWithServiceType) -> Self { Self { base, override_request_alignment: None, diff --git a/iceoryx2/src/service/dynamic_config/request_response.rs b/iceoryx2/src/service/dynamic_config/request_response.rs index 9fc119d3e..8fe0c1030 100644 --- a/iceoryx2/src/service/dynamic_config/request_response.rs +++ b/iceoryx2/src/service/dynamic_config/request_response.rs @@ -23,12 +23,16 @@ use super::PortCleanupAction; #[doc(hidden)] #[repr(C)] #[derive(Debug, Clone, Copy)] -pub struct ServerDetails {} +pub struct ServerDetails { + _stub: usize, +} #[doc(hidden)] #[repr(C)] #[derive(Debug, Clone, Copy)] -pub struct ClientDetails {} +pub struct ClientDetails { + _stub: usize, +} #[repr(C)] #[derive(Debug, Clone, Copy)] From 365f28304111508873acf0074bf1cc9a5c762d29 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Thu, 23 Jan 2025 14:48:03 +0100 Subject: [PATCH 12/26] [#429] Write service builder tests for type safety --- .../tests/service_request_response_tests.rs | 326 ++++++++++++++++++ 1 file changed, 326 insertions(+) create mode 100644 iceoryx2/tests/service_request_response_tests.rs diff --git a/iceoryx2/tests/service_request_response_tests.rs b/iceoryx2/tests/service_request_response_tests.rs new file mode 100644 index 000000000..e774ec4ce --- /dev/null +++ b/iceoryx2/tests/service_request_response_tests.rs @@ -0,0 +1,326 @@ +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#[generic_tests::define] +mod service_request_response { + use iceoryx2::node::NodeBuilder; + use iceoryx2::prelude::*; + use iceoryx2::service::builder::request_response::{ + RequestResponseCreateError, RequestResponseOpenError, + }; + use iceoryx2::testing::*; + use iceoryx2_bb_testing::assert_that; + + #[test] + fn open_existing_service_works() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .create(); + + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open(); + + assert_that!(sut_open, is_ok); + } + + #[test] + fn open_non_existing_service_fails() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open(); + + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotExist) ); + } + + #[test] + fn creating_existing_service_fails() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + + let _sut = node + .service_builder(&service_name) + .request_response::() + .create() + .unwrap(); + + let sut_create = node + .service_builder(&service_name) + .request_response::() + .create(); + + assert_that!(sut_create.err(), eq Some(RequestResponseCreateError::AlreadyExists) ); + } + + #[test] + fn open_or_create_works_with_existing_and_non_existing_services() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + + let sut_create = node + .service_builder(&service_name) + .request_response::() + .open_or_create(); + + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open_or_create(); + + assert_that!(sut_open, is_ok); + } + + #[test] + fn when_created_service_goes_out_of_scope_the_service_is_removed() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + + assert_that!( + Sut::does_exist(&service_name, &config, MessagingPattern::RequestResponse), eq Ok(false)); + + let sut = node + .service_builder(&service_name) + .request_response::() + .create(); + + assert_that!( + Sut::does_exist(&service_name, &config, MessagingPattern::RequestResponse), eq Ok(true)); + + drop(sut); + + assert_that!( + Sut::does_exist(&service_name, &config, MessagingPattern::RequestResponse), eq Ok(false)); + } + + #[test] + fn when_last_opened_service_goes_out_of_scope_the_service_is_removed() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + + assert_that!( + Sut::does_exist(&service_name, &config, MessagingPattern::RequestResponse), eq Ok(false)); + + let sut = node + .service_builder(&service_name) + .request_response::() + .create(); + + let sut_open_1 = node + .service_builder(&service_name) + .request_response::() + .open(); + + let sut_open_2 = node + .service_builder(&service_name) + .request_response::() + .open(); + + assert_that!( + Sut::does_exist(&service_name, &config, MessagingPattern::RequestResponse), eq Ok(true)); + + drop(sut); + + assert_that!( + Sut::does_exist(&service_name, &config, MessagingPattern::RequestResponse), eq Ok(true)); + + drop(sut_open_1); + + assert_that!( + Sut::does_exist(&service_name, &config, MessagingPattern::RequestResponse), eq Ok(true)); + + drop(sut_open_2); + + assert_that!( + Sut::does_exist(&service_name, &config, MessagingPattern::RequestResponse), eq Ok(false)); + } + + #[test] + fn opening_service_with_mismatching_request_type_fails() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .create(); + + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open(); + + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleRequestType)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .request_header::() + .open(); + + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleRequestType)); + } + + #[test] + fn opening_service_with_incompatible_request_type_alignment_fails() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .create(); + + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .request_payload_alignment(Alignment::new(512).unwrap()) + .open(); + + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleRequestType)); + } + + #[test] + fn opening_service_with_compatible_request_type_alignment_works() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .request_payload_alignment(Alignment::new(512).unwrap()) + .create(); + + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .request_payload_alignment(Alignment::new(128).unwrap()) + .open(); + + assert_that!(sut_open, is_ok); + } + + #[test] + fn opening_service_with_mismatching_response_type_fails() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .create(); + + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open(); + + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleResponseType)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .response_header::() + .open(); + + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleResponseType)); + } + + #[test] + fn opening_service_with_incompatible_response_type_alignment_fails() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .create(); + + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .response_payload_alignment(Alignment::new(512).unwrap()) + .open(); + + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleResponseType)); + } + + #[test] + fn opening_service_with_compatible_response_type_alignment_works() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .request_payload_alignment(Alignment::new(512).unwrap()) + .create(); + + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .request_payload_alignment(Alignment::new(128).unwrap()) + .open(); + + assert_that!(sut_open, is_ok); + } + + #[instantiate_tests()] + mod ipc {} + + #[instantiate_tests()] + mod local {} + + // todo: + // service does exist, list, remove with rpc +} From 112859ded291a344658ebbf037e6fd920a6f67b6 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Thu, 23 Jan 2025 16:54:31 +0100 Subject: [PATCH 13/26] [#429] Add requirements checks --- .../tests/service_request_response_tests.rs | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/iceoryx2/tests/service_request_response_tests.rs b/iceoryx2/tests/service_request_response_tests.rs index e774ec4ce..778b33839 100644 --- a/iceoryx2/tests/service_request_response_tests.rs +++ b/iceoryx2/tests/service_request_response_tests.rs @@ -315,6 +315,162 @@ mod service_request_response { assert_that!(sut_open, is_ok); } + #[test] + fn opening_service_with_attributes_and_acquiring_attributes_works() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let attribute_key = "wanna try this head"; + let attribute_value = "no its a brainslug"; + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let _sut_create = node + .service_builder(&service_name) + .request_response::() + .create_with_attributes( + &AttributeSpecifier::new().define(attribute_key, attribute_value), + ) + .unwrap(); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open() + .unwrap(); + + let attributes = sut_open.attributes(); + assert_that!(attributes.len(), eq 1); + assert_that!(attributes.get_key_value_at(attribute_key, 0), eq Some(attribute_value)); + } + + #[test] + fn opening_service_with_incompatible_attributes_fails() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let attribute_key = "there is a muffin"; + let attribute_value = "with molten chocolate"; + let attribute_incompatible_value = "its delicious"; + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let _sut_create = node + .service_builder(&service_name) + .request_response::() + .create_with_attributes( + &AttributeSpecifier::new().define(attribute_key, attribute_value), + ) + .unwrap(); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open_with_attributes( + &AttributeVerifier::new().require(&attribute_key, &attribute_incompatible_value), + ); + + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleAttributes)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open_with_attributes( + &AttributeVerifier::new().require_key(&attribute_incompatible_value), + ); + + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleAttributes)); + } + + #[test] + fn opening_service_with_compatible_attributes_works() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let attribute_key = "kermit the brave knight"; + let attribute_value = "rides on hypnotoad into the sunset"; + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let _sut_create = node + .service_builder(&service_name) + .request_response::() + .create_with_attributes( + &AttributeSpecifier::new().define(attribute_key, attribute_value), + ) + .unwrap(); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open_with_attributes( + &AttributeVerifier::new().require(&attribute_key, &attribute_value), + ); + + assert_that!(sut_open, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open_with_attributes(&AttributeVerifier::new().require_key(&attribute_key)); + + assert_that!(sut_open, is_ok); + } + + #[test] + fn recreate_after_drop_works() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut = node + .service_builder(&service_name) + .request_response::() + .create(); + assert_that!(sut, is_ok); + + drop(sut); + + let sut2 = node + .service_builder(&service_name) + .request_response::() + .create(); + assert_that!(sut2, is_ok); + } + + #[test] + fn open_fails_when_service_does_not_satisfy_request_overflow_requirement() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .enable_safe_overflow_for_requests(true) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .enable_safe_overflow_for_requests(false) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleOverflowBehaviorForRequests)); + } + + #[test] + fn open_fails_when_service_does_not_satisfy_response_overflow_requirement() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .enable_safe_overflow_for_responses(true) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .enable_safe_overflow_for_responses(false) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleOverflowBehaviorForResponses)); + } + #[instantiate_tests()] mod ipc {} From 69c98ffafb7e2d00a4860c0c661141181cd3192a Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Thu, 23 Jan 2025 19:31:24 +0100 Subject: [PATCH 14/26] [#429] Add limit checks --- .../src/service/builder/request_response.rs | 2 +- .../tests/service_request_response_tests.rs | 167 ++++++++++++++++++ 2 files changed, 168 insertions(+), 1 deletion(-) diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index ab7f2eb59..2f76c6843 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -440,7 +440,7 @@ impl< if self.verify_max_nodes && existing_configuration.max_nodes < required_configuration.max_nodes { - fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfClients, + fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfNodes, "{} since the service supports at most {} nodes but {} are required.", msg, existing_configuration.max_nodes, required_configuration.max_nodes); } diff --git a/iceoryx2/tests/service_request_response_tests.rs b/iceoryx2/tests/service_request_response_tests.rs index 778b33839..8a9be007b 100644 --- a/iceoryx2/tests/service_request_response_tests.rs +++ b/iceoryx2/tests/service_request_response_tests.rs @@ -471,6 +471,168 @@ mod service_request_response { assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleOverflowBehaviorForResponses)); } + #[test] + fn open_verifies_max_active_requests_correctly() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .max_active_requests(10) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_active_requests(11) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfActiveRequests)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_active_requests(9) + .open(); + assert_that!(sut_open, is_ok); + } + + #[test] + fn open_verifies_max_borrowed_responses_correctly() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .max_borrowed_responses(10) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_borrowed_responses(11) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedResponses)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_borrowed_responses(9) + .open(); + assert_that!(sut_open, is_ok); + } + + #[test] + fn open_verifies_max_response_buffer_size_correctly() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .max_response_buffer_size(10) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_response_buffer_size(11) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedResponseBufferSize)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_response_buffer_size(9) + .open(); + assert_that!(sut_open, is_ok); + } + + #[test] + fn open_verifies_max_amount_of_servers_correctly() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .max_servers(10) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_servers(11) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfServers)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_servers(9) + .open(); + assert_that!(sut_open, is_ok); + } + + #[test] + fn open_verifies_max_amount_of_clients_correctly() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .max_clients(10) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_clients(11) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfClients)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_clients(9) + .open(); + assert_that!(sut_open, is_ok); + } + + #[test] + fn open_verifies_max_amount_of_nodes_correctly() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .max_nodes(10) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_nodes(11) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfNodes)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_nodes(9) + .open(); + assert_that!(sut_open, is_ok); + } + #[instantiate_tests()] mod ipc {} @@ -479,4 +641,9 @@ mod service_request_response { // todo: // service does exist, list, remove with rpc + // add: + // * request buffer size + // * borrowed requests + // * active responses + // } From a7e559b4d982021894fbcf214a330b3fbcfa5032 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 24 Jan 2025 09:57:44 +0100 Subject: [PATCH 15/26] [#429] Add further request response configuration parameters --- config/iceoryx2.toml | 5 +- iceoryx2/src/config.rs | 8 +- .../src/service/builder/request_response.rs | 78 ++++++++++++++++ .../service/static_config/request_response.rs | 18 ++++ .../tests/service_request_response_tests.rs | 89 +++++++++++++++++-- 5 files changed, 191 insertions(+), 7 deletions(-) diff --git a/config/iceoryx2.toml b/config/iceoryx2.toml index 1e3f7b12a..ba08f331b 100644 --- a/config/iceoryx2.toml +++ b/config/iceoryx2.toml @@ -24,9 +24,12 @@ creation-timeout.nanos = 500000000 [defaults.request-response] enable-safe-overflow-for-requests = true enable-safe-overflow-for-responses = true +max-active-responses = 4 max-active-requests = 2 -max-borrowed-responses = 2 +max-borrowed-responses = 4 +max-borrowed-requests = 2 max-response-buffer-size = 2 +max-request-buffer-size = 4 max-servers = 2 max-clients = 8 max-nodes = 20 diff --git a/iceoryx2/src/config.rs b/iceoryx2/src/config.rs index 1814b3504..f9309e76a 100644 --- a/iceoryx2/src/config.rs +++ b/iceoryx2/src/config.rs @@ -292,9 +292,12 @@ pub struct Event { pub struct RequestResonse { pub enable_safe_overflow_for_requests: bool, pub enable_safe_overflow_for_responses: bool, + pub max_active_responses: usize, pub max_active_requests: usize, pub max_borrowed_responses: usize, + pub max_borrowed_requests: usize, pub max_response_buffer_size: usize, + pub max_request_buffer_size: usize, pub max_servers: usize, pub max_clients: usize, pub max_nodes: usize, @@ -345,9 +348,12 @@ impl Default for Config { request_response: RequestResonse { enable_safe_overflow_for_requests: true, enable_safe_overflow_for_responses: true, + max_active_responses: 4, max_active_requests: 2, - max_borrowed_responses: 2, + max_borrowed_responses: 4, + max_borrowed_requests: 2, max_response_buffer_size: 2, + max_request_buffer_size: 4, max_servers: 2, max_clients: 8, max_nodes: 20, diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index 2f76c6843..ef804c3b6 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -32,9 +32,12 @@ use super::{ServiceState, RETRY_LIMIT}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum RequestResponseOpenError { DoesNotExist, + DoesNotSupportRequestedAmountOfActiveResponses, DoesNotSupportRequestedAmountOfActiveRequests, DoesNotSupportRequestedAmountOfBorrowedResponses, + DoesNotSupportRequestedAmountOfBorrowedRequests, DoesNotSupportRequestedResponseBufferSize, + DoesNotSupportRequestedRequestBufferSize, DoesNotSupportRequestedAmountOfServers, DoesNotSupportRequestedAmountOfClients, DoesNotSupportRequestedAmountOfNodes, @@ -177,9 +180,12 @@ pub struct Builder< override_response_alignment: Option, verify_enable_safe_overflow_for_requests: bool, verify_enable_safe_overflow_for_responses: bool, + verify_max_active_responses: bool, verify_max_active_requests: bool, verify_max_borrowed_responses: bool, + verify_max_borrowed_requests: bool, verify_max_response_buffer_size: bool, + verify_max_request_buffer_size: bool, verify_max_servers: bool, verify_max_clients: bool, verify_max_nodes: bool, @@ -205,9 +211,12 @@ impl< override_response_alignment: None, verify_enable_safe_overflow_for_requests: false, verify_enable_safe_overflow_for_responses: false, + verify_max_active_responses: false, verify_max_active_requests: false, verify_max_borrowed_responses: false, + verify_max_borrowed_requests: false, verify_max_response_buffer_size: false, + verify_max_request_buffer_size: false, verify_max_servers: false, verify_max_clients: false, verify_max_nodes: false, @@ -280,6 +289,12 @@ impl< self } + pub fn max_active_responses(mut self, value: usize) -> Self { + self.config_details_mut().max_active_responses = value; + self.verify_max_active_responses = true; + self + } + pub fn max_active_requests(mut self, value: usize) -> Self { self.config_details_mut().max_active_requests = value; self.verify_max_active_requests = true; @@ -292,12 +307,24 @@ impl< self } + pub fn max_borrowed_requests(mut self, value: usize) -> Self { + self.config_details_mut().max_borrowed_requests = value; + self.verify_max_borrowed_requests = true; + self + } + pub fn max_response_buffer_size(mut self, value: usize) -> Self { self.config_details_mut().max_response_buffer_size = value; self.verify_max_response_buffer_size = true; self } + pub fn max_request_buffer_size(mut self, value: usize) -> Self { + self.config_details_mut().max_request_buffer_size = value; + self.verify_max_request_buffer_size = true; + self + } + pub fn max_servers(mut self, value: usize) -> Self { self.config_details_mut().max_servers = value; self.verify_max_servers = true; @@ -320,18 +347,42 @@ impl< let origin = format!("{:?}", self); let settings = self.base.service_config.request_response_mut(); + if settings.max_request_buffer_size == 0 { + warn!(from origin, + "Setting the maximum size of the request buffer to 0 is not supported. Adjust it to 1, the smallest supported value."); + settings.max_request_buffer_size = 1; + } + + if settings.max_response_buffer_size == 0 { + warn!(from origin, + "Setting the maximum size of the response buffer to 0 is not supported. Adjust it to 1, the smallest supported value."); + settings.max_response_buffer_size = 1; + } + if settings.max_active_requests == 0 { warn!(from origin, "Setting the maximum number of active requests to 0 is not supported. Adjust it to 1, the smallest supported value."); settings.max_active_requests = 1; } + if settings.max_active_responses == 0 { + warn!(from origin, + "Setting the maximum number of active responses to 0 is not supported. Adjust it to 1, the smallest supported value."); + settings.max_active_responses = 1; + } + if settings.max_borrowed_responses == 0 { warn!(from origin, "Setting the maximum number of borrowed responses to 0 is not supported. Adjust it to 1, the smallest supported value."); settings.max_borrowed_responses = 1; } + if settings.max_borrowed_requests == 0 { + warn!(from origin, + "Setting the maximum number of borrowed requests to 0 is not supported. Adjust it to 1, the smallest supported value."); + settings.max_borrowed_requests = 1; + } + if settings.max_servers == 0 { warn!(from origin, "Setting the maximum number of servers to 0 is not supported. Adjust it to 1, the smallest supported value."); @@ -394,6 +445,15 @@ impl< msg); } + if self.verify_max_active_responses + && existing_configuration.max_active_responses + < required_configuration.max_active_responses + { + fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfActiveResponses, + "{} since the service supports only {} active responses but {} are required.", + msg, existing_configuration.max_active_responses, required_configuration.max_active_responses); + } + if self.verify_max_active_requests && existing_configuration.max_active_requests < required_configuration.max_active_requests @@ -412,6 +472,15 @@ impl< msg, existing_configuration.max_borrowed_responses, required_configuration.max_borrowed_responses); } + if self.verify_max_borrowed_requests + && existing_configuration.max_borrowed_requests + < required_configuration.max_borrowed_requests + { + fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedRequests, + "{} since the service supports only {} borrowed requests but {} are required.", + msg, existing_configuration.max_borrowed_requests, required_configuration.max_borrowed_requests); + } + if self.verify_max_response_buffer_size && existing_configuration.max_response_buffer_size < required_configuration.max_response_buffer_size @@ -421,6 +490,15 @@ impl< msg, existing_configuration.max_response_buffer_size, required_configuration.max_response_buffer_size); } + if self.verify_max_request_buffer_size + && existing_configuration.max_request_buffer_size + < required_configuration.max_request_buffer_size + { + fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedRequestBufferSize, + "{} since the service supports a maximum request buffer size of {} but a size of {} is required.", + msg, existing_configuration.max_request_buffer_size, required_configuration.max_request_buffer_size); + } + if self.verify_max_servers && existing_configuration.max_servers < required_configuration.max_servers { diff --git a/iceoryx2/src/service/static_config/request_response.rs b/iceoryx2/src/service/static_config/request_response.rs index 5baac1005..dc34b91d6 100644 --- a/iceoryx2/src/service/static_config/request_response.rs +++ b/iceoryx2/src/service/static_config/request_response.rs @@ -20,9 +20,12 @@ use super::message_type_details::MessageTypeDetails; pub struct StaticConfig { pub(crate) enable_safe_overflow_for_requests: bool, pub(crate) enable_safe_overflow_for_responses: bool, + pub(crate) max_active_responses: usize, pub(crate) max_active_requests: usize, pub(crate) max_borrowed_responses: usize, + pub(crate) max_borrowed_requests: usize, pub(crate) max_response_buffer_size: usize, + pub(crate) max_request_buffer_size: usize, pub(crate) max_servers: usize, pub(crate) max_clients: usize, pub(crate) max_nodes: usize, @@ -41,9 +44,12 @@ impl StaticConfig { .defaults .request_response .enable_safe_overflow_for_responses, + max_active_responses: config.defaults.request_response.max_active_responses, max_active_requests: config.defaults.request_response.max_active_requests, max_borrowed_responses: config.defaults.request_response.max_borrowed_responses, + max_borrowed_requests: config.defaults.request_response.max_borrowed_requests, max_response_buffer_size: config.defaults.request_response.max_response_buffer_size, + max_request_buffer_size: config.defaults.request_response.max_request_buffer_size, max_servers: config.defaults.request_response.max_servers, max_clients: config.defaults.request_response.max_clients, max_nodes: config.defaults.request_response.max_nodes, @@ -60,6 +66,10 @@ impl StaticConfig { self.enable_safe_overflow_for_responses } + pub fn max_active_responses(&self) -> usize { + self.max_active_responses + } + pub fn max_active_requests(&self) -> usize { self.max_active_requests } @@ -68,10 +78,18 @@ impl StaticConfig { self.max_borrowed_responses } + pub fn max_borrowed_requests(&self) -> usize { + self.max_borrowed_requests + } + pub fn max_response_buffer_size(&self) -> usize { self.max_response_buffer_size } + pub fn max_request_buffer_size(&self) -> usize { + self.max_request_buffer_size + } + pub fn max_servers(&self) -> usize { self.max_servers } diff --git a/iceoryx2/tests/service_request_response_tests.rs b/iceoryx2/tests/service_request_response_tests.rs index 8a9be007b..f6e82cfa9 100644 --- a/iceoryx2/tests/service_request_response_tests.rs +++ b/iceoryx2/tests/service_request_response_tests.rs @@ -471,6 +471,33 @@ mod service_request_response { assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleOverflowBehaviorForResponses)); } + #[test] + fn open_verifies_max_active_responses_correctly() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .max_active_responses(10) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_active_responses(11) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfActiveResponses)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_active_responses(9) + .open(); + assert_that!(sut_open, is_ok); + } + #[test] fn open_verifies_max_active_requests_correctly() { let service_name = generate_service_name(); @@ -525,6 +552,33 @@ mod service_request_response { assert_that!(sut_open, is_ok); } + #[test] + fn open_verifies_max_borrowed_requests_correctly() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .max_borrowed_requests(10) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_borrowed_requests(11) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedRequests)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_borrowed_requests(9) + .open(); + assert_that!(sut_open, is_ok); + } + #[test] fn open_verifies_max_response_buffer_size_correctly() { let service_name = generate_service_name(); @@ -552,6 +606,33 @@ mod service_request_response { assert_that!(sut_open, is_ok); } + #[test] + fn open_verifies_max_request_buffer_size_correctly() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let sut_create = node + .service_builder(&service_name) + .request_response::() + .max_request_buffer_size(10) + .create(); + assert_that!(sut_create, is_ok); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_request_buffer_size(11) + .open(); + assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedRequestBufferSize)); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .max_request_buffer_size(9) + .open(); + assert_that!(sut_open, is_ok); + } + #[test] fn open_verifies_max_amount_of_servers_correctly() { let service_name = generate_service_name(); @@ -640,10 +721,8 @@ mod service_request_response { mod local {} // todo: - // service does exist, list, remove with rpc - // add: - // * request buffer size - // * borrowed requests - // * active responses + // * service does exist, list, remove with rpc + // * set from 0 to 1 + // * read limits on open // } From 4820d81e5efb8e5b64df27b0496c3b83e8a9380d Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 24 Jan 2025 12:42:09 +0100 Subject: [PATCH 16/26] [#429] Implement advanced config and list tests --- ...service_request_response_builder_tests.rs} | 204 +++++++++++++++++- 1 file changed, 198 insertions(+), 6 deletions(-) rename iceoryx2/tests/{service_request_response_tests.rs => service_request_response_builder_tests.rs} (74%) diff --git a/iceoryx2/tests/service_request_response_tests.rs b/iceoryx2/tests/service_request_response_builder_tests.rs similarity index 74% rename from iceoryx2/tests/service_request_response_tests.rs rename to iceoryx2/tests/service_request_response_builder_tests.rs index f6e82cfa9..87ae885be 100644 --- a/iceoryx2/tests/service_request_response_tests.rs +++ b/iceoryx2/tests/service_request_response_builder_tests.rs @@ -714,15 +714,207 @@ mod service_request_response { assert_that!(sut_open, is_ok); } + #[test] + fn service_builder_adjusts_config_to_sane_values() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + + let sut_create = node + .service_builder(&service_name) + .request_response::() + .max_active_requests(0) + .max_active_responses(0) + .max_borrowed_requests(0) + .max_borrowed_responses(0) + .max_request_buffer_size(0) + .max_response_buffer_size(0) + .max_servers(0) + .max_clients(0) + .max_nodes(0) + .create(); + assert_that!(sut_create, is_ok); + let sut_create = sut_create.unwrap(); + + assert_that!(sut_create.static_config().max_active_requests(), eq 1); + assert_that!(sut_create.static_config().max_active_responses(), eq 1); + assert_that!(sut_create.static_config().max_borrowed_requests(), eq 1); + assert_that!(sut_create.static_config().max_borrowed_responses(), eq 1); + assert_that!(sut_create.static_config().max_request_buffer_size(), eq 1); + assert_that!(sut_create.static_config().max_response_buffer_size(), eq 1); + assert_that!(sut_create.static_config().max_servers(), eq 1); + assert_that!(sut_create.static_config().max_clients(), eq 1); + assert_that!(sut_create.static_config().max_nodes(), eq 1); + } + + #[test] + fn service_builder_parameters_override_default_config() { + let service_name = generate_service_name(); + let mut config = generate_isolated_config(); + let rpc_config = &mut config.defaults.request_response; + rpc_config.enable_safe_overflow_for_requests = true; + rpc_config.enable_safe_overflow_for_responses = true; + rpc_config.max_active_requests = 100; + rpc_config.max_active_responses = 100; + rpc_config.max_borrowed_requests = 100; + rpc_config.max_borrowed_responses = 100; + rpc_config.max_request_buffer_size = 100; + rpc_config.max_response_buffer_size = 100; + rpc_config.max_servers = 100; + rpc_config.max_clients = 100; + rpc_config.max_nodes = 100; + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + + let sut_create = node + .service_builder(&service_name) + .request_response::() + .enable_safe_overflow_for_requests(false) + .enable_safe_overflow_for_responses(false) + .max_active_requests(1) + .max_active_responses(2) + .max_borrowed_requests(3) + .max_borrowed_responses(4) + .max_request_buffer_size(5) + .max_response_buffer_size(6) + .max_servers(7) + .max_clients(8) + .max_nodes(9) + .create(); + assert_that!(sut_create, is_ok); + let sut_create = sut_create.unwrap(); + + assert_that!(sut_create.static_config().enable_safe_overflow_for_requests(), eq false); + assert_that!(sut_create.static_config().enable_safe_overflow_for_responses(), eq false); + assert_that!(sut_create.static_config().max_active_requests(), eq 1); + assert_that!(sut_create.static_config().max_active_responses(), eq 2); + assert_that!(sut_create.static_config().max_borrowed_requests(), eq 3); + assert_that!(sut_create.static_config().max_borrowed_responses(), eq 4); + assert_that!(sut_create.static_config().max_request_buffer_size(), eq 5); + assert_that!(sut_create.static_config().max_response_buffer_size(), eq 6); + assert_that!(sut_create.static_config().max_servers(), eq 7); + assert_that!(sut_create.static_config().max_clients(), eq 8); + assert_that!(sut_create.static_config().max_nodes(), eq 9); + } + + #[test] + fn service_builder_uses_config_when_user_sets_nothing() { + let service_name = generate_service_name(); + let mut config = generate_isolated_config(); + let rpc_config = &mut config.defaults.request_response; + rpc_config.enable_safe_overflow_for_requests = true; + rpc_config.enable_safe_overflow_for_responses = true; + rpc_config.max_active_requests = 11; + rpc_config.max_active_responses = 12; + rpc_config.max_borrowed_requests = 13; + rpc_config.max_borrowed_responses = 14; + rpc_config.max_request_buffer_size = 15; + rpc_config.max_response_buffer_size = 16; + rpc_config.max_servers = 17; + rpc_config.max_clients = 18; + rpc_config.max_nodes = 19; + + let node = NodeBuilder::new().config(&config).create::().unwrap(); + + let sut_create = node + .service_builder(&service_name) + .request_response::() + .create(); + assert_that!(sut_create, is_ok); + let sut_create = sut_create.unwrap(); + + assert_that!(sut_create.static_config().enable_safe_overflow_for_requests(), eq true); + assert_that!(sut_create.static_config().enable_safe_overflow_for_responses(), eq true); + assert_that!(sut_create.static_config().max_active_requests(), eq 11); + assert_that!(sut_create.static_config().max_active_responses(), eq 12); + assert_that!(sut_create.static_config().max_borrowed_requests(), eq 13); + assert_that!(sut_create.static_config().max_borrowed_responses(), eq 14); + assert_that!(sut_create.static_config().max_request_buffer_size(), eq 15); + assert_that!(sut_create.static_config().max_response_buffer_size(), eq 16); + assert_that!(sut_create.static_config().max_servers(), eq 17); + assert_that!(sut_create.static_config().max_clients(), eq 18); + assert_that!(sut_create.static_config().max_nodes(), eq 19); + } + + #[test] + fn opened_service_reads_config_correctly() { + let service_name = generate_service_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + + let _sut_create = node + .service_builder(&service_name) + .request_response::() + .enable_safe_overflow_for_requests(false) + .enable_safe_overflow_for_responses(false) + .max_active_requests(1) + .max_active_responses(2) + .max_borrowed_requests(3) + .max_borrowed_responses(4) + .max_request_buffer_size(5) + .max_response_buffer_size(6) + .max_servers(7) + .max_clients(8) + .max_nodes(9) + .create() + .unwrap(); + + let sut_open = node + .service_builder(&service_name) + .request_response::() + .open() + .unwrap(); + + assert_that!(sut_open.static_config().enable_safe_overflow_for_requests(), eq false); + assert_that!(sut_open.static_config().enable_safe_overflow_for_responses(), eq false); + assert_that!(sut_open.static_config().max_active_requests(), eq 1); + assert_that!(sut_open.static_config().max_active_responses(), eq 2); + assert_that!(sut_open.static_config().max_borrowed_requests(), eq 3); + assert_that!(sut_open.static_config().max_borrowed_responses(), eq 4); + assert_that!(sut_open.static_config().max_request_buffer_size(), eq 5); + assert_that!(sut_open.static_config().max_response_buffer_size(), eq 6); + assert_that!(sut_open.static_config().max_servers(), eq 7); + assert_that!(sut_open.static_config().max_clients(), eq 8); + assert_that!(sut_open.static_config().max_nodes(), eq 9); + } + + #[test] + fn list_finds_created_services() { + const NUMBER_OF_SERVICES: usize = 12; + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + let mut services = vec![]; + let mut service_names = vec![]; + + for _ in 0..NUMBER_OF_SERVICES { + let service_name = generate_service_name(); + let sut = node + .service_builder(&service_name) + .request_response::() + .create() + .unwrap(); + services.push(sut); + service_names.push(service_name); + } + + for name in &service_names { + assert_that!(Sut::does_exist(name, &config, MessagingPattern::RequestResponse).unwrap(), eq true); + } + + let mut number_of_listed_services = 0; + Sut::list(&config, |service| { + assert_that!(service_names, contains * service.static_details.name()); + number_of_listed_services += 1; + CallbackProgression::Continue + }) + .unwrap(); + + assert_that!(number_of_listed_services, eq service_names.len()); + } + #[instantiate_tests()] mod ipc {} #[instantiate_tests()] mod local {} - - // todo: - // * service does exist, list, remove with rpc - // * set from 0 to 1 - // * read limits on open - // } From 7379335048182205a99eb735dd388583ba763806 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 24 Jan 2025 13:36:37 +0100 Subject: [PATCH 17/26] [#429] Adjust code coverage generation script to use mc dc --- iceoryx2-ffi/ffi/src/api/config.rs | 2 +- iceoryx2-ffi/ffi/src/api/service_builder.rs | 2 +- iceoryx2-ffi/ffi/src/api/subscriber.rs | 2 +- internal/scripts/generate-cov-report.sh | 5 ++++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/iceoryx2-ffi/ffi/src/api/config.rs b/iceoryx2-ffi/ffi/src/api/config.rs index b926f53ef..2217bb648 100644 --- a/iceoryx2-ffi/ffi/src/api/config.rs +++ b/iceoryx2-ffi/ffi/src/api/config.rs @@ -76,7 +76,7 @@ pub(super) struct ConfigOwner { #[repr(C)] #[repr(align(8))] // align_of() pub struct iox2_config_storage_t { - internal: [u8; 3680], // size_of() + internal: [u8; 3704], // size_of() } /// Contains the iceoryx2 config diff --git a/iceoryx2-ffi/ffi/src/api/service_builder.rs b/iceoryx2-ffi/ffi/src/api/service_builder.rs index 1b600ab45..d7397f343 100644 --- a/iceoryx2-ffi/ffi/src/api/service_builder.rs +++ b/iceoryx2-ffi/ffi/src/api/service_builder.rs @@ -100,7 +100,7 @@ impl ServiceBuilderUnion { #[repr(C)] #[repr(align(8))] // alignment of Option pub struct iox2_service_builder_storage_t { - internal: [u8; 608], // magic number obtained with size_of::>() + internal: [u8; 632], // magic number obtained with size_of::>() } #[repr(C)] diff --git a/iceoryx2-ffi/ffi/src/api/subscriber.rs b/iceoryx2-ffi/ffi/src/api/subscriber.rs index 06e782760..931aca6b9 100644 --- a/iceoryx2-ffi/ffi/src/api/subscriber.rs +++ b/iceoryx2-ffi/ffi/src/api/subscriber.rs @@ -98,7 +98,7 @@ impl SubscriberUnion { #[repr(C)] #[repr(align(16))] // alignment of Option pub struct iox2_subscriber_storage_t { - internal: [u8; 960], // magic number obtained with size_of::>() + internal: [u8; 976], // magic number obtained with size_of::>() } #[repr(C)] diff --git a/internal/scripts/generate-cov-report.sh b/internal/scripts/generate-cov-report.sh index 92d023c5d..c735dede4 100755 --- a/internal/scripts/generate-cov-report.sh +++ b/internal/scripts/generate-cov-report.sh @@ -19,9 +19,10 @@ COLOR_RED='\033[1;31m' COLOR_GREEN='\033[1;32m' COLOR_YELLOW='\033[1;33m' +LLVM_PATH=$(dirname $(which llvm-profdata)) LLVM_PROFILE_PATH="target/debug/llvm-profile-files" export LLVM_PROFILE_FILE="${LLVM_PROFILE_PATH}/iceoryx2-%p-%m.profraw" -export RUSTFLAGS="-Cinstrument-coverage" +export RUSTFLAGS="-C instrument-coverage -Z coverage-options=mcdc" COVERAGE_DIR="target/debug/coverage" @@ -132,6 +133,7 @@ generate_html_report() { --ignore "**/benchmarks/*" \ --ignore "**/target/*" \ --ignore "**/.cargo/*" \ + --llvm-path ${LLVM_PATH} \ --output-path ./${COVERAGE_DIR}/html sed -i 's/coverage/grcov/' ${COVERAGE_DIR}/html/coverage.json sed -i 's/coverage/grcov/' ${COVERAGE_DIR}/html/badges/*.svg @@ -157,6 +159,7 @@ generate_lcov_report() { --ignore "**/benchmarks/*" \ --ignore "**/target/*" \ --ignore "**/.cargo/*" \ + --llvm-path ${LLVM_PATH} \ --output-path ./${COVERAGE_DIR}/lcov.info } From f4dcf9985b929cd802d364ec4a5b47a70d9d734c Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 24 Jan 2025 15:53:57 +0100 Subject: [PATCH 18/26] [#429] Add documentation for request response builder --- config/iceoryx2.toml | 4 +- examples/rust/request_response/client.rs | 2 - iceoryx2/src/config.rs | 8 +- iceoryx2/src/port/client.rs | 14 ++ iceoryx2/src/port/mod.rs | 4 + iceoryx2/src/port/server.rs | 14 ++ iceoryx2/src/service/builder/event.rs | 2 + .../src/service/builder/publish_subscribe.rs | 2 + .../src/service/builder/request_response.rs | 176 ++++++++++++++---- iceoryx2/src/service/dynamic_config/mod.rs | 8 +- .../service/static_config/request_response.rs | 22 ++- .../service_request_response_builder_tests.rs | 52 +++--- 12 files changed, 224 insertions(+), 84 deletions(-) create mode 100644 iceoryx2/src/port/client.rs create mode 100644 iceoryx2/src/port/server.rs diff --git a/config/iceoryx2.toml b/config/iceoryx2.toml index ba08f331b..99e4c3efa 100644 --- a/config/iceoryx2.toml +++ b/config/iceoryx2.toml @@ -26,8 +26,8 @@ enable-safe-overflow-for-requests = true enable-safe-overflow-for-responses = true max-active-responses = 4 max-active-requests = 2 -max-borrowed-responses = 4 -max-borrowed-requests = 2 +max-borrowed-response-samples = 4 +max-borrowed-request-samples = 2 max-response-buffer-size = 2 max-request-buffer-size = 4 max-servers = 2 diff --git a/examples/rust/request_response/client.rs b/examples/rust/request_response/client.rs index 84870a0be..a541e8b54 100644 --- a/examples/rust/request_response/client.rs +++ b/examples/rust/request_response/client.rs @@ -10,8 +10,6 @@ // // SPDX-License-Identifier: Apache-2.0 OR MIT -use std::time::Duration; - use examples_common::TransmissionData; use iceoryx2::prelude::*; diff --git a/iceoryx2/src/config.rs b/iceoryx2/src/config.rs index f9309e76a..f0de833d6 100644 --- a/iceoryx2/src/config.rs +++ b/iceoryx2/src/config.rs @@ -294,8 +294,8 @@ pub struct RequestResonse { pub enable_safe_overflow_for_responses: bool, pub max_active_responses: usize, pub max_active_requests: usize, - pub max_borrowed_responses: usize, - pub max_borrowed_requests: usize, + pub max_borrowed_response_samples: usize, + pub max_borrowed_request_samples: usize, pub max_response_buffer_size: usize, pub max_request_buffer_size: usize, pub max_servers: usize, @@ -350,8 +350,8 @@ impl Default for Config { enable_safe_overflow_for_responses: true, max_active_responses: 4, max_active_requests: 2, - max_borrowed_responses: 4, - max_borrowed_requests: 2, + max_borrowed_response_samples: 4, + max_borrowed_request_samples: 2, max_response_buffer_size: 2, max_request_buffer_size: 4, max_servers: 2, diff --git a/iceoryx2/src/port/client.rs b/iceoryx2/src/port/client.rs new file mode 100644 index 000000000..21d2c633e --- /dev/null +++ b/iceoryx2/src/port/client.rs @@ -0,0 +1,14 @@ +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +/// TODO +pub struct Client {} diff --git a/iceoryx2/src/port/mod.rs b/iceoryx2/src/port/mod.rs index 4bbca8150..c35b42407 100644 --- a/iceoryx2/src/port/mod.rs +++ b/iceoryx2/src/port/mod.rs @@ -16,6 +16,8 @@ use tiny_fn::tiny_fn; pub(crate) mod details; +/// Sends requests to a [`Server`](crate::port::server::Server) and receives responses. +pub mod client; /// Defines the event id used to identify the source of an event. pub mod event_id; /// Receiving endpoint (port) for event based communication @@ -26,6 +28,8 @@ pub mod notifier; pub mod port_identifiers; /// Sending endpoint (port) for publish-subscribe based communication pub mod publisher; +/// Receives requests from a [`Client`](crate::port::client::Client) port and sends back responses. +pub mod server; /// Receiving endpoint (port) for publish-subscribe based communication pub mod subscriber; /// Interface to perform cyclic updates to the ports. Required to deliver history to new diff --git a/iceoryx2/src/port/server.rs b/iceoryx2/src/port/server.rs new file mode 100644 index 000000000..b34fb4992 --- /dev/null +++ b/iceoryx2/src/port/server.rs @@ -0,0 +1,14 @@ +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +/// TODO +pub struct Server {} diff --git a/iceoryx2/src/service/builder/event.rs b/iceoryx2/src/service/builder/event.rs index eea9fb284..6171e32db 100644 --- a/iceoryx2/src/service/builder/event.rs +++ b/iceoryx2/src/service/builder/event.rs @@ -142,6 +142,8 @@ pub enum EventOpenOrCreateError { EventOpenError(EventOpenError), /// Failures that can occur when an event [`Service`] is created. EventCreateError(EventCreateError), + /// Can occur when another process creates and removes the same [`Service`] repeatedly with a + /// high frequency. SystemInFlux, } diff --git a/iceoryx2/src/service/builder/publish_subscribe.rs b/iceoryx2/src/service/builder/publish_subscribe.rs index 91e096dc7..05542085f 100644 --- a/iceoryx2/src/service/builder/publish_subscribe.rs +++ b/iceoryx2/src/service/builder/publish_subscribe.rs @@ -182,6 +182,8 @@ pub enum PublishSubscribeOpenOrCreateError { PublishSubscribeOpenError(PublishSubscribeOpenError), /// Failures that can occur when a [`Service`] could not be created. PublishSubscribeCreateError(PublishSubscribeCreateError), + /// Can occur when another process creates and removes the same [`Service`] repeatedly with a + /// high frequency. SystemInFlux, } diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index ef804c3b6..a1b5358a8 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -13,45 +13,72 @@ use std::fmt::Debug; use std::marker::PhantomData; -use iceoryx2_bb_elementary::alignment::Alignment; -use iceoryx2_bb_log::{fail, fatal_panic, warn}; -use iceoryx2_cal::dynamic_storage::{DynamicStorageCreateError, DynamicStorageOpenError}; -use iceoryx2_cal::serialize::Serialize; -use iceoryx2_cal::static_storage::{StaticStorage, StaticStorageCreateError, StaticStorageLocked}; - use crate::prelude::{AttributeSpecifier, AttributeVerifier}; use crate::service::builder::OpenDynamicStorageFailure; use crate::service::dynamic_config::request_response::DynamicConfigSettings; use crate::service::port_factory::request_response; +use crate::service::static_config::messaging_pattern::MessagingPattern; use crate::service::{self, header, static_config}; -use crate::service::{builder, dynamic_config}; +use crate::service::{builder, dynamic_config, Service}; +use iceoryx2_bb_elementary::alignment::Alignment; +use iceoryx2_bb_log::{fail, fatal_panic, warn}; +use iceoryx2_cal::dynamic_storage::{DynamicStorageCreateError, DynamicStorageOpenError}; +use iceoryx2_cal::serialize::Serialize; +use iceoryx2_cal::static_storage::{StaticStorage, StaticStorageCreateError, StaticStorageLocked}; use super::message_type_details::{MessageTypeDetails, TypeVariant}; use super::{ServiceState, RETRY_LIMIT}; +/// Errors that can occur when an existing [`MessagingPattern::RequestResponse`] [`Service`] shall +/// be opened. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum RequestResponseOpenError { + /// Service could not be openen since it does not exist DoesNotExist, + /// The [`Service`] has a lower maximum amount of active responses than requested. DoesNotSupportRequestedAmountOfActiveResponses, + /// The [`Service`] has a lower maximum amount of active requests than requested. DoesNotSupportRequestedAmountOfActiveRequests, + /// The [`Service`] has a lower maximum amount of borrowed responses than requested. DoesNotSupportRequestedAmountOfBorrowedResponses, + /// The [`Service`] has a lower maximum amount of borrowed requests than requested. DoesNotSupportRequestedAmountOfBorrowedRequests, + /// The [`Service`] has a lower maximum response buffer size than requested. DoesNotSupportRequestedResponseBufferSize, + /// The [`Service`] has a lower maximum request buffer size than requested. DoesNotSupportRequestedRequestBufferSize, + /// The [`Service`] has a lower maximum number of servers than requested. DoesNotSupportRequestedAmountOfServers, + /// The [`Service`] has a lower maximum number of clients than requested. DoesNotSupportRequestedAmountOfClients, + /// The [`Service`] has a lower maximum number of nodes than requested. DoesNotSupportRequestedAmountOfNodes, + /// The maximum number of [`Node`](crate::node::Node)s have already opened the [`Service`]. ExceedsMaxNumberOfNodes, + /// The [`Service`]s creation timeout has passed and it is still not initialized. Can be caused + /// by a process that crashed during [`Service`] creation. HangsInCreation, + /// The [`Service`] has the wrong request payload type, request header type or type alignment. IncompatibleRequestType, + /// The [`Service`] has the wrong response payload type, response header type or type alignment. IncompatibleResponseType, + /// The [`AttributeVerifier`] required attributes that the [`Service`] does not satisfy. IncompatibleAttributes, + /// The [`Service`] has the wrong messaging pattern. IncompatibleMessagingPattern, + /// The [`Service`] required overflow behavior for requests is not compatible. IncompatibleOverflowBehaviorForRequests, + /// The [`Service`] required overflow behavior for responses is not compatible. IncompatibleOverflowBehaviorForResponses, + /// The process has not enough permissions to open the [`Service`]. InsufficientPermissions, + /// Errors that indicate either an implementation issue or a wrongly configured system. InternalFailure, + /// The [`Service`] is marked for destruction and currently cleaning up since no one is using it anymore. + /// When the call creation call is repeated with a little delay the [`Service`] should be + /// recreatable. IsMarkedForDestruction, + /// Some underlying resources of the [`Service`] are either missing, corrupted or unaccessible. ServiceInCorruptedState, } @@ -88,13 +115,21 @@ impl From for RequestResponseOpenError { } } +/// Errors that can occur when a new [`MessagingPattern::RequestResponse`] [`Service`] shall be created. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum RequestResponseCreateError { + /// The [`Service`] already exists. AlreadyExists, + /// Errors that indicate either an implementation issue or a wrongly configured system. InternalFailure, + /// Multiple processes are trying to create the same [`Service`]. IsBeingCreatedByAnotherInstance, + /// The process has insufficient permissions to create the [`Service`]. InsufficientPermissions, + /// The [`Service`]s creation timeout has passed and it is still not initialized. Can be caused + /// by a process that crashed during [`Service`] creation. HangsInCreation, + /// Some underlying resources of the [`Service`] are either missing, corrupted or unaccessible. ServiceInCorruptedState, } @@ -127,10 +162,16 @@ impl From for RequestResponseCreateError { } } +/// Errors that can occur when a [`MessagingPattern::RequestResponse`] [`Service`] shall be +/// created or opened. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum RequestResponseOpenOrCreateError { + /// Failures that can occur when an existing [`Service`] could not be opened. RequestResponseOpenError(RequestResponseOpenError), + /// Failures that can occur when a [`Service`] could not be created. RequestResponseCreateError(RequestResponseCreateError), + /// Can occur when another process creates and removes the same [`Service`] repeatedly with a + /// high frequency. SystemInFlux, } @@ -167,13 +208,18 @@ enum ServiceAvailabilityState { IncompatibleResponseType, } +/// Builder to create new [`MessagingPattern::RequestResponse`] based [`Service`]s +/// +/// # Example +/// +/// See [`crate::service`] #[derive(Debug)] pub struct Builder< RequestPayload: Debug, RequestHeader: Debug, ResponsePayload: Debug, ResponseHeader: Debug, - ServiceType: service::Service, + ServiceType: Service, > { base: builder::BuilderWithServiceType, override_request_alignment: Option, @@ -182,8 +228,8 @@ pub struct Builder< verify_enable_safe_overflow_for_responses: bool, verify_max_active_responses: bool, verify_max_active_requests: bool, - verify_max_borrowed_responses: bool, - verify_max_borrowed_requests: bool, + verify_max_borrowed_response_samples: bool, + verify_max_borrowed_request_samples: bool, verify_max_response_buffer_size: bool, verify_max_request_buffer_size: bool, verify_max_servers: bool, @@ -201,7 +247,7 @@ impl< RequestHeader: Debug, ResponsePayload: Debug, ResponseHeader: Debug, - ServiceType: service::Service, + ServiceType: Service, > Builder { pub(crate) fn new(base: builder::BuilderWithServiceType) -> Self { @@ -213,8 +259,8 @@ impl< verify_enable_safe_overflow_for_responses: false, verify_max_active_responses: false, verify_max_active_requests: false, - verify_max_borrowed_responses: false, - verify_max_borrowed_requests: false, + verify_max_borrowed_response_samples: false, + verify_max_borrowed_request_samples: false, verify_max_response_buffer_size: false, verify_max_request_buffer_size: false, verify_max_servers: false, @@ -245,7 +291,8 @@ impl< } } - pub fn request_header( + /// Sets the request user header type of the [`Service`]. + pub fn request_user_header( self, ) -> Builder { unsafe { @@ -256,7 +303,8 @@ impl< } } - pub fn response_header( + /// Sets the response user header type of the [`Service`]. + pub fn response_user_header( self, ) -> Builder { unsafe { @@ -267,76 +315,117 @@ impl< } } + /// If the [`Service`] is created, it defines the request [`Alignment`] of the payload for the + /// service. If an existing [`Service`] is opened it requires the service to have at least the + /// defined [`Alignment`]. If the Payload [`Alignment`] is greater than the provided + /// [`Alignment`] then the Payload [`Alignment`] is used. pub fn request_payload_alignment(mut self, alignment: Alignment) -> Self { self.override_request_alignment = Some(alignment.value()); self } + /// If the [`Service`] is created, it defines the response [`Alignment`] of the payload for the + /// service. If an existing [`Service`] is opened it requires the service to have at least the + /// defined [`Alignment`]. If the Payload [`Alignment`] is greater than the provided + /// [`Alignment`] then the Payload [`Alignment`] is used. pub fn response_payload_alignment(mut self, alignment: Alignment) -> Self { self.override_response_alignment = Some(alignment.value()); self } + /// If the [`Service`] is created, defines the overflow behavior of the service for requests. + /// If an existing [`Service`] is opened it requires the service to have the defined overflow + /// behavior. pub fn enable_safe_overflow_for_requests(mut self, value: bool) -> Self { self.config_details_mut().enable_safe_overflow_for_requests = value; self.verify_enable_safe_overflow_for_requests = true; self } + /// If the [`Service`] is created, defines the overflow behavior of the service for responses. + /// If an existing [`Service`] is opened it requires the service to have the defined overflow + /// behavior. pub fn enable_safe_overflow_for_responses(mut self, value: bool) -> Self { self.config_details_mut().enable_safe_overflow_for_responses = value; self.verify_enable_safe_overflow_for_responses = true; self } + /// Defines how many active responses a [`Client`](crate::port::client::Client) can hold in + /// parallel. The objects are used to receive the samples to a request that was sent earlier + /// to a [`Server`](crate::port::server::Server) pub fn max_active_responses(mut self, value: usize) -> Self { self.config_details_mut().max_active_responses = value; self.verify_max_active_responses = true; self } + /// Defines how many active requests a [`Server`](crate::port::server::Server) can hold in + /// parallel. The objects are used to send answers to a request that was received earlier + /// from a [`Client`](crate::port::client::Client) pub fn max_active_requests(mut self, value: usize) -> Self { self.config_details_mut().max_active_requests = value; self.verify_max_active_requests = true; self } - pub fn max_borrowed_responses(mut self, value: usize) -> Self { - self.config_details_mut().max_borrowed_responses = value; - self.verify_max_borrowed_responses = true; + /// If the [`Service`] is created it defines how many samples a + /// response can borrow at most in parallel. If an existing + /// [`Service`] is opened it defines the minimum required. + pub fn max_borrowed_response_samples(mut self, value: usize) -> Self { + self.config_details_mut().max_borrowed_response_samples = value; + self.verify_max_borrowed_response_samples = true; self } - pub fn max_borrowed_requests(mut self, value: usize) -> Self { - self.config_details_mut().max_borrowed_requests = value; - self.verify_max_borrowed_requests = true; + /// If the [`Service`] is created it defines how many samples a + /// request can borrow at most in parallel. If an existing + /// [`Service`] is opened it defines the minimum required. + pub fn max_borrowed_request_samples(mut self, value: usize) -> Self { + self.config_details_mut().max_borrowed_request_samples = value; + self.verify_max_borrowed_request_samples = true; self } + /// If the [`Service`] is created it defines how many responses fit in the + /// [`Clients`](crate::port::server::Clients)s buffer. If an existing + /// [`Service`] is opened it defines the minimum required. pub fn max_response_buffer_size(mut self, value: usize) -> Self { self.config_details_mut().max_response_buffer_size = value; self.verify_max_response_buffer_size = true; self } + /// If the [`Service`] is created it defines how many requests fit in the + /// [`Server`](crate::port::server::Server)s buffer. If an existing + /// [`Service`] is opened it defines the minimum required. pub fn max_request_buffer_size(mut self, value: usize) -> Self { self.config_details_mut().max_request_buffer_size = value; self.verify_max_request_buffer_size = true; self } + /// If the [`Service`] is created it defines how many [`crate::port::server::Server`]s shall + /// be supported at most. If an existing [`Service`] is opened it defines how many + /// [`crate::port::server::Server`]s must be at least supported. pub fn max_servers(mut self, value: usize) -> Self { self.config_details_mut().max_servers = value; self.verify_max_servers = true; self } + /// If the [`Service`] is created it defines how many [`crate::port::client::Client`]s shall + /// be supported at most. If an existing [`Service`] is opened it defines how many + /// [`crate::port::client::Client`]s must be at least supported. pub fn max_clients(mut self, value: usize) -> Self { self.config_details_mut().max_clients = value; self.verify_max_clients = true; self } + /// If the [`Service`] is created it defines how many [`Node`](crate::node::Node)s shall + /// be able to open it in parallel. If an existing [`Service`] is opened it defines how many + /// [`Node`](crate::node::Node)s must be at least supported. pub fn max_nodes(mut self, value: usize) -> Self { self.config_details_mut().max_nodes = value; self.verify_max_nodes = true; @@ -371,16 +460,16 @@ impl< settings.max_active_responses = 1; } - if settings.max_borrowed_responses == 0 { + if settings.max_borrowed_response_samples == 0 { warn!(from origin, "Setting the maximum number of borrowed responses to 0 is not supported. Adjust it to 1, the smallest supported value."); - settings.max_borrowed_responses = 1; + settings.max_borrowed_response_samples = 1; } - if settings.max_borrowed_requests == 0 { + if settings.max_borrowed_request_samples == 0 { warn!(from origin, "Setting the maximum number of borrowed requests to 0 is not supported. Adjust it to 1, the smallest supported value."); - settings.max_borrowed_requests = 1; + settings.max_borrowed_request_samples = 1; } if settings.max_servers == 0 { @@ -419,7 +508,7 @@ impl< let required_configuration = self.base.service_config.request_response(); let existing_configuration = match &existing_settings.messaging_pattern { - static_config::messaging_pattern::MessagingPattern::RequestResponse(ref v) => v, + MessagingPattern::RequestResponse(ref v) => v, p => { fail!(from self, with RequestResponseOpenError::IncompatibleMessagingPattern, "{} since a service with the messaging pattern {:?} exists but MessagingPattern::RequestResponse is required.", @@ -463,22 +552,22 @@ impl< msg, existing_configuration.max_active_requests, required_configuration.max_active_requests); } - if self.verify_max_borrowed_responses - && existing_configuration.max_borrowed_responses - < required_configuration.max_borrowed_responses + if self.verify_max_borrowed_response_samples + && existing_configuration.max_borrowed_response_samples + < required_configuration.max_borrowed_response_samples { fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedResponses, "{} since the service supports only {} borrowed responses but {} are required.", - msg, existing_configuration.max_borrowed_responses, required_configuration.max_borrowed_responses); + msg, existing_configuration.max_borrowed_response_samples, required_configuration.max_borrowed_response_samples); } - if self.verify_max_borrowed_requests - && existing_configuration.max_borrowed_requests - < required_configuration.max_borrowed_requests + if self.verify_max_borrowed_request_samples + && existing_configuration.max_borrowed_request_samples + < required_configuration.max_borrowed_request_samples { fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedRequests, "{} since the service supports only {} borrowed requests but {} are required.", - msg, existing_configuration.max_borrowed_requests, required_configuration.max_borrowed_requests); + msg, existing_configuration.max_borrowed_request_samples, required_configuration.max_borrowed_request_samples); } if self.verify_max_response_buffer_size @@ -611,7 +700,7 @@ impl< }; let dynamic_config = match self.base.create_dynamic_config_storage( - dynamic_config::MessagingPattern::RequestResonse( + dynamic_config::MessagingPattern::RequestResponse( dynamic_config::request_response::DynamicConfig::new( &dynamic_config_setting, ), @@ -725,9 +814,7 @@ impl< }; self.base.service_config.messaging_pattern = - static_config::messaging_pattern::MessagingPattern::RequestResponse( - request_response_static_config.clone(), - ); + MessagingPattern::RequestResponse(request_response_static_config.clone()); if let Some(mut service_tag) = service_tag { service_tag.release_ownership(); @@ -820,12 +907,20 @@ impl< } } + /// If the [`Service`] exists, it will be opened otherwise a new [`Service`] will be + /// created. pub fn open_or_create( self, ) -> Result, RequestResponseOpenOrCreateError> { self.open_or_create_with_attributes(&AttributeVerifier::new()) } + /// If the [`Service`] exists, it will be opened otherwise a new [`Service`] will be + /// created. It defines a set of attributes. + /// + /// If the [`Service`] already exists all attribute requirements must be satisfied, + /// and service payload type must be the same, otherwise the open process will fail. + /// If the [`Service`] does not exist the required attributes will be defined in the [`Service`]. pub fn open_or_create_with_attributes( mut self, required_attributes: &AttributeVerifier, @@ -834,12 +929,15 @@ impl< self.open_or_create_impl(required_attributes) } + /// Opens an existing [`Service`]. pub fn open( self, ) -> Result, RequestResponseOpenError> { self.open_with_attributes(&AttributeVerifier::new()) } + /// Opens an existing [`Service`] with attribute requirements. If the defined attribute + /// requirements are not satisfied the open process will fail. pub fn open_with_attributes( mut self, required_attributes: &AttributeVerifier, @@ -848,12 +946,14 @@ impl< self.open_impl(required_attributes) } + /// Creates a new [`Service`]. pub fn create( self, ) -> Result, RequestResponseCreateError> { self.create_with_attributes(&AttributeSpecifier::new()) } + /// Creates a new [`Service`] with a set of attributes. pub fn create_with_attributes( mut self, attributes: &AttributeSpecifier, diff --git a/iceoryx2/src/service/dynamic_config/mod.rs b/iceoryx2/src/service/dynamic_config/mod.rs index 0a0551e71..1560c79d3 100644 --- a/iceoryx2/src/service/dynamic_config/mod.rs +++ b/iceoryx2/src/service/dynamic_config/mod.rs @@ -58,7 +58,7 @@ pub(crate) enum RemoveDeadNodeResult { #[derive(Debug)] pub(crate) enum MessagingPattern { - RequestResonse(request_response::DynamicConfig), + RequestResponse(request_response::DynamicConfig), PublishSubscribe(publish_subscribe::DynamicConfig), Event(event::DynamicConfig), } @@ -101,7 +101,7 @@ impl DynamicConfig { match &mut self.messaging_pattern { MessagingPattern::PublishSubscribe(ref mut v) => v.init(allocator), MessagingPattern::Event(ref mut v) => v.init(allocator), - MessagingPattern::RequestResonse(ref mut v) => v.init(allocator), + MessagingPattern::RequestResponse(ref mut v) => v.init(allocator), } } @@ -117,7 +117,7 @@ impl DynamicConfig { v.remove_dead_node_id(node_id, port_cleanup_callback) } MessagingPattern::Event(ref v) => v.remove_dead_node_id(node_id, port_cleanup_callback), - MessagingPattern::RequestResonse(ref v) => { + MessagingPattern::RequestResponse(ref v) => { v.remove_dead_node_id(node_id, port_cleanup_callback) } }; @@ -176,7 +176,7 @@ impl DynamicConfig { pub(crate) fn request_response(&self) -> &request_response::DynamicConfig { match &self.messaging_pattern { - MessagingPattern::RequestResonse(ref v) => v, + MessagingPattern::RequestResponse(ref v) => v, m => { fatal_panic!(from self, "This should never happen! Trying to access request_response::DynamicConfig when the messaging pattern is actually {:?}.", m); } diff --git a/iceoryx2/src/service/static_config/request_response.rs b/iceoryx2/src/service/static_config/request_response.rs index dc34b91d6..ecc26dac2 100644 --- a/iceoryx2/src/service/static_config/request_response.rs +++ b/iceoryx2/src/service/static_config/request_response.rs @@ -22,8 +22,8 @@ pub struct StaticConfig { pub(crate) enable_safe_overflow_for_responses: bool, pub(crate) max_active_responses: usize, pub(crate) max_active_requests: usize, - pub(crate) max_borrowed_responses: usize, - pub(crate) max_borrowed_requests: usize, + pub(crate) max_borrowed_response_samples: usize, + pub(crate) max_borrowed_request_samples: usize, pub(crate) max_response_buffer_size: usize, pub(crate) max_request_buffer_size: usize, pub(crate) max_servers: usize, @@ -46,8 +46,14 @@ impl StaticConfig { .enable_safe_overflow_for_responses, max_active_responses: config.defaults.request_response.max_active_responses, max_active_requests: config.defaults.request_response.max_active_requests, - max_borrowed_responses: config.defaults.request_response.max_borrowed_responses, - max_borrowed_requests: config.defaults.request_response.max_borrowed_requests, + max_borrowed_response_samples: config + .defaults + .request_response + .max_borrowed_response_samples, + max_borrowed_request_samples: config + .defaults + .request_response + .max_borrowed_request_samples, max_response_buffer_size: config.defaults.request_response.max_response_buffer_size, max_request_buffer_size: config.defaults.request_response.max_request_buffer_size, max_servers: config.defaults.request_response.max_servers, @@ -74,12 +80,12 @@ impl StaticConfig { self.max_active_requests } - pub fn max_borrowed_responses(&self) -> usize { - self.max_borrowed_responses + pub fn max_borrowed_response_samples(&self) -> usize { + self.max_borrowed_response_samples } - pub fn max_borrowed_requests(&self) -> usize { - self.max_borrowed_requests + pub fn max_borrowed_request_samples(&self) -> usize { + self.max_borrowed_request_samples } pub fn max_response_buffer_size(&self) -> usize { diff --git a/iceoryx2/tests/service_request_response_builder_tests.rs b/iceoryx2/tests/service_request_response_builder_tests.rs index 87ae885be..bc0964b06 100644 --- a/iceoryx2/tests/service_request_response_builder_tests.rs +++ b/iceoryx2/tests/service_request_response_builder_tests.rs @@ -190,7 +190,7 @@ mod service_request_response { let sut_open = node .service_builder(&service_name) .request_response::() - .request_header::() + .request_user_header::() .open(); assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleRequestType)); @@ -264,7 +264,7 @@ mod service_request_response { let sut_open = node .service_builder(&service_name) .request_response::() - .response_header::() + .response_user_header::() .open(); assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::IncompatibleResponseType)); @@ -533,21 +533,21 @@ mod service_request_response { let sut_create = node .service_builder(&service_name) .request_response::() - .max_borrowed_responses(10) + .max_borrowed_response_samples(10) .create(); assert_that!(sut_create, is_ok); let sut_open = node .service_builder(&service_name) .request_response::() - .max_borrowed_responses(11) + .max_borrowed_response_samples(11) .open(); assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedResponses)); let sut_open = node .service_builder(&service_name) .request_response::() - .max_borrowed_responses(9) + .max_borrowed_response_samples(9) .open(); assert_that!(sut_open, is_ok); } @@ -560,21 +560,21 @@ mod service_request_response { let sut_create = node .service_builder(&service_name) .request_response::() - .max_borrowed_requests(10) + .max_borrowed_request_samples(10) .create(); assert_that!(sut_create, is_ok); let sut_open = node .service_builder(&service_name) .request_response::() - .max_borrowed_requests(11) + .max_borrowed_request_samples(11) .open(); assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedRequests)); let sut_open = node .service_builder(&service_name) .request_response::() - .max_borrowed_requests(9) + .max_borrowed_request_samples(9) .open(); assert_that!(sut_open, is_ok); } @@ -725,8 +725,8 @@ mod service_request_response { .request_response::() .max_active_requests(0) .max_active_responses(0) - .max_borrowed_requests(0) - .max_borrowed_responses(0) + .max_borrowed_request_samples(0) + .max_borrowed_response_samples(0) .max_request_buffer_size(0) .max_response_buffer_size(0) .max_servers(0) @@ -738,8 +738,8 @@ mod service_request_response { assert_that!(sut_create.static_config().max_active_requests(), eq 1); assert_that!(sut_create.static_config().max_active_responses(), eq 1); - assert_that!(sut_create.static_config().max_borrowed_requests(), eq 1); - assert_that!(sut_create.static_config().max_borrowed_responses(), eq 1); + assert_that!(sut_create.static_config().max_borrowed_request_samples(), eq 1); + assert_that!(sut_create.static_config().max_borrowed_response_samples(), eq 1); assert_that!(sut_create.static_config().max_request_buffer_size(), eq 1); assert_that!(sut_create.static_config().max_response_buffer_size(), eq 1); assert_that!(sut_create.static_config().max_servers(), eq 1); @@ -756,8 +756,8 @@ mod service_request_response { rpc_config.enable_safe_overflow_for_responses = true; rpc_config.max_active_requests = 100; rpc_config.max_active_responses = 100; - rpc_config.max_borrowed_requests = 100; - rpc_config.max_borrowed_responses = 100; + rpc_config.max_borrowed_request_samples = 100; + rpc_config.max_borrowed_response_samples = 100; rpc_config.max_request_buffer_size = 100; rpc_config.max_response_buffer_size = 100; rpc_config.max_servers = 100; @@ -773,8 +773,8 @@ mod service_request_response { .enable_safe_overflow_for_responses(false) .max_active_requests(1) .max_active_responses(2) - .max_borrowed_requests(3) - .max_borrowed_responses(4) + .max_borrowed_request_samples(3) + .max_borrowed_response_samples(4) .max_request_buffer_size(5) .max_response_buffer_size(6) .max_servers(7) @@ -788,8 +788,8 @@ mod service_request_response { assert_that!(sut_create.static_config().enable_safe_overflow_for_responses(), eq false); assert_that!(sut_create.static_config().max_active_requests(), eq 1); assert_that!(sut_create.static_config().max_active_responses(), eq 2); - assert_that!(sut_create.static_config().max_borrowed_requests(), eq 3); - assert_that!(sut_create.static_config().max_borrowed_responses(), eq 4); + assert_that!(sut_create.static_config().max_borrowed_request_samples(), eq 3); + assert_that!(sut_create.static_config().max_borrowed_response_samples(), eq 4); assert_that!(sut_create.static_config().max_request_buffer_size(), eq 5); assert_that!(sut_create.static_config().max_response_buffer_size(), eq 6); assert_that!(sut_create.static_config().max_servers(), eq 7); @@ -806,8 +806,8 @@ mod service_request_response { rpc_config.enable_safe_overflow_for_responses = true; rpc_config.max_active_requests = 11; rpc_config.max_active_responses = 12; - rpc_config.max_borrowed_requests = 13; - rpc_config.max_borrowed_responses = 14; + rpc_config.max_borrowed_request_samples = 13; + rpc_config.max_borrowed_response_samples = 14; rpc_config.max_request_buffer_size = 15; rpc_config.max_response_buffer_size = 16; rpc_config.max_servers = 17; @@ -827,8 +827,8 @@ mod service_request_response { assert_that!(sut_create.static_config().enable_safe_overflow_for_responses(), eq true); assert_that!(sut_create.static_config().max_active_requests(), eq 11); assert_that!(sut_create.static_config().max_active_responses(), eq 12); - assert_that!(sut_create.static_config().max_borrowed_requests(), eq 13); - assert_that!(sut_create.static_config().max_borrowed_responses(), eq 14); + assert_that!(sut_create.static_config().max_borrowed_request_samples(), eq 13); + assert_that!(sut_create.static_config().max_borrowed_response_samples(), eq 14); assert_that!(sut_create.static_config().max_request_buffer_size(), eq 15); assert_that!(sut_create.static_config().max_response_buffer_size(), eq 16); assert_that!(sut_create.static_config().max_servers(), eq 17); @@ -849,8 +849,8 @@ mod service_request_response { .enable_safe_overflow_for_responses(false) .max_active_requests(1) .max_active_responses(2) - .max_borrowed_requests(3) - .max_borrowed_responses(4) + .max_borrowed_request_samples(3) + .max_borrowed_response_samples(4) .max_request_buffer_size(5) .max_response_buffer_size(6) .max_servers(7) @@ -869,8 +869,8 @@ mod service_request_response { assert_that!(sut_open.static_config().enable_safe_overflow_for_responses(), eq false); assert_that!(sut_open.static_config().max_active_requests(), eq 1); assert_that!(sut_open.static_config().max_active_responses(), eq 2); - assert_that!(sut_open.static_config().max_borrowed_requests(), eq 3); - assert_that!(sut_open.static_config().max_borrowed_responses(), eq 4); + assert_that!(sut_open.static_config().max_borrowed_request_samples(), eq 3); + assert_that!(sut_open.static_config().max_borrowed_response_samples(), eq 4); assert_that!(sut_open.static_config().max_request_buffer_size(), eq 5); assert_that!(sut_open.static_config().max_response_buffer_size(), eq 6); assert_that!(sut_open.static_config().max_servers(), eq 7); From ff90d78960f21ae8b50da241ff906b217167452b Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 24 Jan 2025 16:13:47 +0100 Subject: [PATCH 19/26] [#429] Add documentation for the static config --- .../static_config/messaging_pattern.rs | 2 + .../service/static_config/request_response.rs | 58 ++++++++++++++++++- .../service_request_response_builder_tests.rs | 36 ++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/iceoryx2/src/service/static_config/messaging_pattern.rs b/iceoryx2/src/service/static_config/messaging_pattern.rs index b2e4ff4e9..90ed7d6db 100644 --- a/iceoryx2/src/service/static_config/messaging_pattern.rs +++ b/iceoryx2/src/service/static_config/messaging_pattern.rs @@ -25,6 +25,8 @@ use super::request_response; #[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] #[serde(tag = "messaging_pattern")] pub enum MessagingPattern { + /// Stores the static config of the + /// [`service::MessagingPattern::RequestResponse`](crate::service::messaging_pattern::MessagingPattern::RequestResponse) RequestResponse(request_response::StaticConfig), /// Stores the static config of the diff --git a/iceoryx2/src/service/static_config/request_response.rs b/iceoryx2/src/service/static_config/request_response.rs index ecc26dac2..8e8634dae 100644 --- a/iceoryx2/src/service/static_config/request_response.rs +++ b/iceoryx2/src/service/static_config/request_response.rs @@ -10,12 +10,44 @@ // // SPDX-License-Identifier: Apache-2.0 OR MIT +//! # Example +//! +//! ``` +//! use iceoryx2::prelude::*; +//! +//! # fn main() -> Result<(), Box> { +//! let node = NodeBuilder::new().create::()?; +//! let pubsub = node.service_builder(&"My/Funk/ServiceName".try_into()?) +//! .request_response::() +//! .open_or_create()?; +//! +//! println!("type details: {:?}", pubsub.static_config().message_type_details()); +//! println!("max active requests: {:?}", pubsub.static_config().max_active_requests()); +//! println!("max active responses: {:?}", pubsub.static_config().max_active_responses()); +//! println!("max borrowed response samples: {:?}", pubsub.static_config().max_borrowed_response_samples()); +//! println!("max borrowed request samples: {:?}", pubsub.static_config().max_borrowed_request_samples()); +//! println!("max response buffer size: {:?}", pubsub.static_config().max_response_buffer_size()); +//! println!("max request buffer size: {:?}", pubsub.static_config().max_request_buffer_size()); +//! println!("max servers: {:?}", pubsub.static_config().max_clients()); +//! println!("max clients: {:?}", pubsub.static_config().max_servers()); +//! println!("max nodes: {:?}", pubsub.static_config().max_nodes()); +//! println!("request safe overflow: {:?}", pubsub.static_config().has_safe_overflow_for_requests()); +//! println!("response safe overflow: {:?}", pubsub.static_config().has_safe_overflow_for_responses()); +//! +//! # Ok(()) +//! # } +//! ``` + use serde::{Deserialize, Serialize}; use crate::config; use super::message_type_details::MessageTypeDetails; +/// The static configuration of an +/// [`MessagingPattern::RequestResponse`](crate::service::messaging_pattern::MessagingPattern::RequestResponse) +/// based service. Contains all parameters that do not change during the lifetime of a +/// [`Service`](crate::service::Service). #[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct StaticConfig { pub(crate) enable_safe_overflow_for_requests: bool, @@ -64,18 +96,40 @@ impl StaticConfig { } } - pub fn enable_safe_overflow_for_requests(&self) -> bool { + /// Returns the request type details of the [`crate::service::Service`]. + pub fn request_message_type_details(&self) -> &MessageTypeDetails { + &self.request_message_type_details + } + + /// Returns the response type details of the [`crate::service::Service`]. + pub fn response_message_type_details(&self) -> &MessageTypeDetails { + &self.response_message_type_details + } + + /// Returns true if the request buffer of the [`crate::service::Service`] safely overflows, + /// otherwise false. Safe overflow means that the [`crate::port::client::Client`] will + /// recycle the oldest requests from the [`crate::port::server::Server`] when its buffer + /// is full. + pub fn has_safe_overflow_for_requests(&self) -> bool { self.enable_safe_overflow_for_requests } - pub fn enable_safe_overflow_for_responses(&self) -> bool { + /// Returns true if the response buffer of the [`crate::service::Service`] safely overflows, + /// otherwise false. Safe overflow means that the [`crate::port::server::Server`] will + /// recycle the oldest responses from the [`crate::port::client::Client`] when its buffer + /// is full. + pub fn has_safe_overflow_for_responses(&self) -> bool { self.enable_safe_overflow_for_responses } + /// Returns the maximum of active responses a [`crate::port::server::Server`] can hold in + /// parallel. pub fn max_active_responses(&self) -> usize { self.max_active_responses } + /// Returns the maximum of active requests a [`crate::port::client::Client`] can hold in + /// parallel. pub fn max_active_requests(&self) -> usize { self.max_active_requests } diff --git a/iceoryx2/tests/service_request_response_builder_tests.rs b/iceoryx2/tests/service_request_response_builder_tests.rs index bc0964b06..78b193335 100644 --- a/iceoryx2/tests/service_request_response_builder_tests.rs +++ b/iceoryx2/tests/service_request_response_builder_tests.rs @@ -912,6 +912,42 @@ mod service_request_response { assert_that!(number_of_listed_services, eq service_names.len()); } + #[test] + fn service_cannot_be_opened_by_more_nodes_than_specified() { + let config = generate_isolated_config(); + let service_name = generate_service_name(); + + let node_1 = NodeBuilder::new().config(&config).create::().unwrap(); + let node_2 = NodeBuilder::new().config(&config).create::().unwrap(); + let node_3 = NodeBuilder::new().config(&config).create::().unwrap(); + + let sut_1 = node_1 + .service_builder(&service_name) + .request_response::() + .max_nodes(2) + .create(); + assert_that!(sut_1, is_ok); + + let sut_2 = node_2 + .service_builder(&service_name) + .request_response::() + .open(); + assert_that!(sut_2, is_ok); + + let sut_3 = node_3 + .service_builder(&service_name) + .request_response::() + .open(); + assert_that!(sut_3.err(), eq Some(RequestResponseOpenError::ExceedsMaxNumberOfNodes)); + drop(sut_2); + + let sut_3 = node_3 + .service_builder(&service_name) + .request_response::() + .open(); + assert_that!(sut_3, is_ok); + } + #[instantiate_tests()] mod ipc {} From ad34e8279d36ea52294811ec8736e5cd2f21087e Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 24 Jan 2025 16:57:32 +0100 Subject: [PATCH 20/26] [#429] Simple sequence diagram for request response --- doc/user-documentation/request-response.md | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 doc/user-documentation/request-response.md diff --git a/doc/user-documentation/request-response.md b/doc/user-documentation/request-response.md new file mode 100644 index 000000000..699e56519 --- /dev/null +++ b/doc/user-documentation/request-response.md @@ -0,0 +1,39 @@ +# Request-Response + +## Sending Request: Client View + +```mermaid +sequenceDiagram + User->>+Client: loan + Client-->>-User: RequestMut + create participant RequestMut + User->>RequestMut: write_payload + destroy RequestMut + User->>+RequestMut: send + RequestMut-->>-User: ActiveRequest + create participant ActiveRequest + User->>+ActiveRequest: receive + ActiveRequest-->>-User: Response + create participant Response + User->>Response: read_payload + destroy ActiveRequest + User->>ActiveRequest: drop +``` + +## Responding: Server View + +```mermaid +sequenceDiagram + User->>+Server: receive + Server-->>-User: ActiveResponse + create participant ActiveResponse + User->ActiveResponse: read_payload + User->>+ActiveResponse: loan + ActiveResponse-->>-User: ResponseMut + create participant ResponseMut + User->>ResponseMut: write_payload + destroy ResponseMut + User->>ResponseMut: send + destroy ActiveResponse + User->>ActiveResponse: drop +``` From 97ff7ee978bfaeb38ed9d52340ae77e044350898 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 24 Jan 2025 18:08:20 +0100 Subject: [PATCH 21/26] [#429] Update user docs and finish static config docs --- doc/user-documentation/request-response.md | 14 +++++ iceoryx2/src/config.rs | 8 +-- .../src/service/builder/request_response.rs | 44 +++++++------- .../service/static_config/request_response.rs | 57 ++++++++++-------- .../service_request_response_builder_tests.rs | 60 +++++++++---------- 5 files changed, 101 insertions(+), 82 deletions(-) diff --git a/doc/user-documentation/request-response.md b/doc/user-documentation/request-response.md index 699e56519..80cfca79f 100644 --- a/doc/user-documentation/request-response.md +++ b/doc/user-documentation/request-response.md @@ -1,5 +1,19 @@ # Request-Response +## Classes Involved In ActiveRequest to ActiveResponse Stream Communication + +User has send request to the server and receives a stream of responses. + +```mermaid +classDiagram + Client "1" --> "1" DataSegment: stores request payload + Server "1" --> "1" DataSegment: stores response payload + Client "1" --> "1..*" ActiveRequest + Server "1" --> "1..*" ActiveResponse + ActiveRequest "1" --> "1" ZeroCopyConnection: receive response + ActiveResponse "1" --> "1" ZeroCopyConnection: send response +``` + ## Sending Request: Client View ```mermaid diff --git a/iceoryx2/src/config.rs b/iceoryx2/src/config.rs index f0de833d6..f9309e76a 100644 --- a/iceoryx2/src/config.rs +++ b/iceoryx2/src/config.rs @@ -294,8 +294,8 @@ pub struct RequestResonse { pub enable_safe_overflow_for_responses: bool, pub max_active_responses: usize, pub max_active_requests: usize, - pub max_borrowed_response_samples: usize, - pub max_borrowed_request_samples: usize, + pub max_borrowed_responses: usize, + pub max_borrowed_requests: usize, pub max_response_buffer_size: usize, pub max_request_buffer_size: usize, pub max_servers: usize, @@ -350,8 +350,8 @@ impl Default for Config { enable_safe_overflow_for_responses: true, max_active_responses: 4, max_active_requests: 2, - max_borrowed_response_samples: 4, - max_borrowed_request_samples: 2, + max_borrowed_responses: 4, + max_borrowed_requests: 2, max_response_buffer_size: 2, max_request_buffer_size: 4, max_servers: 2, diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index a1b5358a8..a0bc46c40 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -228,8 +228,8 @@ pub struct Builder< verify_enable_safe_overflow_for_responses: bool, verify_max_active_responses: bool, verify_max_active_requests: bool, - verify_max_borrowed_response_samples: bool, - verify_max_borrowed_request_samples: bool, + verify_max_borrowed_responses: bool, + verify_max_borrowed_requests: bool, verify_max_response_buffer_size: bool, verify_max_request_buffer_size: bool, verify_max_servers: bool, @@ -259,8 +259,8 @@ impl< verify_enable_safe_overflow_for_responses: false, verify_max_active_responses: false, verify_max_active_requests: false, - verify_max_borrowed_response_samples: false, - verify_max_borrowed_request_samples: false, + verify_max_borrowed_responses: false, + verify_max_borrowed_requests: false, verify_max_response_buffer_size: false, verify_max_request_buffer_size: false, verify_max_servers: false, @@ -372,18 +372,18 @@ impl< /// If the [`Service`] is created it defines how many samples a /// response can borrow at most in parallel. If an existing /// [`Service`] is opened it defines the minimum required. - pub fn max_borrowed_response_samples(mut self, value: usize) -> Self { - self.config_details_mut().max_borrowed_response_samples = value; - self.verify_max_borrowed_response_samples = true; + pub fn max_borrowed_responses(mut self, value: usize) -> Self { + self.config_details_mut().max_borrowed_responses = value; + self.verify_max_borrowed_responses = true; self } /// If the [`Service`] is created it defines how many samples a /// request can borrow at most in parallel. If an existing /// [`Service`] is opened it defines the minimum required. - pub fn max_borrowed_request_samples(mut self, value: usize) -> Self { - self.config_details_mut().max_borrowed_request_samples = value; - self.verify_max_borrowed_request_samples = true; + pub fn max_borrowed_requests(mut self, value: usize) -> Self { + self.config_details_mut().max_borrowed_requests = value; + self.verify_max_borrowed_requests = true; self } @@ -460,16 +460,16 @@ impl< settings.max_active_responses = 1; } - if settings.max_borrowed_response_samples == 0 { + if settings.max_borrowed_responses == 0 { warn!(from origin, "Setting the maximum number of borrowed responses to 0 is not supported. Adjust it to 1, the smallest supported value."); - settings.max_borrowed_response_samples = 1; + settings.max_borrowed_responses = 1; } - if settings.max_borrowed_request_samples == 0 { + if settings.max_borrowed_requests == 0 { warn!(from origin, "Setting the maximum number of borrowed requests to 0 is not supported. Adjust it to 1, the smallest supported value."); - settings.max_borrowed_request_samples = 1; + settings.max_borrowed_requests = 1; } if settings.max_servers == 0 { @@ -552,22 +552,22 @@ impl< msg, existing_configuration.max_active_requests, required_configuration.max_active_requests); } - if self.verify_max_borrowed_response_samples - && existing_configuration.max_borrowed_response_samples - < required_configuration.max_borrowed_response_samples + if self.verify_max_borrowed_responses + && existing_configuration.max_borrowed_responses + < required_configuration.max_borrowed_responses { fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedResponses, "{} since the service supports only {} borrowed responses but {} are required.", - msg, existing_configuration.max_borrowed_response_samples, required_configuration.max_borrowed_response_samples); + msg, existing_configuration.max_borrowed_responses, required_configuration.max_borrowed_responses); } - if self.verify_max_borrowed_request_samples - && existing_configuration.max_borrowed_request_samples - < required_configuration.max_borrowed_request_samples + if self.verify_max_borrowed_requests + && existing_configuration.max_borrowed_requests + < required_configuration.max_borrowed_requests { fail!(from self, with RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedRequests, "{} since the service supports only {} borrowed requests but {} are required.", - msg, existing_configuration.max_borrowed_request_samples, required_configuration.max_borrowed_request_samples); + msg, existing_configuration.max_borrowed_requests, required_configuration.max_borrowed_requests); } if self.verify_max_response_buffer_size diff --git a/iceoryx2/src/service/static_config/request_response.rs b/iceoryx2/src/service/static_config/request_response.rs index 8e8634dae..bfdadd3c5 100644 --- a/iceoryx2/src/service/static_config/request_response.rs +++ b/iceoryx2/src/service/static_config/request_response.rs @@ -21,18 +21,18 @@ //! .request_response::() //! .open_or_create()?; //! -//! println!("type details: {:?}", pubsub.static_config().message_type_details()); -//! println!("max active requests: {:?}", pubsub.static_config().max_active_requests()); -//! println!("max active responses: {:?}", pubsub.static_config().max_active_responses()); -//! println!("max borrowed response samples: {:?}", pubsub.static_config().max_borrowed_response_samples()); -//! println!("max borrowed request samples: {:?}", pubsub.static_config().max_borrowed_request_samples()); -//! println!("max response buffer size: {:?}", pubsub.static_config().max_response_buffer_size()); -//! println!("max request buffer size: {:?}", pubsub.static_config().max_request_buffer_size()); -//! println!("max servers: {:?}", pubsub.static_config().max_clients()); -//! println!("max clients: {:?}", pubsub.static_config().max_servers()); -//! println!("max nodes: {:?}", pubsub.static_config().max_nodes()); -//! println!("request safe overflow: {:?}", pubsub.static_config().has_safe_overflow_for_requests()); -//! println!("response safe overflow: {:?}", pubsub.static_config().has_safe_overflow_for_responses()); +//! println!("type details: {:?}", pubsub.static_config().message_type_details()); +//! println!("max active requests: {:?}", pubsub.static_config().max_active_requests()); +//! println!("max active responses: {:?}", pubsub.static_config().max_active_responses()); +//! println!("max borrowed responses: {:?}", pubsub.static_config().max_borrowed_responses()); +//! println!("max borrowed requests: {:?}", pubsub.static_config().max_borrowed_requests()); +//! println!("max response buffer size: {:?}", pubsub.static_config().max_response_buffer_size()); +//! println!("max request buffer size: {:?}", pubsub.static_config().max_request_buffer_size()); +//! println!("max servers: {:?}", pubsub.static_config().max_clients()); +//! println!("max clients: {:?}", pubsub.static_config().max_servers()); +//! println!("max nodes: {:?}", pubsub.static_config().max_nodes()); +//! println!("request safe overflow: {:?}", pubsub.static_config().has_safe_overflow_for_requests()); +//! println!("response safe overflow: {:?}", pubsub.static_config().has_safe_overflow_for_responses()); //! //! # Ok(()) //! # } @@ -54,8 +54,8 @@ pub struct StaticConfig { pub(crate) enable_safe_overflow_for_responses: bool, pub(crate) max_active_responses: usize, pub(crate) max_active_requests: usize, - pub(crate) max_borrowed_response_samples: usize, - pub(crate) max_borrowed_request_samples: usize, + pub(crate) max_borrowed_responses: usize, + pub(crate) max_borrowed_requests: usize, pub(crate) max_response_buffer_size: usize, pub(crate) max_request_buffer_size: usize, pub(crate) max_servers: usize, @@ -78,14 +78,8 @@ impl StaticConfig { .enable_safe_overflow_for_responses, max_active_responses: config.defaults.request_response.max_active_responses, max_active_requests: config.defaults.request_response.max_active_requests, - max_borrowed_response_samples: config - .defaults - .request_response - .max_borrowed_response_samples, - max_borrowed_request_samples: config - .defaults - .request_response - .max_borrowed_request_samples, + max_borrowed_responses: config.defaults.request_response.max_borrowed_responses, + max_borrowed_requests: config.defaults.request_response.max_borrowed_requests, max_response_buffer_size: config.defaults.request_response.max_response_buffer_size, max_request_buffer_size: config.defaults.request_response.max_request_buffer_size, max_servers: config.defaults.request_response.max_servers, @@ -134,30 +128,41 @@ impl StaticConfig { self.max_active_requests } - pub fn max_borrowed_response_samples(&self) -> usize { - self.max_borrowed_response_samples + /// Returns the maximum number of responses a [`crate::port::client::Client`] can borrow from + /// an active request. + pub fn max_borrowed_responses(&self) -> usize { + self.max_borrowed_responses } - pub fn max_borrowed_request_samples(&self) -> usize { - self.max_borrowed_request_samples + /// Returns the maximum number of requests a [`crate::port::server::Server`] can borrow. + pub fn max_borrowed_requests(&self) -> usize { + self.max_borrowed_requests } + /// Returns the maximum buffer size for responses for an active request. pub fn max_response_buffer_size(&self) -> usize { self.max_response_buffer_size } + /// Returns the maximum buffer size for requests for a [`crate::port::server::Server`]. pub fn max_request_buffer_size(&self) -> usize { self.max_request_buffer_size } + /// Returns the maximum number of supported [`crate::port::server::Server`] ports for the + /// [`crate::service::Service`]. pub fn max_servers(&self) -> usize { self.max_servers } + /// Returns the maximum number of supported [`crate::port::client::Client`] ports for the + /// [`crate::service::Service`]. pub fn max_clients(&self) -> usize { self.max_clients } + /// Returns the maximum number of supported [`crate::node::Node`]s for the + /// [`crate::service::Service`]. pub fn max_nodes(&self) -> usize { self.max_nodes } diff --git a/iceoryx2/tests/service_request_response_builder_tests.rs b/iceoryx2/tests/service_request_response_builder_tests.rs index 78b193335..369e7e6fc 100644 --- a/iceoryx2/tests/service_request_response_builder_tests.rs +++ b/iceoryx2/tests/service_request_response_builder_tests.rs @@ -533,21 +533,21 @@ mod service_request_response { let sut_create = node .service_builder(&service_name) .request_response::() - .max_borrowed_response_samples(10) + .max_borrowed_responses(10) .create(); assert_that!(sut_create, is_ok); let sut_open = node .service_builder(&service_name) .request_response::() - .max_borrowed_response_samples(11) + .max_borrowed_responses(11) .open(); assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedResponses)); let sut_open = node .service_builder(&service_name) .request_response::() - .max_borrowed_response_samples(9) + .max_borrowed_responses(9) .open(); assert_that!(sut_open, is_ok); } @@ -560,21 +560,21 @@ mod service_request_response { let sut_create = node .service_builder(&service_name) .request_response::() - .max_borrowed_request_samples(10) + .max_borrowed_requests(10) .create(); assert_that!(sut_create, is_ok); let sut_open = node .service_builder(&service_name) .request_response::() - .max_borrowed_request_samples(11) + .max_borrowed_requests(11) .open(); assert_that!(sut_open.err(), eq Some(RequestResponseOpenError::DoesNotSupportRequestedAmountOfBorrowedRequests)); let sut_open = node .service_builder(&service_name) .request_response::() - .max_borrowed_request_samples(9) + .max_borrowed_requests(9) .open(); assert_that!(sut_open, is_ok); } @@ -725,8 +725,8 @@ mod service_request_response { .request_response::() .max_active_requests(0) .max_active_responses(0) - .max_borrowed_request_samples(0) - .max_borrowed_response_samples(0) + .max_borrowed_requests(0) + .max_borrowed_responses(0) .max_request_buffer_size(0) .max_response_buffer_size(0) .max_servers(0) @@ -738,8 +738,8 @@ mod service_request_response { assert_that!(sut_create.static_config().max_active_requests(), eq 1); assert_that!(sut_create.static_config().max_active_responses(), eq 1); - assert_that!(sut_create.static_config().max_borrowed_request_samples(), eq 1); - assert_that!(sut_create.static_config().max_borrowed_response_samples(), eq 1); + assert_that!(sut_create.static_config().max_borrowed_requests(), eq 1); + assert_that!(sut_create.static_config().max_borrowed_responses(), eq 1); assert_that!(sut_create.static_config().max_request_buffer_size(), eq 1); assert_that!(sut_create.static_config().max_response_buffer_size(), eq 1); assert_that!(sut_create.static_config().max_servers(), eq 1); @@ -756,8 +756,8 @@ mod service_request_response { rpc_config.enable_safe_overflow_for_responses = true; rpc_config.max_active_requests = 100; rpc_config.max_active_responses = 100; - rpc_config.max_borrowed_request_samples = 100; - rpc_config.max_borrowed_response_samples = 100; + rpc_config.max_borrowed_requests = 100; + rpc_config.max_borrowed_responses = 100; rpc_config.max_request_buffer_size = 100; rpc_config.max_response_buffer_size = 100; rpc_config.max_servers = 100; @@ -773,8 +773,8 @@ mod service_request_response { .enable_safe_overflow_for_responses(false) .max_active_requests(1) .max_active_responses(2) - .max_borrowed_request_samples(3) - .max_borrowed_response_samples(4) + .max_borrowed_requests(3) + .max_borrowed_responses(4) .max_request_buffer_size(5) .max_response_buffer_size(6) .max_servers(7) @@ -784,12 +784,12 @@ mod service_request_response { assert_that!(sut_create, is_ok); let sut_create = sut_create.unwrap(); - assert_that!(sut_create.static_config().enable_safe_overflow_for_requests(), eq false); - assert_that!(sut_create.static_config().enable_safe_overflow_for_responses(), eq false); + assert_that!(sut_create.static_config().has_safe_overflow_for_requests(), eq false); + assert_that!(sut_create.static_config().has_safe_overflow_for_responses(), eq false); assert_that!(sut_create.static_config().max_active_requests(), eq 1); assert_that!(sut_create.static_config().max_active_responses(), eq 2); - assert_that!(sut_create.static_config().max_borrowed_request_samples(), eq 3); - assert_that!(sut_create.static_config().max_borrowed_response_samples(), eq 4); + assert_that!(sut_create.static_config().max_borrowed_requests(), eq 3); + assert_that!(sut_create.static_config().max_borrowed_responses(), eq 4); assert_that!(sut_create.static_config().max_request_buffer_size(), eq 5); assert_that!(sut_create.static_config().max_response_buffer_size(), eq 6); assert_that!(sut_create.static_config().max_servers(), eq 7); @@ -806,8 +806,8 @@ mod service_request_response { rpc_config.enable_safe_overflow_for_responses = true; rpc_config.max_active_requests = 11; rpc_config.max_active_responses = 12; - rpc_config.max_borrowed_request_samples = 13; - rpc_config.max_borrowed_response_samples = 14; + rpc_config.max_borrowed_requests = 13; + rpc_config.max_borrowed_responses = 14; rpc_config.max_request_buffer_size = 15; rpc_config.max_response_buffer_size = 16; rpc_config.max_servers = 17; @@ -823,12 +823,12 @@ mod service_request_response { assert_that!(sut_create, is_ok); let sut_create = sut_create.unwrap(); - assert_that!(sut_create.static_config().enable_safe_overflow_for_requests(), eq true); - assert_that!(sut_create.static_config().enable_safe_overflow_for_responses(), eq true); + assert_that!(sut_create.static_config().has_safe_overflow_for_requests(), eq true); + assert_that!(sut_create.static_config().has_safe_overflow_for_responses(), eq true); assert_that!(sut_create.static_config().max_active_requests(), eq 11); assert_that!(sut_create.static_config().max_active_responses(), eq 12); - assert_that!(sut_create.static_config().max_borrowed_request_samples(), eq 13); - assert_that!(sut_create.static_config().max_borrowed_response_samples(), eq 14); + assert_that!(sut_create.static_config().max_borrowed_requests(), eq 13); + assert_that!(sut_create.static_config().max_borrowed_responses(), eq 14); assert_that!(sut_create.static_config().max_request_buffer_size(), eq 15); assert_that!(sut_create.static_config().max_response_buffer_size(), eq 16); assert_that!(sut_create.static_config().max_servers(), eq 17); @@ -849,8 +849,8 @@ mod service_request_response { .enable_safe_overflow_for_responses(false) .max_active_requests(1) .max_active_responses(2) - .max_borrowed_request_samples(3) - .max_borrowed_response_samples(4) + .max_borrowed_requests(3) + .max_borrowed_responses(4) .max_request_buffer_size(5) .max_response_buffer_size(6) .max_servers(7) @@ -865,12 +865,12 @@ mod service_request_response { .open() .unwrap(); - assert_that!(sut_open.static_config().enable_safe_overflow_for_requests(), eq false); - assert_that!(sut_open.static_config().enable_safe_overflow_for_responses(), eq false); + assert_that!(sut_open.static_config().has_safe_overflow_for_requests(), eq false); + assert_that!(sut_open.static_config().has_safe_overflow_for_responses(), eq false); assert_that!(sut_open.static_config().max_active_requests(), eq 1); assert_that!(sut_open.static_config().max_active_responses(), eq 2); - assert_that!(sut_open.static_config().max_borrowed_request_samples(), eq 3); - assert_that!(sut_open.static_config().max_borrowed_response_samples(), eq 4); + assert_that!(sut_open.static_config().max_borrowed_requests(), eq 3); + assert_that!(sut_open.static_config().max_borrowed_responses(), eq 4); assert_that!(sut_open.static_config().max_request_buffer_size(), eq 5); assert_that!(sut_open.static_config().max_response_buffer_size(), eq 6); assert_that!(sut_open.static_config().max_servers(), eq 7); From 0a37ad0dee915c5b7c370ba0e1c76a8ac5a9c522 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 24 Jan 2025 18:32:13 +0100 Subject: [PATCH 22/26] [#429] Finalize request response documentation --- config/README.md | 28 +++++++++++++++ iceoryx2/src/config.rs | 17 ++++++++- iceoryx2/src/service/builder/mod.rs | 3 ++ .../src/service/builder/request_response.rs | 4 +-- iceoryx2/src/service/dynamic_config/mod.rs | 3 ++ .../dynamic_config/request_response.rs | 28 +++++---------- iceoryx2/src/service/header/mod.rs | 2 ++ .../src/service/header/request_response.rs | 4 +++ iceoryx2/src/service/messaging_pattern.rs | 3 ++ .../service/port_factory/request_response.rs | 35 +++++++++++++++++++ .../service/static_config/request_response.rs | 26 +++++++------- 11 files changed, 117 insertions(+), 36 deletions(-) diff --git a/config/README.md b/config/README.md index c56bf5080..79f8640b0 100644 --- a/config/README.md +++ b/config/README.md @@ -94,3 +94,31 @@ Adjusting `global` settings ensures a non-interfering setup. Expired connection buffer size of the subscriber. Connections to publishers are expired when the publisher disconnected from the service and the connection contains unconsumed samples. + +### Service: Request Response Messaging Pattern + +* `defaults.request-response.enable_safe_overflow_for_requests` - [`true`|`false`]: + Defines if the request buffer of the service safely overflows. +* `defaults.request-response.enable_safe_overflow_for_responses` - [`true`|`false`]: + Defines if the request buffer of the service safely overflows. +* `defaults.request-response.max_active_responses` - [int]: + The maximum of active responses a [`crate::port::server::Server`] can hold in + parallel. +* `defaults.request-response.max_active_requests` - [int]: + The maximum of active requests a client can hold in parallel. +* `defaults.request-response.max_borrowed_responses` - [int]: + The maximum number of responses a client can borrow from an active request. +* `defaults.request-response.max_borrowed_requests` - [int]: + The maximum number of requests a server can borrow. +* `defaults.request-response.max_response_buffer_size` - [int]: + The maximum buffer size for responses for an active request. +* `defaults.request-response.max_request_buffer_size` - [int]: + The maximum buffer size for requests for a server. +* `defaults.request-response.max_servers` - [int]: + The maximum amount of supported servers. +* `defaults.request-response.max_clients` - [int]: + The maximum amount of supported clients. +* `defaults.request-response.max_nodes` - [int]`: + The maximum amount of supported nodess. Defines indirectly how many + processes can open the service at the same time. + diff --git a/iceoryx2/src/config.rs b/iceoryx2/src/config.rs index f9309e76a..237d09052 100644 --- a/iceoryx2/src/config.rs +++ b/iceoryx2/src/config.rs @@ -215,7 +215,7 @@ pub struct Defaults { pub publish_subscribe: PublishSubscribe, /// Default settings for the messaging pattern event pub event: Event, - + /// Default settings for the messaging pattern request-response pub request_response: RequestResonse, } @@ -286,20 +286,35 @@ pub struct Event { pub notifier_dead_event: Option, } +/// Default settings for the request response messaging pattern. These settings are used unless +/// the user specifies custom QoS or port settings. #[non_exhaustive] #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "kebab-case")] pub struct RequestResonse { + /// Defines if the request buffer of the [`Service`] safely overflows. pub enable_safe_overflow_for_requests: bool, + /// Defines if the response buffer of the [`Service`] safely overflows. pub enable_safe_overflow_for_responses: bool, + /// The maximum of active responses a [`crate::port::server::Server`] can hold in parallel. pub max_active_responses: usize, + /// The maximum of active requests a [`crate::port::client::Client`] can hold in parallel. pub max_active_requests: usize, + /// The maximum number of responses a [`crate::port::client::Client`] can borrow from + /// an active request. pub max_borrowed_responses: usize, + /// The maximum number of requests a [`crate::port::server::Server`] can borrow. pub max_borrowed_requests: usize, + /// The maximum buffer size for responses for an active request. pub max_response_buffer_size: usize, + /// The maximum buffer size for requests for a [`crate::port::server::Server`]. pub max_request_buffer_size: usize, + /// The maximum amount of supported [`crate::port::server::Server`] pub max_servers: usize, + /// The maximum amount of supported [`crate::port::client::Client`] pub max_clients: usize, + /// The maximum amount of supported [`crate::node::Node`]s. Defines indirectly how many + /// processes can open the service at the same time. pub max_nodes: usize, } diff --git a/iceoryx2/src/service/builder/mod.rs b/iceoryx2/src/service/builder/mod.rs index 5e0b3e1f8..f061593be 100644 --- a/iceoryx2/src/service/builder/mod.rs +++ b/iceoryx2/src/service/builder/mod.rs @@ -20,6 +20,7 @@ pub mod event; /// Builder for [`MessagingPattern::PublishSubscribe`](crate::service::messaging_pattern::MessagingPattern::PublishSubscribe) pub mod publish_subscribe; +/// Builder for [`MessagingPattern::RequestResponse`](crate::service::messaging_pattern::MessagingPattern::RequestResponse) pub mod request_response; use crate::node::SharedNode; @@ -116,6 +117,8 @@ impl Builder { } } + /// Create a new builder to create a + /// [`MessagingPattern::RequestResponse`](crate::service::messaging_pattern::MessagingPattern::RequestResponse) [`Service`]. pub fn request_response( self, ) -> request_response::Builder { diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index a0bc46c40..699776478 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -10,8 +10,8 @@ // // SPDX-License-Identifier: Apache-2.0 OR MIT -use std::fmt::Debug; -use std::marker::PhantomData; +use core::fmt::Debug; +use core::marker::PhantomData; use crate::prelude::{AttributeSpecifier, AttributeVerifier}; use crate::service::builder::OpenDynamicStorageFailure; diff --git a/iceoryx2/src/service/dynamic_config/mod.rs b/iceoryx2/src/service/dynamic_config/mod.rs index 1560c79d3..608cb02ea 100644 --- a/iceoryx2/src/service/dynamic_config/mod.rs +++ b/iceoryx2/src/service/dynamic_config/mod.rs @@ -20,6 +20,9 @@ pub mod event; /// based service. pub mod publish_subscribe; +/// The dynamic service configuration of an +/// [`MessagingPattern::RequestResponse`](crate::service::messaging_pattern::MessagingPattern::RequestResponse) +/// based service. pub mod request_response; use core::fmt::Display; diff --git a/iceoryx2/src/service/dynamic_config/request_response.rs b/iceoryx2/src/service/dynamic_config/request_response.rs index 8fe0c1030..439d49ec0 100644 --- a/iceoryx2/src/service/dynamic_config/request_response.rs +++ b/iceoryx2/src/service/dynamic_config/request_response.rs @@ -12,7 +12,7 @@ use iceoryx2_bb_container::queue::RelocatableContainer; use iceoryx2_bb_elementary::CallbackProgression; -use iceoryx2_bb_lock_free::mpmc::container::{Container, ContainerHandle, ReleaseMode}; +use iceoryx2_bb_lock_free::mpmc::container::Container; use iceoryx2_bb_log::fatal_panic; use iceoryx2_bb_memory::bump_allocator::BumpAllocator; @@ -41,6 +41,9 @@ pub(crate) struct DynamicConfigSettings { pub number_of_clients: usize, } +/// The dynamic configuration of an +/// [`crate::service::messaging_pattern::MessagingPattern::RequestResponse`] +/// based service. Contains dynamic parameters like the connected endpoints etc.. #[repr(C)] #[derive(Debug)] pub struct DynamicConfig { @@ -70,11 +73,12 @@ impl DynamicConfig { + Container::::memory_size(config.number_of_clients) } + /// Returns how many [`crate::port::client::Client`] ports are currently connected. pub fn number_of_clients(&self) -> usize { self.clients.len() } - /// Returns how many [`crate::port::subscriber::Subscriber`] ports are currently connected. + /// Returns how many [`crate::port::server::Server`] ports are currently connected. pub fn number_of_servers(&self) -> usize { self.servers.len() } @@ -83,8 +87,8 @@ impl DynamicConfig { PortCleanup: FnMut(UniquePortId) -> PortCleanupAction, >( &self, - node_id: &NodeId, - mut port_cleanup_callback: PortCleanup, + _node_id: &NodeId, + mut _port_cleanup_callback: PortCleanup, ) { todo!() } @@ -108,20 +112,4 @@ impl DynamicConfig { CallbackProgression::Continue }); } - - pub(crate) fn add_server(&self, details: ServerDetails) -> Option { - unsafe { self.servers.add(details).ok() } - } - - pub(crate) fn release_server_handle(&self, handle: ContainerHandle) { - unsafe { self.servers.remove(handle, ReleaseMode::Default) }; - } - - pub(crate) fn add_client(&self, details: ClientDetails) -> Option { - unsafe { self.clients.add(details).ok() } - } - - pub(crate) fn release_publisher_handle(&self, handle: ContainerHandle) { - unsafe { self.clients.remove(handle, ReleaseMode::Default) }; - } } diff --git a/iceoryx2/src/service/header/mod.rs b/iceoryx2/src/service/header/mod.rs index 060419b75..1d5690184 100644 --- a/iceoryx2/src/service/header/mod.rs +++ b/iceoryx2/src/service/header/mod.rs @@ -14,4 +14,6 @@ /// [`MessagingPattern::PublishSubscribe`](crate::service::messaging_pattern::MessagingPattern::PublishSubscribe) pub mod publish_subscribe; +/// Payload headers used by +/// [`MessagingPattern::RequestResponse`](crate::service::messaging_pattern::MessagingPattern::RequestResponse) pub mod request_response; diff --git a/iceoryx2/src/service/header/request_response.rs b/iceoryx2/src/service/header/request_response.rs index e799c59ea..6d10a024b 100644 --- a/iceoryx2/src/service/header/request_response.rs +++ b/iceoryx2/src/service/header/request_response.rs @@ -10,10 +10,14 @@ // // SPDX-License-Identifier: Apache-2.0 OR MIT +/// Request header used by +/// [`MessagingPattern::RequestResponse`](crate::service::messaging_pattern::MessagingPattern::RequestResponse) #[derive(Debug, Copy, Clone)] #[repr(C)] pub struct RequestHeader {} +/// Response header used by +/// [`MessagingPattern::RequestResponse`](crate::service::messaging_pattern::MessagingPattern::RequestResponse) #[derive(Debug, Copy, Clone)] #[repr(C)] pub struct ResponseHeader {} diff --git a/iceoryx2/src/service/messaging_pattern.rs b/iceoryx2/src/service/messaging_pattern.rs index df23c7cd6..5f12d341e 100644 --- a/iceoryx2/src/service/messaging_pattern.rs +++ b/iceoryx2/src/service/messaging_pattern.rs @@ -47,5 +47,8 @@ pub enum MessagingPattern { /// Building block to realize push-notifications. Event, + /// Biidirectional communication pattern where the + /// [`Client`](crate::port::client::Client) sends arbitrary data in form of requests to the + /// [`Server`](crate::port::server::Server) and receives a stream of responses. RequestResponse, } diff --git a/iceoryx2/src/service/port_factory/request_response.rs b/iceoryx2/src/service/port_factory/request_response.rs index e74ee756e..73ddd4198 100644 --- a/iceoryx2/src/service/port_factory/request_response.rs +++ b/iceoryx2/src/service/port_factory/request_response.rs @@ -10,6 +10,36 @@ // // SPDX-License-Identifier: Apache-2.0 OR MIT +//! # Example +//! +//! ``` +//! use iceoryx2::prelude::*; +//! +//! # fn main() -> Result<(), Box> { +//! let node = NodeBuilder::new().create::()?; +//! let req_res = node.service_builder(&"My/Funk/ServiceName".try_into()?) +//! .request_response::() +//! .open_or_create()?; +//! +//! println!("name: {:?}", req_res.name()); +//! println!("service id: {:?}", req_res.service_id()); +//! println!("type details: {:?}", req_res.static_config().message_type_details()); +//! println!("max active requests: {:?}", req_res.static_config().max_active_requests()); +//! println!("max active responses: {:?}", req_res.static_config().max_active_responses()); +//! println!("max borrowed responses: {:?}", req_res.static_config().max_borrowed_responses()); +//! println!("max borrowed requests: {:?}", req_res.static_config().max_borrowed_requests()); +//! println!("max response buffer size: {:?}", req_res.static_config().max_response_buffer_size()); +//! println!("max request buffer size: {:?}", req_res.static_config().max_request_buffer_size()); +//! println!("max servers: {:?}", req_res.static_config().max_clients()); +//! println!("max clients: {:?}", req_res.static_config().max_servers()); +//! println!("max nodes: {:?}", req_res.static_config().max_nodes()); +//! println!("request safe overflow: {:?}", req_res.static_config().has_safe_overflow_for_requests()); +//! println!("response safe overflow: {:?}", req_res.static_config().has_safe_overflow_for_responses()); +//! +//! # Ok(()) +//! # } +//! ``` + use iceoryx2_bb_elementary::CallbackProgression; use iceoryx2_cal::dynamic_storage::DynamicStorage; @@ -23,6 +53,11 @@ use crate::{ use super::nodes; +/// The factory for +/// [`MessagingPattern::RequestResponse`](crate::service::messaging_pattern::MessagingPattern::RequestResponse). +/// It can acquire dynamic and static service informations and create +/// [`crate::port::client::Client`] +/// or [`crate::port::server::Server`] ports. #[derive(Debug)] pub struct PortFactory { pub(crate) service: Service, diff --git a/iceoryx2/src/service/static_config/request_response.rs b/iceoryx2/src/service/static_config/request_response.rs index bfdadd3c5..d1c7b23ac 100644 --- a/iceoryx2/src/service/static_config/request_response.rs +++ b/iceoryx2/src/service/static_config/request_response.rs @@ -17,22 +17,22 @@ //! //! # fn main() -> Result<(), Box> { //! let node = NodeBuilder::new().create::()?; -//! let pubsub = node.service_builder(&"My/Funk/ServiceName".try_into()?) +//! let req_res = node.service_builder(&"My/Funk/ServiceName".try_into()?) //! .request_response::() //! .open_or_create()?; //! -//! println!("type details: {:?}", pubsub.static_config().message_type_details()); -//! println!("max active requests: {:?}", pubsub.static_config().max_active_requests()); -//! println!("max active responses: {:?}", pubsub.static_config().max_active_responses()); -//! println!("max borrowed responses: {:?}", pubsub.static_config().max_borrowed_responses()); -//! println!("max borrowed requests: {:?}", pubsub.static_config().max_borrowed_requests()); -//! println!("max response buffer size: {:?}", pubsub.static_config().max_response_buffer_size()); -//! println!("max request buffer size: {:?}", pubsub.static_config().max_request_buffer_size()); -//! println!("max servers: {:?}", pubsub.static_config().max_clients()); -//! println!("max clients: {:?}", pubsub.static_config().max_servers()); -//! println!("max nodes: {:?}", pubsub.static_config().max_nodes()); -//! println!("request safe overflow: {:?}", pubsub.static_config().has_safe_overflow_for_requests()); -//! println!("response safe overflow: {:?}", pubsub.static_config().has_safe_overflow_for_responses()); +//! println!("type details: {:?}", req_res.static_config().message_type_details()); +//! println!("max active requests: {:?}", req_res.static_config().max_active_requests()); +//! println!("max active responses: {:?}", req_res.static_config().max_active_responses()); +//! println!("max borrowed responses: {:?}", req_res.static_config().max_borrowed_responses()); +//! println!("max borrowed requests: {:?}", req_res.static_config().max_borrowed_requests()); +//! println!("max response buffer size: {:?}", req_res.static_config().max_response_buffer_size()); +//! println!("max request buffer size: {:?}", req_res.static_config().max_request_buffer_size()); +//! println!("max servers: {:?}", req_res.static_config().max_clients()); +//! println!("max clients: {:?}", req_res.static_config().max_servers()); +//! println!("max nodes: {:?}", req_res.static_config().max_nodes()); +//! println!("request safe overflow: {:?}", req_res.static_config().has_safe_overflow_for_requests()); +//! println!("response safe overflow: {:?}", req_res.static_config().has_safe_overflow_for_responses()); //! //! # Ok(()) //! # } From 798d775a451e523890966230c9a89c0b67e79288 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 24 Jan 2025 18:43:32 +0100 Subject: [PATCH 23/26] [#429] Fix doc tests --- config/README.md | 15 ++++++++------- config/iceoryx2.toml | 4 ++-- examples/rust/request_response/README.md | 1 - iceoryx2/src/service/builder/request_response.rs | 2 +- .../src/service/port_factory/request_response.rs | 3 ++- .../src/service/static_config/request_response.rs | 3 ++- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/config/README.md b/config/README.md index 79f8640b0..40e754594 100644 --- a/config/README.md +++ b/config/README.md @@ -97,10 +97,12 @@ Adjusting `global` settings ensures a non-interfering setup. ### Service: Request Response Messaging Pattern -* `defaults.request-response.enable_safe_overflow_for_requests` - [`true`|`false`]: - Defines if the request buffer of the service safely overflows. -* `defaults.request-response.enable_safe_overflow_for_responses` - [`true`|`false`]: - Defines if the request buffer of the service safely overflows. +* `defaults.request-response.enable_safe_overflow_for_requests` - + [`true`|`false`]: Defines if the request buffer of the service safely + overflows. +* `defaults.request-response.enable_safe_overflow_for_responses` - + [`true`|`false`]: Defines if the request buffer of the service safely + overflows. * `defaults.request-response.max_active_responses` - [int]: The maximum of active responses a [`crate::port::server::Server`] can hold in parallel. @@ -118,7 +120,6 @@ Adjusting `global` settings ensures a non-interfering setup. The maximum amount of supported servers. * `defaults.request-response.max_clients` - [int]: The maximum amount of supported clients. -* `defaults.request-response.max_nodes` - [int]`: - The maximum amount of supported nodess. Defines indirectly how many +* `defaults.request-response.max_nodes` - [int]: + The maximum amount of supported nodes. Defines indirectly how many processes can open the service at the same time. - diff --git a/config/iceoryx2.toml b/config/iceoryx2.toml index 99e4c3efa..ba08f331b 100644 --- a/config/iceoryx2.toml +++ b/config/iceoryx2.toml @@ -26,8 +26,8 @@ enable-safe-overflow-for-requests = true enable-safe-overflow-for-responses = true max-active-responses = 4 max-active-requests = 2 -max-borrowed-response-samples = 4 -max-borrowed-request-samples = 2 +max-borrowed-responses = 4 +max-borrowed-requests = 2 max-response-buffer-size = 2 max-request-buffer-size = 4 max-servers = 2 diff --git a/examples/rust/request_response/README.md b/examples/rust/request_response/README.md index 2eef01b8c..c51dd1463 100644 --- a/examples/rust/request_response/README.md +++ b/examples/rust/request_response/README.md @@ -1,2 +1 @@ # Request-Response - diff --git a/iceoryx2/src/service/builder/request_response.rs b/iceoryx2/src/service/builder/request_response.rs index 699776478..7ca974701 100644 --- a/iceoryx2/src/service/builder/request_response.rs +++ b/iceoryx2/src/service/builder/request_response.rs @@ -388,7 +388,7 @@ impl< } /// If the [`Service`] is created it defines how many responses fit in the - /// [`Clients`](crate::port::server::Clients)s buffer. If an existing + /// [`Clients`](crate::port::client::Client)s buffer. If an existing /// [`Service`] is opened it defines the minimum required. pub fn max_response_buffer_size(mut self, value: usize) -> Self { self.config_details_mut().max_response_buffer_size = value; diff --git a/iceoryx2/src/service/port_factory/request_response.rs b/iceoryx2/src/service/port_factory/request_response.rs index 73ddd4198..b44870119 100644 --- a/iceoryx2/src/service/port_factory/request_response.rs +++ b/iceoryx2/src/service/port_factory/request_response.rs @@ -23,7 +23,8 @@ //! //! println!("name: {:?}", req_res.name()); //! println!("service id: {:?}", req_res.service_id()); -//! println!("type details: {:?}", req_res.static_config().message_type_details()); +//! println!("request type details: {:?}", req_res.static_config().request_message_type_details()); +//! println!("response type details: {:?}", req_res.static_config().response_message_type_details()); //! println!("max active requests: {:?}", req_res.static_config().max_active_requests()); //! println!("max active responses: {:?}", req_res.static_config().max_active_responses()); //! println!("max borrowed responses: {:?}", req_res.static_config().max_borrowed_responses()); diff --git a/iceoryx2/src/service/static_config/request_response.rs b/iceoryx2/src/service/static_config/request_response.rs index d1c7b23ac..496965f77 100644 --- a/iceoryx2/src/service/static_config/request_response.rs +++ b/iceoryx2/src/service/static_config/request_response.rs @@ -21,7 +21,8 @@ //! .request_response::() //! .open_or_create()?; //! -//! println!("type details: {:?}", req_res.static_config().message_type_details()); +//! println!("request type details: {:?}", req_res.static_config().request_message_type_details()); +//! println!("response type details: {:?}", req_res.static_config().response_message_type_details()); //! println!("max active requests: {:?}", req_res.static_config().max_active_requests()); //! println!("max active responses: {:?}", req_res.static_config().max_active_responses()); //! println!("max borrowed responses: {:?}", req_res.static_config().max_borrowed_responses()); From a425531cb5ab8e0e9c1752ecb8bb0fd81f0a79df Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Sat, 25 Jan 2025 09:31:59 +0100 Subject: [PATCH 24/26] [#429] Code coverage generation script: activate MC/DC coverage only when nightly compiler is available --- internal/scripts/generate-cov-report.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/scripts/generate-cov-report.sh b/internal/scripts/generate-cov-report.sh index c735dede4..1a7b922b0 100755 --- a/internal/scripts/generate-cov-report.sh +++ b/internal/scripts/generate-cov-report.sh @@ -22,7 +22,15 @@ COLOR_YELLOW='\033[1;33m' LLVM_PATH=$(dirname $(which llvm-profdata)) LLVM_PROFILE_PATH="target/debug/llvm-profile-files" export LLVM_PROFILE_FILE="${LLVM_PROFILE_PATH}/iceoryx2-%p-%m.profraw" -export RUSTFLAGS="-C instrument-coverage -Z coverage-options=mcdc" + +if [[ "$(rustc --version | grep nightly | wc -l)" == "1" ]] +then + echo -e "${COLOR_GREEN}rust nightly compiler found, activating MC/DC coverage check${COLOR_OFF}" + export RUSTFLAGS="-C instrument-coverage -Z coverage-options=mcdc" +else + echo -e "${COLOR_YELLOW}no rust nightly compiler found, MC/DC coverage is not available only line coverage${COLOR_OFF}" + export RUSTFLAGS="-C instrument-coverage" +fi COVERAGE_DIR="target/debug/coverage" From b4d268945a727fdf2815e945a6241e68b8598d80 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Sat, 25 Jan 2025 12:21:54 +0100 Subject: [PATCH 25/26] [#429] Add missing enum translation --- iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp | 4 ++++ iceoryx2-ffi/cxx/include/iox2/service_builder_event_error.hpp | 3 +++ .../include/iox2/service_builder_publish_subscribe_error.hpp | 3 +++ iceoryx2-ffi/ffi/src/api/service_builder_event.rs | 2 +- iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs | 2 +- 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp b/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp index 558ab86b1..d18bfaf75 100644 --- a/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp @@ -342,6 +342,8 @@ constexpr auto from(const int value) noexcept return iox2::EventOpenOrCreateError::CreateInsufficientPermissions; case iox2_event_open_or_create_error_e_C_OLD_CONNECTION_STILL_ACTIVE: return iox2::EventOpenOrCreateError::CreateOldConnectionsStillActive; + case iox2_event_open_or_create_error_e_SYSTEM_IN_FLUX: + return iox2::EventOpenOrCreateError::SystemInFlux; } IOX_UNREACHABLE(); @@ -585,6 +587,8 @@ constexpr auto from(const int valu return iox2::PublishSubscribeOpenOrCreateError::CreateHangsInCreation; case iox2_pub_sub_open_or_create_error_e_C_OLD_CONNECTION_STILL_ACTIVE: return iox2::PublishSubscribeOpenOrCreateError::CreateOldConnectionsStillActive; + case iox2_pub_sub_open_or_create_error_e_SYSTEM_IN_FLUX: + return iox2::PublishSubscribeOpenOrCreateError::SystemInFlux; } IOX_UNREACHABLE(); diff --git a/iceoryx2-ffi/cxx/include/iox2/service_builder_event_error.hpp b/iceoryx2-ffi/cxx/include/iox2/service_builder_event_error.hpp index a94509618..dafca5580 100644 --- a/iceoryx2-ffi/cxx/include/iox2/service_builder_event_error.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/service_builder_event_error.hpp @@ -167,6 +167,9 @@ enum class EventOpenOrCreateError : uint8_t { /// [`Sample`] or /// [`SampleMut`] in use. CreateOldConnectionsStillActive, + /// Can occur when another process creates and removes the same [`Service`] repeatedly with a + /// high frequency. + SystemInFlux, }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe_error.hpp b/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe_error.hpp index cf4c5af4a..89c6d6490 100644 --- a/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe_error.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe_error.hpp @@ -174,6 +174,9 @@ enum class PublishSubscribeOpenOrCreateError : uint8_t { /// initialized. Can be caused /// by a process that crashed during [`Service`] creation. CreateHangsInCreation, + /// Can occur when another process creates and removes the same [`Service`] repeatedly with a + /// high frequency. + SystemInFlux, }; } // namespace iox2 diff --git a/iceoryx2-ffi/ffi/src/api/service_builder_event.rs b/iceoryx2-ffi/ffi/src/api/service_builder_event.rs index 7ead475bd..690a8af8c 100644 --- a/iceoryx2-ffi/ffi/src/api/service_builder_event.rs +++ b/iceoryx2-ffi/ffi/src/api/service_builder_event.rs @@ -86,7 +86,7 @@ pub enum iox2_event_open_or_create_error_e { #[CStr = "old connection still active"] C_OLD_CONNECTION_STILL_ACTIVE, #[CStr = "same service is created and removed repeatedly"] - SERVICE_IN_FLUX, + SYSTEM_IN_FLUX, } impl IntoCInt for EventOpenError { diff --git a/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs b/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs index c83d452b4..c4b9f3720 100644 --- a/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs +++ b/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs @@ -93,7 +93,7 @@ pub enum iox2_pub_sub_open_or_create_error_e { #[CStr = "hangs in creation"] C_HANGS_IN_CREATION, #[CStr = "same service is created and removed repeatedly"] - SERVICE_IN_FLUX, + SYSTEM_IN_FLUX, } impl IntoCInt for PublishSubscribeOpenError { From 9f4133968901cbeac1a20990733729d31e55561f Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Tue, 28 Jan 2025 02:37:41 +0100 Subject: [PATCH 26/26] [#429] Replace _ with - --- config/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/config/README.md b/config/README.md index 40e754594..19542a8b3 100644 --- a/config/README.md +++ b/config/README.md @@ -97,29 +97,29 @@ Adjusting `global` settings ensures a non-interfering setup. ### Service: Request Response Messaging Pattern -* `defaults.request-response.enable_safe_overflow_for_requests` - +* `defaults.request-response.enable-safe-overflow-for-requests` - [`true`|`false`]: Defines if the request buffer of the service safely overflows. -* `defaults.request-response.enable_safe_overflow_for_responses` - +* `defaults.request-response.enable-safe-overflow-for-responses` - [`true`|`false`]: Defines if the request buffer of the service safely overflows. -* `defaults.request-response.max_active_responses` - [int]: +* `defaults.request-response.max-active-responses` - [int]: The maximum of active responses a [`crate::port::server::Server`] can hold in parallel. -* `defaults.request-response.max_active_requests` - [int]: +* `defaults.request-response.max-active-requests` - [int]: The maximum of active requests a client can hold in parallel. -* `defaults.request-response.max_borrowed_responses` - [int]: +* `defaults.request-response.max-borrowed-responses` - [int]: The maximum number of responses a client can borrow from an active request. -* `defaults.request-response.max_borrowed_requests` - [int]: +* `defaults.request-response.max-borrowed-requests` - [int]: The maximum number of requests a server can borrow. -* `defaults.request-response.max_response_buffer_size` - [int]: +* `defaults.request-response.max-response-buffer-size` - [int]: The maximum buffer size for responses for an active request. -* `defaults.request-response.max_request_buffer_size` - [int]: +* `defaults.request-response.max-request-buffer-size` - [int]: The maximum buffer size for requests for a server. -* `defaults.request-response.max_servers` - [int]: +* `defaults.request-response.max-servers` - [int]: The maximum amount of supported servers. -* `defaults.request-response.max_clients` - [int]: +* `defaults.request-response.max-clients` - [int]: The maximum amount of supported clients. -* `defaults.request-response.max_nodes` - [int]: +* `defaults.request-response.max-nodes` - [int]: The maximum amount of supported nodes. Defines indirectly how many processes can open the service at the same time.