From c2d4ac8ec20d3c909bd20c3e12dcce310b0cf8ec Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Mon, 25 Mar 2024 14:51:29 -0500 Subject: [PATCH 01/37] Added lease duration to ParticipantLocationBuiltinTopicData --- dds/DCPS/RTPS/DiscoveredEntities.h | 2 ++ dds/DCPS/RTPS/Spdp.cpp | 18 ++++++++++-------- dds/OpenddsDcpsExt.idl | 1 + .../ParticipantLocationListener.java | 5 +++-- .../ParticipantLocationListenerImpl.cpp | 3 ++- .../dds/DCPS/RTPS/DiscoveredEntities.cpp | 2 ++ 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/dds/DCPS/RTPS/DiscoveredEntities.h b/dds/DCPS/RTPS/DiscoveredEntities.h index 2295af67b75..2f929e3ad57 100644 --- a/dds/DCPS/RTPS/DiscoveredEntities.h +++ b/dds/DCPS/RTPS/DiscoveredEntities.h @@ -118,6 +118,8 @@ struct DiscoveredParticipant { location_data_.ice6_timestamp.nanosec = 0; location_data_.relay6_timestamp.sec = 0; location_data_.relay6_timestamp.nanosec = 0; + location_data_.lease_duration.sec = 0; + location_data_.lease_duration.nanosec = 0; #ifdef OPENDDS_SECURITY security_info_.participant_security_attributes = 0; diff --git a/dds/DCPS/RTPS/Spdp.cpp b/dds/DCPS/RTPS/Spdp.cpp index db304256876..54aec880fba 100644 --- a/dds/DCPS/RTPS/Spdp.cpp +++ b/dds/DCPS/RTPS/Spdp.cpp @@ -522,10 +522,16 @@ void Spdp::process_location_updates_i(const DiscoveredParticipantIter& iter, con ACE_DEBUG((LM_DEBUG, "(%P|%t) DEBUG: Spdp::process_location_updates_i: %@ %C has %B location update(s) force_publish=%d reason=%C\n", this, LogGuid(iter->first).c_str(), location_updates.size(), force_publish, reason)); } + const DCPS::TimeDuration leaseDuration = rtps_duration_to_time_duration(iter->second.pdata_.leaseDuration, + iter->second.pdata_.participantProxy.protocolVersion, + iter->second.pdata_.participantProxy.vendorId); + + DCPS::ParticipantLocationBuiltinTopicData& location_data = iter->second.location_data_; + location_data.lease_duration = leaseDuration.to_dds_duration(); + bool published = false; for (DiscoveredParticipant::LocationUpdateList::const_iterator pos = location_updates.begin(), - limit = location_updates.end(); iter != participants_.end() && pos != limit; ++pos) { - DCPS::ParticipantLocationBuiltinTopicData& location_data = iter->second.location_data_; + limit = location_updates.end(); pos != limit; ++pos) { OPENDDS_STRING addr = ""; const DCPS::ParticipantLocation old_mask = location_data.location; @@ -572,12 +578,8 @@ void Spdp::process_location_updates_i(const DiscoveredParticipantIter& iter, con break; } - const DDS::Time_t expr = - ( - pos->timestamp_ - rtps_duration_to_time_duration(iter->second.pdata_.leaseDuration, - iter->second.pdata_.participantProxy.protocolVersion, - iter->second.pdata_.participantProxy.vendorId) - ).to_dds_time(); + const DDS::Time_t expr = (pos->timestamp_ - leaseDuration).to_dds_time(); + if ((location_data.location & DCPS::LOCATION_LOCAL) && DCPS::operator<(location_data.local_timestamp, expr)) { location_data.location &= ~(DCPS::LOCATION_LOCAL); location_data.change_mask |= DCPS::LOCATION_LOCAL; diff --git a/dds/OpenddsDcpsExt.idl b/dds/OpenddsDcpsExt.idl index 8b9f931b0ad..84366fd3f89 100644 --- a/dds/OpenddsDcpsExt.idl +++ b/dds/OpenddsDcpsExt.idl @@ -55,6 +55,7 @@ module OpenDDS DDS::Time_t ice6_timestamp; string relay6_addr; DDS::Time_t relay6_timestamp; + DDS::Duration_t lease_duration; }; const string RTPS_RELAY_STUN_PROTOCOL = "RtpsRelay:STUN"; diff --git a/java/tests/participant_location/ParticipantLocationListener.java b/java/tests/participant_location/ParticipantLocationListener.java index bebee5716cb..28a5225d3c6 100644 --- a/java/tests/participant_location/ParticipantLocationListener.java +++ b/java/tests/participant_location/ParticipantLocationListener.java @@ -48,8 +48,8 @@ public synchronized void on_data_available(DDS.DataReader reader) { } ParticipantLocationBuiltinTopicDataHolder participant = new ParticipantLocationBuiltinTopicDataHolder( - new ParticipantLocationBuiltinTopicData(new byte[16], 0, 0, "", new DDS.Time_t(), "", new DDS.Time_t(), "", - new DDS.Time_t(), "", new DDS.Time_t(), "", new DDS.Time_t(), "", new DDS.Time_t())); + new ParticipantLocationBuiltinTopicData(new byte[16], 0, 0, "", new DDS.Time_t(), "", new DDS.Time_t(), "", + new DDS.Time_t(), "", new DDS.Time_t(), "", new DDS.Time_t(), "", new DDS.Time_t(), new DDS.Duration_t())); SampleInfoHolder si = new SampleInfoHolder( new SampleInfo(0, 0, 0, new DDS.Time_t(), 0, 0, 0, 0, 0, 0, 0, false, 0)); @@ -93,6 +93,7 @@ public synchronized void on_data_available(DDS.DataReader reader) { System.out.println(" : " + participant.value.ice_timestamp.sec); System.out.println(" relay: " + participant.value.relay_addr); System.out.println(" : " + participant.value.relay_timestamp.sec); + System.out.println(" lease: " + participant.value.lease_duration.sec); // update locations if SampleInfo is valid if (si.value.valid_data) { diff --git a/tests/DCPS/ParticipantLocationTopic/ParticipantLocationListenerImpl.cpp b/tests/DCPS/ParticipantLocationTopic/ParticipantLocationListenerImpl.cpp index 3d157de4e86..eb866192995 100644 --- a/tests/DCPS/ParticipantLocationTopic/ParticipantLocationListenerImpl.cpp +++ b/tests/DCPS/ParticipantLocationTopic/ParticipantLocationListenerImpl.cpp @@ -86,7 +86,8 @@ void ParticipantLocationListenerImpl::on_data_available(DDS::DataReader_ptr read << " ice6: " << participant.ice6_addr << std::endl << " : " << participant.ice6_timestamp.sec << std::endl << "relay6: " << participant.relay6_addr << std::endl - << " : " << participant.relay6_timestamp.sec << std::endl; + << " : " << participant.relay6_timestamp.sec << std::endl + << " lease: " << OpenDDS::DCPS::TimeDuration(participant.lease_duration).str(9) << std::endl; // update locations if SampleInfo is valid. if (si.valid_data == 1) diff --git a/tests/unit-tests/dds/DCPS/RTPS/DiscoveredEntities.cpp b/tests/unit-tests/dds/DCPS/RTPS/DiscoveredEntities.cpp index c1256b2c6df..0f53ac3156a 100644 --- a/tests/unit-tests/dds/DCPS/RTPS/DiscoveredEntities.cpp +++ b/tests/unit-tests/dds/DCPS/RTPS/DiscoveredEntities.cpp @@ -83,6 +83,8 @@ TEST(dds_DCPS_RTPS_DiscoveredEntities, DiscoveredParticipant_ctor) EXPECT_EQ(uut.location_data_.ice6_timestamp.nanosec, 0u); EXPECT_EQ(uut.location_data_.relay6_timestamp.sec, 0); EXPECT_EQ(uut.location_data_.relay6_timestamp.nanosec, 0u); + EXPECT_EQ(uut.location_data_.lease_duration.sec, 0); + EXPECT_EQ(uut.location_data_.lease_duration.nanosec, 0u); #ifdef OPENDDS_SECURITY EXPECT_EQ(uut.have_spdp_info_, false); From 240180b14220110a181859502b2c1c0cdb25f2c6 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Mon, 25 Mar 2024 17:20:07 -0500 Subject: [PATCH 02/37] updated docs --- docs/devguide/built_in_topics.rst | 2 ++ docs/news.d/participant-location-duration.rst | 8 ++++++++ 2 files changed, 10 insertions(+) create mode 100644 docs/news.d/participant-location-duration.rst diff --git a/docs/devguide/built_in_topics.rst b/docs/devguide/built_in_topics.rst index 8fa303f4f70..89949c2fcea 100644 --- a/docs/devguide/built_in_topics.rst +++ b/docs/devguide/built_in_topics.rst @@ -253,6 +253,8 @@ The topic type ParticipantLocationBuiltinTopicData is defined in :ghfile:`dds/Op * ``local6_addr``, ``local6_timestamp``, ``ice6_addr``, ``ice6_timestamp``, ``relay6_addr``, and ``relay6_timestamp`` -- Are the IPV6 equivalents. +* ``lease_duration`` -- The remote participant's lease duration (see Lease Duration in :ref:`run_time_configuration--rtps-disc-config-options`) + .. _built_in_topics--openddsconnectionrecord-topic: OpenDDSConnectionRecord Topic diff --git a/docs/news.d/participant-location-duration.rst b/docs/news.d/participant-location-duration.rst new file mode 100644 index 00000000000..87229095535 --- /dev/null +++ b/docs/news.d/participant-location-duration.rst @@ -0,0 +1,8 @@ +.. news-prs: 4545 + +.. news-start-section: Additions +- The data type for the OpenDDS-specific Built-in ParticpiantLocation Topic now includes the lease duration. + + - See :ref:`built_in_topics--openddsparticipantlocation-topic` for details. + +.. news-end-section From 536ffb960868214c20863cf346838378ec113f9c Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Tue, 26 Mar 2024 11:18:03 -0500 Subject: [PATCH 03/37] Update docs/news.d/participant-location-duration.rst Co-authored-by: Son Dinh --- docs/news.d/participant-location-duration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/news.d/participant-location-duration.rst b/docs/news.d/participant-location-duration.rst index 87229095535..25a471d024e 100644 --- a/docs/news.d/participant-location-duration.rst +++ b/docs/news.d/participant-location-duration.rst @@ -1,7 +1,7 @@ .. news-prs: 4545 .. news-start-section: Additions -- The data type for the OpenDDS-specific Built-in ParticpiantLocation Topic now includes the lease duration. +- The data type for the OpenDDS-specific Built-in ParticipantLocation Topic now includes the lease duration. - See :ref:`built_in_topics--openddsparticipantlocation-topic` for details. From dac02d4835fcd4c4fd052257b6564374c8fae843 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Thu, 28 Mar 2024 16:45:26 -0500 Subject: [PATCH 04/37] constify --- dds/idl/marshal_generator.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dds/idl/marshal_generator.cpp b/dds/idl/marshal_generator.cpp index e6c9a62c169..d5588ccbee3 100644 --- a/dds/idl/marshal_generator.cpp +++ b/dds/idl/marshal_generator.cpp @@ -500,7 +500,7 @@ namespace { AST_Type* elem = resolveActualType(seq->base_type()); TryConstructFailAction try_construct = be_global->sequence_element_try_construct(seq); - Classification elem_cls = classify(elem); + const Classification elem_cls = classify(elem); const bool primitive = elem_cls & CL_PRIMITIVE; if (!elem->in_main_file()) { if (elem->node_type() == AST_Decl::NT_pre_defined) { @@ -918,7 +918,7 @@ namespace { AST_Type* elem = resolveActualType(arr->base_type()); TryConstructFailAction try_construct = be_global->array_element_try_construct(arr); - Classification elem_cls = classify(elem); + const Classification elem_cls = classify(elem); const bool primitive = elem_cls & CL_PRIMITIVE; if (!elem->in_main_file() && elem->node_type() != AST_Decl::NT_pre_defined) { @@ -1260,7 +1260,7 @@ namespace { if (type == type_stack[i]) return false; } type_stack.push_back(type); - Classification fld_cls = classify(type); + const Classification fld_cls = classify(type); if ((fld_cls & CL_STRING) && !(fld_cls & CL_BOUNDED)) { bounded = false; } else if (fld_cls & CL_STRUCTURE) { @@ -2477,7 +2477,7 @@ namespace { " if (!" << generate_field_stream( indent, field, ">> stru" + value_access, wrap_nested_key_only, intro) << ") {\n"; AST_Type* const field_type = resolveActualType(field->field_type()); - Classification fld_cls = classify(field_type); + const Classification fld_cls = classify(field_type); if (use_cxx11) { field_name += "()"; @@ -3046,7 +3046,7 @@ marshal_generator::gen_field_getValueFromSerialized(AST_Structure* node, const s const OpenDDS::XTypes::MemberId id = be_global->get_id(field); std::string field_name = field->local_name()->get_string(); AST_Type* const field_type = resolveActualType(field->field_type()); - Classification fld_cls = classify(field_type); + const Classification fld_cls = classify(field_type); cases << " case " << id << ": {\n"; if (fld_cls & CL_SCALAR) { @@ -3131,7 +3131,7 @@ marshal_generator::gen_field_getValueFromSerialized(AST_Structure* node, const s size_t size = 0; const std::string idl_name = canonical_name(field); AST_Type* const field_type = resolveActualType(field->field_type()); - Classification fld_cls = classify(field_type); + const Classification fld_cls = classify(field_type); if (fld_cls & CL_SCALAR) { const std::string cxx_type = to_cxx_type(field_type, size); const std::string val = (fld_cls & CL_STRING) ? (use_cxx11 ? "val" : "val.out()") @@ -3492,7 +3492,7 @@ bool marshal_generator::gen_union(AST_Union* node, UTL_ScopedName* name, NamespaceGuard ng; be_global->add_include("dds/DCPS/Serializer.h"); string cxx = scoped(name); // name as a C++ class - Classification disc_cls = classify(discriminator); + const Classification disc_cls = classify(discriminator); FieldInfo::EleLenSet anonymous_seq_generated; for (size_t i = 0; i < branches.size(); ++i) { From 9835582361331bff0335b16bdbca2a97f037ce46 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Thu, 28 Mar 2024 16:46:19 -0500 Subject: [PATCH 05/37] Update integer type used internally for enums --- dds/idl/dds_generator.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dds/idl/dds_generator.h b/dds/idl/dds_generator.h index e0d9225c240..d09d7a6a9bb 100644 --- a/dds/idl/dds_generator.h +++ b/dds/idl/dds_generator.h @@ -538,7 +538,9 @@ inline std::string to_cxx_type(AST_Type* type, std::size_t& size) const AstTypeClassification::Classification cls = AstTypeClassification::classify(type); if (cls & AstTypeClassification::CL_ENUM) { size = 4; - return "ACE_CDR::ULong"; + // Using the XTypes definition of Enums, this type is signed. + // It contradicts the OMG standard CDR definition. + return "ACE_CDR::Long"; } if (cls & AstTypeClassification::CL_STRING) { return string_type(cls); From cc6d4b55bb1c3cb757cacbd3b527dfeb26d602e2 Mon Sep 17 00:00:00 2001 From: "Justin R. Wilson" Date: Thu, 28 Mar 2024 16:12:50 -0500 Subject: [PATCH 06/37] RtpsUdpDataLink sends nacks when writer has clearly moved on Problem ------- When doing interoperability testing, OpenDDS was observed to send a nack for a sequence number that is no longer available. The offending sequence is 1. Writer sends a HB for [X, X]. 2. OpenDDS Reader sends a NACK for X. 3. Writer sends DATA with sequence number X + 1. 4. Writer sends HB for [X+1, X+1]. 5. OpenDDS Reader sends a NACK for X. OpenDDS should treat X as unavailable. Solution -------- The RtpsUdpDataLink contains a code fragment that handles this case but it is limited to the first heartbeat that was received. Move this code out so that it is processed for each heartbeat. --- dds/DCPS/transport/rtps_udp/RtpsUdpDataLink.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dds/DCPS/transport/rtps_udp/RtpsUdpDataLink.cpp b/dds/DCPS/transport/rtps_udp/RtpsUdpDataLink.cpp index e02921c5dcd..cd3d90cfc20 100644 --- a/dds/DCPS/transport/rtps_udp/RtpsUdpDataLink.cpp +++ b/dds/DCPS/transport/rtps_udp/RtpsUdpDataLink.cpp @@ -1968,7 +1968,13 @@ RtpsUdpDataLink::RtpsReader::process_heartbeat_i(const RTPS::HeartBeatSubmessage log_progress("RTPS reader/writer association complete", id_, writer->id_, writer->participant_discovered_at_); } log_remote_counts("process_heartbeat_i"); + first_ever_hb = true; + } + + ACE_CDR::ULong cumulative_bits_added = 0; + if (!writer->recvd_.empty() || first_ever_hb) { + // "gap" everything before the heartbeat range const SequenceRange sr(zero, hb_first.previous()); writer->recvd_.insert(sr); while (!writer->held_.empty() && writer->held_.begin()->first <= sr.second) { @@ -1978,11 +1984,7 @@ RtpsUdpDataLink::RtpsReader::process_heartbeat_i(const RTPS::HeartBeatSubmessage writer->recvd_.insert(it->first); } link->receive_strategy()->remove_fragments(sr, writer->id_); - first_ever_hb = true; - } - ACE_CDR::ULong cumulative_bits_added = 0; - if (!writer->recvd_.empty()) { writer->hb_last_ = std::max(writer->hb_last_, hb_last); gather_ack_nacks_i(writer, link, !is_final, meta_submessages, cumulative_bits_added); } From 8597d50fd6e07f1b3a061052108b098fd1aee2f2 Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Wed, 7 Feb 2024 07:01:44 -0600 Subject: [PATCH 07/37] Configuration Domain for Sphinx Also refactored the common domain code to make cmake_domain.py simpler. --- docs/conf.py | 1 + docs/internal/docs.rst | 131 ++++++++++- docs/sphinx_extensions/cmake_domain.py | 125 +++-------- docs/sphinx_extensions/config_domain.py | 283 ++++++++++++++++++++++++ docs/sphinx_extensions/custom_domain.py | 240 ++++++++++++-------- 5 files changed, 592 insertions(+), 188 deletions(-) create mode 100644 docs/sphinx_extensions/config_domain.py diff --git a/docs/conf.py b/docs/conf.py index c58b73d6ebb..935c3879a52 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -103,6 +103,7 @@ def setup(app): # Custom ones 'links', 'cmake_domain', + 'config_domain', # Official ones 'sphinx.ext.ifconfig', diff --git a/docs/internal/docs.rst b/docs/internal/docs.rst index 18487f26b6e..ef9c8d0e287 100644 --- a/docs/internal/docs.rst +++ b/docs/internal/docs.rst @@ -308,7 +308,7 @@ CMake Domain For :doc:`/devguide/building/cmake` there's a custom CMake Sphinx domain in :ghfile:`docs/sphinx_extensions/cmake_domain.py`. There is an official CMake domain used by CMake for their own documentation, but it would be impractical for us to use because it requires a separate RST file for every property and variable. -.. rst:directive:: .. cmake:func:: NAME +.. rst:directive:: .. cmake:func:: Use to document public CMake functions. @@ -350,7 +350,7 @@ There is an official CMake domain used by CMake for their own documentation, but This is a keyword argument -.. rst:directive:: .. cmake:func:arg:: NAME [SIGNATURE] +.. rst:directive:: .. cmake:func:arg:: [...] Use to document arguments and options for public CMake functions. Should be nested in :rst:dir:`cmake:func` of the function the argument belongs to. @@ -376,7 +376,7 @@ There is an official CMake domain used by CMake for their own documentation, but :cmake:func:`opendds_cmake_function(ARG)` -.. rst:directive:: .. cmake:var:: NAME +.. rst:directive:: .. cmake:var:: Use to document public variables. @@ -406,7 +406,7 @@ There is an official CMake domain used by CMake for their own documentation, but :cmake:var:`OPENDDS_CMAKE_VARIABLE` -.. rst:directive:: .. cmake:prop:: NAME +.. rst:directive:: .. cmake:prop:: Use to document properties on CMake targets, or possibly other kinds of properties, that we're looking for or creating for the user. @@ -436,7 +436,7 @@ There is an official CMake domain used by CMake for their own documentation, but :cmake:prop:`OPENDDS_CMAKE_PROPERTY` -.. rst:directive:: .. cmake:tgt:: NAME +.. rst:directive:: .. cmake:tgt:: Use to document a library or executable CMake target meant to users that can be imported or exported. @@ -466,6 +466,127 @@ There is an official CMake domain used by CMake for their own documentation, but :cmake:tgt:`OpenDDS::MessengerPigeonTransport` +Config Domain +------------- + +For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphinx domain in :ghfile:`docs/sphinx_extensions/config_domain.py`. + +.. rst:directive:: .. cfg:sec:: [:][/] + + Use to document a configuration section that can contain :rst:dir:`cfg:key` and most other RST content. + ```` is an optional extension of the name to document cases where the available keys depend on something. + Using discriminators requires separate :rst:dir:`cfg:sec` entires. + ```` is just for display and has no restrictions on the contents. + +.. rst:role:: cfg:sec + + Use to reference a :rst:dir:`cfg:sec` by name and optional discriminator. + If the section has a discriminator, it must be separated by a colon. + Do not include arguments if it has arguments in the directive. + +.. rst:directive:: .. cfg:key:: = + + Use to document a configuration key that can contain :rst:dir:`cfg:val` and most other RST content. + ```` describe what sort of text is accepted. + It is just for display and has no restrictions on the contents, but should follow the following syntax conventions to describe the accepted values: + + - ``|`` indicates an OR + - ``[]`` indicates an optional part of the value + - ``...`` indicates the previous part can be repeated + - Words surrounded angle brackets (ex: ````) indicate placeholders. + - Everything else should be considered literal. + + For example: ``log_level=none|error|warn|debug``, ``memory_limit=``, ``addresses=[:],...``. + +.. rst:role:: cfg:key + + Use to reference a :rst:dir:`cfg:val` by name. + Do not include values if it has values in the directive. + +.. rst:directive:: .. cfg:val:: [<][>] + + Use to document a part of what a configuration key accepts. + The optional angle brackets (``<>``) are just for display and are meant to help distinguish between the value being a literal and a placeholder. + +.. rst:role:: cfg:val + + Use to reference a :rst:dir:`cfg:val` by name. + Do not include brackets if it has brackets in the directive. + +Example +^^^^^^^ + +This is a example made up for the following INI file: + +.. code-block:: ini + + [server/Alpha] + os=windows + + [server/Beta] + os=linux + distro=Debian + +.. code-block:: rst + + Outside their sections, references to keys and values must be complete: :cfg:val:`server.os.linux`, :cfg:key:`server:linux.distro` + + .. cfg:sec:: server/ + + A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os.windows` + + .. cfg:key:: os=windows|linux + + A value's key can be omitted from references within their keys: :cfg:val:`linux` + + .. cfg:val:: windows + + Implied titles will be shortened within their scopes: :cfg:key:`server.os`, :cfg:val:`server.os.windows` + + .. cfg:val:: linux + + Sections with discriminators require them in the reference targets: cfg:sec:`server:linux`, :cfg:key:`server:linux.distro` + + .. cfg:sec:: server:linux/ + + .. cfg:key:: distro= + +Turns into: + + Outside their sections, references to keys and values must be complete: :cfg:val:`server.os.linux`, :cfg:key:`server:linux.distro` + + .. cfg:sec:: server/ + :no-contents-entry: + :no-index-entry: + + A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os.windows` + + .. cfg:key:: os=windows|linux + :no-contents-entry: + :no-index-entry: + + A value's key can be omitted from references within their keys: :cfg:val:`linux` + + .. cfg:val:: windows + :no-contents-entry: + :no-index-entry: + + Implied titles will be shortened within their scopes: :cfg:key:`server.os`, :cfg:val:`server.os.windows` + + .. cfg:val:: linux + :no-contents-entry: + :no-index-entry: + + Sections with discriminators require them in the reference targets: :cfg:sec:`server:linux`, :cfg:key:`server:linux.distro` + + .. cfg:sec:: server:linux/ + :no-contents-entry: + :no-index-entry: + + .. cfg:key:: distro= + :no-contents-entry: + :no-index-entry: + .. _docs-news: **** diff --git a/docs/sphinx_extensions/cmake_domain.py b/docs/sphinx_extensions/cmake_domain.py index a608545bcf8..18bd224aeb9 100644 --- a/docs/sphinx_extensions/cmake_domain.py +++ b/docs/sphinx_extensions/cmake_domain.py @@ -10,118 +10,63 @@ from sphinx import addnodes from sphinx.addnodes import desc_signature from sphinx.application import Sphinx -from sphinx.domains import ObjType -from sphinx.locale import _, __ -from sphinx.roles import XRefRole from sphinx.util import logging -from custom_domain import CustomDomain, CustomDomainObject, CustomDomainParentObject +from custom_domain import CustomDomain, CustomDomainObject -class CMakeDomainObject(CustomDomainObject): - @classmethod - def domain_name(cls): - return 'cmake' - - -class CMakeFunction(CMakeDomainObject, CustomDomainParentObject): - @classmethod - def use_name(cls): - return 'func' - - @classmethod - def index_discriminator(cls): - return 'CMake function' - - @classmethod - def parent_category(cls): - return 'function' - +class CMakeDomain(CustomDomain): + name = 'cmake' + label = 'CMake' + logger = logging.getLogger(__name__) -class CMakeFunctionArgument(CMakeDomainObject): - @classmethod - def use_name(cls): - return 'func:arg' - @classmethod - def index_discriminator(cls): - return 'CMake function argument' +@CMakeDomain.add_type +class CMakeFunction(CustomDomainObject): + our_name = 'func' + our_index_discriminator = 'CMake function' - @classmethod - def parent_class(cls): - return True, CMakeFunction - def link_name(cls, name, parents): - return f'{parents[-1][0]}({name})' +@CMakeDomain.add_type +class CMakeFunctionArgument(CustomDomainObject): + our_name = 'func:arg' + our_index_discriminator = 'CMake function argument' + our_parent_required = True + our_parent_type = CMakeFunction + # Use the :func: role for this + our_role_name = 'func' + our_ref_role_type = None - def handle_signature(self, sig: str, signode: desc_signature) -> str: + def parse_sig(self, ctx, sig): try: - name, arguments = re.split(r'\s+', sig.strip()) + name, arguments = re.split(r'\s+', sig) except ValueError: name, arguments = sig, None + ctx.push(self, name, ctx.get_full_name() + f'({name})') + return arguments, - signode['fullname'] = name.strip() + def create_signode(self, ctx, name, signode, arguments): signode += addnodes.desc_name(name, name) if arguments: signode += addnodes.desc_annotation(' ' + arguments, ' ' + arguments) - return name - - -class CMakeVariable(CMakeDomainObject): - @classmethod - def use_name(cls): - return 'var' - @classmethod - def index_discriminator(cls): - return 'CMake variable' +@CMakeDomain.add_type +class CMakeVariable(CustomDomainObject): + our_name = 'var' + our_index_discriminator = 'CMake variable' -class CMakeProperty(CMakeDomainObject): - @classmethod - def use_name(cls): - return 'prop' - @classmethod - def index_discriminator(cls): - return 'CMake property' +@CMakeDomain.add_type +class CMakeProperty(CustomDomainObject): + our_name = 'prop' + our_index_discriminator = 'CMake property' -class CMakeTarget(CMakeDomainObject): - @classmethod - def use_name(cls): - return 'tgt' - - @classmethod - def index_discriminator(cls): - return 'CMake target' - - -class CMakeDomain(CustomDomain): - name = 'cmake' - label = 'CMake' - logger = logging.getLogger(__name__) - - object_types = { - 'func': ObjType(_('func'), 'func'), - 'func:arg': ObjType(_('func-arg'), 'func'), - 'var': ObjType(_('var'), 'var'), - 'prop': ObjType(_('prop'), 'prop'), - 'tgt': ObjType(_('tgt'), 'tgt'), - } - directives = { - 'func': CMakeFunction, - 'func:arg': CMakeFunctionArgument, - 'var': CMakeVariable, - 'prop': CMakeProperty, - 'tgt': CMakeTarget, - } - roles = { - 'func': XRefRole(), - 'var': XRefRole(), - 'prop': XRefRole(), - 'tgt': XRefRole(), - } +@CMakeDomain.add_type +class CMakeTarget(CustomDomainObject): + our_name = 'tgt' + index_discriminator = 'CMake target' def setup(app: Sphinx) -> dict[str, Any]: diff --git a/docs/sphinx_extensions/config_domain.py b/docs/sphinx_extensions/config_domain.py new file mode 100644 index 00000000000..7098e923d6d --- /dev/null +++ b/docs/sphinx_extensions/config_domain.py @@ -0,0 +1,283 @@ +# Sphinx Domain for Configuration Values +# Pass -vv to sphinx-build to get it to log the directives it's getting. + +from __future__ import annotations + +import sys +import re +from typing import Any +import re + +from docutils import nodes + +from sphinx import addnodes +from sphinx.application import Sphinx +from sphinx.util import logging +from sphinx.roles import XRefRole + +from custom_domain import CustomDomain, CustomDomainObject, ContextWrapper + + +class ConfigDomain(CustomDomain): + name = 'cfg' + label = 'config' + logger = logging.getLogger(__name__) + + +def parse(what, regex, string, node, *ret): + m = re.fullmatch(regex, string) + if not m: + if node is None: + return None + else: + e = ValueError(f'{repr(string)} isn\'t a valid value for a {what}') + ConfigDomain.logger.warning(e, location=node.get_location()) + raise e + if ret: + groups = m.groupdict() + return [groups[name] for name in ret] + return m.groups() + + +# cfg:sec ===================================================================== + +section_re = r'(?P\w+)(?::(?P\w+))?' + + +def parse_section_name(full_name, node=None): + return parse(ConfigSection._full_name, section_re, full_name, node, + 'sec_name', 'sec_disc') + + +def section_text(sec_name, sec_disc, insert=''): + text = f'[{sec_name}]{insert}' + if sec_disc: + text += f' ({sec_disc})' + return text + + +class ConfigSectionRefRole(XRefRole): + def process_link(self, env: BuildEnvironment, refnode: Element, + has_explicit_title: bool, title: str, target: str) -> tuple[str, str]: + target = target.strip() + if not has_explicit_title: + sec_name, sec_disc = parse_section_name(target, self) + title = section_text(sec_name, sec_disc) + return title, target + + +@ConfigDomain.add_type +class ConfigSection(CustomDomainObject): + our_name = 'sec' + our_ref_role_type = ConfigSectionRefRole + + def get_index_text(self, name, full_name): + sec_name, sec_disc = parse_section_name(name) + if sec_disc: + sec_disc += ' ' + else: + sec_disc = '' + return f'{sec_name} ({sec_disc}config section)' + + def parse_sig(self, ctx, sig): + name, arguments = parse(self._full_name, r'(\w+(?::\w+)?)(?:/(.*))?', sig, self) + sec_name, sec_disc = parse_section_name(name) + ctx.push(self, name, sec_name=sec_name, sec_disc=sec_name, arguments=arguments) + return (sec_name, sec_disc, arguments) + + def create_signode(self, ctx, name, signode, sec_name, sec_disc, arguments): + signode += addnodes.desc_addname('[', '[') + signode += addnodes.desc_name(sec_name, sec_name) + if arguments: + text = '/' + arguments + signode += addnodes.desc_addname(text, text) + signode += addnodes.desc_addname(']', ']') + if sec_disc: + text = f' ({sec_disc})' + signode += addnodes.desc_annotation(text, text) + + +# cfg:key ===================================================================== + +key_re = r'(?:(?P' + section_re + ')\.)?(?P\w+)' + + +def parse_key_name(full_name, node=None): + return parse(ConfigKey._full_name, key_re, full_name, node, + 'sec', 'sec_name', 'sec_disc', 'key_name') + + +def key_text(sec_name, sec_disc, key_name, insert=''): + text = key_name + insert + if sec_name is not None: + text = section_text(sec_name, sec_disc, '.' + text) + return text + + +class ConfigKeyRefRole(XRefRole): + def process_link(self, env: BuildEnvironment, refnode: Element, + has_explicit_title: bool, title: str, target: str) -> tuple[str, str]: + ctx = ContextWrapper(env, 'cfg') + target = target.strip() + + # Normalize target for the current scope + sec, sec_name, sec_disc, key_name = parse_key_name(target, self) + scope_kind = len(ctx.stack) + if sec is not None: + # sec.key anywhere + pass + elif scope_kind >= 1: + # key anywhere in a section + prefix = ctx.get_full_name(0) + target = f'{prefix}.{target}' + else: + ConfigDomain.logger.warning(f'{repr(target)} is an invalid target here', + location=self.get_location()) + + if not has_explicit_title: + # Reparse target and hide parts of title that are in the current scope + sec, sec_name, sec_disc, key_name = parse_key_name(target, self) + scope = ctx.get_all_names() + scope = scope + [None] * (2 - len(scope)) + if scope[0] == sec: + sec_name = None + + title = key_text(sec_name, sec_disc, key_name) + + return title, target + + +@ConfigDomain.add_type +class ConfigKey(CustomDomainObject): + our_name = 'key' + our_parent_required = True + our_parent_type = ConfigSection + our_ref_role_type = ConfigKeyRefRole + + def get_index_text(self, name, full_name): + sec, sec_name, sec_disc, key = parse_key_name(full_name) + return f'{key} (config key)' + + def parse_sig(self, ctx, sig): + name, arguments = parse(self._full_name, r'(\w+)(?:=(.*))?', sig, self) + ctx.push(self, name, ctx.get_full_name() + f'.{name}', arguments=arguments) + return (arguments,) + + def create_signode(self, ctx, name, signode, arguments): + signode += addnodes.desc_name(name, name) + if arguments is not None: + text = '=' + arguments + signode += addnodes.desc_addname(text, text) + + def transform_content(self, contentnode: addnodes.desc_content) -> None: + ctx = self.get_context() + + # Insert the config store key at the top of the content + p = nodes.paragraph() + contentnode.insert(0, p) + text = 'Config store key: ' + p += nodes.inline(text, text) + text = ctx.get(-2, 'sec_name').upper() + '_' + sec_args = ctx.get(-2, 'arguments') + if sec_args: + text += sec_args + '_' + text += ctx.get_name().upper() + p += nodes.literal(text, text) + + +# cfg:val ===================================================================== + +value_re = r'(?:(?P' + key_re + ')\.)?(?P\w+)' + + +def parse_value_name(full_name, node=None): + return parse(ConfigValue._full_name, value_re, full_name, node, + 'sec', 'sec_name', 'sec_disc', 'key', 'key_name', 'val_name') + + +def value_text(sec_name, sec_disc, key_name, val_name): + text = val_name + if key_name is not None: + text = key_text(sec_name, sec_disc, key_name, '.' + text) + return text + + +class ConfigValueRefRole(XRefRole): + def process_link(self, env: BuildEnvironment, refnode: Element, + has_explicit_title: bool, title: str, target: str) -> tuple[str, str]: + ctx = ContextWrapper(env, 'cfg') + target = target.strip() + + # Normalize target for the current scope + sec, sec_name, sec_disc, key, key_name, val_name = parse_value_name(target, self) + scope_kind = len(ctx.stack) + if sec is not None: + # sec.key.val anywhere + pass + elif scope_kind >= 1 and key is not None: + # key.val anywhere in a section + prefix = ctx.get_full_name(0) + target = f'{prefix}.{target}' + elif scope_kind >= 2 and key is None: + # val anywhere in a key + prefix = ctx.get_full_name(1) + target = f'{prefix}.{target}' + else: + ConfigDomain.logger.warning(f'{repr(target)} is an invalid target here', + location=self.get_location()) + + if not has_explicit_title: + # Reparse target and hide parts of title that are in the current scope + sec, sec_name, sec_disc, key, key_name, val_name = parse_value_name(target, self) + scope = ctx.get_all_names() + scope = scope + [None] * (3 - len(scope)) + if scope[0] == sec: + sec_name = None + if scope[1] == key_name: + key_name = None + + title = value_text(sec_name, sec_disc, key_name, val_name) + + return title, target + + +@ConfigDomain.add_type +class ConfigValue(CustomDomainObject): + our_name = 'val' + our_parent_required = True + our_parent_type = ConfigKey + our_ref_role_type = ConfigValueRefRole + + def run(self): + # Values should probably never appear on the index or the page TOC + self.options['no-contents-entry'] = '' + self.options['no-index-entry'] = '' + return super().run() + + def get_index_text(self, name, full_name): + sec, sec_name, sec_disc, key, key_name, val_name = parse_value_name(full_name, self) + return f'{val_name} (config value)' + + def parse_sig(self, ctx, sig): + name_wo_brackets, name_w_brackets = parse(self._full_name, r'(\w+)|<(\w+)>', sig, self) + brackets = bool(name_w_brackets) + name = name_w_brackets if brackets else name_wo_brackets + ctx.push(self, name, ctx.get_full_name() + f'.{name}') + return (brackets,) + + def create_signode(self, ctx, name, signode, brackets): + if brackets: + signode += addnodes.desc_addname('<', '<') + signode += addnodes.desc_name(name, name) + if brackets: + signode += addnodes.desc_addname('>', '>') + + +def setup(app: Sphinx) -> dict[str, Any]: + app.add_domain(ConfigDomain) + + return { + 'version': '0.1', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/docs/sphinx_extensions/custom_domain.py b/docs/sphinx_extensions/custom_domain.py index 939efcccfeb..92783e48828 100644 --- a/docs/sphinx_extensions/custom_domain.py +++ b/docs/sphinx_extensions/custom_domain.py @@ -11,9 +11,67 @@ from sphinx.directives import ObjectDescription from sphinx.util.nodes import make_id, make_refnode, process_index_entry from sphinx.util.typing import OptionSpec -from sphinx.domains import Domain +from sphinx.domains import Domain, ObjType from sphinx.environment import BuildEnvironment from sphinx.builders import Builder +from sphinx.roles import XRefRole + + +class ContextWrapper: + def __init__(self, env, domain): + self.ctx = env.ref_context.setdefault(f'{domain}-context', dict( + stack=[], + needs_push=True, + )) + + def needs_push(self): + return self.ctx['needs_push'] + + def reset_needs_push(self): + self.ctx['needs_push'] = True + + @property + def stack(self): + return self.ctx['stack'] + + def push(self, obj, name, full_name=None, **kw): + data = dict( + obj=obj, + name=name, + full_name=name if full_name is None else full_name, + index_text=None, + **kw + ) + self.stack.append(data) + self.ctx['needs_push'] = False + data['index_text'] = obj.get_index_text(name, full_name) + return data + + def pop(self): + self.stack.pop() + self.reset_needs_push() + + def get_all_names(self): + return [scope['name'] for scope in self.stack] + + def get(self, index, key=None): + try: + frame = self.stack[index] + except IndexError: + return None + return frame if key is None else frame[key] + + def get_parent(self, index=-2): + return self.get(index) + + def get_name(self, index=-1): + return self.get(index, 'name') + + def get_full_name(self, index=-1): + return self.get(index, 'full_name') + + def get_index_text(self, index=-1): + return self.get(index, 'index_text') class CustomDomainObject(ObjectDescription[str]): @@ -23,126 +81,100 @@ class CustomDomainObject(ObjectDescription[str]): 'no-contents-entry': directives.flag, # This is implemented by Sphinx } - @classmethod - def domain_name(cls): - raise NotImplementedError() - - @classmethod - def use_name(cls): - raise NotImplementedError() - - @classmethod - def index_discriminator(cls): - raise NotImplementedError() + our_name = None + our_index_discriminator = None + our_parent_required = False + our_parent_type = None + our_ref_role_type = XRefRole + our_role_name = None + _full_name = None + _domain_name = None + + def get_index_text(self, name, full_name): + t = name + if self.our_index_discriminator is None: + t += f' ({self.index_discriminator})' + return t + + def get_context(self): + return ContextWrapper(self.env, self._domain_name) + + def check_parentage(self): + domain = self.env.get_domain(self._domain_name) + parent = self.get_context().get_parent() + if self.our_parent_required and (parent is None or + not isinstance(parent['obj'], self.our_parent_type)): + e = ValueError(f'{self._full_name} must be in a {self.our_parent_type._full_name}') + domain.logger.warning(e, location=self.get_location()) + raise e - @classmethod - def parent_class(cls): - '''Returns if the parent is required and the class - ''' - return False, None - - def link_name(cls, name, parents): - '''Returns the default text used when linking - ''' - return name + def parse_sig(self, ctx, sig): + ctx.push(self, sig) + return () - def handle_signature(self, sig: str, signode: desc_signature) -> str: - '''Returns the header node for the defintion. It can be modifed to - serperate things like arguments. - ''' - name = sig.strip() - signode['fullname'] = name + def create_signode(self, ctx, name, signode): signode += addnodes.desc_name(name, name) - return name - @classmethod - def use_full_name(cls): - return cls.domain_name() + ':' + cls.use_name() + def handle_signature(self, sig: str, signode: desc_signature) -> str: + domain = self.env.get_domain(self._domain_name) + ctx = self.get_context() - def get_context(self, key): - return self.env.ref_context.setdefault(key, []) + try: + extra = self.parse_sig(ctx, sig.strip()) + except Exception as e: + domain.logger.exception('Exception in parse_sig:', location=self.get_location()) + raise e - def get_parents(self): - required, parent_class = self.parent_class() - if parent_class is None: - parents = [] - else: - parents = self.get_context(parent_class.parents_key()) - if required and parent_class and not parents: - domain = self.env.get_domain(self.domain_name()) - e = ValueError('Domain object is required to be in a ' + parent_class.use_full_name()) - domain.logger.warning(e, location=self.get_location()) + self.check_parentage() + signode['fullname'] = ctx.get_full_name() + name = ctx.get_name() + try: + self.create_signode(ctx, name, signode, *extra) + except Exception as e: + domain.logger.exception('Exception in create_signode:', location=self.get_location()) raise e - return parents - def get_index_text(self, objectname: str, name: str) -> str: - return _('{} ({})').format(name, self.index_discriminator()) + return name + + def _object_hierarchy_parts(self, signode: desc_signature) -> tuple[str, ...]: + return tuple(self.get_context().get_all_names()) + + def _toc_entry_name(self, signode: desc_signature) -> str: + *parents, name = signode['_toc_parts'] + return name def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None: - domain = self.env.get_domain(self.domain_name()) + domain = self.env.get_domain(self._domain_name) + ctx = self.get_context() # Create the reference target - parents = self.get_parents() - prefix_list = [self.objtype] - prefix_list.extend([x[0] for x in parents]) + prefix_list = [self._domain_name, self.objtype] + prefix_list.extend(ctx.get_all_names()) + prefix_list.pop() prefix = '-'.join(prefix_list) node_id = make_id(self.env, self.state.document, prefix, name) # Register reference target signode['ids'].append(node_id) self.state.document.note_explicit_target(signode) - domain.note_object(self.objtype, self.link_name(name, parents), node_id, location=signode) + full_name = ctx.get_full_name() + domain.note_object(self.objtype, full_name, node_id, location=signode) if 'no-index-entry' not in self.options: - indextext = self.get_index_text(self.objtype, name) + indextext = ctx.get_index_text() if indextext: - if parents: - parent_name = parents[-1][0] - parent = parents[-1][1] - parent_indextext = parent.get_index_text(parent_name, parent_name) + parent = ctx.get_parent() + if parent: + parent_indextext = parent['index_text'] entry = process_index_entry(f'pair: {indextext}; {parent_indextext}', node_id) else: entry = process_index_entry(indextext, node_id) self.indexnode['entries'].extend(entry) - def _object_hierarchy_parts(self, sig_node: desc_signature) -> tuple[str, ...]: - if 'fullname' not in sig_node: - return () - parts = [x[0] for x in self.get_parents()] - parts.append(sig_node['fullname']) - return tuple(parts) - - def _toc_entry_name(self, sig_node: desc_signature) -> str: - if not sig_node.get('_toc_parts'): - return '' - - config = self.env.app.config - objtype = sig_node.parent.get('objtype') - *parents, name = sig_node['_toc_parts'] - return name - - -class CustomDomainParentObject(CustomDomainObject): - @classmethod - def parent_category(cls): - raise NotImplementedError() - - @classmethod - def parents_key(cls): - return cls.domain_name() + ':' + cls.parent_category() - - def get_parents(self): - return self.get_context(self.parents_key()) - - def handle_signature(self, sig: str, signode: desc_signature) -> str: - name = super().handle_signature(sig, signode) - self._append_parents_in_before_content = (name, self) - return name - def before_content(self) -> None: - self.get_parents().append(self._append_parents_in_before_content) + self.get_context().reset_needs_push() def after_content(self) -> None: - self.get_parents().pop() + self.get_context().pop() class CustomDomain(Domain): @@ -212,3 +244,25 @@ def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Bui def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]: for (typ, name), (docname, node_id) in self.data['objects'].items(): yield name, name, typ, docname, node_id, 1 + + @classmethod + def add_type(cls, Type): + if Type.our_name is None: + raise ValueError(f'{Type.__name__} is missing our_name') + if Type.our_parent_required and Type.our_parent_type is None: + raise ValueError( + f'{Type.__name__} has our_parent_required = True, but our_parent_type = None') + + Type._full_name = f'{cls.name}:{Type.our_name}' + Type._domain_name = cls.name + cls.directives[Type.our_name] = Type + if Type.our_ref_role_type is not None: + cls.roles[Type.our_name] = Type.our_ref_role_type() + if Type.our_role_name is None: + role_name = Type.our_name + else: + role_name = Type.our_role_name + obj_type = ObjType(Type.our_name.replace(':', '-'), role_name) + cls.object_types[Type.our_name] = obj_type + + return Type From 153f100c386b85beb06ff2e5480e826358d459e5 Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Tue, 13 Feb 2024 00:41:03 -0600 Subject: [PATCH 08/37] Revise and Improve Config Domain Also add testing for Sphinx code. --- docs/build.py | 16 ++- docs/internal/docs.rst | 67 ++++++++-- docs/sphinx_extensions/config_domain.py | 164 ++++++++++++++++++++---- docs/sphinx_extensions/custom_domain.py | 7 +- docs/sphinx_extensions/newsd.py | 77 ++++++----- 5 files changed, 248 insertions(+), 83 deletions(-) diff --git a/docs/build.py b/docs/build.py index 32dea73b695..85c4b9c150b 100755 --- a/docs/build.py +++ b/docs/build.py @@ -31,7 +31,8 @@ def log(*args, **kwargs): class DocEnv: - def __init__(self, venv_path, build_path, gh_links_commit=None, conf_defines=None): + def __init__(self, venv_path, build_path, + gh_links_commit=None, conf_defines=None, debug=False): self.venv_path = Path(venv_path) self.abs_venv_path = self.venv_path.resolve() self.bin_path = self.abs_venv_path / 'bin' @@ -42,6 +43,7 @@ def __init__(self, venv_path, build_path, gh_links_commit=None, conf_defines=Non self.conf_defines.extend(conf_defines) if gh_links_commit is not None: self.conf_defines.append('github_links_commitish=' + gh_links_commit) + self.debug = debug self.done = set() def run(self, *cmd, cwd=abs_docs_path): @@ -82,6 +84,8 @@ def sphinx_build(self, builder, *args): args = list(args) for define in self.conf_defines: args.append('-D' + define) + if self.debug: + args.append('-vv') self.run('sphinx-build', '-M', builder, '.', str(self.abs_build_path), *args) def do(self, actions, because_of=None, open_result=False): @@ -104,7 +108,15 @@ def do(self, actions, because_of=None, open_result=False): def all_actions(cls): return [k[3:] for k, v in vars(cls).items() if k.startswith('do_')] + def do_test(self): + self.run('python3', '-m', 'unittest', 'discover', '--verbose', + '--start-directory', 'sphinx_extensions', + '--pattern', '*.py', + cwd=abs_docs_path) + return None + def do_strict(self): + self.do(['test'], because_of='strict') self.sphinx_build('dummy', '-W') self.sphinx_build('linkcheck') return None @@ -162,12 +174,14 @@ def do_markdown(self): action='append', help='Passed to sphinx-build to override conf.py values.' ) + arg_parser.add_argument('-d', '--debug', action='store_true') args = arg_parser.parse_args() doc_env = DocEnv( venv_path=args.venv, build_path=args.build, gh_links_commit=args.gh_links_commit, conf_defines=args.conf_defines, + debug=args.debug, ) doc_env.setup() doc_env.do(args.actions, open_result=args.open) diff --git a/docs/internal/docs.rst b/docs/internal/docs.rst index ef9c8d0e287..c748e241f64 100644 --- a/docs/internal/docs.rst +++ b/docs/internal/docs.rst @@ -471,7 +471,7 @@ Config Domain For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphinx domain in :ghfile:`docs/sphinx_extensions/config_domain.py`. -.. rst:directive:: .. cfg:sec:: [:][/] +.. rst:directive:: .. cfg:sec:: [@][/] Use to document a configuration section that can contain :rst:dir:`cfg:key` and most other RST content. ```` is an optional extension of the name to document cases where the available keys depend on something. @@ -481,12 +481,14 @@ For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphin .. rst:role:: cfg:sec Use to reference a :rst:dir:`cfg:sec` by name and optional discriminator. - If the section has a discriminator, it must be separated by a colon. + If the section has a discriminator, it must be separated by a ``@`` symbol. Do not include arguments if it has arguments in the directive. + The possible formats are ```` and ``@``. .. rst:directive:: .. cfg:key:: = Use to document a configuration key that can contain :rst:dir:`cfg:val` and most other RST content. + Must be in a :rst:dir:`cfg:sec`. ```` describe what sort of text is accepted. It is just for display and has no restrictions on the contents, but should follow the following syntax conventions to describe the accepted values: @@ -498,20 +500,51 @@ For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphin For example: ``log_level=none|error|warn|debug``, ``memory_limit=``, ``addresses=[:],...``. + .. rst:directive:option:: required + + Indicates the key is required for the section + + .. rst:directive:option:: default + + The default value of the key if ommitted + .. rst:role:: cfg:key - Use to reference a :rst:dir:`cfg:val` by name. + Use to reference a :rst:dir:`cfg:key` by name. Do not include values if it has values in the directive. + The possible formats are: + + - ```` + + Inside of a :rst:dir:`cfg:sec`, it refers to a key in that section. + Outside of a :rst:dir:`cfg:sec`, the key is assumed to be ``common``. + + - ``[]`` + - ``[@]`` .. rst:directive:: .. cfg:val:: [<][>] Use to document a part of what a configuration key accepts. + Must be in a :rst:dir:`cfg:key`. The optional angle brackets (``<>``) are just for display and are meant to help distinguish between the value being a literal and a placeholder. .. rst:role:: cfg:val Use to reference a :rst:dir:`cfg:val` by name. Do not include brackets if it has brackets in the directive. + The possible formats are: + + - ```` + + This must be inside a :rst:dir:`cfg:key`. + + - ``:`` + + Inside of a :rst:dir:`cfg:sec`, it refers to a value of a key in that section. + Outside of a :rst:dir:`cfg:sec`, the key is assumed to be ``common``. + + - ``[]:`` + - ``[@]:`` Example ^^^^^^^ @@ -529,39 +562,46 @@ This is a example made up for the following INI file: .. code-block:: rst - Outside their sections, references to keys and values must be complete: :cfg:val:`server.os.linux`, :cfg:key:`server:linux.distro` + Outside their sections, references to keys and values must be complete: :cfg:val:`[server]os:linux`, :cfg:key:`[server@linux]distro` + + Otherwise the ``common`` section will be assumed. .. cfg:sec:: server/ - A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os.windows` + A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os:windows` .. cfg:key:: os=windows|linux + :required: A value's key can be omitted from references within their keys: :cfg:val:`linux` .. cfg:val:: windows - Implied titles will be shortened within their scopes: :cfg:key:`server.os`, :cfg:val:`server.os.windows` + Implied titles will be shortened within their scopes: :cfg:key:`[server]os`, :cfg:val:`[server]os:windows` .. cfg:val:: linux - Sections with discriminators require them in the reference targets: cfg:sec:`server:linux`, :cfg:key:`server:linux.distro` + Sections with discriminators require them in the reference targets: cfg:sec:`server@linux`, :cfg:key:`[server@linux]distro` - .. cfg:sec:: server:linux/ + .. cfg:sec:: server@linux/ .. cfg:key:: distro= + :default: ``Ubuntu`` Turns into: - Outside their sections, references to keys and values must be complete: :cfg:val:`server.os.linux`, :cfg:key:`server:linux.distro` + Outside their sections, references to keys and values must be complete: :cfg:val:`[server]os:linux`, :cfg:key:`[server@linux]distro` + + Otherwise the ``common`` section will be assumed. .. cfg:sec:: server/ :no-contents-entry: :no-index-entry: - A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os.windows` + A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os:windows` .. cfg:key:: os=windows|linux + :required: :no-contents-entry: :no-index-entry: @@ -571,19 +611,20 @@ Turns into: :no-contents-entry: :no-index-entry: - Implied titles will be shortened within their scopes: :cfg:key:`server.os`, :cfg:val:`server.os.windows` + Implied titles will be shortened within their scopes: :cfg:key:`[server]os`, :cfg:val:`[server]os:windows` .. cfg:val:: linux :no-contents-entry: :no-index-entry: - Sections with discriminators require them in the reference targets: :cfg:sec:`server:linux`, :cfg:key:`server:linux.distro` + Sections with discriminators require them in the reference targets: cfg:sec:`server@linux`, :cfg:key:`[server@linux]distro` - .. cfg:sec:: server:linux/ + .. cfg:sec:: server@linux/ :no-contents-entry: :no-index-entry: .. cfg:key:: distro= + :default: ``Ubuntu`` :no-contents-entry: :no-index-entry: diff --git a/docs/sphinx_extensions/config_domain.py b/docs/sphinx_extensions/config_domain.py index 7098e923d6d..64d148180fc 100644 --- a/docs/sphinx_extensions/config_domain.py +++ b/docs/sphinx_extensions/config_domain.py @@ -1,5 +1,5 @@ # Sphinx Domain for Configuration Values -# Pass -vv to sphinx-build to get it to log the directives it's getting. +# Pass -d to build.py to get it to log the directives it's getting. from __future__ import annotations @@ -7,12 +7,16 @@ import re from typing import Any import re +import unittest from docutils import nodes +from docutils.parsers.rst import directives +from docutils.statemachine import ViewList from sphinx import addnodes from sphinx.application import Sphinx from sphinx.util import logging +from sphinx.util.nodes import nested_parse_with_titles from sphinx.roles import XRefRole from custom_domain import CustomDomain, CustomDomainObject, ContextWrapper @@ -35,13 +39,15 @@ def parse(what, regex, string, node, *ret): raise e if ret: groups = m.groupdict() - return [groups[name] for name in ret] + return tuple([groups[name] for name in ret]) return m.groups() +id_re = r'[\w-]+' + # cfg:sec ===================================================================== -section_re = r'(?P\w+)(?::(?P\w+))?' +section_re = r'(?P' + id_re + r')(?:@(?P' + id_re + r'))?' def parse_section_name(full_name, node=None): @@ -63,7 +69,7 @@ def process_link(self, env: BuildEnvironment, refnode: Element, if not has_explicit_title: sec_name, sec_disc = parse_section_name(target, self) title = section_text(sec_name, sec_disc) - return title, target + return title, f'[{target}]' @ConfigDomain.add_type @@ -80,9 +86,11 @@ def get_index_text(self, name, full_name): return f'{sec_name} ({sec_disc}config section)' def parse_sig(self, ctx, sig): - name, arguments = parse(self._full_name, r'(\w+(?::\w+)?)(?:/(.*))?', sig, self) + name, arguments = parse(self._full_name, + r'(' + id_re + r'(?:@' + id_re + r')?)(?:/(.*))?', sig, self) sec_name, sec_disc = parse_section_name(name) - ctx.push(self, name, sec_name=sec_name, sec_disc=sec_name, arguments=arguments) + ctx.push(self, name, f'[{name}]', + sec_name=sec_name, sec_disc=sec_name, arguments=arguments, keys=[]) return (sec_name, sec_disc, arguments) def create_signode(self, ctx, name, signode, sec_name, sec_disc, arguments): @@ -99,7 +107,8 @@ def create_signode(self, ctx, name, signode, sec_name, sec_disc, arguments): # cfg:key ===================================================================== -key_re = r'(?:(?P' + section_re + ')\.)?(?P\w+)' +key_name_re = id_re + r'(?:\.' + id_re + r')*' +key_re = r'(?:\[(?P' + section_re + r')\])?(?P' + key_name_re + r')' def parse_key_name(full_name, node=None): @@ -110,10 +119,25 @@ def parse_key_name(full_name, node=None): def key_text(sec_name, sec_disc, key_name, insert=''): text = key_name + insert if sec_name is not None: - text = section_text(sec_name, sec_disc, '.' + text) + text = section_text(sec_name, sec_disc, text) return text +# This should be equivalent to ConfigPair::canonicalize +def key_canonicalize(key): + # Replace everything that's not a letter, number, or underscore + key = re.sub(r'[^\w]', '_', key) + + # Convert CamelCase to camel_case + key = re.sub(r'([A-Z][a-z])', r'_\1', key) + key = re.sub(r'([a-z])([A-Z])', r'\1_\2', key) + + # Removed repeated underscores + key = re.sub(r'_+', r'_', key) + + return key.strip('_').upper() + + class ConfigKeyRefRole(XRefRole): def process_link(self, env: BuildEnvironment, refnode: Element, has_explicit_title: bool, title: str, target: str) -> tuple[str, str]: @@ -124,12 +148,15 @@ def process_link(self, env: BuildEnvironment, refnode: Element, sec, sec_name, sec_disc, key_name = parse_key_name(target, self) scope_kind = len(ctx.stack) if sec is not None: - # sec.key anywhere + # [sec]key anywhere pass + elif scope_kind == 0 and sec is None: + # Assume key outside section should be in [common] + target = f'[common]{target}' elif scope_kind >= 1: # key anywhere in a section prefix = ctx.get_full_name(0) - target = f'{prefix}.{target}' + target = f'{prefix}{target}' else: ConfigDomain.logger.warning(f'{repr(target)} is an invalid target here', location=self.get_location()) @@ -149,6 +176,12 @@ def process_link(self, env: BuildEnvironment, refnode: Element, @ConfigDomain.add_type class ConfigKey(CustomDomainObject): + option_spec: OptionSpec = CustomDomainObject.option_spec.copy() + option_spec.update({ + 'required': directives.flag, + 'default': directives.unchanged, + }) + our_name = 'key' our_parent_required = True our_parent_type = ConfigSection @@ -159,8 +192,10 @@ def get_index_text(self, name, full_name): return f'{key} (config key)' def parse_sig(self, ctx, sig): - name, arguments = parse(self._full_name, r'(\w+)(?:=(.*))?', sig, self) - ctx.push(self, name, ctx.get_full_name() + f'.{name}', arguments=arguments) + name, arguments = parse(self._full_name, r'(' + key_name_re + r')(?:=(.*))?', sig, self) + sec = ctx.get_full_name() + ctx.push(self, name, f'{sec}{name}', arguments=arguments) + ctx.get(-2, 'keys').append((name, self.get_location())) return (arguments,) def create_signode(self, ctx, name, signode, arguments): @@ -172,22 +207,38 @@ def create_signode(self, ctx, name, signode, arguments): def transform_content(self, contentnode: addnodes.desc_content) -> None: ctx = self.get_context() - # Insert the config store key at the top of the content + # Insert this stuff at the top p = nodes.paragraph() contentnode.insert(0, p) - text = 'Config store key: ' - p += nodes.inline(text, text) - text = ctx.get(-2, 'sec_name').upper() + '_' + rst = ViewList() + + # Config store key + key = key_canonicalize(ctx.get(-2, 'sec_name')) + '_' sec_args = ctx.get(-2, 'arguments') if sec_args: - text += sec_args + '_' - text += ctx.get_name().upper() - p += nodes.literal(text, text) + key += sec_args + '_' + key += key_canonicalize(ctx.get_name()) + rst.append(f'| **Config store key**: ``{key}``', f'{__name__}', 1) + + # :required: flag + required = 'required' in self.options + if required: + rst.append(f'| **Required**', f'{__name__}', 1) + + # :default: flag + default = self.options.get('default') + if default: + if required: + e = ValueError(f'A {self._full_name} shouldn\'t be both default and required') + ConfigDomain.logger.warning(e, location=self.get_location()) + rst.append(f'| **Default:** {default}\n', f'{__name__}', 1) + + nested_parse_with_titles(self.state, rst, p) # cfg:val ===================================================================== -value_re = r'(?:(?P' + key_re + ')\.)?(?P\w+)' +value_re = r'(?:(?P' + key_re + r'):)?(?P' + id_re + r')' def parse_value_name(full_name, node=None): @@ -198,7 +249,7 @@ def parse_value_name(full_name, node=None): def value_text(sec_name, sec_disc, key_name, val_name): text = val_name if key_name is not None: - text = key_text(sec_name, sec_disc, key_name, '.' + text) + text = key_text(sec_name, sec_disc, key_name, ':' + text) return text @@ -212,16 +263,19 @@ def process_link(self, env: BuildEnvironment, refnode: Element, sec, sec_name, sec_disc, key, key_name, val_name = parse_value_name(target, self) scope_kind = len(ctx.stack) if sec is not None: - # sec.key.val anywhere + # [sec]key=val anywhere pass + elif scope_kind == 0 and sec is None: + # key:val outside section + target = f'[common]{target}' elif scope_kind >= 1 and key is not None: - # key.val anywhere in a section + # key:val anywhere in a section prefix = ctx.get_full_name(0) - target = f'{prefix}.{target}' + target = f'{prefix}{target}' elif scope_kind >= 2 and key is None: # val anywhere in a key prefix = ctx.get_full_name(1) - target = f'{prefix}.{target}' + target = f'{prefix}:{target}' else: ConfigDomain.logger.warning(f'{repr(target)} is an invalid target here', location=self.get_location()) @@ -259,10 +313,11 @@ def get_index_text(self, name, full_name): return f'{val_name} (config value)' def parse_sig(self, ctx, sig): - name_wo_brackets, name_w_brackets = parse(self._full_name, r'(\w+)|<(\w+)>', sig, self) + name_wo_brackets, name_w_brackets = parse(self._full_name, + r'(' + id_re + r')|<(' + id_re + r')>', sig, self) brackets = bool(name_w_brackets) name = name_w_brackets if brackets else name_wo_brackets - ctx.push(self, name, ctx.get_full_name() + f'.{name}') + ctx.push(self, name, ctx.get_full_name() + f':{name}') return (brackets,) def create_signode(self, ctx, name, signode, brackets): @@ -273,6 +328,8 @@ def create_signode(self, ctx, name, signode, brackets): signode += addnodes.desc_addname('>', '>') +# setup ======================================================================= + def setup(app: Sphinx) -> dict[str, Any]: app.add_domain(ConfigDomain) @@ -281,3 +338,56 @@ def setup(app: Sphinx) -> dict[str, Any]: 'parallel_read_safe': True, 'parallel_write_safe': True, } + +class TestConfigDomain(unittest.TestCase): + + def test_parse_section_name(self): + cases = { + # sec_name, sec_disc + 'sn': ('sn', None), + 'sn@sd': ('sn', 'sd'), + } + + for ref, expected in cases.items(): + self.assertEqual(parse_section_name(ref), expected) + + def test_parse_key_name(self): + cases = { + # sec, sec_name, sec_disc, key_name + 'kn': (None, None, None, 'kn'), + 'kn.a.b.c': (None, None, None, 'kn.a.b.c'), + '[sn]kn': ('sn', 'sn', None, 'kn'), + '[sn]kn.a.b.c': ('sn', 'sn', None, 'kn.a.b.c'), + '[sn@sd]kn': ('sn@sd', 'sn', 'sd', 'kn'), + '[sn@sd]kn.a.b.c': ('sn@sd', 'sn', 'sd', 'kn.a.b.c'), + } + + for ref, expected in cases.items(): + self.assertEqual(parse_key_name(ref), expected, f'On key {repr(ref)}') + + def test_parse_key_name(self): + cases = { + # sec, sec_name, sec_disc, key, key_name, val_name + 'vn': (None, None, None, None, None, 'vn'), + 'kn:vn': (None, None, None, 'kn', 'kn', 'vn'), + 'kn.a.b.c:vn': (None, None, None, 'kn.a.b.c', 'kn.a.b.c', 'vn'), + '[sn]kn:vn': ('sn', 'sn', None, '[sn]kn', 'kn', 'vn'), + '[sn]kn.a.b.c:vn': ('sn', 'sn', None, '[sn]kn.a.b.c', 'kn.a.b.c', 'vn'), + '[sn@sd]kn:vn': ('sn@sd', 'sn', 'sd', '[sn@sd]kn', 'kn', 'vn'), + '[sn@sd]kn.a.b.c:vn': ('sn@sd', 'sn', 'sd', '[sn@sd]kn.a.b.c', 'kn.a.b.c', 'vn'), + } + + for ref, expected in cases.items(): + self.assertEqual(parse_value_name(ref), expected, f'On value {repr(ref)}') + + def test_key_canonicalize(self): + cases = { + '~!abc.123__CamelCase/CAMELCase#$%': 'ABC_123_CAMEL_CASE_CAMEL_CASE', + 'CamelCase': 'CAMEL_CASE', + '##CamelCase##': 'CAMEL_CASE', + 'UseXTypes': 'USE_X_TYPES', + 'UseXYZTypes': 'USE_XYZ_TYPES', + } + + for value, expected in cases.items(): + self.assertEqual(key_canonicalize(value), expected) diff --git a/docs/sphinx_extensions/custom_domain.py b/docs/sphinx_extensions/custom_domain.py index 92783e48828..6d6147a2647 100644 --- a/docs/sphinx_extensions/custom_domain.py +++ b/docs/sphinx_extensions/custom_domain.py @@ -173,8 +173,13 @@ def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> def before_content(self) -> None: self.get_context().reset_needs_push() + def our_after_content(self, ctx): + pass + def after_content(self) -> None: - self.get_context().pop() + ctx = self.get_context() + self.our_after_content(ctx) + ctx.pop() class CustomDomain(Domain): diff --git a/docs/sphinx_extensions/newsd.py b/docs/sphinx_extensions/newsd.py index 1f6a7f6f03e..cc84e2329a3 100755 --- a/docs/sphinx_extensions/newsd.py +++ b/docs/sphinx_extensions/newsd.py @@ -6,6 +6,7 @@ import io from datetime import datetime, timezone import textwrap +import unittest from version_info import VersionInfo @@ -68,12 +69,9 @@ def put_level_separator(self): print(file=self.file) self.printed_blank_line = True - def test(self, expected): + def test_str(self): assert isinstance(self.file, io.StringIO) - got = self.file.getvalue() - if got != expected: - print('ERROR: internal test failed, expected:', expected, 'but got:', got, sep='\n', file=sys.stderr) - raise AssertionError() + return self.file.getvalue() class Node: @@ -129,10 +127,11 @@ def print(self, h): h.put(self.level - 1, line, decorate=decorate) -def test_text(): - ph = PrintHelper(None) - Text(0, set([1, 2]), 3, ['- Item\n - SubItem\n- Additional Item']).print(ph) - ph.test('''\ +class TestText(unittest.TestCase): + def test_text(self): + ph = PrintHelper(None) + Text(0, set([1, 2]), 3, ['- Item\n - SubItem\n- Additional Item']).print(ph) + self.assertEqual(ph.test_str(), '''\ - Item (:ghpr:`1`, :ghpr:`2`) - SubItem - Additional Item (:ghpr:`1`, :ghpr:`2`) @@ -216,33 +215,34 @@ def print_all(self, file=sys.stdout): self.print(h) -def test_section(): - root = Section() - a = root.get_section('Section A') - a.add_text(set([0]), ['- This is some text\n', '- This is a separate item\n']) - aa = a.get_section('Section AA') - aa.add_text(set([3]), ['- This is some text\n - This is some more\n']) - aa.add_text(set([1]), ['- This is some text \n - This is some more\n']) - aa.add_text(set([5]), ['- This is some text\n - This is some more\n \n']) - aa.add_text(set([50]), ['- (Should be second in Section AA)\n'], 9) - aaa = aa.get_section('Section AAA (Should be first in Section AA)', 10) - aaa.add_text(set([4]), ['- This is some text\n - This is some more\n']) - aab = aa.get_section('Section AAB') - aab.add_text(set([10]), ['- This is some text\n']) - aaba = aab.get_section('Section AABA') - aaba.add_text(set([9]), ['- This is some text\n']) - aac = aa.get_section('Section AAC') - aac.add_text(set([1]), ['- This is some text\n']) - b = root.get_section('Section B') - b.add_text(set([12]), ['- This is some text\n']) - root.get_section('This should be hidden') \ - .get_section('This should be hidden') \ - .get_section('This should be hidden') - - ph = PrintHelper(None) - ph.show_rank = True - root.print(ph) - ph.test('''\ +class TestSection(unittest.TestCase): + def test_section(self): + root = Section() + a = root.get_section('Section A') + a.add_text(set([0]), ['- This is some text\n', '- This is a separate item\n']) + aa = a.get_section('Section AA') + aa.add_text(set([3]), ['- This is some text\n - This is some more\n']) + aa.add_text(set([1]), ['- This is some text \n - This is some more\n']) + aa.add_text(set([5]), ['- This is some text\n - This is some more\n \n']) + aa.add_text(set([50]), ['- (Should be second in Section AA)\n'], 9) + aaa = aa.get_section('Section AAA (Should be first in Section AA)', 10) + aaa.add_text(set([4]), ['- This is some text\n - This is some more\n']) + aab = aa.get_section('Section AAB') + aab.add_text(set([10]), ['- This is some text\n']) + aaba = aab.get_section('Section AABA') + aaba.add_text(set([9]), ['- This is some text\n']) + aac = aa.get_section('Section AAC') + aac.add_text(set([1]), ['- This is some text\n']) + b = root.get_section('Section B') + b.add_text(set([12]), ['- This is some text\n']) + root.get_section('This should be hidden') \ + .get_section('This should be hidden') \ + .get_section('This should be hidden') + + ph = PrintHelper(None) + ph.show_rank = True + root.print(ph) + self.assertEqual(ph.test_str(), '''\ Section A ========= @@ -425,11 +425,6 @@ def print_all_news(file=sys.stdout): Older releases can be found in :ghfile:`NEWS.md`'''), file=file) -# Since we can, always do testing. -test_text() -test_section() - - if __name__ == '__main__': parse_newsd().print_all() From a95517324f8ca41068ec5a51487fadafbfde6e91 Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Fri, 29 Mar 2024 22:13:08 -0500 Subject: [PATCH 09/37] Small Tweaks to Config Domain --- docs/sphinx_extensions/config_domain.py | 34 ++++++++++++++----------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/docs/sphinx_extensions/config_domain.py b/docs/sphinx_extensions/config_domain.py index 64d148180fc..10f979a883b 100644 --- a/docs/sphinx_extensions/config_domain.py +++ b/docs/sphinx_extensions/config_domain.py @@ -43,7 +43,8 @@ def parse(what, regex, string, node, *ret): return m.groups() -id_re = r'[\w-]+' +id_re = r'[\$\w-]+' + # cfg:sec ===================================================================== @@ -124,7 +125,9 @@ def key_text(sec_name, sec_disc, key_name, insert=''): # This should be equivalent to ConfigPair::canonicalize -def key_canonicalize(key): +def key_canonicalize(*parts): + key = '_'.join(filter(None, parts)) + # Replace everything that's not a letter, number, or underscore key = re.sub(r'[^\w]', '_', key) @@ -195,7 +198,9 @@ def parse_sig(self, ctx, sig): name, arguments = parse(self._full_name, r'(' + key_name_re + r')(?:=(.*))?', sig, self) sec = ctx.get_full_name() ctx.push(self, name, f'{sec}{name}', arguments=arguments) - ctx.get(-2, 'keys').append((name, self.get_location())) + sec_ctx = ctx.get(-2, 'keys') + if sec_ctx is not None: + sec_ctx.append((name, self.get_location())) return (arguments,) def create_signode(self, ctx, name, signode, arguments): @@ -213,11 +218,7 @@ def transform_content(self, contentnode: addnodes.desc_content) -> None: rst = ViewList() # Config store key - key = key_canonicalize(ctx.get(-2, 'sec_name')) + '_' - sec_args = ctx.get(-2, 'arguments') - if sec_args: - key += sec_args + '_' - key += key_canonicalize(ctx.get_name()) + key = key_canonicalize(ctx.get(-2, 'sec_name'), ctx.get(-2, 'arguments'), ctx.get_name()) rst.append(f'| **Config store key**: ``{key}``', f'{__name__}', 1) # :required: flag @@ -382,12 +383,15 @@ def test_parse_key_name(self): def test_key_canonicalize(self): cases = { - '~!abc.123__CamelCase/CAMELCase#$%': 'ABC_123_CAMEL_CASE_CAMEL_CASE', - 'CamelCase': 'CAMEL_CASE', - '##CamelCase##': 'CAMEL_CASE', - 'UseXTypes': 'USE_X_TYPES', - 'UseXYZTypes': 'USE_XYZ_TYPES', + ('~!abc.123__CamelCase/CAMELCase#$%',): 'ABC_123_CAMEL_CASE_CAMEL_CASE', + ('CamelCase',): 'CAMEL_CASE', + ('TheSection', None, 'TheKey'): 'THE_SECTION_THE_KEY', + ('TheSection', '', 'TheKey'): 'THE_SECTION_THE_KEY', + ('TheSection', 'TheInstance', 'TheKey'): 'THE_SECTION_THE_INSTANCE_THE_KEY', + ('##CamelCase##',): 'CAMEL_CASE', + ('UseXTypes',): 'USE_X_TYPES', + ('UseXYZTypes',): 'USE_XYZ_TYPES', } - for value, expected in cases.items(): - self.assertEqual(key_canonicalize(value), expected) + for args, expected in cases.items(): + self.assertEqual(key_canonicalize(*args), expected) From 9a4204d8d161614fa5df5403107ee65820664a09 Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Fri, 29 Mar 2024 22:39:36 -0500 Subject: [PATCH 10/37] Use config domain in [common] and add library info - Config - Use the config domain for the common config section options. Tried to make as many links as possible. - Added info and links to option descriptions as seemed needed. - Introduction - Add general info on how plugin libraries are initialized, specifically about static initialization headers. - Add boxes with vital info about the plugins, including their various names initialization headers. - Add sections summarizing the transports. - Make spelling and capitalization of "built-in topic" consistent. --- NEWS.md | 6 +- .../devguide/alternate_interfaces_to_data.rst | 4 +- docs/devguide/building/cmake.rst | 16 +- docs/devguide/built_in_topics.rst | 34 +- .../devguide/content_subscription_profile.rst | 12 +- docs/devguide/dds_security.rst | 12 +- docs/devguide/introduction.rst | 291 +++++++-- docs/devguide/introduction_to_dds.rst | 59 +- docs/devguide/quality_of_service.rst | 11 +- docs/devguide/run_time_configuration.rst | 568 ++++++++++-------- docs/devguide/safety_profile.rst | 37 +- docs/glossary.rst | 2 +- docs/internal/bench.rst | 6 +- docs/internal/release.rst | 4 +- docs/news.d/_releases/v3.26.0.rst | 2 +- docs/news.d/_releases/v3.27.0.rst | 8 +- docs/news.d/devguide-config.rst | 8 + docs/news.d/devguide-intro.rst | 12 + docs/news.d/devguide-qos.rst | 5 +- docs/news.d/value-reader-writer-fixed.rst | 2 +- 20 files changed, 695 insertions(+), 404 deletions(-) create mode 100644 docs/news.d/devguide-config.rst create mode 100644 docs/news.d/devguide-intro.rst diff --git a/NEWS.md b/NEWS.md index 474e2af50b0..d422d746a03 100644 --- a/NEWS.md +++ b/NEWS.md @@ -29,9 +29,9 @@ Read [the documentation for this release on Read the Docs](https://opendds.readt ### Fixes - Updated the [read](https://opendds.readthedocs.io/en/dds-3.27/devguide/xtypes.html#xtypes-interpreting-data-samples-with-dynamicdata) and [write](https://opendds.readthedocs.io/en/dds-3.27/devguide/xtypes.html#xtypes-populating-data-samples-with-dynamicdata) semantics of DynamicData for union, expandable collections (sequence and string), and optional member of an aggregated type. ([PR #4278](https://github.com/OpenDDS/OpenDDS/pull/4278)) -- Fixed memory leak where instances were not cleaned up with exlusive ownership. ([PR #4343](https://github.com/OpenDDS/OpenDDS/pull/4343)) +- Fixed memory leak where instances were not cleaned up with exclusive ownership. ([PR #4343](https://github.com/OpenDDS/OpenDDS/pull/4343)) - Removed the special handling for sequence members with length code of 5,6, or 7. ([PR #4376](https://github.com/OpenDDS/OpenDDS/pull/4376)) -- Reading data from a dynamic data object for a primitive type now must use MEMBER_ID_INVALID id. ([PR #4376](https://github.com/OpenDDS/OpenDDS/pull/4376)) +- Reading data from a dynamic data object for a primitive type now must use `MEMBER_ID_INVALID` id. ([PR #4376](https://github.com/OpenDDS/OpenDDS/pull/4376)) - `create_datawriter` and `create_datareader` check if the topic belongs to the same participant as the publisher/subscriber. ([PR #4398](https://github.com/OpenDDS/OpenDDS/pull/4398)) - Fixed uninitialized `durability_service` in Topic QoS when using QoS-XML. ([PR #4424](https://github.com/OpenDDS/OpenDDS/pull/4424)) - Fixed a bug where compiling IDL with `-Lc++11 -Gequality` produced code outside of a namespace that didn't compile. ([PR #4450](https://github.com/OpenDDS/OpenDDS/pull/4450)) @@ -105,7 +105,7 @@ Read [the documentation for this release on Read the Docs](https://opendds.readt ### Documentation -* Remove -Grapidjson flag [opendds_idl] ([PR #4231](https://github.com/OpenDDS/OpenDDS/pull/4231)) +* Removed documentation for `-Grapidjson` option of `opendds_idl` that was removed in 3.20.0 ([PR #4231](https://github.com/OpenDDS/OpenDDS/pull/4231)) * Remove reference to mailing lists ([PR #4234](https://github.com/OpenDDS/OpenDDS/pull/4234)) * Restructured parts of [DDS Security](https://opendds.readthedocs.io/en/dds-3.26/devguide/dds_security.html#dds-security) page and expanded documentation of some XML security document elements. ([PR #4281](https://github.com/OpenDDS/OpenDDS/pull/4281)) * OS-specific instructions will now be automatically selected based on the browser's user agent. ([PR #4281](https://github.com/OpenDDS/OpenDDS/pull/4281)) diff --git a/docs/devguide/alternate_interfaces_to_data.rst b/docs/devguide/alternate_interfaces_to_data.rst index 3494a2cb79b..5686d613e64 100644 --- a/docs/devguide/alternate_interfaces_to_data.rst +++ b/docs/devguide/alternate_interfaces_to_data.rst @@ -66,7 +66,7 @@ Usage Model Sect<12.1.2> The application creates any number of ``Recorder``\s and ``Replayer``\s as necessary. -This could be based on using the Built-In Topics to dynamically discover which topics are active in the Domain. +This could be based on using the :term:`built-in topics` to dynamically discover which topics are active in the Domain. Creating a ``Recorder`` or ``Replayer`` requires the application to provide a topic name and type name (as in ``DomainParticipant::create_topic()``) and also the relevant QoS data structures. The ``Recorder`` requires SubscriberQos and DataReaderQos whereas the ``Replayer`` requires PublisherQos and DataWriterQos. These values are used in discovery's reader/writer matching. @@ -141,7 +141,7 @@ The properties can be divided into a few categories: * Durability Service * Ownership and Ownership Strength (still used for reader/writer match) -* Affects reader/writer matching and Built-In Topics but otherwise ignored +* Affects reader/writer matching and :term:`built-in topics` but otherwise ignored * Partition * Reliability (still used by transport negotiation) diff --git a/docs/devguide/building/cmake.rst b/docs/devguide/building/cmake.rst index cf8dc794f23..8ed46e9ded7 100644 --- a/docs/devguide/building/cmake.rst +++ b/docs/devguide/building/cmake.rst @@ -248,35 +248,35 @@ The CMake package can provide library targets that can be linked using `target_l .. cmake:tgt:: OpenDDS::Rtps - :ref:`RTPS Discovery ` + :ref:`rtps-disc` .. cmake:tgt:: OpenDDS::InfoRepoDiscovery - :ref:`InfoRepo Discovery ` + :ref:`inforepo-disc` .. cmake:tgt:: OpenDDS::Rtps_Udp - :ref:`RTPS/UDP Transport ` + :ref:`rtps-udp-transport` .. cmake:tgt:: OpenDDS::Multicast - :ref:`Multicast Transport ` + :ref:`multicast-transport` .. cmake:tgt:: OpenDDS::Shmem - :ref:`Shared Memory Transport ` + :ref:`shmem-transport` .. cmake:tgt:: OpenDDS::Tcp - :ref:`TCP Transport ` + :ref:`tcp-transport` .. cmake:tgt:: OpenDDS::Udp - :ref:`UDP Transport ` + :ref:`udp-transport` .. cmake:tgt:: OpenDDS::Security - :doc:`/devguide/dds_security` + :ref:`sec` .. cmake:tgt:: OpenDDS::RtpsRelayLib diff --git a/docs/devguide/built_in_topics.rst b/docs/devguide/built_in_topics.rst index 89949c2fcea..32e338b7054 100644 --- a/docs/devguide/built_in_topics.rst +++ b/docs/devguide/built_in_topics.rst @@ -2,7 +2,7 @@ .. _bit: ############### -Built-In Topics +Built-in Topics ############### .. @@ -17,18 +17,17 @@ Introduction .. Sect<6.1> -In OpenDDS, Built-In-Topics are created and published by default to exchange information about DDS participants operating in the deployment. -When OpenDDS is used in a centralized discovery approach using the ``DCPSInfoRepo`` service, the Built-In-Topics are published by this service. -For DDSI-RTPS discovery, the internal OpenDDS implementation instantiated in a process populates the caches of the Built-In Topic DataReaders. -See :ref:`run_time_configuration--configuring-for-ddsi-rtps-discovery` for a description of RTPS discovery configuration. +In OpenDDS, built-in topics are created and published by default to exchange information about DDS participants operating in the deployment. +When OpenDDS is :ref:`inforepo-disc`, the built-in topics are published by this service. +For :ref:`rtps-disc`, the internal OpenDDS implementation instantiated in a process populates the caches of the built-In topic DataReaders. -The IDL struct ``BuiltinTopicKey_t`` is used by the Built-In Topics. +The IDL struct ``BuiltinTopicKey_t`` is used by the built-in topics. This structure contains an array of 16 octets (bytes) which corresponds to an InfoRepo identifier or a DDSI-RTPS GUID. .. _built_in_topics--built-in-topics-for-dcpsinforepo-configuration: ********************************************** -Built-In Topics for DCPSInfoRepo Configuration +Built-in Topics for DCPSInfoRepo Configuration ********************************************** .. @@ -40,15 +39,15 @@ Four separate topics are defined for each domain. Each is dedicated to a particular entity (domain participant :ref:`built_in_topics--dcpsparticipant-topic`, topic :ref:`built_in_topics--dcpsparticipant-topic`, data writer :ref:`built_in_topics--dcpspublication-topic`, data reader :ref:`built_in_topics--dcpssubscription-topic`) and publishes instances describing the state for each entity in the domain. Subscriptions to built-in topics are automatically created for each domain participant. -A participant's support for Built-In-Topics can be toggled via the ``DCPSBit`` configuration option (see the table in :ref:`run_time_configuration--common-configuration-options`). +A participant's support for built-in topics can be toggled via the :cfg:key:`DCPSBit` configuration option. To view the built-in topic data, simply obtain the built-in Subscriber and then use it to access the Data Reader for the built-in topic of interest. The Data Reader can then be used like any other Data Reader. See :ref:`built_in_topics--built-in-topic-subscription-example` for an example showing how to read from a built-in topic. -If you are not planning on using Built-in-Topics in your application, you can configure OpenDDS to remove Built-In-Topic support at build time. +If you are not planning on using built-in topics in your application, you can configure OpenDDS to remove built-in topic support at build time. Doing so can reduce the footprint of the core DDS library by up to 30%. -See :ref:`building--disabling-the-building-of-built-in-topic-support` for information on disabling Built-In-Topic support. +See :ref:`building--disabling-the-building-of-built-in-topic-support` for information on disabling built-in topic support. .. _built_in_topics--dcpsparticipant-topic: @@ -80,7 +79,7 @@ DCPSTopic Topic .. Sect<6.4> -.. note:: OpenDDS does not support this Built-In-Topic when configured for RTPS discovery. +.. note:: OpenDDS does not support this built-in topic when configured for :ref:`rtps-disc`. The ``DCPSTopic`` topic publishes information about the topics in the domain. Here is the IDL that defines the structure published for this topic: @@ -183,7 +182,7 @@ The fields above identify the Domain Participant (via its key) that the Data Rea .. _built_in_topics--built-in-topic-subscription-example: *********************************** -Built-In Topic Subscription Example +Built-in Topic Subscription Example *********************************** .. @@ -214,7 +213,7 @@ The code for the other built-in topics is similar. .. _built_in_topics--opendds-specific-built-in-topics: ******************************** -OpenDDS-specific Built-In Topics +OpenDDS-specific Built-in Topics ******************************** .. @@ -228,7 +227,7 @@ OpenDDSParticipantLocation Topic .. Sect<6.8.1> -The Built-In Topic "OpenDDSParticipantLocation" is published by the DDSI-RTPS discovery implementation to give applications visibility into the details of how each remote participant is connected over the network. +The built-in topic ``OpenDDSParticipantLocation`` is published by the DDSI-RTPS discovery implementation to give applications visibility into the details of how each remote participant is connected over the network. If the RtpsRelay (:ref:`internet_enabled_rtps--the-rtpsrelay`) and/or IETF ICE (:ref:`internet_enabled_rtps--interactive-connectivity-establishment-ice-for-rtps`) are enabled, their usage is reflected in the OpenDDSParticipantLocation topic data. The topic type ParticipantLocationBuiltinTopicData is defined in :ghfile:`dds/OpenddsDcpsExt.idl` in the ``OpenDDS::DCPS`` module: @@ -263,7 +262,7 @@ OpenDDSConnectionRecord Topic .. Sect<6.8.2> -The Built-In Topic "OpenDDSConnectionRecord" is published by the DDSI-RTPS discovery implementation and RTPS_UDP transport implementation to give applications visibility into the details of a participant's connection to an RtpsRelay instance. +The built-in topic ``OpenDDSConnectionRecord`` is published by the DDSI-RTPS discovery implementation and RTPS_UDP transport implementation to give applications visibility into the details of a participant's connection to an RtpsRelay instance. Security must be enabled in the build of OpenDDS (:ref:`dds_security--building-opendds-with-security-enabled`) to use this topic. The topic type ConnectionRecord is defined in :ghfile:`dds/OpenddsDcpsExt.idl` in the ``OpenDDS::DCPS`` module: @@ -286,8 +285,8 @@ OpenDDSInternalThread Topic .. Sect<6.8.3> -The Built-In Topic "OpenDDSInternalThread" is published by the DDSI-RTPS discovery implementation when OpenDDS is configured with DCPSThreadStatusInterval (:ref:`run_time_configuration--common-configuration-options`). -When enabled, the DataReader for this Built-In Topic will report the status of threads created and managed by OpenDDS within the current process. +The built-in topic ``OpenDDSInternalThread`` is published when OpenDDS is configured with :cfg:key:`DCPSThreadStatusInterval`. +When enabled, the DataReader for this built-in topic will report the status of threads created and managed by OpenDDS within the current process. The timestamp associated with samples can be used to determine the health (responsiveness) of the thread. The topic type InternalThreadBuiltinTopicData is defined in :ghfile:`dds/OpenddsDcpsExt.idl` in the ``OpenDDS::DCPS`` module: @@ -295,4 +294,3 @@ The topic type InternalThreadBuiltinTopicData is defined in :ghfile:`dds/Opendds * ``thread_id`` (key) -- A string identifier for the thread. * ``utilization`` -- Estimated utilization of this thread (0.0-1.0). - diff --git a/docs/devguide/content_subscription_profile.rst b/docs/devguide/content_subscription_profile.rst index b4ccfa5142d..c5254b30c42 100644 --- a/docs/devguide/content_subscription_profile.rst +++ b/docs/devguide/content_subscription_profile.rst @@ -56,7 +56,7 @@ Creating a content-filtered topic requires the following parameters: * Filter expression - An SQL-like expression (:ref:`content_subscription_profile--filter-expressions`) which defines the subset of samples published on the related topic that should be received by the content-filtered topic's data readers. + An :ref:`SQL-like expression ` which defines the subset of samples published on the related topic that should be received by the content-filtered topic's data readers. * Expression parameters @@ -68,11 +68,11 @@ Once the content-filtered topic has been created, it is used by the subscriber's This data reader is functionally equivalent to a normal data reader except that incoming data samples which do not meet the filter expression's criteria are dropped. Filter expressions are first evaluated at the publisher so that data samples which would be ignored by the subscriber can be dropped before even getting to the transport. -This feature can be turned off with ``-DCPSPublisherContentFilter 0`` or the equivalent setting in the ``[common]`` section of the configuration file. +This feature can be turned off by setting :cfg:key:`DCPSPublisherContentFilter` to ``0``. The behavior of non-default :ref:`qos-deadline` or :ref:`qos-liveliness` policies may be affected by this policy. Special consideration must be given to how the "missing" samples impact the QoS behavior, see the document in :ghfile:`docs/design/CONTENT_SUBSCRIPTION`. -.. note:: RTPS_UDP transport does not always do Writer-side filtering. +.. note:: :ref:`rtps-udp-transport` does not always do Writer-side filtering. It does not currently implement transport level filtering, but may be able to filter above the transport layer. .. _content_subscription_profile--filter-expressions: @@ -83,9 +83,9 @@ Filter Expressions .. Sect<5.2.1> -The formal grammar for filter expressions is defined in Annex A of the DDS specification. +The formal grammar for filter expressions is defined in :omgspec:`dds:Annex B - Syntax for Queries and Filters`. This section provides an informal summary of that grammar. -Query expressions (:ref:`content_subscription_profile--query-expressions`) and topic expressions (:ref:`content_subscription_profile--topic-expressions`) are also defined in Annex A. +:ref:`Query expressions ` and :ref:`topic expressions ` are also defined in the DDS specification. Filter expressions are combinations of one or more predicates. Each predicate is a logical expression taking one of two forms: @@ -141,7 +141,7 @@ Filtering and Dispose/Unregister Samples .. Sect<5.2.3> -DataReaders without filtering can see samples with the ``valid_data`` field of SampleInfo set to false. +DataReaders without filtering can see samples with the ``valid_data`` field of ``SampleInfo`` set to ``false``. This happens when the matching DataWriter disposes or unregisters the instance. Content filtering (whether achieved through Content-Filtered Topics, Query Conditions, or Multi Topics) will filter such samples when the filter expression explicitly uses key fields. Filter expressions that don't meet that criteria will result in no such samples passing the filter. diff --git a/docs/devguide/dds_security.rst b/docs/devguide/dds_security.rst index 16469ac702e..46921a59f75 100644 --- a/docs/devguide/dds_security.rst +++ b/docs/devguide/dds_security.rst @@ -11,6 +11,16 @@ DDS Security OpenDDS includes an implementation of the :ref:`DDS Security specification `. This allows participants to encrypt messages and to authenticate remote participants before engaging with them. +.. important:: + + Library filename: ``OpenDDS_Security`` + + MPC base project name: :ghfile:`\`\`opendds_security\`\` ` + + CMake target Name: :cmake:tgt:`OpenDDS::Security` + + :ref:`Initialization header `: :ghfile:`dds/DCPS/security/BuiltInPlugins.h` + .. _dds_security--building-opendds-with-security-enabled: ************************************** @@ -140,7 +150,7 @@ The following configuration steps are required to enable OpenDDS Security featur * Via API: ``TheServiceParticipant->set_security(true);`` or - * Via config file: ``DCPSSecurity=1`` in the ``[common]`` section. + * Via config file: setting :cfg:key:`DCPSSecurity` to ``1``. .. _dds_security--dds-security-configuration-via-propertyqospolicy: diff --git a/docs/devguide/introduction.rst b/docs/devguide/introduction.rst index dc5c83d340a..0bc41095a60 100644 --- a/docs/devguide/introduction.rst +++ b/docs/devguide/introduction.rst @@ -70,7 +70,7 @@ Real-time Publish-Subscribe (RTPS) The full name of this specification is the *Real-time Publish-Subscribe Protocol DDS Interoperability Wire Protocol* (DDSI-RTPS), but can also be just called RTPS. This specification describes the requirements for interoperability between DDS implementations. -See :ref:`introduction--peer-to-peer-discovery-with-rtps` for more information. +See :ref:`rtps-disc` for more information. The version OpenDDS uses is :omgspec:`rtps`. Although the document number is v2.3, it specifies protocol version 2.4. @@ -178,7 +178,7 @@ Section 2 of the DDS specification defines five compliance points for a DDS impl OpenDDS complies with the entire DDS specification (including all optional profiles). This includes the implementation of all Quality of Service policies with the following notes: -* :ref:`qos-reliability` ``RELIABLE_RELIABILITY_QOS`` is supported by the RTPS_UDP transport, the TCP transport, and the IP Multicast transport (when configured as reliable). +* :ref:`qos-reliability` ``RELIABLE_RELIABILITY_QOS`` is supported by the :ref:`rtps-udp-transport`, the :ref:`tcp-transport`, and the :ref:`multicast-transport` (when configured as reliable). * :ref:`qos-transport-priority` is not implemented as changeable. @@ -336,32 +336,190 @@ The main deviation from the OMG IDL PSM is that local interfaces are used for th These are defined as unconstrained (non-local) interfaces in the DDS specification. Defining them as local interfaces improves performance, reduces memory usage, simplifies the client's interaction with these interfaces, and makes it easier for clients to build their own implementations. -.. _introduction--extensible-transport-framework-etf: +.. _plugins: -Extensible Transport Framework (ETF) -==================================== +Plugins +======= + +OpenDDS puts many implementation details into libraries that are outside the core ``OpenDDS_Dcps`` library. +Making these features modular allows users to build and distribute their applications without building or distributing code their applications won't use. +It also makes it easier to replace these libraries with custom ones. + +- :ref:`transports `: + + - :ref:`tcp-transport` + - :ref:`rtps-udp-transport` + - :ref:`udp-transport` + - :ref:`multicast-transport` + - :ref:`shmem-transport` + +- :ref:`discovery ` [#plugins-static-disc]_: + + - :ref:`inforepo-disc` + - :ref:`rtps-disc` + +- :ref:`security ` [#plugins-sec]_ + +How to enable and use a particular plugin will differ based on the kind of plugin and the plugin itself, but generally they are enabled by some form of configuration setting, for example using ``[transport]transport_type`` or :cfg:key:`DCPSSecurity` in a configuration file. +The plugin will also have to be linked and initialized at runtime. +For dynamic libraries (``.dll``, ``.dynlib`` or, ``.so`` files) this is done automatically as the OpenDDS will load the dynamic library and then run any initialization the plugin requires. +When the plugins are statically linked, then it requires explicit linking and including an initialization header in the application that contains a global object that will initialize the plugin. +If OpenDDS was :ref:`built using CMake `, then :ghfile:`dds/DCPS/StaticIncludes.h` can be included and the initialization headers will be included automatically. +Explicit linking and initialization headers can also be used with dynamic libraries. +This will always load and initialize the plugin when the application starts instead of delaying until the plugin is needed. + +.. _transports: + +Transports +========== .. Sect<1.2.3.2> -OpenDDS uses the IDL interfaces defined by the DDS specification to initialize and control service usage. -Data transmission is accomplished via an OpenDDS-specific transport framework that allows the service to be used with a variety of transport protocols. -This is referred to as *pluggable transports* and makes the extensibility of OpenDDS an important part of its architecture. -OpenDDS currently supports TCP/IP, UDP/IP, IP multicast, shared-memory, and RTPS_UDP transport protocols as shown below. +Transmission of :term:`samples ` and information related to their management is accomplished via an OpenDDS-specific transport framework that allows the service to be used with a variety of transport protocols. +Transports are typically specified via configuration files and are attached to various entities in the publisher and subscriber processes. +See :ref:`config-transport` for details on configuring transports generally. .. figure:: images/pluggable.png - OpenDDS Transport Framework +Transports are used along with :ref:`discovery ` to define how OpenDDS communicates. -Transports are typically specified via configuration files and are attached to various entities in the publisher and subscriber processes. -See :ref:`run_time_configuration--transport-configuration-options` for details on configuring ETF components. +.. _tcp-transport: + +TCP Transport +------------- + +The TCP transport (``tcp``) uses `TCP `__ as the transmission mechanism. +It's the default transport normally. +It's :ref:`reliable `, regardless of configuration. + +.. important:: + + Library filename: ``OpenDDS_Tcp`` + + MPC base project name: :ghfile:`\`\`dcps_tcp\`\` ` + + CMake target Name: :cmake:tgt:`OpenDDS::Tcp` + + :ref:`Initialization header `: :ghfile:`dds/DCPS/transport/tcp/Tcp.h` + + ``[transport]transport_type``: ``tcp`` + + Configuration: :ref:`tcp-transport-config` + +.. _rtps-udp-transport: + +RTPS/UDP Transport +------------------ + +The RTPS/UDP transport (``rtps_udp``) uses the UDP-based transport described in :ref:`spec-rtps` as the transmission mechanism. +It's interoperable with other DDS implementations when used with :ref:`rtps-disc`. +It's the default transport when :doc:`safety_profile` is being used. +It supports :ref:`reliability `. + +.. important:: + + Library filename: ``OpenDDS_Rtps_Udp`` + + MPC base project name: :ghfile:`\`\`dcps_rtps_udp\`\` ` + + CMake target Name: :cmake:tgt:`OpenDDS::Rtps_Udp` + + :ref:`Initialization header `: :ghfile:`dds/DCPS/transport/rtps_udp/RtpsUdp.h` + + ``[transport]transport_type``: ``rtps_udp`` + + Configuration: :ref:`rtps-udp-transport-config` + +.. seealso:: + + :doc:`dds_security` + For security capabilities that are possible when using :ref:`rtps-disc` and the :ref:`rtps-udp-transport` + + :doc:`internet_enabled_rtps` + For using :ref:`rtps-disc` and the :ref:`rtps-udp-transport` over the internet + +.. _udp-transport: + +UDP Transport +------------- + +The UDP transport (``udp``) uses `unicasted `__ `UDP `__ as the transmission mechanism. +It doesn't support :ref:`reliability ` at all. + +.. important:: + + Library filename: ``OpenDDS_Udp`` + + MPC base project name: :ghfile:`\`\`dcps_udp\`\` ` + + CMake target Name: :cmake:tgt:`OpenDDS::Udp` + + :ref:`Initialization header `: :ghfile:`dds/DCPS/transport/udp/Udp.h` + + ``[transport]transport_type``: ``udp`` + + Configuration: :ref:`udp-transport-config` + +.. _multicast-transport: + +Multicast Transport +------------------- + +The multicast transport (``mutlicast``) uses `multicasted `__ `UDP `__ as the transmission mechanism. +It supports :ref:`reliability `. + +.. important:: + + Library filename: ``OpenDDS_Multicast`` + + MPC base project name: :ghfile:`\`\`dcps_multicast\`\` ` + + CMake target Name: :cmake:tgt:`OpenDDS::Multicast` + + :ref:`Initialization header `: :ghfile:`dds/DCPS/transport/multicast/Multicast.h` -The ETF enables application developers to implement their own customized transports. + ``[transport]transport_type``: ``mulicast`` + + Configuration: :ref:`multicast-transport-config` + +.. _shmem-transport: + +Shared Memory Transport +----------------------- + +.. note:: + + This transport is not currently supported on macOS because `macOS lacks support for POSIX unnamed semaphores `__. + +The shared memory transport (``shmem``) uses `shared memory `__ on the local host as the transmission mechanism. +It's :ref:`reliable `, regardless of configuration. + +.. important:: + + Library filename: ``OpenDDS_Shmem`` + + MPC base project name: :ghfile:`\`\`dcps_shmem\`\` ` + + CMake target Name: :cmake:tgt:`OpenDDS::Shmem` + + :ref:`Initialization header `: :ghfile:`dds/DCPS/transport/shmem/Shmem.h` + + ``[transport]transport_type``: ``shmem`` + + Configuration: :ref:`shmem-transport-config` + +.. _introduction--custom-transports: + +Custom Transports +----------------- + +The transport framework enables application developers to implement their own customized transports. Implementing a custom transport involves specializing a number of classes defined in the transport framework. The ``udp`` transport provides a good foundation developers may use when creating their own implementation. See the :ghfile:`dds/DCPS/transport/udp/` directory for details. -.. _introduction--dds-discovery: +.. _discovery: Discovery ========= @@ -369,38 +527,56 @@ Discovery .. Sect<1.2.3.3> -DDS applications must discover one another via some central agent or through some distributed scheme (see :ref:`dds-introduction--discovery`). -OpenDDS provides three options for discovery: :ref:`introduction--centralized-discovery-with-dcpsinforepo`, :ref:`introduction--peer-to-peer-discovery-with-rtps`, and :ref:`introduction--static-discovery`. +DDS applications must :ref:`discover ` one another via some central agent or through some distributed scheme. +OpenDDS provides three options for discovery: :ref:`inforepo-disc`, :ref:`rtps-disc`, and :ref:`static-disc`. The choice of discovery is independent of the choice of transport in most cases. -For example, one can use the tcp transport with RTPS Discovery. -Two notable exceptions are: +For example, one can use the :ref:`tcp-transport` with :ref:`rtps-disc`. +Notable exceptions are: -#. If using DDS Security, RTPS must be used for both the transport and discovery. -#. RTPS must be used for the transport when using Static Discovery. +#. :doc:`dds_security` requires using both :ref:`rtps-disc` and the :ref:`rtps-udp-transport`. +#. To get the most out of :doc:`xtypes`, it's recommended to both :ref:`rtps-disc` and the :ref:`rtps-udp-transport` +#. :ref:`static-disc` requires :ref:`rtps-udp-transport`. Like transports, additional discovery implementations can be created and plugged in. .. _introduction--centralized-discovery-with-dcpsinforepo: +.. _inforepo-disc: -DCPSInfoRepo ------------- +InfoRepo Discovery +------------------ .. Sect<1.2.3.3.1> -.. figure:: images/inforepo_discovery.png +.. note:: - Centralized Discovery with DCPSInfoRepo + InfoRepo discovery is scheduled for deprecation with OpenDDS 4 and scheduled for removal with OpenDDS 5. OpenDDS contains a standalone CORBA service called :ref:`inforepo`. An instance of the DCPSInfoRepo is shared by all the participants in a domain and constitutes a centralized approach to discovery. Each OpenDDS application connects to the DCPSInfoRepo and creates records for its participants, topics, data writers, and data readers. As records for data writers and data readers are created, they are matched against the existing set of records. When matches are found, the DCPSInfoRepo invokes the participant to perform the necessary associations. + +.. figure:: images/inforepo_discovery.png + + Centralized Discovery with DCPSInfoRepo + +.. important:: + + Library filename: ``OpenDDS_InfoRepoDiscovery`` + + MPC base project name: :ghfile:`\`\`dcps_inforepodiscovery\`\` ` + + CMake target Name: :cmake:tgt:`OpenDDS::InfoRepoDiscovery` + + :ref:`Initialization header `: :ghfile:`dds/DCPS/InfoRepoDiscovery/InfoRepoDiscovery.h` + + Configuration: :ref:`inforepo-disc-config` + The DCPSInfoRepo is not involved in data propagation; its role is limited in scope to OpenDDS applications discovering one another. The DCPSInfoRepo populates the :ref:`introduction--built-in-topics` for a participant if configured to do so. OpenDDS creates its own ORB and a separate thread to run that ORB when using DCPSInfoRepo discovery. -See :ref:`run_time_configuration--configuring-applications-for-dcpsinforepo` for details on how applications can be configured to use the DCPSInfoRepo. Application developers are free to run multiple information repositories with each managing their own non-overlapping sets of DCPS domains. @@ -409,7 +585,13 @@ This is known as *Repository Federation*. In order for individual repositories to participate in a federation, each one must specify its own federation identifier value (a 32-bit numeric value) upon start-up. See :ref:`the_dcps_information_repository--repository-federation` for further information about repository federations. +.. seealso:: + + :ref:`inforepo` + Documentation on the ``DCPSInfoRepo`` program + .. _introduction--peer-to-peer-discovery-with-rtps: +.. _rtps-disc: RTPS Discovery -------------- @@ -417,21 +599,31 @@ RTPS Discovery .. Sect<1.2.3.3.2> +RTPS discovery is a peer-to-peer discovery mechanism standardized as part of the :omgspec:`RTPS spec ` +Other DDS implementations can interoperate with OpenDDS when RTPS discovery is used with the :ref:`rtps-udp-transport`. + .. figure:: images/rtps_discovery.png Peer-to-peer Discovery with RTPS -RTPS Discovery is an implementation of the OMG DDSI-RTPS ``(formal/2014-09-01)`` specification (see :omgspec:`rtps:8.5 Discovery Module`). +.. important:: + + Library filename: ``OpenDDS_Rtps`` + + MPC base project name: :ghfile:`\`\`dcps_rtps\`\` ` + + CMake target Name: :cmake:tgt:`OpenDDS::Rtps` + + :ref:`Initialization header `: :ghfile:`dds/DCPS/RTPS/RtpsDiscovery.h` + + Configuration: :ref:`rtps-disc-config` + RTPS Discovery uses the RTPS protocol to advertise and discover participants, data writers, and data readers. -RTPS Discovery uses multicast to discover participants and *builtin endpoints* (not to be confused with Builtin Topics). +RTPS Discovery uses multicast to discover participants and *built-in endpoints* (not to be confused with :term:`built-in topics`) each other without a centralized broker such as InfoRepo. This part of RTPS discovery is called the Simple Participant Discovery Protocol (SPDP). -After the builtin endpoints are discovered and associated, they exchange information about data writers and data readers which are called *endpoints*. +After the built-in endpoints are discovered and associated, they exchange information about data writers and data readers which are called *endpoints*. This part of RTPS discovery is called Simple Endpoint Discovery Protocol (SEDP). RTPS Discovery is a peer-to-peer approach to discovery as each participant interacts directly with other participants to accomplish discovery. -RTPS is interoperable and supports :ref:`dds_security`. -RTPS discovery populates the Builtin Topics for a participant. -See :ref:`run_time_configuration--configuring-for-ddsi-rtps-discovery` for details on how applications can be configured to use RTPS Discovery. -See also :ref:`run_time_configuration--rtps-udp-transport-configuration-options` as the parameters for configuring an RTPS transport also apply to SEDP. The following are additional implementation limits that developers need to take into consideration when developing and deploying applications that use RTPS discovery: @@ -440,18 +632,37 @@ The following are additional implementation limits that developers need to take #. Topic names and type identifiers are limited to 256 characters. -#. OpenDDS's native multicast transport does not work with RTPS Discovery due to the way GUIDs are assigned (a warning will be issued if this is attempted). +#. The :ref:`multicast-transport` does not work with RTPS Discovery due to the way GUIDs are assigned (a warning will be issued if this is attempted). + +.. seealso:: + + :doc:`xtypes` + For expanded type-system capabilities that are possible when using RTPS discovery + + :doc:`dds_security` + For security capabilities that are possible when using :ref:`rtps-disc` and the :ref:`rtps-udp-transport` + + :doc:`internet_enabled_rtps` + For using :ref:`rtps-disc` and the :ref:`rtps-udp-transport` over the internet .. _introduction--static-discovery: +.. _static-disc: Static Discovery ---------------- -In Static Discovery, each particpant starts with a database containing identifiers, QoS settings, and network locators for all participants, topics, data writers, data readers. -The RTPS transport must be used with Static Discovery. +In Static Discovery, each participant starts with a database containing identifiers, QoS settings, and network locators for all participants, topics, data writers, data readers. + +.. important:: + + The :ref:`rtps-udp-transport` is the only transport that can be used with Static Discovery. + + Static Discovery is built-in to the core Dcps library, so it doesn't require linking a separate library or including an initialization header. + + Configuration: :ref:`static-disc-config` + When an application creates a data writer or data reader, Static Discovery causes it to send out periodic announcements. Upon receiving one of these announcements, Static Discovery consults its local database of entities to look up the details necessary for matching and matches it against local entities. -See :ref:`run_time_configuration--configuring-for-static-discovery` for details on how applications can be configured to use Static Discovery. Static Discovery requires that the :ref:`quality_of_service--user-data` QoS be configured for each participant, data writer, and data reader. This user data must contain the identifier of the entity that is being created. @@ -488,3 +699,11 @@ Configuration OpenDDS includes a file-based configuration framework for configuring both global items such as debug level, memory allocation, and discovery, as well as transport implementation details for publishers and subscribers. Configuration can also be achieved directly in code, however, it is recommended that configuration be externalized for ease of maintenance and reduction in runtime errors. The complete set of configuration options are described in :ref:`config`. + +.. rubric:: Footnotes + +.. [#plugins-static-disc] :ref:`static-disc` is built-in to the core Dcps library, so it doesn't require linking a separate library or including an initialization header. + +.. [#plugins-sec] Within DDS Security there is :ref:`a concept of plugins ` that is mostly separate from the plugins described here. + They are for implementing specific security features such as different encryption methods. + The built-in security library is a default implementation of these, but a custom OpenDDS security plugin could implement one or more of these DDS Security plugins. diff --git a/docs/devguide/introduction_to_dds.rst b/docs/devguide/introduction_to_dds.rst index 61a4830293c..6535c5e8545 100644 --- a/docs/devguide/introduction_to_dds.rst +++ b/docs/devguide/introduction_to_dds.rst @@ -115,7 +115,7 @@ Each data writer is bound to a particular topic. The application uses the data writer's type-specific interface to publish samples on that topic. The data writer is responsible for marshaling the data and passing it to the publisher for transmission. -Dynamic data writers (:ref:`xtypes--creating-and-using-a-dynamicdatawriter-or-dynamicdatareader`) can be used when code generated from IDL is not available or desired. +:ref:`Dynamic data writers ` can be used when code generated from IDL is not available or desired. Dynamic data writers are also type-safe, but type checking happens at runtime. .. _introduction--publisher: @@ -154,7 +154,7 @@ A *data reader* takes data from the subscriber, demarshals it into the appropria Each data reader is bound to a particular topic. The application uses the data reader's type-specific interfaces to receive the samples. -Dynamic data readers (:ref:`xtypes--creating-and-using-a-dynamicdatawriter-or-dynamicdatareader`) can be used when code generated from IDL is not available or desired. +:ref:`Dynamic data readers ` can be used when code generated from IDL is not available or desired. Dynamic data readers are also type-safe, but type checking happens at runtime. .. _dds-introduction--discovery: @@ -164,8 +164,7 @@ Discovery, Matching, and Association ************************************ *Discovery* is the process whereby a participant learns about the publications and subscriptions offered by other participants. -The OMG DDS specification (``formal/2015-04-10``) leaves the details of discovery to the implementation. -However, the OMG DDSI-RTPS specification (``formal/2014-09-01``) defines an interoperable peer-to-peer system for discovery. +The :ref:`spec-dds` leaves the details of discovery to the implementation. After discovering a remote publication and subscription, a participant compares the remote entity with its local entities to determine if they are compatible. This process is called *matching*. @@ -174,6 +173,11 @@ A data writer and data reader match if they are on the same topic, they have com If a local entity matches a remote entity, then the implementation is configured to allow data to flow from the data writer to the data reader. This is called *association*. +.. seealso:: + + :ref:`discovery` + The discovery impementations availables in OpenDDS. + .. _introduction--quality-of-service-policies: *************************** @@ -192,7 +196,10 @@ Subscribers *request* a set of policies that are minimally required. Publishers *offer* a set of QoS policies to potential subscribers. The DDS implementation then attempts to match the requested policies with the offered policies; if these policies are compatible then the association is formed. -The QoS policies currently implemented by OpenDDS are discussed in detail in :ref:`qos`. +.. seealso:: + + :ref:`qos` + The QoS policies available in OpenDDS and how to use them. ******************** Conceptual Data Flow @@ -220,30 +227,10 @@ The DDS specification defines a number of topics that are built-in to the DDS im Subscribing to these *built-in topics* gives application developers access to the state of the domain being used including which topics are registered, which data readers and data writers have been discovered and their status, and the QoS settings of the various entities. While subscribed, the application receives samples indicating changes in the entities within the domain. -The following table shows the built-in topics defined within the DDS specification: - -.. list-table:: Built-in Topics - :header-rows: 1 - - * - Topic Name - - - Description - - * - ``DCPSParticipant`` - - - Each instance represents a domain participant. - - * - ``DCPSTopic`` +.. seealso:: - - Each instance represents a normal (not built-in) topic. - - * - ``DCPSPublication`` - - - Each instance represents a data writer. - - * - ``DCPSSubscription`` - - - Each instance represents a data reader. + :ref:`bit` + The built-in topics available in OpenDDS and how to use them. .. _introduction--listeners: @@ -257,6 +244,11 @@ Listeners The DCPS API defines a callback interface for each entity that allows an application to listen for certain state changes or events pertaining to that entity. For example, a Data Reader Listener is notified when there are data values available for reading. +.. seealso:: + + :ref:`conditions_and_listeners--listeners` + The listeners available in OpenDDS and how to use them. + .. _introduction--conditions: ********** @@ -267,9 +259,7 @@ Conditions Sect<1.1.5> *Conditions* and *Wait Sets* can also be used to detect events of interest in DDS Entities and are an alternative to listeners. -The general pattern is - -The application creates a specific kind of ``Condition`` object, such as a ``StatusCondition``, and attaches it to a ``WaitSet``. +The general pattern is the application creates a specific kind of ``Condition`` object, such as a ``StatusCondition``, and attaches it to a ``WaitSet``. * The application waits on the ``WaitSet`` until one or more conditions become true. @@ -277,5 +267,10 @@ The application creates a specific kind of ``Condition`` object, such as a ``Sta * The ``DataReader`` interface also has operations that take a ``ReadCondition`` argument. -* ``QueryCondition`` objects are provided as part of the implementation of the Content-Subscription Profile. +* ``QueryCondition`` objects are provided as part of the implementation of the :ref:`content_subscription_profile`. The ``QueryCondition`` interface extends the ``ReadCondition`` interface. + +.. seealso:: + + :ref:`conditions_and_listeners--conditions` + The conditions available in OpenDDS and how to use them. diff --git a/docs/devguide/quality_of_service.rst b/docs/devguide/quality_of_service.rst index 3a3bc8f32fd..d5e0390afe8 100644 --- a/docs/devguide/quality_of_service.rst +++ b/docs/devguide/quality_of_service.rst @@ -722,6 +722,7 @@ User Data QoS Sect<3.2.11> The user data QoS policy can be used to attach arbitrary information to the created :term:`entity`. +It is not available to the user when using :ref:`static-disc`. This policy applies to the domain participant, data reader, and data writer entities via the ``user_data`` member of their respective QoS structures. .. important:: @@ -867,7 +868,7 @@ This policy applies to topic and data writer entities via the ``transport_priori .. important:: - OpenDDS currently only uses this in the tcp and udp transports. + OpenDDS currently only implements this for the :ref:`tcp ` and :ref:`udp ` transports. This policy is :ref:`immutable ` and does not affect association. This is opposed to the DDS specification, which specifies that it's mutable. @@ -1526,13 +1527,13 @@ This XTypes concept is explained in detail in :ref:`xtypes--data-representation` - :ref:`Default values ` - * - :term:`DataWriter` using rtps_udp + * - :term:`DataWriter` using the :ref:`rtps-udp-transport` - ``value`` - (empty sequence) -- interpreted as a sequence containing ``XCDR2_DATA_REPRESENTATION`` - * - :term:`DataReader` using rtps_udp + * - :term:`DataReader` using the :ref:`rtps-udp-transport` - ``value`` @@ -1556,7 +1557,7 @@ This XTypes concept is explained in detail in :ref:`xtypes--data-representation` The default interpretation of ``value`` is OpenDDS-specific as of XTypes 1.3. The XTypes specification v1.3 specifies that it should be interpreted as a sequence containing ``XCDR_DATA_REPRESENTATION``. - This is because OpenDDS defaults to XCDR2 instead of XCDR1 when using rtps_udp, the use of unaligned CDR, and the desire to have readers be as compatible as possible by default. + This is because OpenDDS defaults to XCDR2 instead of XCDR1 when using the :ref:`rtps-udp-transport`, the use of unaligned CDR, and the desire to have readers be as compatible as possible by default. See :ref:`xtypes--data-representation` for details. .. _qos-data-representation-association: @@ -1574,7 +1575,7 @@ This XTypes concept is explained in detail in :ref:`xtypes--type-consistency-enf .. important:: - This is only used when using RTPS discovery. + OpenDDS only supports this with :ref:`rtps-disc`. This policy is :ref:`immutable ` and affects :ref:`association `. diff --git a/docs/devguide/run_time_configuration.rst b/docs/devguide/run_time_configuration.rst index 42e4ac2e739..094df14af30 100644 --- a/docs/devguide/run_time_configuration.rst +++ b/docs/devguide/run_time_configuration.rst @@ -1,3 +1,5 @@ +.. default-domain:: cfg + .. _run_time_configuration: .. _config: @@ -25,13 +27,14 @@ OpenDDS configuration is concerned with three main areas: #. **Common Configuration Options** -- configure the behavior of DCPS entities at a global level. This allows separately deployed processes in a computing environment to share common settings for the specified behavior (e.g. all readers and writers should use RTPS discovery). - See :ref:`run_time_configuration--common-configuration-options` for details. + See :ref:`config-common` for details. -#. **Discovery Configuration Options** -- configure the behavior of the discovery mechanism(s). - OpenDDS supports multiple approaches for discovering and associating writers and readers as detailed in :ref:`run_time_configuration--discovery-configuration`. +#. **Discovery Configuration Options** -- configure the behavior of the :ref:`discovery mechanism(s) `. + OpenDDS supports multiple approaches for discovering and associating writers and readers as detailed in :ref:`config-disc`. -#. **Transport Configuration Options** -- configure the Extensible Transport Framework (ETF) which abstracts the transport layer from the DCPS layer of OpenDDS. +#. **Transport Configuration Options** -- configure the :ref:`transport framework ` which abstracts the transport layer from the DCPS layer of OpenDDS. Each pluggable transport can be configured separately. + See :ref:`config-transport` for details. The configuration file for OpenDDS is a human-readable ini-style text file. :ref:`This table ` shows a list of the available configuration section types as they relate to the area of OpenDDS that they configure. @@ -45,19 +48,23 @@ The configuration file for OpenDDS is a human-readable ini-style text file. - **File Section Title** - * - :ref:`Global Settings ` + * - :ref:`Global Settings ` - - ``[common]`` + - :sec:`common` - * - Discovery + * - :ref:`config-disc` - ``[domain]`` - ``[repository]`` + * - :ref:`inforepo-disc-config` + + - ``[repository]`` - ``[rtps_discovery]`` + * - :ref:`rtps-disc-config` - * - Static Discovery + - ``[rtps_discovery]`` + + * - :ref:`static-disc-config` - ``[endpoint]`` @@ -71,7 +78,7 @@ The configuration file for OpenDDS is a human-readable ini-style text file. ``[subscriberqos]`` - * - Transport + * - :ref:`config-transport` - ``[config]`` @@ -81,11 +88,16 @@ The configuration file for OpenDDS is a human-readable ini-style text file. - ``[ice]`` -For each of the section types with the exception of ``[common]`` and ``[ice]``, the syntax of a section header takes the form of ``[section type/instance]``. -For example, a ``[repository]`` section type would always be used in a configuration file like so: +For each of the section types with the exception of :sec:`common` and ``[ice]``, the syntax of a section header takes the form of ``[/]``. +For example, a ``[repository]`` section type would always be used in a configuration file like so: ``[repository/repo_1]`` where ``repository`` is the section type and ``repo_1`` is an instance name of a repository configuration. + +How to use instances to configure discovery and transports is explained further in :ref:`config-disc` and :ref:`config-transport` respectively. -``[repository/repo_1]`` where ``repository`` is the section type and ``repo_1`` is an instance name of a repository configuration. -How to use instances to configure discovery and transports is explained further in :ref:`run_time_configuration--discovery-configuration` and :ref:`run_time_configuration--transport-configuration`. +.. _DCPSConfigFile: + +******************* +``-DCPSConfigFile`` +******************* The ``-DCPSConfigFile`` command-line argument can be used to pass the location of a configuration file to OpenDDS. For example: @@ -144,7 +156,7 @@ For example, the following commands would have the same effect: .. code-block:: bash ./publisher -DCPSConfigFile /pretend/this/is/a/long/path/a.ini - ./subscriber -DCPSConfigFile /pretend//this/is/a/long/path/b.ini + ./subscriber -DCPSConfigFile /pretend/this/is/a/long/path/b.ini export OPENDDS_CONFIG_DIR=/pretend/this/is/a/long/path ./publisher -DCPSConfigFile a.ini @@ -155,6 +167,7 @@ See the header file :ghfile:`dds/DCPS/Service_Participant.h` for details. The following subsections detail each of the configuration file sections and the available options related to those sections. +.. _config-common: .. _run_time_configuration--common-configuration-options: **************************** @@ -164,7 +177,7 @@ Common Configuration Options .. Sect<7.2> -The ``[common]`` section of an OpenDDS configuration file contains options such as the debugging output level, the location of the ``DCPSInfoRepo`` process, and memory preallocation settings. +The :sec:`common` section of an OpenDDS configuration file contains options such as the debugging output level, the location of the ``DCPSInfoRepo`` process, and memory preallocation settings. A sample ``[common]`` section follows: .. code-block:: ini @@ -180,7 +193,7 @@ A sample ``[common]`` section follows: It is not necessary to specify every option. -Option values in the ``[common]`` section with names that begin with ``DCPS`` can be overridden by a command-line argument. +Option values in the ``[common]`` section with names that begin with ``DCPS`` or ``ORB`` [#orbprefix]_ can be overridden by a command-line argument. The command-line argument has the same name as the configuration option with a ``-`` prepended to it. For example: @@ -188,311 +201,307 @@ For example: subscriber -DCPSInfoRepo localhost:12345 -The following table summarizes the ``[common]`` configuration options: - -.. list-table:: - :header-rows: 1 - - * - Option - - - Description - - - Default - - * - ``DCPSBit=[1|0]`` +.. sec:: common - - Toggle Built-In-Topic support. - - - ``1`` + .. key:: DCPSBidirGIOP= + :default: ``1`` (enabled) - * - ``DCPSBitLookupDurationMsec=msec`` - - - The maximum duration in milliseconds that the framework will wait for latent Built-In Topic information when retrieving BIT data given an instance handle. - The participant code may get an instance handle for a remote entity before the framework receives and processes the related BIT information. - The framework waits for up to the given amount of time before it fails the operation. - - - ``2000`` + .. note:: This key is only applicable when using :ref:`inforepo-disc`. - * - ``DCPSBitTransportIPAddress=addr`` + Use TAO's BiDirectional GIOP feature for interaction with the :ref:`inforepo`. + With BiDir enabled, fewer sockets are needed since the same socket can be used for both client and server roles. - - IP address identifying the local interface to be used by tcp transport for the Built-In Topics. + .. key:: DCPSBit= + :default: ``1`` (enabled) - .. note:: This property is only applicable to a ``DCPSInfoRepo`` configuration. - - - ``INADDR_ANY`` - - * - ``DCPSBitTransportPort=port`` - - - Port used by the tcp transport for Built-In Topics. - If the default of ``0`` is used, the operating system will choose a port to use. - - .. note:: This property is only applicable to a ``DCPSInfoRepo`` configuration. - - - ``0`` + Controls if :ref:`bit` are enabled. - * - ``DCPSChunks=n`` + .. key:: DCPSBitLookupDurationMsec= + :default: ``2000`` (2 seconds) - - Configurable number of chunks that a data writer's and reader's cached allocators will preallocate when the :ref:`qos-resource-limits` QoS value is infinite. - When all of the preallocated chunks are in use, OpenDDS allocates from the heap. + The maximum duration in milliseconds that the framework will wait for latent :ref:`bit` information when retrieving BIT data given an instance handle. + The participant code may get an instance handle for a remote entity before the framework receives and processes the related BIT information. + The framework waits for up to the given amount of time before it fails the operation. - - ``20`` + .. key:: DCPSBitTransportIPAddress= + :default: ``INADDR_ANY`` - * - ``DCPSChunkAssociationMultiplier=n`` + .. note:: This key is only applicable when using :ref:`inforepo-disc`. - - Multiplier for ``DCPSChunks`` or the :ref:`qos-resource-limits` ``max_samples`` value to determine the total number of shallow copy chunks that are preallocated. - Set this to a value greater than the number of connections so the preallocated chunk handles do not run out. - A sample written to multiple data readers will not be copied multiple times but there is a shallow copy handle to that sample used to manage the delivery to each data reader. - The size of the handle is small so there is not great need to set this value close to the number of connections. + IP address identifying the local interface to be used by :ref:`tcp-transport` for the :ref:`bit`. - - ``10`` + .. key:: DCPSBitTransportPort= + :default: ``0`` - * - ``DCPSDebugLevel=n`` + .. note:: This key is only applicable when using :ref:`inforepo-disc`. - - Integer value that controls the amount of debug information the DCPS layer prints. - Valid values are 0 through 10. + Port used by the :ref:`tcp-transport` for :ref:`bit`. + If the default of ``0`` is used, the operating system will choose a port to use. - - 0 + .. key:: DCPSChunkAssociationMultiplier= + :default: ``10`` - * - ``ORBLogFile=filename`` + Multiplier for the :key:`DCPSChunks` or the ``max_samples`` value in :ref:`qos-resource-limits` to determine the total number of shallow copy chunks that are preallocated. + Set this to a value greater than the number of connections so the preallocated chunk handles do not run out. + A sample written to multiple data readers will not be copied multiple times but there is a shallow copy handle to that sample used to manage the delivery to each data reader. + The size of the handle is small so there is not great need to set this value close to the number of connections. - - Change log message destination to the file specified, which is opened in appending mode. - See the note below this table regarding the ORB prefix. + .. key:: DCPSChunks= + :default: ``20`` - - None: use standard error + Configurable number of chunks that a data writer's and reader's cached allocators will preallocate when the :ref:`qos-resource-limits` value is infinite. + When all of the preallocated chunks are in use, OpenDDS allocates from the heap. + This feature of allocating from the heap when the preallocated memory is exhausted provides flexibility but performance will decrease when the preallocated memory is exhausted. - * - ``ORBVerboseLogging=[0|1|2]`` + .. key:: DCPSDebugLevel= + :default: ``0`` (disabled) - - Add a prefix to each log message, using a format defined by the ACE library: + Integer value that controls the amount of :ref:`debug information the DCPS layer logs `. + Valid values are ``0`` through ``10``. - 0 -- no prefix + .. key:: DCPSDefaultAddress= + :default: ``0.0.0.0`` - 1 -- verbose "lite": adds timestamp and priority + Default value for the host portion of ``local_address`` in transport instances and some other host address values: - 2 -- verbose: in addition to "lite" has host name, PID, program name + - ``[transport]local_address`` (tcp) + - ``[transport]local_address`` (udp) + - ``[transport]local_address`` (multicast) + - ``[transport]local_address`` (rtps_udp) + - ``[transport]ipv6_local_address`` (rstp_udp) + - ``[transport]multicast_interface`` (rtps_udp) + - ``[rtps_discovery]SedpLocalAddress`` + - ``[rtps_discovery]SpdpLocalAddress`` + - ``[rtps_discovery]MulticastInterface`` - See the note below this table regarding the ORB prefix. + .. key:: DCPSDefaultDiscovery=DEFAULT_REPO|DEFAULT_RTPS|DEFAULT_STATIC| + :default: :val:`DEFAULT_REPO` - - 0 + Specifies a discovery configuration to use for any domain not explicitly configured. - * - ``DCPSDefaultAddress=addr`` + .. val:: DEFAULT_REPO - - Default value for the host portion of ``local_address`` for transport instances containing a ``local_address``. - Only applied when ``DCPSDefaultAddress`` is set to a non-empty value and no ``local_address`` is specified in the transport. + Uses a default :ref:`inforepo-disc` configuration. - Other subsystems (such as DDSI-RTPS Discovery) use ``DCPSDefaultAddress`` as a default value as well. + .. val:: DEFAULT_RTPS - - + Uses a default :ref:`rtps-disc` configuration. - * - ``DCPSDefaultDiscovery=[`` + .. val:: DEFAULT_STATIC - ``DEFAULT_REPO|`` + Uses a default :ref:`static-disc` configuration. - ``DEFAULT_RTPS|`` + .. val:: - ``DEFAULT_STATIC|`` + Name of a user-defined discovery configuration. + This can either be a ``repository`` or ``rtps_discovery`` section - ``user-defined configuration instance name]`` + See :ref:`config-disc` for details about configuring discovery. - - Specifies a discovery configuration to use for any domain not explicitly configured. - ``DEFAULT_REPO`` translates to using the ``DCPSInfoRepo``. - ``DEFAULT_RTPS`` specifies the use of RTPS for discovery. - ``DEFAULT_STATIC`` specifies the use of static discovery. - See :ref:`run_time_configuration--discovery-configuration` for details about configuring discovery. + .. key:: DCPSGlobalTransportConfig=|$file + :default: The default configuration is used as described in :ref:`run_time_configuration--overview`. - - ``DEFAULT_REPO`` + The :ref:`transport configuration ` that should be used as the global default one. - * - ``DCPSGlobalTransportConfig=name`` + .. val:: - - Specifies the name of the transport configuration that should be used as the global configuration. - This configuration is used by all entities that do not otherwise specify a transport configuration. - A special value of $file uses a transport configuration that includes all transport instances defined in the configuration file. + Name of a user-defined ``config`` section. - - The default configuration is used as described in :ref:`run_time_configuration--overview` + .. val:: $file - * - ``DCPSInfoRepo=objref`` + ``$file`` uses a transport configuration that includes all transport instances defined in the configuration file. - - Object reference for locating the DCPS Information Repository. - This can either be a full CORBA IOR or a simple host:port string. + .. key:: DCPSInfoRepo= + :default: ``file://repo.ior`` - - ``file://repo.ior`` + Object reference for locating the :ref:`inforepo` in :ref:`inforepo-disc`. + This value is passed to ``CORBA::ORB::string_to_object()`` and can be any Object URL type understandable by :term:`TAO` (file, IOR, corbaloc, corbaname). + A simplified endpoint description of the form ``:`` is also accepted, which is equivalent to ``corbaloc:::/DCPSInfoRepo``. - * - ``DCPSLivelinessFactor=n`` + .. key:: DCPSLivelinessFactor= + :default: ``80`` - - Percent of the liveliness lease duration after which a liveliness message is sent. - A value of 80 implies a 20% cushion of latency from the last detected heartbeat message. + Percent of the :ref:`qos-liveliness` lease duration after which a liveliness message is sent. + A value of ``80`` implies a 20% cushion of latency from the last detected heartbeat message. - - ``80`` + .. key:: DCPSLogLevel=none|error|warning|notice|info|debug + :default: :val:`warning` - * - ``DCPSLogLevel=`` + General logging control. - ``none|`` + .. val:: none - ``error|`` + See :ref:`none log level ` - ``warning|`` + .. val:: error - ``notice|`` + See :ref:`error log level ` - ``info|`` + .. val:: warning - ``debug`` + See :ref:`warning log level ` - - General logging control. - See :ref:`run_time_configuration--logging` for details. + .. val:: notice - - ``warning`` + See :ref:`notice log level ` - * - ``DCPSMonitor=[0|1]`` + .. val:: info - - Use the OpenDDS_monitor library to publish data on monitoring topics (see dds/monitor/README). + See :ref:`info log level ` - - ``0`` + .. val:: debug - * - ``DCPSPendingTimeout=sec`` + See :ref:`debug log level ` - - The maximum duration in seconds a data writer will block to allow unsent samples to drain on deletion. - By default, this option blocks indefinitely. + See :ref:`run_time_configuration--logging` for details. - - ``0`` + .. key:: DCPSMonitor= + :default: ``0`` - * - ``DCPSPersistentDataDir=path`` + Use the Monitor library to publish data on monitoring topics (see :ghfile:`dds/monitor/README`). - - The path on the file system where durable data will be stored. - If the directory does not exist it will be created automatically. + .. key:: DCPSPendingTimeout= + :default: ``0`` - - ``OpenDDS-durable-data-dir`` + The maximum duration in seconds a data writer will block to allow unsent samples to drain on deletion. + The default, ``0``, blocks indefinitely. - * - ``DCPSPublisherContentFilter=[1|0]`` + .. key:: DCPSPersistentDataDir= + :default: ``OpenDDS-durable-data-dir`` - - Controls the filter expression evaluation policy for content filtered topics. - When enabled (1), the publisher may drop any samples, before handing them off to the transport when these samples would have been ignored by all subscribers. + The path to a directory on where durable data will be stored for :ref:`PERSISTENT_DURABILITY_QOS `. + If the directory does not exist it will be created automatically. - - ``1`` + .. key:: DCPSPublisherContentFilter= + :default: ``1`` - * - ``DCPSSecurity=[0|1]`` + Controls the filter expression evaluation policy for :ref:`content filtered topics `. + When the value is ``1`` the publisher may drop any samples, before handing them off to the transport when these samples would have been ignored by all subscribers. - - This setting is only available when OpenDDS is compiled with DDS Security enabled. - If set to 1, enable DDS Security framework and built-in plugins. - Each Domain Participant using security must be created with certain QoS policy values. - See :ref:`dds_security`: DDS Security for more information. + .. key:: DCPSSecurity= + :default: ``0`` - - ``0`` + This setting is only available when OpenDDS is compiled with :ref:`dds_security`. + If set to ``1``, enable DDS Security framework and built-in plugins. + Each Domain Participant using security must be created with the correct :ref:`property QoS `. - * - ``DCPSSecurityDebug=CAT[,CAT...]`` + See :ref:`dds_security` for more information. - - This setting is only available when OpenDDS is compiled with DDS Security enabled. - This controls the security debug logging granularity by category. - See :ref:`run_time_configuration--security-debug-logging` for details. + .. key:: DCPSSecurityDebug=[,]... + :default: ``0`` (No security logging) - - ``0`` + This setting is only available when OpenDDS is compiled with :ref:`dds_security` enabled. + This controls the :ref:`security debug logging ` granularity by category. - * - ``DCPSSecurityDebugLevel=n`` + .. key:: DCPSSecurityDebugLevel= + :default: ``0`` (No security logging) - - This setting is only available when OpenDDS is compiled with DDS Security enabled. - This controls the security debug logging granularity by debug level. - See :ref:`run_time_configuration--security-debug-logging` for details. + This setting is only available when OpenDDS is compiled with :ref:`dds_security` enabled. + This controls the :ref:`security debug logging ` granularity by debug level. - - ``N/A`` + .. key:: DCPSSecurityFakeEncryption= + :default: ``0`` (Real encryption when that's setup) - * - ``DCPSSecurityFakeEncryption=[0|1]`` + This setting is only available when OpenDDS is compiled with :ref:`dds_security` enabled. + This option, when set to ``1``, disables all encryption by making encryption and decryption no-ops. + OpenDDS still generates keys and performs other security bookkeeping, so this option is useful for debugging the security infrastructure by making it possible to manually inspect all messages. - - This setting is only available when OpenDDS is compiled with DDS Security enabled. - This option, when set to 1, disables all encryption by making encryption and decryption no-ops. - OpenDDS still generates keys and performs other security bookkeeping, so this option is useful for debugging the security infrastructure by making it possible to manually inspect all messages. + .. key:: DCPSThreadStatusInterval= + :default: ``0`` (disabled) - - ``0`` + Enable :ref:`internal thread status reporting ` using the specified reporting interval, in seconds. - * - ``DCPSTransportDebugLevel=n`` + .. key:: DCPSTransportDebugLevel= + :default: ``0`` (disabled) - - Integer value that controls the amount of debug information the transport layer prints. - See :ref:`run_time_configuration--transport-layer-debug-logging` for details. + Integer value that controls the amount of :ref:`debug information the transport layer logs `. + Valid values are ``0`` through ``5``. - - ``0`` + .. key:: DCPSTypeObjectEncoding=Normal|WriteOldFormat|ReadOldFormat + :default: :val:`Normal` - * - ``pool_size=n_bytes`` + From when :term:`XTypes` was first implemented in OpenDDS from 3.16.0 until 3.18.0, there was a bug in the encoding and decoding of ``TypeObject`` and related data types for :ref:`representing user types `. + This was fixed in 3.18.0, but if an application needs to be compatible with an application built with 3.16 or 3.17, then it can use this option to do that and migrate to the correct encoding without taking everything down all at once. - - Size of safety profile memory pool, in bytes. + .. val:: WriteOldFormat - - ``41943040 (40 MiB)`` + This setting makes OpenDDS use the incorrect encoding. + To start to migrate an existing set of OpenDDS applications, this should be the setting of applications using OpenDDS 3.18 or later. - * - ``pool_granularity=n_bytes`` + .. val:: ReadOldFormat - - Granularity of safety profile memory pool in bytes. - Must be multiple of 8. + This setting allows OpenDDS to read the incorrect encoding, but it will always write the correct one. + Once all application using OpenDDS 3.16 or 3.17 have been upgraded to OpenDDS 3.18 or later, ``WriteOldFormat`` can be set to communicate with ``ReadOldFormat`` and ``Normal``. - - ``8`` + .. val:: Normal - * - ``Scheduler=[`` + The default, correct encoding is used. + Once all applications are using both OpenDDS 3.18 or later and ``ReadOldFormat``, then ``Normal`` can be used. - ``SCHED_RR|`` + .. key:: ORBLogFile= + :default: Output to standard error stream on most platforms - ``SCHED_FIFO|`` + Change :ref:`log ` message destination to the file specified, which is opened in appending mode. [#orbprefix]_ - ``SCHED_OTHER]`` + .. key:: ORBVerboseLogging=0|1|2 + :default: ``0`` - - Selects the thread scheduler to use. - Setting the scheduler to a value other than the default requires privileges on most systems. - A value of ``SCHED_RR``, ``SCHED_FIFO``, or ``SCHED_OTHER`` can be set. - ``SCHED_OTHER`` is the default scheduler on most systems; ``SCHED_RR`` is a round robin scheduling algorithm; and ``SCHED_FIFO`` allows each thread to run until it either blocks or completes before switching to a different thread. + Add a prefix to each :ref:`log ` message, using a format defined by the :term:`ACE` library: [#orbprefix]_ - - SCHED_OTHER + .. val:: 0 - * - ``scheduler_slice=usec`` + No prefix - - Some operating systems, such as SunOS, require a time slice value to be set when selecting schedulers other than the default. - For those systems, this option can be used to set a value in microseconds. + .. val:: 1 - - ``none`` + Verbose "lite", adds timestamp and priority - * - ``DCPSBidirGIOP=[0|1]`` + .. val:: 2 - - Use TAO's BiDirectional GIOP feature for interaction with the DCPSInfoRepo. - With BiDir enabled, fewer sockets are needed since the same socket can be used for both client and server roles. + Verbose, in addition to "lite" has host name, PID, program name - - ``1`` + .. key:: pool_size= + :default: ``41943040`` bytes (40 MiB) - * - ``DCPSThreadStatusInterval=sec`` + Size of :ref:`safety_profile` memory pool, in bytes. - - Enable internal thread status reporting (:ref:`built_in_topics--openddsinternalthread-topic`) using the specified reporting interval, in seconds. + .. key:: pool_granularity= + :default: ``8`` - - ``0 (disabled)`` + Granularity of :ref:`safety_profile` memory pool in bytes. + Must be multiple of 8. - * - ``DCPSTypeObjectEncoding=[`` + .. key:: Scheduler=SCHED_RR|SCHED_FIFO|SCHED_OTHER + :default: :val:`SCHED_OTHER` - ``Normal |`` + Selects the scheduler to use for transport sending threads. + Setting the scheduler to a value other than the default requires privileges on most systems. - ``WriteOldFormat |`` + .. val:: SCHED_RR - ``ReadOldFormat ]`` + Round robin scheduling algorithm - - Before version 3.18, OpenDDS had a bug in the encoding used for TypeObject (from XTypes) and related data types. + .. val:: SCHED_FIFO - If this application needs to be compatible with an application built with an older OpenDDS (that has XTypes), select one of WriteOldFormat or ReadOldFormat. + Allows each thread to run until it either blocks or completes before switching to a different thread - Using WriteOldFormat means that the TypeInformation written by this application will be understood by legacy applications. + .. val:: SCHED_OTHER - Using WriteOldFormat or ReadOldFormat means that TypeInformation written in the legacy format will be understood by this application. + The default scheduler on most systems - These options are designed to enable a phased migration from the incorrect implementation (pre-3.18) to a compliant one. - In the first phase, legacy applications can coexist with WriteOldFormat. - In the second phase (once all legacy applications have been upgraded), WriteOldFormat can communicate with ReadOldFormat. - In the final phase (once all WriteOldFormat applications have been upgraded), ReadOldFormat applications can be transitioned to Normal. + .. seealso:: - - ``Normal`` + :manpage:`sched(7)` -The ``DCPSInfoRepo`` option's value is passed to ``CORBA::ORB::string_to_object()`` and can be any Object URL type understandable by TAO (file, IOR, corbaloc, corbaname). -A simplified endpoint description of the form ``:`` is also accepted. -It is equivalent to ``corbaloc:::/DCPSInfoRepo``. + :ref:`qos-transport-priority` -Certain options that begin with "ORB" instead of "DCPS" are listed in the table above. -They are named differently since they are inherited from TAO. -The options starting with "ORB" listed in this table are implemented directly by OpenDDS (not passed to TAO) and are supported either on the command line (using a "-" prefix) or in the configuration file. -Other command-line options that begin with ``-ORB`` are passed to TAO's ``ORB_init`` if DCPSInfoRepo discovery is used. + .. key:: scheduler_slice= + :default: ``0`` -The ``DCPSChunks`` option allows application developers to tune the amount of memory preallocated when the :ref:`qos-resource-limits` are set to infinite. -Once the allocated memory is exhausted, additional chunks are allocated/deallocated from the heap. -This feature of allocating from the heap when the preallocated memory is exhausted provides flexibility but performance will decrease when the preallocated memory is exhausted. + Some operating systems require a time slice value to be set when selecting a :key:`Scheduler` other than the default. + For those systems, this option can be used to set a value in microseconds. +.. _config-disc: .. _run_time_configuration--discovery-configuration: *********************** @@ -649,10 +658,11 @@ Here are the available properties for the ``[domain]`` section: - A user-defined string that refers to the instance name of a ``[config]`` section. See :ref:`run_time_configuration--transport-configuration`. +.. _inforepo-disc-config: .. _run_time_configuration--configuring-applications-for-dcpsinforepo: -Configuring Applications for DCPSInfoRepo -========================================= +Configuring for InfoRepo Discovery +================================== .. Sect<7.3.2> @@ -851,10 +861,11 @@ Here are the valid properties for a ``[repository]`` section: (Deprecated. Provided for backward compatibility) +.. _rtps-disc-config: .. _run_time_configuration--configuring-for-ddsi-rtps-discovery: -Configuring for DDSI-RTPS Discovery -=================================== +Configuring for RTPS Discovery +============================== .. Sect<7.3.3> @@ -1342,6 +1353,7 @@ Additional DDSI-RTPS Discovery Features The DDSI_RTPS discovery implementation creates and manages a transport instance -- specifically an object of class ``RtpsUdpInst``. In order for applications to access this object and enable advanced features (:ref:`Additional RTPS_UDP Features `), the ``RtpsDiscovery`` class provides the method ``sedp_transport_inst(domainId, participant)``. +.. _static-disc-config: .. _run_time_configuration--configuring-for-static-discovery: Configuring for Static Discovery @@ -1966,6 +1978,7 @@ The static discovery implementation also checks that the QoS of a data reader or - +.. _config-transport: .. _run_time_configuration--transport-configuration: *********************** @@ -2399,10 +2412,11 @@ Enabling the ``thread_per_connection`` option will increase performance when wri This balance of network performance to context switching overhead is best determined by experimenting. If a machine has multiple network cards, it may improve performance by creating a transport for each network card. +.. _tcp-transport-config: .. _run_time_configuration--tcp-ip-transport-configuration-options: -TCP/IP Transport Configuration Options --------------------------------------- +TCP Transport Configuration Options +----------------------------------- .. Sect<7.4.5.2> @@ -2535,10 +2549,11 @@ The reconnection process is (a successful reconnect ends this sequence): * While we have not tried more than ``conn_retry_attempts``, wait (previous wait time * ``conn_retry_backoff_multiplier``) milliseconds and attempt to reconnect. +.. _udp-transport-config: .. _run_time_configuration--udp-ip-transport-configuration-options: -UDP/IP Transport Configuration Options --------------------------------------- +UDP Transport Configuration Options +------------------------------------ .. Sect<7.4.5.3> @@ -2584,10 +2599,11 @@ The following table summarizes the transport configuration options that are uniq - ``Platform value of ACE_DEFAULT_MAX_SOCKET_BUFSIZ`` +.. _multicast-transport-config: .. _run_time_configuration--ip-multicast-transport-configuration-options: -IP Multicast Transport Configuration Options --------------------------------------------- +Multicast Transport Configuration Options +----------------------------------------- .. Sect<7.4.5.4> @@ -2772,9 +2788,10 @@ The following table summarizes the transport configuration options that are uniq - +.. _rtps-udp-transport-config: .. _run_time_configuration--rtps-udp-transport-configuration-options: -RTPS_UDP Transport Configuration Options +RTPS UDP Transport Configuration Options ---------------------------------------- .. @@ -2990,13 +3007,13 @@ Some implementation notes related to using the ``rtps_udp`` transport protocol a .. _run_time_configuration--additional-rtps-udp-features: -Additional RTPS_UDP Features +Additional RTPS UDP Features ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. Sect<7.4.5.5.1> -The RTPS_UDP transport implementation has capabilities that can only be enabled by API. +The RTPS UDP transport implementation has capabilities that can only be enabled by API. These features cannot be enabled using configuration files. The ``RtpsUdpInst`` class has a method ``count_messages(bool flag)`` via inheritance from ``TransportInst``. @@ -3104,9 +3121,10 @@ The elements of that sequence are defined in IDL: ``OpenDDS::DCPS::TransportStat - Number of bytes received from the locator. +.. _shmem-transport-config: .. _run_time_configuration--shared-memory-transport-configuration-options: -Shared-Memory Transport Configuration Options +Shared Memory Transport Configuration Options --------------------------------------------- .. @@ -3376,78 +3394,100 @@ By default, the OpenDDS framework will only log serious errors and warnings that An OpenDDS user may increase the amount of logging via the log level and debug logging via controls at the DCPS, Transport, or Security layers. The default destination of these log messages is the process's standard error stream. -See :ref:`run_time_configuration--common-configuration-options` for options controlling the destination and formatting of log messages. +See :ref:`config-common` for options controlling the destination and formatting of log messages. The highest level logging is controlled by the general log levels listed in the following table. .. list-table:: :header-rows: 1 - * - Level + * - Level - - Values + - Values - - Description + - Description - * - ``Error`` + * - .. _log-none: - - ``DCPSLogLevel``: ``error`` + N/A - ``log_level``: ``Log_Level::Error`` + - :val:`DCPSLogLevel:none` - ``ACE_Log_Priority``: ``LM_ERROR`` + ``log_level``: ``LogLevel::None`` - - Logs issues that may prevent OpenDDS from functioning properly or functioning as configured. + ``ACE_Log_Priority``: N/A - * - ``Warning`` + - Disables all logging. - - ``DCPSLogLevel``: ``warning`` + * - .. _log-error: - ``log_level``: ``Log_Level::Warning`` + Error - ``ACE_Log_Priority``: ``LM_WARNING`` + - :val:`DCPSLogLevel:error` - - Log issues that should probably be addressed, but don't prevent OpenDDS from functioning. - This is the default. + ``log_level``: ``LogLevel::Error`` - * - ``Notice`` + ``ACE_Log_Priority``: ``LM_ERROR`` - - ``DCPSLogLevel``: ``notice`` + - Logs issues that may prevent OpenDDS from functioning properly or functioning as configured. - ``log_level``: ``Log_Level::Notice`` + * - .. _log-warning: - ``ACE_Log_Priority``: ``LM_NOTICE`` + Warning - - Logs details of issues that are returned to the user via the API, for example through a ``DDS::ReturnCode_t``. + - :val:`DCPSLogLevel:warning` - * - ``Info`` + ``log_level``: ``LogLevel::Warning`` - - ``DCPSLogLevel``: ``info`` + ``ACE_Log_Priority``: ``LM_WARNING`` - ``log_level``: ``Log_Level::Info`` + - Log issues that should probably be addressed, but don't prevent OpenDDS from functioning. + This is the default. - ``ACE_Log_Priority``: ``LM_INFO`` + * - .. _log-notice: - - Logs a small amount of basic information, such as the version of OpenDDS being used. + Notice - * - ``Debug`` + - :val:`DCPSLogLevel:notice` - - ``DCPSLogLevel``: ``debug`` + ``log_level``: ``LogLevel::Notice`` - ``log_level``: ``Log_Level::Debug`` + ``ACE_Log_Priority``: ``LM_NOTICE`` - ``ACE_Log_Priority``: ``LM_DEBUG`` + - Logs details of issues that are returned to the user via the API, for example through a ``DDS::ReturnCode_t``. - - This level doesn't directly control any logging but will enable at least DCPS and security debug level 1. - For backwards compatibility, setting DCPS debug logging to greater than zero will set this log level. - Setting the log level to below this level will disable all debug logging. + * - .. _log-info: + + Info + + - :val:`DCPSLogLevel:info` + + ``log_level``: ``LogLevel::Info`` + + ``ACE_Log_Priority``: ``LM_INFO`` + + - Logs a small amount of basic information, such as the version of OpenDDS being used. + + * - .. _log-debug: + + Debug + + - :val:`DCPSLogLevel:debug` + + ``log_level``: ``LogLevel::Debug`` + + ``ACE_Log_Priority``: ``LM_DEBUG`` + + - This level doesn't directly control any logging but will enable at least DCPS and security debug level 1. + For backwards compatibility, setting :ref:`DCPS debug logging ` to greater than zero will set this log level. + Setting the log level to below this level will disable all debug logging. The log level can be set a number of ways. To do it with command line arguments, pass: .. code-block:: bash - -DCPSLogLevel notice + -DCPSLogLevel notice Using a configuration file option is similar: @@ -3460,8 +3500,8 @@ Doing this from code can be done using an enumerator or a string: .. code-block:: cpp - OpenDDS::DCPS::log_level.set(OpenDDS::DCPS::LogLevel::Notice); - OpenDDS::DCPS::log_level.set_from_string("notice"); + OpenDDS::DCPS::log_level.set(OpenDDS::DCPS::LogLevel::Notice); + OpenDDS::DCPS::log_level.set_from_string("notice"); Passing invalid levels to the text-based methods will cause warning messages to be logged unconditionally, but will not cause the ``DomainParticipantFactory`` to fail to initialize. @@ -3473,7 +3513,7 @@ DCPS Layer Debug Logging .. Sect<7.6.1> -Debug logging in the DCPS layer of OpenDDS is controlled by the ``DCPSDebugLevel`` configuration option and command-line option. +Debug logging in the DCPS layer of OpenDDS is controlled by the :key:`DCPSDebugLevel` configuration option and command-line option. It can also be set in application code using: .. code-block:: cpp @@ -3504,7 +3544,7 @@ Transport Layer Debug Logging .. Sect<7.6.2> -OpenDDS transport debug layer logging is controlled via the ``DCPSTransportDebugLevel`` configuration option. +OpenDDS transport debug layer logging is controlled via the :key:`DCPSTransportDebugLevel` configuration option. For example, to add transport layer logging to any OpenDDS application that uses ``TheParticipantFactoryWithArgs``, add the following option to the command line: .. code-block:: bash @@ -3569,8 +3609,8 @@ Security Debug Logging .. Sect<7.6.3> -When OpenDDS is compiled with security enabled, debug logging for security can be enabled using ``DCPSecurityDebug`` (:ref:`run_time_configuration--common-configuration-options`). -Security logging is divided into categories, although ``DCPSSecurityDebugLevel`` is also provided, which controls the categories in a similar manner and using the same scale as ``DCPSDebugLevel``. +When OpenDDS is compiled with security enabled, debug logging for security can be enabled using :key:`DCPSSecurityDebug`. +Security logging is divided into categories, although :key:`DCPSSecurityDebugLevel` is also provided, which controls the categories in a similar manner and using the same scale as :key:`DCPSDebugLevel`. .. _run_time_configuration--reftable28: @@ -3691,3 +3731,9 @@ All the following are equivalent: OpenDDS::DCPS::security_debug.access_warn = true; OpenDDS::DCPS::security_debug.set_debug_level(1); OpenDDS::DCPS::security_debug.parse_flags(ACE_TEXT("access_warn")); + +.. rubric:: Footnotes + +.. [#orbprefix] :key:`ORBLogFile` and :key:`ORBVerboseLogging` start with "ORB" because they are inherited from :term:`TAO`. + They are implemented directly by OpenDDS (not passed to TAO) and are supported either on the command line (using a "-" prefix) or in the configuration file. + Other command-line options that begin with ``-ORB`` are passed to TAO's ``ORB_init`` if :ref:`inforepo-disc` is used. diff --git a/docs/devguide/safety_profile.rst b/docs/devguide/safety_profile.rst index 19fd1f97d87..0abf6d9dda6 100644 --- a/docs/devguide/safety_profile.rst +++ b/docs/devguide/safety_profile.rst @@ -21,7 +21,7 @@ The Safety Profile configuration allows OpenDDS to be used in environments that OpenDDS Safety Profile (and the corresponding features in ACE) were developed for the `Open Group's FACE specification, edition 2.1 `__. It can be used along with the support for FACE Transport Services to create FACE-conformant DDS applications, or it can be used by general DDS applications that are not written to the FACE Transport Services APIs. This latter use-case is described by this section of the developer's guide. -For more information on the former use-case see the file FACE/README.txt in the source distribution. +For more information on the former use-case see the file :ghfile:`FACE/README.txt` in the source distribution. .. _safety_profile--safety-profile-subset-of-opendds: @@ -57,7 +57,7 @@ It is possible that enabling any of these compliance profiles in a Safety Profil To build OpenDDS Safety Profile, pass the command line argument ``--safety-profile`` to the configure script along with any other arguments needed for your platform or configuration. When safety profile is enabled in the configure script, the four compliance profiles listed above default to disabled. -See :ref:`install` and the ``INSTALL.md`` file in the source distribution for more information about the configure script. +See :ref:`install` for more information about the configure script. .. _safety_profile--safety-profile-configurations-of-ace: @@ -81,7 +81,7 @@ Pass the command line argument ``--safety-profile=base`` to select the Safety Ba Otherwise a ``--safety-profile`` (no equals sign) configuration will default to Safety Extended with Memory Pool. The Safety Extended with Standard C++ Dynamic Allocation configuration is not automatically generated by the configure script, but the file ``build/target/ACE_wrappers/ace/config.h`` can be edited after it is generated by configure (and before running make). -Remove the macro definition for ACE_HAS_ALLOC_HOOKS to disable the memory pool. +Remove the macro definition for ``ACE_HAS_ALLOC_HOOKS`` to disable the memory pool. ACE's safety profile configurations have been tested on Linux and on LynxOS-178 version 2.3.2+patches. Other platforms may work too but may require additional configuration. @@ -96,7 +96,7 @@ Run-time Configurable Options Sect<13.4> The memory pool used by OpenDDS can be configured by setting values in the ``[common]`` section of the configuration file. -See ``pool_size`` and ``pool_granularity`` in :ref:`run_time_configuration--common-configuration-options`. +See :cfg:key:`pool_size` and :cfg:key:`pool_granularity`. .. _safety_profile--running-ace-and-opendds-tests: @@ -109,11 +109,11 @@ Running ACE and OpenDDS Tests After configuring and building OpenDDS Safety Profile, note that there are two sub-directories of the top level that each contain some binary artifacts: -* build/host has the build-time code generators tao_idl and opendds_idl +* ``build/host`` has the build-time code generators tao_idl and opendds_idl -* build/target has the run-time libraries for safety profile ACE and OpenDDS and the OpenDDS tests +* ``build/target`` has the run-time libraries for safety profile ACE and OpenDDS and the OpenDDS tests -Therefore, testing needs to be relative to the build/target sub-directory. +Therefore, testing needs to be relative to the ``build/target`` sub-directory. Source-in the generated file ``build/target/setenv.sh`` to get all of the needed environment variables. ACE tests are not built by default, but once this environment is set up all it takes to build them is generating makefiles and running make: @@ -124,14 +124,14 @@ ACE tests are not built by default, but once this environment is set up all it t #. ``make`` -Run ACE tests by changing to the $ACE_ROOT/tests directory and using run_test.pl. -Pass any ``-Config XYZ`` options required for your configuration (use run_test.pl -h to see the available Config options). +Run ACE tests by changing to the ``$ACE_ROOT/tests`` directory and using ``run_test.pl``. +Pass any ``-Config XYZ`` options required for your configuration (use ``run_test.pl -h`` to see the available Config options). -Run OpenDDS tests by changing to the $DDS_ROOT and using bin/auto_run_tests.pl. +Run OpenDDS tests by changing to the ``$DDS_ROOT`` and using :ghfile:`tests/auto_run_tests.pl`. Pass ``-Config OPENDDS_SAFETY_PROFILE``, ``-Config SAFETY_BASE`` (if using safety base), ``-Config RTPS``, and ``-Config`` options corresponding to each disabled compliance profile, by default: ``-Config DDS_NO_OBJECT_MODEL_PROFILE -Config DDS_NO_OWNERSHIP_KIND_EXCLUSIVE -Config DDS_NO_PERSISTENCE_PROFILE -Config DDS_NO_CONTENT_SUBSCRIPTION``. -Alternatively, an individual test can be run using run_test.pl from that test's directory. -Pass the same set of -Config options to run_test.pl. +Alternatively, an individual test can be run using ``run_test.pl`` from that test's directory. +Pass the same set of ``-Config`` options to ``run_test.pl``. .. _safety_profile--using-the-memory-pool-in-applications: @@ -150,14 +150,13 @@ The class ``OpenDDS::DCPS::MemoryPool`` (:ghfile:`dds/DCPS/MemoryPool.h`) contai However, most client code shouldn't interact directly with it. The class ``OpenDDS::DCPS::SafetyProfilePool`` (:ghfile:`dds/DCPS/SafetyProfilePool.h`) adapts the pool to the ACE_Allocator interface. ``OpenDDS::DCPS::PoolAllocator`` (:ghfile:`dds/DCPS/PoolAllocator.h`) adapts the pool to the C++ Allocator concept (C++03). -Since the PoolAllocator is stateless, it depends on the ACE_Allocator's singleton. -When OpenDDS is configured with the memory pool, ACE_Allocator's singleton instance will point to an object of class SafetyProfilePool. +Since the ``PoolAllocator`` is stateless, it depends on the ``ACE_Allocator``'s singleton. +When OpenDDS is configured with the memory pool, ``ACE_Allocator``'s singleton instance will point to an object of class SafetyProfilePool. -Application code that makes use of C++ Standard Library classes can either use PoolAllocator directly, or make use of the macros defined in PoolAllocator.h (for example OPENDDS_STRING). +Application code that makes use of C++ Standard Library classes can either use ``PoolAllocator`` directly, or make use of the macros defined in :ghfile:`dds/DCPS/PoolAllocator.h` (for example ``String``). -Application code that allocates raw (untyped) buffers of dynamic memory can use SafetyProfilePool either directly or via the ACE_Allocator::instance() singleton. +Application code that allocates raw (untyped) buffers of dynamic memory can use ``SafetyProfilePool`` either directly or via the ``ACE_Allocator::instance()`` singleton. -Application code that allocates objects from the heap can use the PoolAllocator template. - -Classes written by the application developer can derive from PoolAllocationBase (see PoolAllocationBase.h) to inherit class-scoped operators new and delete, thus redirecting all dynamic allocation of these classes to the pool. +Application code that allocates objects from the heap can use the ``PoolAllocator`` template. +Classes written by the application developer can derive from ``PoolAllocationBase`` (see :ghfile:`dds/DCPS/PoolAllocationBase.h`) to inherit class-scoped operators ``new`` and ``delete``, thus redirecting all dynamic allocation of these classes to the pool. diff --git a/docs/glossary.rst b/docs/glossary.rst index 0b46ae45027..ec9a3105c03 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -75,7 +75,7 @@ Common Terms Discovery Discovery is the configurable method that :term:`DomainParticipant`\s use to find one another. - See :ref:`introduction--dds-discovery` for more information. + See :ref:`dds-introduction--discovery` for more information. Dispose When an :term:`instance` is disposed by a :term:`DataWriter`, it means keeping the cached data related to it is no longer necessary. diff --git a/docs/internal/bench.rst b/docs/internal/bench.rst index e7a9cf504c3..6862e6713a3 100644 --- a/docs/internal/bench.rst +++ b/docs/internal/bench.rst @@ -106,7 +106,7 @@ Assuming you already have scenario and worker configuration files defined, the g Configuration Files ******************* -As a general rule, Bench uses JSON configuration files that directly map onto the C++ Platform Specific Model (PSM) of the IDL found in :ghfile:`performance-tests/bench/idl` and the IDL used in the `DDS specification `_. +As a general rule, Bench uses JSON configuration files that directly map onto the C++ Platform Specific Model (PSM) of the IDL found in :ghfile:`performance-tests/bench/idl` and the IDL used in the :ref:`spec-dds`. This allows the test applications to easily convert between configuration files and the C++ structures used for the configuration of DDS entities. Scenario Configuration Files @@ -437,9 +437,9 @@ with configuration of OpenDDS. "config_sections": [ -The elements of this section are functionally identical to the sections of an OpenDDS ``.ini`` file with the same name. +The elements of this section are functionally identical to the :ref:`config` sections of an OpenDDS ``.ini`` file with the same name. Each config section is created programmatically within the worker process using the name provided and made available to the OpenDDS ``ServiceParticipant`` during entity creation. -The example here sets the value of both the ``DCPSSecurity`` and ``DCPSDebugLevel`` keys to 0 within the ``[common]`` section of the configuration. +The example here sets the value of both the :cfg:key:`DCPSSecurity` and :cfg:key:`DCPSDebugLevel` keys to ``0``. :: diff --git a/docs/internal/release.rst b/docs/internal/release.rst index c98c24da1b2..da6bc5f88ee 100644 --- a/docs/internal/release.rst +++ b/docs/internal/release.rst @@ -91,13 +91,13 @@ These are files or the parts of the files that the release script won't be able This file is automatically generated from git history by the release script during the release. It can also be generated ahead of time to get a preview: - - Fetch the latest ``master`` branch and run ``./tools/scripts/gitrelease.pl --update-authors`` to see what the file will look like after release. + - Fetch the latest ``master`` branch and run ``tools/scripts/gitrelease.pl --update-authors`` to see what the file will look like after release. This doesn't require any other arguments like the release script normally does. - If the file changed, but something is wrong, then it might be good to correct it before the release. For example a contributor might have used a Git client that is inserting an name/email that might not be what they want in the file or including a name/email might be in addition to their existing name/email combo. Corrections will have to be inserted into :ghfile:`.mailmap` using the format described in the git documentation listed in the file. In addition to that there are general rules in the release script such as ignoring bots, preferring ``objectcomputing.com`` email addresses to ``ociweb.com`` ones, and dealing with GitHub-specific issues. - - Run ``./tools/scripts/gitrelease.pl --update-authors`` again to make sure the changes worked. + - Run ``tools/scripts/gitrelease.pl --update-authors`` again to make sure the changes worked. - Update :ghfile:`README.md` and :doc:`/devguide/building/dependencies` for any platform or dependency changes. - Document changes to building OpenDDS, at least in :doc:`/devguide/building/index`, but possibly also in :ghfile:`java/README` and :ghfile:`java/INSTALL`. diff --git a/docs/news.d/_releases/v3.26.0.rst b/docs/news.d/_releases/v3.26.0.rst index da9ce255dbd..d81942a2324 100644 --- a/docs/news.d/_releases/v3.26.0.rst +++ b/docs/news.d/_releases/v3.26.0.rst @@ -55,7 +55,7 @@ Fixes Documentation ============= -- Remove -Grapidjson flag [opendds_idl] (:ghpr:`4231`) +- Removed documentation for ``-Grapidjson`` option of ``opendds_idl`` that was removed in 3.20.0 (:ghpr:`4231`) - Remove reference to mailing lists (:ghpr:`4234`) - Restructured parts of :ref:`dds_security` page and expanded documentation of some XML security document elements. (:ghpr:`4281`) - OS-specific instructions will now be automatically selected based on the browser's user agent. (:ghpr:`4281`) diff --git a/docs/news.d/_releases/v3.27.0.rst b/docs/news.d/_releases/v3.27.0.rst index daa1abaeebe..1a40fd1feba 100644 --- a/docs/news.d/_releases/v3.27.0.rst +++ b/docs/news.d/_releases/v3.27.0.rst @@ -33,18 +33,18 @@ Fixes ===== - Updated the :ref:`read ` and :ref:`write ` semantics of DynamicData for union, expandable collections (sequence and string), and optional member of an aggregated type. (:ghpr:`4278`) -- Fixed memory leak where instances were not cleaned up with exlusive ownership. (:ghpr:`4343`) +- Fixed memory leak where instances were not cleaned up with :ref:`exclusive ownership `. (:ghpr:`4343`) - Removed the special handling for sequence members with length code of 5,6, or 7. (:ghpr:`4376`) -- Reading data from a dynamic data object for a primitive type now must use MEMBER_ID_INVALID id. (:ghpr:`4376`) +- Reading data from a dynamic data object for a primitive type now must use ``MEMBER_ID_INVALID`` id. (:ghpr:`4376`) - ``create_datawriter`` and ``create_datareader`` check if the topic belongs to the same participant as the publisher/subscriber. (:ghpr:`4398`) - Fixed uninitialized ``durability_service`` in Topic QoS when using QoS-XML. (:ghpr:`4424`) - Fixed a bug where compiling IDL with ``-Lc++11 -Gequality`` produced code outside of a namespace that didn't compile. (:ghpr:`4450`) -- ``SedpLocalAddress`` now defaults to ``DCPSDefaultAddress`` to behave like ``SpdpLocalAddress`` and ``local_address``. (:ghpr:`4451`) +- ``SedpLocalAddress`` now defaults to :cfg:key:`DCPSDefaultAddress` to behave like ``SpdpLocalAddress`` and ``local_address``. (:ghpr:`4451`) Notes ===== -- ``TheParticipantFactory*`` will now return a null pointer when ``DCPSConfigFile`` doesn't exist. (:ghpr:`4372`) +- ``TheParticipantFactory*`` will now return a null pointer when :ref:`DCPSConfigFile` doesn't exist. (:ghpr:`4372`) diff --git a/docs/news.d/devguide-config.rst b/docs/news.d/devguide-config.rst new file mode 100644 index 00000000000..64bdcd7aae7 --- /dev/null +++ b/docs/news.d/devguide-config.rst @@ -0,0 +1,8 @@ +.. news-prs: 4467 + +.. news-start-section: Documentation +- :ref:`config` + + - Restructured configuration options so they can be linked to directly. + Also reviewed each option description to correct or add missing context as needed. +.. news-end-section diff --git a/docs/news.d/devguide-intro.rst b/docs/news.d/devguide-intro.rst new file mode 100644 index 00000000000..d615fd225f7 --- /dev/null +++ b/docs/news.d/devguide-intro.rst @@ -0,0 +1,12 @@ +.. news-prs: 4467 + +.. news-start-section: Documentation +- :ref:`introduction` + + - Added :ref:`plugins` to explain generally how discovery, transports, and security libraries must be initialized when statically linking these libraries. + - Added summaries of important information needed to use the discovery and transport libraries. + +.. news-start-section: :ref:`sec` +- Added summary of important information needed to use the security library. +.. news-end-section +.. news-end-section diff --git a/docs/news.d/devguide-qos.rst b/docs/news.d/devguide-qos.rst index 30b285aef4f..6ba02edd711 100644 --- a/docs/news.d/devguide-qos.rst +++ b/docs/news.d/devguide-qos.rst @@ -8,6 +8,9 @@ Also removed large default value tables and put the default values in these boxes. - Added links to the QoS policies. -- Moved :ref:`fnmatch-exprs` into an "annex" file so it can be common between security and partitions QoS. - Added definitions for :term:`instance`, :term:`unregister`, and :term:`dispose` to the glossary. + +.. news-start-section: :ref:`sec` +- Moved :ref:`fnmatch-exprs` into an "annex" file so it can be common between security and partitions QoS. +.. news-end-section .. news-end-section diff --git a/docs/news.d/value-reader-writer-fixed.rst b/docs/news.d/value-reader-writer-fixed.rst index a146b138cdd..a542b9d0032 100644 --- a/docs/news.d/value-reader-writer-fixed.rst +++ b/docs/news.d/value-reader-writer-fixed.rst @@ -1,5 +1,5 @@ .. news-prs: 4466 .. news-start-section: Fixes -- The ValueReader and ValueWriter interfaces now use ACE_CDR::Fixed as the type of IDL fixed values +- The ValueReader and ValueWriter interfaces now use ``ACE_CDR::Fixed`` as the type of IDL fixed values .. news-end-section From 8fd9b85809b447f91b1ac1c9b6200dd0f6222086 Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Sat, 30 Mar 2024 00:11:28 -0500 Subject: [PATCH 11/37] Fix Typo and Section Args in Config Store Keys --- docs/internal/docs.rst | 2 +- docs/sphinx_extensions/config_domain.py | 33 ++++++++++++++----------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/docs/internal/docs.rst b/docs/internal/docs.rst index c748e241f64..8d25f509267 100644 --- a/docs/internal/docs.rst +++ b/docs/internal/docs.rst @@ -617,7 +617,7 @@ Turns into: :no-contents-entry: :no-index-entry: - Sections with discriminators require them in the reference targets: cfg:sec:`server@linux`, :cfg:key:`[server@linux]distro` + Sections with discriminators require them in the reference targets: :cfg:sec:`server@linux`, :cfg:key:`[server@linux]distro` .. cfg:sec:: server@linux/ :no-contents-entry: diff --git a/docs/sphinx_extensions/config_domain.py b/docs/sphinx_extensions/config_domain.py index 10f979a883b..eafc43b233e 100644 --- a/docs/sphinx_extensions/config_domain.py +++ b/docs/sphinx_extensions/config_domain.py @@ -125,20 +125,25 @@ def key_text(sec_name, sec_disc, key_name, insert=''): # This should be equivalent to ConfigPair::canonicalize -def key_canonicalize(*parts): - key = '_'.join(filter(None, parts)) - +def name_canonicalize(name): # Replace everything that's not a letter, number, or underscore - key = re.sub(r'[^\w]', '_', key) + name = re.sub(r'[^\w]', '_', name) # Convert CamelCase to camel_case - key = re.sub(r'([A-Z][a-z])', r'_\1', key) - key = re.sub(r'([a-z])([A-Z])', r'\1_\2', key) + name = re.sub(r'([A-Z][a-z])', r'_\1', name) + name = re.sub(r'([a-z])([A-Z])', r'\1_\2', name) # Removed repeated underscores - key = re.sub(r'_+', r'_', key) + name = re.sub(r'_+', r'_', name) + + return name.strip('_').upper() + - return key.strip('_').upper() +def key_canonicalize(sec_name, sec_args, key_name): + sec = name_canonicalize(sec_name) + if sec_args: + sec += '_' + sec_args + return sec + '_' + name_canonicalize(key_name) class ConfigKeyRefRole(XRefRole): @@ -383,14 +388,14 @@ def test_parse_key_name(self): def test_key_canonicalize(self): cases = { - ('~!abc.123__CamelCase/CAMELCase#$%',): 'ABC_123_CAMEL_CASE_CAMEL_CASE', - ('CamelCase',): 'CAMEL_CASE', + ('CamelCase', None, 'key'): 'CAMEL_CASE_KEY', + ('##CamelCase##', None, 'key'): 'CAMEL_CASE_KEY', + ('~!abc.123_''_CamelCase/CAMELCase#$%', None, 'key'): 'ABC_123_CAMEL_CASE_CAMEL_CASE_KEY', + ('sect', None, 'UseXTypes',): 'SECT_USE_X_TYPES', + ('sect', None, 'UseXYZTypes',): 'SECT_USE_XYZ_TYPES', ('TheSection', None, 'TheKey'): 'THE_SECTION_THE_KEY', ('TheSection', '', 'TheKey'): 'THE_SECTION_THE_KEY', - ('TheSection', 'TheInstance', 'TheKey'): 'THE_SECTION_THE_INSTANCE_THE_KEY', - ('##CamelCase##',): 'CAMEL_CASE', - ('UseXTypes',): 'USE_X_TYPES', - ('UseXYZTypes',): 'USE_XYZ_TYPES', + ('TheSection', '', 'TheKey'): 'THE_SECTION__THE_KEY', } for args, expected in cases.items(): From b0d54fcee5e4743074c8be5d88f61573c168abc5 Mon Sep 17 00:00:00 2001 From: "Justin R. Wilson" Date: Fri, 29 Mar 2024 17:11:26 -0500 Subject: [PATCH 12/37] Add missing news --- docs/news.d/config_store3.rst | 7 ++++--- docs/news.d/config_store_environment_variables.rst | 7 +++++++ docs/news.d/config_store_java.rst | 7 +++++++ docs/news.d/config_store_multiple_files.rst | 7 +++++++ docs/news.d/configstore-bug.rst | 6 ++++++ docs/news.d/rtps-reader-bug.rst | 5 +++++ docs/news.d/shapes-interoperability.rst | 5 +++++ docs/news.d/vread-bug.rst | 5 +++++ 8 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 docs/news.d/config_store_environment_variables.rst create mode 100644 docs/news.d/config_store_java.rst create mode 100644 docs/news.d/config_store_multiple_files.rst create mode 100644 docs/news.d/configstore-bug.rst create mode 100644 docs/news.d/rtps-reader-bug.rst create mode 100644 docs/news.d/shapes-interoperability.rst create mode 100644 docs/news.d/vread-bug.rst diff --git a/docs/news.d/config_store3.rst b/docs/news.d/config_store3.rst index ae804124774..88e8b7dfcbf 100644 --- a/docs/news.d/config_store3.rst +++ b/docs/news.d/config_store3.rst @@ -1,5 +1,6 @@ -.. news-prs: 4454 - +.. news-prs: 4454 4469 4475 4488 .. news-start-section: Additions -- Convert ``domain`` sections to key-value store. +.. news-start-section: ``ConfigStore`` +- Converted the transport and discovery loading and ``domain`` section to use ``ConfigStore``. +.. news-end-section .. news-end-section diff --git a/docs/news.d/config_store_environment_variables.rst b/docs/news.d/config_store_environment_variables.rst new file mode 100644 index 00000000000..8baa1aa82e0 --- /dev/null +++ b/docs/news.d/config_store_environment_variables.rst @@ -0,0 +1,7 @@ +.. news-prs: 4491 + +.. news-start-section: Additions +.. news-start-section: ``ConfigStore`` +- OpenDDS can now be configured with environment variables. DevGuide update to follow. +.. news-end-section +.. news-end-section diff --git a/docs/news.d/config_store_java.rst b/docs/news.d/config_store_java.rst new file mode 100644 index 00000000000..84521aa7b3c --- /dev/null +++ b/docs/news.d/config_store_java.rst @@ -0,0 +1,7 @@ +.. news-prs: 4515 + +.. news-start-section: Additions +.. news-start-section: ``ConfigStore`` +- The ConfigStore is available in Java. +.. news-end-section +.. news-end-section diff --git a/docs/news.d/config_store_multiple_files.rst b/docs/news.d/config_store_multiple_files.rst new file mode 100644 index 00000000000..4f18392ccb5 --- /dev/null +++ b/docs/news.d/config_store_multiple_files.rst @@ -0,0 +1,7 @@ +.. news-prs: 4505 + +.. news-start-section: Additions +.. news-start-section: ``ConfigStore`` +- OpenDDS now supports multiple config files. DevGuide update to follow. +.. news-end-section +.. news-end-section diff --git a/docs/news.d/configstore-bug.rst b/docs/news.d/configstore-bug.rst new file mode 100644 index 00000000000..5ffd063ddba --- /dev/null +++ b/docs/news.d/configstore-bug.rst @@ -0,0 +1,6 @@ +.. news-prs: 4540 4485 + +.. news-start-section: Fixes +- Fixed bug so ConfigStore entries generated by SEDP are cleaned up. +- Fixed bug where various RtpsDiscoveryConfig setters didn't set. +.. news-end-section diff --git a/docs/news.d/rtps-reader-bug.rst b/docs/news.d/rtps-reader-bug.rst new file mode 100644 index 00000000000..ac4ad3b3015 --- /dev/null +++ b/docs/news.d/rtps-reader-bug.rst @@ -0,0 +1,5 @@ +.. news-prs: 4548 + +.. news-start-section: Fixes +- Fixed bug where an RTPS Reader gets stuck when heartbeat advances. +.. news-end-section diff --git a/docs/news.d/shapes-interoperability.rst b/docs/news.d/shapes-interoperability.rst new file mode 100644 index 00000000000..1203af585fa --- /dev/null +++ b/docs/news.d/shapes-interoperability.rst @@ -0,0 +1,5 @@ +.. news-prs: 4528 + +.. news-start-section: Additions +- The IDL for the Shapes example was updated for interoperability. +.. news-end-section diff --git a/docs/news.d/vread-bug.rst b/docs/news.d/vread-bug.rst new file mode 100644 index 00000000000..2fcaa12d66d --- /dev/null +++ b/docs/news.d/vread-bug.rst @@ -0,0 +1,5 @@ +.. news-prs: 4544 + +.. news-start-section: Fixes +- Fixed bug where ``vread`` for unions used uninitialized memory. +.. news-end-section From 8f1aefbad0dcd33c47786476fc4d4266b2c2b8d1 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Mon, 1 Apr 2024 16:58:42 -0500 Subject: [PATCH 13/37] TransportImpl: remove unused member function decls This made a block of code public that probably wasn't supposed to be. DataReaderImpl should not have conditional logic based on transport_type() --- dds/DCPS/DataReaderImpl.cpp | 9 +-------- dds/DCPS/transport/framework/DataLink.h | 3 ++- dds/DCPS/transport/framework/TransportImpl.h | 14 -------------- dds/DCPS/transport/multicast/MulticastDataLink.h | 2 ++ dds/DCPS/transport/rtps_udp/RtpsUdpDataLink.h | 2 ++ dds/DCPS/transport/rtps_udp/RtpsUdpTransport.cpp | 8 ++++---- 6 files changed, 11 insertions(+), 27 deletions(-) diff --git a/dds/DCPS/DataReaderImpl.cpp b/dds/DCPS/DataReaderImpl.cpp index ec531ebf555..e110172230e 100644 --- a/dds/DCPS/DataReaderImpl.cpp +++ b/dds/DCPS/DataReaderImpl.cpp @@ -3231,15 +3231,8 @@ DataReaderImpl::add_link(const DataLink_rch& link, const GUID_t& peer) } } TransportClient::add_link(link, peer); - OPENDDS_STRING type; - { - TransportImpl_rch impl = link->impl(); - if (impl) { - type = impl->transport_type(); - } - } - if (type == "rtps_udp" || type == "multicast") { + if (!link->uses_end_historic_control_messages()) { resume_sample_processing(peer); } } diff --git a/dds/DCPS/transport/framework/DataLink.h b/dds/DCPS/transport/framework/DataLink.h index ee5e702dbc3..71c7af35a1b 100644 --- a/dds/DCPS/transport/framework/DataLink.h +++ b/dds/DCPS/transport/framework/DataLink.h @@ -282,13 +282,14 @@ class OpenDDS_Dcps_Export DataLink void set_scheduling_release(bool scheduling_release); - virtual void send_final_acks (const GUID_t& readerid); + virtual void send_final_acks(const GUID_t& readerid); virtual WeakRcHandle get_ice_endpoint() const { return WeakRcHandle(); } virtual bool is_leading(const GUID_t& /*writer*/, const GUID_t& /*reader*/) const { return false; } + virtual bool uses_end_historic_control_messages() const { return true; } protected: diff --git a/dds/DCPS/transport/framework/TransportImpl.h b/dds/DCPS/transport/framework/TransportImpl.h index a215c97483b..1886398d9eb 100644 --- a/dds/DCPS/transport/framework/TransportImpl.h +++ b/dds/DCPS/transport/framework/TransportImpl.h @@ -265,20 +265,6 @@ class OpenDDS_Dcps_Export TransportImpl : public virtual RcObject { virtual void local_crypto_handle(DDS::Security::ParticipantCryptoHandle) {} #endif -public: - /// Called by our friends, the TransportClient, and the DataLink. - /// Since this TransportImpl can be attached to many TransportClient - /// objects, and each TransportClient object could be "running" in - /// a separate thread, we need to protect all of the "reservation" - /// methods with a lock. The protocol is that a client of ours - /// must "acquire" our reservation_lock_ before it can proceed to - /// call any methods that affect the DataLink reservations. It - /// should release the reservation_lock_ as soon as it is done. - int acquire(); - int tryacquire(); - int release(); - int remove(); - virtual OPENDDS_STRING transport_type() const = 0; /// Called by our friend, the TransportClient. diff --git a/dds/DCPS/transport/multicast/MulticastDataLink.h b/dds/DCPS/transport/multicast/MulticastDataLink.h index 9ce06ee6f71..e193e95c5e3 100644 --- a/dds/DCPS/transport/multicast/MulticastDataLink.h +++ b/dds/DCPS/transport/multicast/MulticastDataLink.h @@ -108,6 +108,8 @@ class OpenDDS_Multicast_Export MulticastDataLink void release_remote_i(const GUID_t& remote); RepoIdSet readers_selected_, readers_withheld_; bool ready_to_deliver(const ReceivedDataSample& data); + + bool uses_end_historic_control_messages() const { return false; } }; } // namespace DCPS diff --git a/dds/DCPS/transport/rtps_udp/RtpsUdpDataLink.h b/dds/DCPS/transport/rtps_udp/RtpsUdpDataLink.h index 507178983e1..bd3685ce411 100644 --- a/dds/DCPS/transport/rtps_udp/RtpsUdpDataLink.h +++ b/dds/DCPS/transport/rtps_udp/RtpsUdpDataLink.h @@ -935,6 +935,8 @@ class OpenDDS_Rtps_Udp_Export RtpsUdpDataLink RcHandle > network_interface_address_reader_; MulticastManager multicast_manager_; + + bool uses_end_historic_control_messages() const { return false; } }; } // namespace DCPS diff --git a/dds/DCPS/transport/rtps_udp/RtpsUdpTransport.cpp b/dds/DCPS/transport/rtps_udp/RtpsUdpTransport.cpp index 2d8effbace8..46686827a05 100644 --- a/dds/DCPS/transport/rtps_udp/RtpsUdpTransport.cpp +++ b/dds/DCPS/transport/rtps_udp/RtpsUdpTransport.cpp @@ -108,7 +108,7 @@ RtpsUdpTransport::make_datalink(const GuidPrefix_t& local_prefix) #if defined(OPENDDS_SECURITY) { if (core_.use_ice()) { - ReactorInterceptor_rch ri = reactor_task_->interceptor(); + ReactorInterceptor_rch ri = reactor_task()->interceptor(); ri->execute_or_enqueue(make_rch(unicast_socket_.get_handle(), static_cast(ACE_Event_Handler::READ_MASK))); #ifdef ACE_HAS_IPV6 ri->execute_or_enqueue(make_rch(ipv6_unicast_socket_.get_handle(), static_cast(ACE_Event_Handler::READ_MASK))); @@ -613,7 +613,7 @@ RtpsUdpTransport::configure_i(const RtpsUdpInst_rch& config) create_reactor_task(false, "RtpsUdpTransport" + config->name()); - ACE_Reactor* reactor = reactor_task_->get_reactor(); + ACE_Reactor* reactor = reactor_task()->get_reactor(); job_queue_ = DCPS::make_rch(reactor); #ifdef OPENDDS_SECURITY @@ -950,7 +950,7 @@ RtpsUdpTransport::start_ice() GuardThreadType guard_links(links_lock_); if (!link_) { - ReactorInterceptor_rch ri = reactor_task_->interceptor(); + ReactorInterceptor_rch ri = reactor_task()->interceptor(); ri->execute_or_enqueue(make_rch(unicast_socket_.get_handle(), ice_endpoint_.get(), static_cast(ACE_Event_Handler::READ_MASK))); #ifdef ACE_HAS_IPV6 ri->execute_or_enqueue(make_rch(ipv6_unicast_socket_.get_handle(), ice_endpoint_.get(), static_cast(ACE_Event_Handler::READ_MASK))); @@ -968,7 +968,7 @@ RtpsUdpTransport::stop_ice() GuardThreadType guard_links(links_lock_); if (!link_) { - ReactorInterceptor_rch ri = reactor_task_->interceptor(); + ReactorInterceptor_rch ri = reactor_task()->interceptor(); ri->execute_or_enqueue(make_rch(unicast_socket_.get_handle(), static_cast(ACE_Event_Handler::READ_MASK))); #ifdef ACE_HAS_IPV6 ri->execute_or_enqueue(make_rch(ipv6_unicast_socket_.get_handle(), static_cast(ACE_Event_Handler::READ_MASK))); From fa0a9d8d83ccae17ebc4359dc511fc1003988edc Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Mon, 1 Apr 2024 18:19:54 -0500 Subject: [PATCH 14/37] Change Value Seperator to =, Add Space to Key Name Also fixed a few typos --- docs/devguide/run_time_configuration.rst | 12 ++++----- docs/internal/docs.rst | 24 ++++++++--------- docs/sphinx_extensions/config_domain.py | 34 ++++++++++++------------ 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/devguide/run_time_configuration.rst b/docs/devguide/run_time_configuration.rst index 094df14af30..ce52e9da466 100644 --- a/docs/devguide/run_time_configuration.rst +++ b/docs/devguide/run_time_configuration.rst @@ -3411,7 +3411,7 @@ The highest level logging is controlled by the general log levels listed in the N/A - - :val:`DCPSLogLevel:none` + - :val:`DCPSLogLevel=none` ``log_level``: ``LogLevel::None`` @@ -3423,7 +3423,7 @@ The highest level logging is controlled by the general log levels listed in the Error - - :val:`DCPSLogLevel:error` + - :val:`DCPSLogLevel=error` ``log_level``: ``LogLevel::Error`` @@ -3435,7 +3435,7 @@ The highest level logging is controlled by the general log levels listed in the Warning - - :val:`DCPSLogLevel:warning` + - :val:`DCPSLogLevel=warning` ``log_level``: ``LogLevel::Warning`` @@ -3448,7 +3448,7 @@ The highest level logging is controlled by the general log levels listed in the Notice - - :val:`DCPSLogLevel:notice` + - :val:`DCPSLogLevel=notice` ``log_level``: ``LogLevel::Notice`` @@ -3460,7 +3460,7 @@ The highest level logging is controlled by the general log levels listed in the Info - - :val:`DCPSLogLevel:info` + - :val:`DCPSLogLevel=info` ``log_level``: ``LogLevel::Info`` @@ -3472,7 +3472,7 @@ The highest level logging is controlled by the general log levels listed in the Debug - - :val:`DCPSLogLevel:debug` + - :val:`DCPSLogLevel=debug` ``log_level``: ``LogLevel::Debug`` diff --git a/docs/internal/docs.rst b/docs/internal/docs.rst index 8d25f509267..1df6b46e98c 100644 --- a/docs/internal/docs.rst +++ b/docs/internal/docs.rst @@ -490,7 +490,7 @@ For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphin Use to document a configuration key that can contain :rst:dir:`cfg:val` and most other RST content. Must be in a :rst:dir:`cfg:sec`. ```` describe what sort of text is accepted. - It is just for display and has no restrictions on the contents, but should follow the following syntax conventions to describe the accepted values: + It is just for display and has no restrictions on the contents, but should follow the following conventions to describe the accepted values: - ``|`` indicates an OR - ``[]`` indicates an optional part of the value @@ -506,7 +506,7 @@ For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphin .. rst:directive:option:: default - The default value of the key if ommitted + The default value of the key if omitted .. rst:role:: cfg:key @@ -538,13 +538,13 @@ For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphin This must be inside a :rst:dir:`cfg:key`. - - ``:`` + - ``=`` Inside of a :rst:dir:`cfg:sec`, it refers to a value of a key in that section. Outside of a :rst:dir:`cfg:sec`, the key is assumed to be ``common``. - - ``[]:`` - - ``[@]:`` + - ``[]=`` + - ``[@]=`` Example ^^^^^^^ @@ -562,13 +562,13 @@ This is a example made up for the following INI file: .. code-block:: rst - Outside their sections, references to keys and values must be complete: :cfg:val:`[server]os:linux`, :cfg:key:`[server@linux]distro` + Outside their sections, references to keys and values must be complete: :cfg:val:`[server]os=linux`, :cfg:key:`[server@linux]distro` Otherwise the ``common`` section will be assumed. .. cfg:sec:: server/ - A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os:windows` + A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os=windows` .. cfg:key:: os=windows|linux :required: @@ -577,11 +577,11 @@ This is a example made up for the following INI file: .. cfg:val:: windows - Implied titles will be shortened within their scopes: :cfg:key:`[server]os`, :cfg:val:`[server]os:windows` + Implied titles will be shortened within their scopes: :cfg:key:`[server]os`, :cfg:val:`[server]os=windows` .. cfg:val:: linux - Sections with discriminators require them in the reference targets: cfg:sec:`server@linux`, :cfg:key:`[server@linux]distro` + Sections with discriminators require them in the reference targets: :cfg:sec:`server@linux`, :cfg:key:`[server@linux]distro` .. cfg:sec:: server@linux/ @@ -590,7 +590,7 @@ This is a example made up for the following INI file: Turns into: - Outside their sections, references to keys and values must be complete: :cfg:val:`[server]os:linux`, :cfg:key:`[server@linux]distro` + Outside their sections, references to keys and values must be complete: :cfg:val:`[server]os=linux`, :cfg:key:`[server@linux]distro` Otherwise the ``common`` section will be assumed. @@ -598,7 +598,7 @@ Turns into: :no-contents-entry: :no-index-entry: - A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os:windows` + A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os=windows` .. cfg:key:: os=windows|linux :required: @@ -611,7 +611,7 @@ Turns into: :no-contents-entry: :no-index-entry: - Implied titles will be shortened within their scopes: :cfg:key:`[server]os`, :cfg:val:`[server]os:windows` + Implied titles will be shortened within their scopes: :cfg:key:`[server]os`, :cfg:val:`[server]os=windows` .. cfg:val:: linux :no-contents-entry: diff --git a/docs/sphinx_extensions/config_domain.py b/docs/sphinx_extensions/config_domain.py index eafc43b233e..1d551750ddc 100644 --- a/docs/sphinx_extensions/config_domain.py +++ b/docs/sphinx_extensions/config_domain.py @@ -120,7 +120,7 @@ def parse_key_name(full_name, node=None): def key_text(sec_name, sec_disc, key_name, insert=''): text = key_name + insert if sec_name is not None: - text = section_text(sec_name, sec_disc, text) + text = section_text(sec_name, sec_disc, ' ' + text) return text @@ -244,7 +244,9 @@ def transform_content(self, contentnode: addnodes.desc_content) -> None: # cfg:val ===================================================================== -value_re = r'(?:(?P' + key_re + r'):)?(?P' + id_re + r')' +value_sep = '=' +value_sep_re = re.escape(value_sep) +value_re = r'(?:(?P' + key_re + r')' + value_sep_re + r')?(?P' + id_re + r')' def parse_value_name(full_name, node=None): @@ -255,7 +257,7 @@ def parse_value_name(full_name, node=None): def value_text(sec_name, sec_disc, key_name, val_name): text = val_name if key_name is not None: - text = key_text(sec_name, sec_disc, key_name, ':' + text) + text = key_text(sec_name, sec_disc, key_name, value_sep + text) return text @@ -272,16 +274,14 @@ def process_link(self, env: BuildEnvironment, refnode: Element, # [sec]key=val anywhere pass elif scope_kind == 0 and sec is None: - # key:val outside section + # key=val outside section target = f'[common]{target}' elif scope_kind >= 1 and key is not None: - # key:val anywhere in a section - prefix = ctx.get_full_name(0) - target = f'{prefix}{target}' + # key=val anywhere in a section + target = ctx.get_full_name(0) + target elif scope_kind >= 2 and key is None: # val anywhere in a key - prefix = ctx.get_full_name(1) - target = f'{prefix}:{target}' + target = ctx.get_full_name(1) + value_sep + target else: ConfigDomain.logger.warning(f'{repr(target)} is an invalid target here', location=self.get_location()) @@ -323,7 +323,7 @@ def parse_sig(self, ctx, sig): r'(' + id_re + r')|<(' + id_re + r')>', sig, self) brackets = bool(name_w_brackets) name = name_w_brackets if brackets else name_wo_brackets - ctx.push(self, name, ctx.get_full_name() + f':{name}') + ctx.push(self, name, ctx.get_full_name() + value_sep + name) return (brackets,) def create_signode(self, ctx, name, signode, brackets): @@ -371,16 +371,16 @@ def test_parse_key_name(self): for ref, expected in cases.items(): self.assertEqual(parse_key_name(ref), expected, f'On key {repr(ref)}') - def test_parse_key_name(self): + def test_parse_value_name(self): cases = { # sec, sec_name, sec_disc, key, key_name, val_name 'vn': (None, None, None, None, None, 'vn'), - 'kn:vn': (None, None, None, 'kn', 'kn', 'vn'), - 'kn.a.b.c:vn': (None, None, None, 'kn.a.b.c', 'kn.a.b.c', 'vn'), - '[sn]kn:vn': ('sn', 'sn', None, '[sn]kn', 'kn', 'vn'), - '[sn]kn.a.b.c:vn': ('sn', 'sn', None, '[sn]kn.a.b.c', 'kn.a.b.c', 'vn'), - '[sn@sd]kn:vn': ('sn@sd', 'sn', 'sd', '[sn@sd]kn', 'kn', 'vn'), - '[sn@sd]kn.a.b.c:vn': ('sn@sd', 'sn', 'sd', '[sn@sd]kn.a.b.c', 'kn.a.b.c', 'vn'), + 'kn=vn': (None, None, None, 'kn', 'kn', 'vn'), + 'kn.a.b.c=vn': (None, None, None, 'kn.a.b.c', 'kn.a.b.c', 'vn'), + '[sn]kn=vn': ('sn', 'sn', None, '[sn]kn', 'kn', 'vn'), + '[sn]kn.a.b.c=vn': ('sn', 'sn', None, '[sn]kn.a.b.c', 'kn.a.b.c', 'vn'), + '[sn@sd]kn=vn': ('sn@sd', 'sn', 'sd', '[sn@sd]kn', 'kn', 'vn'), + '[sn@sd]kn.a.b.c=vn': ('sn@sd', 'sn', 'sd', '[sn@sd]kn.a.b.c', 'kn.a.b.c', 'vn'), } for ref, expected in cases.items(): From af5094bdddd7cd741f12bd7a10de27df9336a12b Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Wed, 3 Apr 2024 20:37:57 +0000 Subject: [PATCH 15/37] Imported and adapted commits from earlier attempt at using CLOCK_BOOTTIME. This only includes configuration, CI, and documentation changes. Squashed commit of the following: commit 77d7689470c45469f688545434c81d973398d44e Merge: 2ba17977e0 0f79a06c8d Author: Adam Mitz Date: Fri Mar 22 09:51:00 2024 -0500 Merge branch 'master' into boottime # Conflicts: # cmake/init.cmake # configure commit 2ba17977e0c2e10f1068884e13d9ec037950b570 Author: Adam Mitz Date: Wed Feb 28 17:20:58 2024 -0600 updated lint config commit 819665da3c365b4337b97011f7fb3d98e385a09c Author: Adam Mitz Date: Wed Feb 28 17:18:17 2024 -0600 corrected CMakeLists commit bb92bf2a36b74fd61e80a961bb46a586845083b3 Author: Adam Mitz Date: Wed Feb 28 15:56:34 2024 -0600 Update configure Co-authored-by: Son Dinh commit 515141480b9c9414fa13f9ecf4cd074e5ee2e563 Author: Adam Mitz Date: Wed Feb 28 15:55:01 2024 -0600 Specialize the ACE_Condition_Attributes_T template commit 9ae1d8eb7f2dcf0034f21dbd9349a296ce8c0023 Author: Adam Mitz Date: Wed Feb 28 09:35:02 2024 -0600 Added export macro commit 8dbd712e8475a871a6b808d8da93ab883a7b1873 Author: Adam Mitz Date: Wed Feb 28 08:56:48 2024 -0600 fixed perl closure commit 419547e5a53da17de00f46fc36c04da058f72d29 Author: Adam Mitz Date: Wed Feb 28 08:52:16 2024 -0600 Add to dds/CMakeLists.txt commit 073d23d03b8c94fc7f3ce0a450a78a3f4847cadb Author: Adam Mitz Date: Wed Feb 28 08:51:46 2024 -0600 fixed perl closure commit 4a2e3596cd6015814c714c8c55c8e36ffce01da1 Author: Adam Mitz Date: Wed Feb 28 08:28:34 2024 -0600 try the new configs in CI commit 2777735b240229ad1a73ef22b8eb4d1c1b587d04 Author: Adam Mitz Date: Tue Feb 27 14:40:33 2024 -0600 Moved content in devguide commit 013c2cafa085d958af754866cd7036088f7f7e9b Author: Adam Mitz Date: Tue Feb 27 13:24:23 2024 -0600 Apply suggestions from code review Co-authored-by: Fred Hornsey commit 9198ab4d8cf98cd119756426d9f72b6b4823f007 Author: Adam Mitz Date: Tue Feb 27 12:49:36 2024 -0600 NEWS for this change commit 63324e166838cdefcbecc5d3741f08b298f73134 Author: Adam Mitz Date: Tue Feb 27 12:48:07 2024 -0600 Update docs/devguide/building/cmake.rst Co-authored-by: Justin Wilson commit 518a4308789fedddd1a6ba3b86e33eb51bf0486c Author: Adam Mitz Date: Tue Feb 27 08:58:39 2024 -0600 Configure boottime from CMake commit ef251c87930a730cfb38a7896c79e1dddf3cb6cc Author: Adam Mitz Date: Tue Feb 27 08:58:23 2024 -0600 Updated build docs commit c1757ef2bb9c2c59fcaaacec12b4de736bd3b764 Author: Fred Hornsey Date: Mon Feb 26 17:45:48 2024 -0600 Set `OPENDDS_CONFIG_` values in CMake (#37) commit fb365183fcf4a8c2fdb71f051c83da0a2731d748 Author: Adam Mitz Date: Mon Feb 26 15:29:12 2024 -0600 Update lint regex for gettimeofday to be more selective commit 8506a96dbbf76ad0d9643ef08380c0dd5c331f98 Author: Adam Mitz Date: Fri Feb 23 17:15:31 2024 -0600 Optionally use CLOCK_BOOTTIME for monotonic time --- .github/workflows/build_and_test.yml | 2 +- .github/workflows/cmake.yml | 1 + cmake/init.cmake | 1 + configure | 2 ++ dds/OpenDDSConfig.h.in | 4 +++- docs/devguide/building/index.rst | 10 ++++++++++ docs/news.d/boottime.rst | 7 +++++++ 7 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 docs/news.d/boottime.rst diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index c92fdd0b81e..8c1b2fbbab8 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -2736,7 +2736,7 @@ jobs: - name: configure OpenDDS run: | cd OpenDDS - ./configure --compiler=g++-11 --std=c++20 --no-inline --tests --rapidjson --ace=$GITHUB_WORKSPACE/ACE_TAO/ACE --mpc=$GITHUB_WORKSPACE/MPC + ./configure --compiler=g++-11 --std=c++20 --no-inline --tests --rapidjson --boottime --ace=$GITHUB_WORKSPACE/ACE_TAO/ACE --mpc=$GITHUB_WORKSPACE/MPC - name: check build configuration shell: bash run: | diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 009c364a54e..1ee1638748e 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -89,6 +89,7 @@ jobs: -DCMAKE_UNITY_BUILD=TRUE \ -DBUILD_SHARED_LIBS=TRUE \ -DCMAKE_BUILD_TYPE=Debug \ + -DOPENDDS_BOOTTIME_TIMERS=TRUE \ -DOPENDDS_SECURITY=TRUE \ -DOPENDDS_ACE_TAO_SRC=$GITHUB_WORKSPACE/OpenDDS/build/ACE_TAO \ -DOPENDDS_MPC=$GITHUB_WORKSPACE/MPC \ diff --git a/cmake/init.cmake b/cmake/init.cmake index bc36a070744..d5437793771 100644 --- a/cmake/init.cmake +++ b/cmake/init.cmake @@ -149,6 +149,7 @@ _opendds_feature(QUERY_CONDITION "${OPENDDS_CONTENT_SUBSCRIPTION}" CONFIG _opendds_feature(SUPPRESS_ANYS ON CONFIG DOC "Default for opendds_target_sources(SUPPRESS_ANYS)") _opendds_feature(SECURITY OFF CONFIG DOC "Build with RTPS Security support") _opendds_feature(SAFETY_PROFILE OFF CONFIG DOC "Build using Safety Profile (Not for CMake-built OpenDDS)") +_opendds_feature(BOOTTIME_TIMERS OFF CONFIG DOC "Use CLOCK_BOOTTIME for timers") # ACE Features if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/configure b/configure index e55759adacc..e8e25f6d95d 100755 --- a/configure +++ b/configure @@ -227,6 +227,7 @@ my @specs = # Array of array-refs, each inner array is an option group which 'macros=s@', 'Extra text for platform_macros.GNU', 'features=s@', 'Extra text for default.features', 'mpcopts=s@', 'Extra command-line args for MPC', + 'boottime|boottime!', 'Use CLOCK_BOOTTIME for timers (no)', ], ['Optional dependencies for OpenDDS (disabled by default unless noted otherwise):', 'java:s', 'Java development kit (use JAVA_HOME)', @@ -1357,6 +1358,7 @@ sub write_opendds_configh { my %config = ( 'OPENDDS_CONFIG_AUTO_STATIC_INCLUDES' => 0, + 'OPENDDS_CONFIG_BOOTTIME_TIMERS' => $opts{'boottime'} // 0, ); my $replace_value = sub { diff --git a/dds/OpenDDSConfig.h.in b/dds/OpenDDSConfig.h.in index 8dc1c128c10..2d94f0e2d40 100644 --- a/dds/OpenDDSConfig.h.in +++ b/dds/OpenDDSConfig.h.in @@ -7,8 +7,10 @@ // This file should not #include any other files. -// To add variables to this file, update both CMakeLists.txt and configure. +// To add variables to this file, update both cmake/init.cmake and configure. #define OPENDDS_CONFIG_AUTO_STATIC_INCLUDES @OPENDDS_CONFIG_AUTO_STATIC_INCLUDES@ +#define OPENDDS_CONFIG_BOOTTIME_TIMERS @OPENDDS_CONFIG_BOOTTIME_TIMERS@ + #endif diff --git a/docs/devguide/building/index.rst b/docs/devguide/building/index.rst index 5b23c3a036e..544d199f345 100644 --- a/docs/devguide/building/index.rst +++ b/docs/devguide/building/index.rst @@ -672,6 +672,16 @@ These are all the variables that are exclusive to building OpenDDS with CMake: See :ref:`cmake-running-tests` for how to run them. The default for this is ``TRUE``. +.. cmake:var:: OPENDDS_BOOTTIME_TIMERS + :no-contents-entry: + + .. versionadded:: 3.28 + + OpenDDS uses CLOCK_BOOTTIME when scheduling timers. + On some platforms the default is to use CLOCK_MONOTONIC which does not increment when the system is suspended. + Enable this option to use CLOCK_BOOTTIME as the timer base clock instead of CLOCK_MONOTONIC. + Default is ``OFF``. + Speeding up the build --------------------- diff --git a/docs/news.d/boottime.rst b/docs/news.d/boottime.rst new file mode 100644 index 00000000000..903024e2c94 --- /dev/null +++ b/docs/news.d/boottime.rst @@ -0,0 +1,7 @@ +.. news-prs: TODO + +.. news-start-section: Additions +- Allow compile-time configuration of CLOCK_BOOTTIME as the clock used for timers + + - When the platform supports it, this can be done using ``--boottime`` when building with the configure script or :cmake:var:`OPENDDS_BOOTTIME_TIMERS` when building with CMake. +.. news-end-section From f25a24a71b82eb244ccb98dd2de9ddb34b1bc9be Mon Sep 17 00:00:00 2001 From: "Justin R. Wilson" Date: Wed, 3 Apr 2024 11:49:56 -0500 Subject: [PATCH 16/37] Configuration with ConfigStore is not documented Problem ------- The new capabilities from the ConfigStore are not documented for users. Solution -------- Add to the configuration documentation. --- docs/devguide/run_time_configuration.rst | 219 ++++++++++++++++++--- docs/news.d/config_store_documentation.rst | 6 + 2 files changed, 193 insertions(+), 32 deletions(-) create mode 100644 docs/news.d/config_store_documentation.rst diff --git a/docs/devguide/run_time_configuration.rst b/docs/devguide/run_time_configuration.rst index ce52e9da466..0c87acec434 100644 --- a/docs/devguide/run_time_configuration.rst +++ b/docs/devguide/run_time_configuration.rst @@ -12,17 +12,6 @@ Run-time Configuration .. _run_time_configuration--configuration-approach: -********************** -Configuration Approach -********************** - -.. - Sect<7.1> - -OpenDDS includes a file-based configuration framework for configuring global options and options related to specific publishers and subscribers such as discovery and transport configuration. -OpenDDS also allows configuration via the command line for a limited number of options and via a configuration API. -This section summarizes the configuration options supported by OpenDDS. - OpenDDS configuration is concerned with three main areas: #. **Common Configuration Options** -- configure the behavior of DCPS entities at a global level. @@ -36,17 +25,50 @@ OpenDDS configuration is concerned with three main areas: Each pluggable transport can be configured separately. See :ref:`config-transport` for details. -The configuration file for OpenDDS is a human-readable ini-style text file. +********************** +Configuration Approach +********************** + +.. + Sect<7.1> + +Most of OpenDDS is configured through a key-value store. +Keys are strings that are converted to a canonical form before being stored by 1) converting camel case to snake case, 2) capitalizing all alphabetic characers, 3) replacing all non-alphanumeric characters with underscores, and 4) stripping leading, trailing, and duplicate underscores. +For example, the key ``!SectionInstance__PROPERTY`` is canonicalized into ``SECTION_INSTANCE_PROPERTY`` before being stored. +Values are stored as strings and converted to other types as necessary. +The documentation for each key contains its canonical name. + +A key has the following parts: + +#. **section** -- The section describes the area of functionality that is being configured. + +#. **instance** -- (optional) The instance names a particular collection of configuration values. + Configuration keys that do not have an instance imply a singleton or global. + +#. **property** -- The property names a variable relative to the section and instance. + +Sections, instances, and properties can contain underscores meaning that underscores are not used as delimiters to separate the section, instance, and property. +This ambiguity is resolved by the following rules: + +* Sections are known by OpenDDS. + For example, OpenDDS will look for :ref:`DDSI-RTPS Discovery` instances under keys prefixed by ``RTPS_DISCOVERY``. + +* Instances must be introduced by a special key-value pair where the value is prefixed by ``@``. + For example, ``RTPS_DISCOVERY_MY_DISCOVERY=@MY_DISCOVERY`` introduces an instance named ``MY_DISCOVERY`` under the ``RTPS_DISCOVERY`` section. + +Suppose the configuration store contains the following key-pairs: ``RTPS_DISCOVERY_MY_DISCOVERY=@MY_DISCOVERY`` and ``RTPS_DISCOVERY_MY_DISCOVERY_RESEND_PERIOD=5``. +In this case, the ``MY_DISCOVERY`` instance of ``RTPS_DISCOVERY`` will have a ``RESEND_PERIOD`` with a value of ``5`` (seconds). + :ref:`This table ` shows a list of the available configuration section types as they relate to the area of OpenDDS that they configure. .. _run_time_configuration--sections: -.. list-table:: Configuration File Sections +.. list-table:: Configuration Sections :header-rows: 1 * - **Focus Area** - - **File Section Title** + - **Section Title** * - :ref:`Global Settings ` @@ -88,32 +110,59 @@ The configuration file for OpenDDS is a human-readable ini-style text file. - ``[ice]`` -For each of the section types with the exception of :sec:`common` and ``[ice]``, the syntax of a section header takes the form of ``[/]``. -For example, a ``[repository]`` section type would always be used in a configuration file like so: ``[repository/repo_1]`` where ``repository`` is the section type and ``repo_1`` is an instance name of a repository configuration. +The configuration store can be populated in a number of ways: -How to use instances to configure discovery and transports is explained further in :ref:`config-disc` and :ref:`config-transport` respectively. +* :ref:`Environment variables ` -.. _DCPSConfigFile: +* :ref:`Command-line arguments ` -******************* -``-DCPSConfigFile`` -******************* +* :ref:`Configuration file(s) ` -The ``-DCPSConfigFile`` command-line argument can be used to pass the location of a configuration file to OpenDDS. -For example: +* :ref:`Specific and generic APIs ` -.. tab:: Linux, macOS, BSDs, etc. +By default and for backwards compatibility, the different configuration mechanisms are processed in the following order: - .. code-block:: bash +#. Environment variables - ./publisher -DCPSConfigFile pub.ini +#. Command-line arguments (will overwrite configuration from environment variables) -.. tab:: Windows +#. Configuration file (will not overwrite configuration from environment variables or command-line arguments) - .. code-block:: batch +#. APIs called by the user (will overwrite existing configuration) - publisher -DCPSConfigFile pub.ini +However, multiple configuration files can be processed by setting ``DCPS_SINGLE_CONFIG_FILE=0``. +This can be done with an environment variable ``OPENDDS_DCPS_SINGLE_CONFIG_FILE=0`` or a command-line argument ``-DCPSSingleConfigFile 0``. +This causes the different configuration mechanisms to be processed in the following order: + +#. Environment variables + +#. Command-line arguments and configuration files are processed sequentially and overwrite existing configuration + +#. APIs called by the user (which also overwrite existing configuration) +Users can store configuration data for their applications in the configuration store. +Users taking advantage of this capability should use the section names of ``APP`` and ``USER`` which are reserved for this purpose. + +.. _config-environment-variables: + +Configuration with Environment Variables +======================================== + +OpenDDS reads environment variables that begin with ``OPENDDS_`` to populate the configuration store. +An environment variable ``OPENDDS_KEY=VALUE`` causes ``KEY=VALUE`` to be saved in the configuration store. +``KEY`` is canonicalized before being stored. + +To set the ``ResendPeriod`` on an ``rtps_discovery`` instance named ``MyDiscovery`` to 5 seconds using environment variables, one would set the following: + +* ``OPENDDS_RTPS_DISCOVERY_MY_DISCOVERY=@MY_DISCOVERY`` +* ``OPENDDS_RTPS_DISCOVERY_MY_DISCOVERY_RESEND_PERIOD=5`` + +.. _config-command-line-arguments: + +Configuration with Command-line Arguments +========================================= + +This section describes the command-line arguments that are relevant to OpenDDS and how they are processed. Command-line arguments are passed to the service participant singleton when initializing the domain participant factory. This is accomplished by using the ``TheParticipantFactoryWithArgs`` macro: @@ -128,6 +177,60 @@ This is accomplished by using the ``TheParticipantFactoryWithArgs`` macro: // ... } +Command-line arguments are parsed in two phases. +The following arguments are parse in the first phase: + +#. ``-ORBLogFile PATH`` - Causes logging output to be written to the file indicated by ``PATH``. + +#. ``-ORBVerboseLogging [0|1]`` - Enables/disables verbose logging (default 0). + Verbose logging causes each log message to be prefixed with a timestamp. + +#. ``-DCPSSingleConfigFile [0|1]`` - Enables/disables the legacy behavior of a single configuration file that is processed after environment variables and command-line arguments and does not overwrite existing configuration (default 1). + When disabled, arguments processed in the second phase are processed as they are encountered and overwrite existing configuration. + +The following arguments are processed in the second phase: + +#. ``-DCPSConfigFile PATH`` - Causes configuration to be read from the file indicated by ``PATH``. + It is processed immediately if ``-DCPSSingleConfigFile 0`` and deferred to the end of argument processing, otherwise. + +#. ``-OpenDDSKEY VALUE`` - Causes ``KEY=VALUE`` to be saved in the configuration store. + The key ``KEY`` is canonicalized before being stored. + To set the ``ResendPeriod`` on an ``rtps_discovery`` instance named ``MyDiscovery`` to 5 seconds using environment variables, one could use the following arguments: + + * ``-OpenDDS_rtps_discovery_MyDiscovery @MY_DISCOVERY`` + * ``-OpenDDS_rtps_discovery_MyDiscovery_ResendPeriod 5`` + +#. ``-DCPSx VALUE`` - Causes ``COMMON_DCPS_x=VALUE`` to be saved in the configuration store. + The key ``COMMON_DCPS_x`` is canonicalized before being stored. + +#. ``-FederationX VALUE`` - Causes ``COMMON_FEDERATION_X=VALUE`` to be saved in the configuration store. + The key ``COMMON_FEDERATION_X`` is canonicalized before being stored. + +.. _dcpsconfigfile: + +Configuration with a File +========================= + +The ``-DCPSConfigFile PATH`` argument described above causes OpenDDS to read configuration from a human-readable ini-style text file. +For example: + +.. tab:: Linux, macOS, BSDs, etc. + + .. code-block:: bash + + ./publisher -DCPSConfigFile pub.ini + +.. tab:: Windows + + .. code-block:: batch + + publisher -DCPSConfigFile pub.ini + +For each of the section types with the exception of :sec:`common` and ``[ice]``, the syntax of a section header takes the form of ``[/]``. +For example, a ``[repository]`` section type would always be used in a configuration file like so: ``[repository/repo_1]`` where ``repository`` is the section type and ``repo_1`` is an instance name of a repository configuration. + +Using instances to configure discovery and transports is explained further in :ref:`config-disc` and :ref:`config-transport` respectively. + .. Keep the "word joiner" U+FEFF in the next sentence, otherwise the line is broken up and it comes out strange in the output. @@ -162,10 +265,62 @@ For example, the following commands would have the same effect: ./publisher -DCPSConfigFile a.ini ./subscriber -DCPSConfigFile b.ini -The ``Service_Participant`` class also provides methods that allow an application to configure the DDS service. -See the header file :ghfile:`dds/DCPS/Service_Participant.h` for details. +.. _config-api: + +Configuration with API +====================== + +ConfigStore API +--------------- + +The configuration store API allows any configuration value to be set and retrieved. +The interface for the ConfigStore is intentionally generic to facilitate multiple language bindings without specific support for every configuration property. +See :ghfile:`dds/DdsDcpsInfrastructure.idl` and :ghfile:`dds/DCPS/ConfigStoreImpl.h` for more details. + +.. tab:: C++ + + .. code-block:: cpp + + #include + + int main(int argc, char* argv[]) + { + // ... + TheServiceParticipant->config_store()->set_string("RTPS_DISCOVERY_MY_DISCOVERY", "@MY_DISCOVERY"); + TheServiceParticipant->config_store()->set_string("RTPS_DISCOVERY_MY_DISCOVERY_RESEND_PERIOD", "5"); + // ... + } + +.. tab:: Java + + .. code-block:: java + + import OpenDDS.DCPS.TheServiceParticipant; + import OpenDDS.DCPS.ConfigStore; + // ... + ConfigStore cs = TheServiceParticipant.config_store(); + cs.set_string("RTPS_DISCOVERY_MY_DISCOVERY", "@MY_DISCOVERY"); + cs.set_string("RTPS_DISCOVERY_MY_DISCOVERY_RESEND_PERIOD", "5"); + // ... + +Specific APIs +------------- + +Various classes provide methods that allow an application to configure OpenDDS. + +* See ``Service_Participant`` in :ghfile:`dds/DCPS/Service_Participant.h` + +* See ``InfoRepoDiscovery`` in :ghfile:`dds/DCPS/InfoRepoDiscovery/InfoRepoDiscovery.h` + +* See ``RtpsDiscoveryConfig`` in :ghfile:`dds/DCPS/RTPS/RtpsDiscoveryConfig.h` + +* See ``TransportRegistry`` in :ghfile:`dds/DCPS/transport/framework/TransportRegistry.h` + +* See ``RtpsUdpInst`` in :ghfile:`dds/DCPS/transport/rtps_udp/RtpsUdpInst.h` + +* See ``TcpInst`` in :ghfile:`dds/DCPS/transport/tcp/TcpInst.h` -The following subsections detail each of the configuration file sections and the available options related to those sections. +* See ``ShmemInst`` in :ghfile:`dds/DCPS/transport/shmem/ShmemInst.h` .. _config-common: .. _run_time_configuration--common-configuration-options: diff --git a/docs/news.d/config_store_documentation.rst b/docs/news.d/config_store_documentation.rst new file mode 100644 index 00000000000..875f3af7488 --- /dev/null +++ b/docs/news.d/config_store_documentation.rst @@ -0,0 +1,6 @@ +.. news-prs: 4556 +.. news-start-section: Documentation +.. news-start-section: ``ConfigStore`` +- Add :ref:`configuration capabilities ` to DevGuide. +.. news-end-section +.. news-end-section From 03226fe97d55319b454315adad6fbe654e794853 Mon Sep 17 00:00:00 2001 From: Johnny Willemsen Date: Thu, 4 Apr 2024 12:13:19 +0200 Subject: [PATCH 17/37] Cleanup ACE_TEMPLATES_REQUIRE_PRAGMA and ACE_TEMPLATES_REQUIRE_SOURCE, fixed #4560 * dds/DCPS/DataCollector_T.h: * dds/DCPS/MultiTopicDataReader_T.h: * dds/DCPS/RakeResults_T.h: * dds/DCPS/TimePoint_T.h: * dds/DCPS/ZeroCopyAllocator_T.h: * dds/DCPS/ZeroCopySeq_T.h: * dds/DCPS/transport/framework/TransportReceiveStrategy_T.h: * dds/InfoRepo/UpdateListener_T.h: * dds/InfoRepo/UpdateManager.h: * dds/InfoRepo/UpdateProcessor_T.h: * dds/InfoRepo/UpdateReceiver_T.h: * tests/DCPS/TestFramework/TestFramework_T.h: * tools/modeling/codegen/model/Service_T.h: --- dds/DCPS/DataCollector_T.h | 6 ------ dds/DCPS/MultiTopicDataReader_T.h | 2 -- dds/DCPS/RakeResults_T.h | 2 -- dds/DCPS/TimePoint_T.h | 6 ------ dds/DCPS/ZeroCopyAllocator_T.h | 6 ------ dds/DCPS/ZeroCopySeq_T.h | 7 ------- dds/DCPS/transport/framework/TransportReceiveStrategy_T.h | 2 -- dds/InfoRepo/UpdateListener_T.h | 7 ------- dds/InfoRepo/UpdateManager.h | 7 ------- dds/InfoRepo/UpdateProcessor_T.h | 7 ------- dds/InfoRepo/UpdateReceiver_T.h | 7 ------- tests/DCPS/TestFramework/TestFramework_T.h | 7 ------- tools/modeling/codegen/model/Service_T.h | 6 ------ 13 files changed, 72 deletions(-) diff --git a/dds/DCPS/DataCollector_T.h b/dds/DCPS/DataCollector_T.h index c85d06968a6..3d9e222bf99 100644 --- a/dds/DCPS/DataCollector_T.h +++ b/dds/DCPS/DataCollector_T.h @@ -113,12 +113,6 @@ OPENDDS_END_VERSIONED_NAMESPACE_DECL #include "DataCollector_T.inl" #endif /* __ACE_INLINE__ */ -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) #include "DataCollector_T.cpp" -#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ - -#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) -#pragma implementation ("DataCollector_T.cpp") -#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ #endif /* DATA_COLLECTOR_H */ diff --git a/dds/DCPS/MultiTopicDataReader_T.h b/dds/DCPS/MultiTopicDataReader_T.h index 0969bd37eef..393a79356e5 100644 --- a/dds/DCPS/MultiTopicDataReader_T.h +++ b/dds/DCPS/MultiTopicDataReader_T.h @@ -193,9 +193,7 @@ class MultiTopicDataReader_T OPENDDS_END_VERSIONED_NAMESPACE_DECL -#ifdef ACE_TEMPLATES_REQUIRE_SOURCE #include "MultiTopicDataReader_T.cpp" -#endif #endif #endif diff --git a/dds/DCPS/RakeResults_T.h b/dds/DCPS/RakeResults_T.h index d64af597cbf..7fee17ad870 100644 --- a/dds/DCPS/RakeResults_T.h +++ b/dds/DCPS/RakeResults_T.h @@ -120,8 +120,6 @@ class RakeResults { OPENDDS_END_VERSIONED_NAMESPACE_DECL -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) #include "RakeResults_T.cpp" -#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ #endif /* RAKERESULTS_H */ diff --git a/dds/DCPS/TimePoint_T.h b/dds/DCPS/TimePoint_T.h index 3f909fd9c85..4f59f05909f 100644 --- a/dds/DCPS/TimePoint_T.h +++ b/dds/DCPS/TimePoint_T.h @@ -158,12 +158,6 @@ OPENDDS_END_VERSIONED_NAMESPACE_DECL # include "TimePoint_T.inl" #endif /* __ACE_INLINE__ */ -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) # include "TimePoint_T.cpp" -#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ - -#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) -# pragma implementation ("TimePoint_T.cpp") -#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ #endif diff --git a/dds/DCPS/ZeroCopyAllocator_T.h b/dds/DCPS/ZeroCopyAllocator_T.h index f0e6201569a..8c316ebeab8 100644 --- a/dds/DCPS/ZeroCopyAllocator_T.h +++ b/dds/DCPS/ZeroCopyAllocator_T.h @@ -72,12 +72,6 @@ OPENDDS_END_VERSIONED_NAMESPACE_DECL #include "ZeroCopyAllocator_T.inl" #endif /* __ACE_INLINE__ */ -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) #include "ZeroCopyAllocator_T.cpp" -#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ - -#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) -#pragma implementation ("ZeroCopyAllocator_T.cpp") -#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ #endif /* ZEROCOPYALLOCATOR_H */ diff --git a/dds/DCPS/ZeroCopySeq_T.h b/dds/DCPS/ZeroCopySeq_T.h index 63bdc87d68b..3db2ee8d6ee 100644 --- a/dds/DCPS/ZeroCopySeq_T.h +++ b/dds/DCPS/ZeroCopySeq_T.h @@ -222,13 +222,6 @@ TAO_END_VERSIONED_NAMESPACE_DECL #include "ZeroCopySeq_T.inl" #endif /* __ACE_INLINE__ */ -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) #include "ZeroCopySeq_T.cpp" -#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ - -#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) -#pragma message ("ZeroCopySeq_T.cpp template inst") -#pragma implementation ("ZeroCopySeq_T.cpp") -#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ #endif /* ZEROCOPYSEQ_H */ diff --git a/dds/DCPS/transport/framework/TransportReceiveStrategy_T.h b/dds/DCPS/transport/framework/TransportReceiveStrategy_T.h index a5935683d76..525f6a1cd92 100644 --- a/dds/DCPS/transport/framework/TransportReceiveStrategy_T.h +++ b/dds/DCPS/transport/framework/TransportReceiveStrategy_T.h @@ -186,8 +186,6 @@ OPENDDS_END_VERSIONED_NAMESPACE_DECL #include "TransportReceiveStrategy_T.inl" #endif /* __ACE_INLINE__ */ -#ifdef ACE_TEMPLATES_REQUIRE_SOURCE #include "TransportReceiveStrategy_T.cpp" -#endif #endif /* OPENDDS_DCPS_TRANSPORTRECEIVESTRATEGY */ diff --git a/dds/InfoRepo/UpdateListener_T.h b/dds/InfoRepo/UpdateListener_T.h index d11566bcc73..723a222034c 100644 --- a/dds/InfoRepo/UpdateListener_T.h +++ b/dds/InfoRepo/UpdateListener_T.h @@ -78,13 +78,6 @@ class UpdateListener OPENDDS_END_VERSIONED_NAMESPACE_DECL -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) #include "UpdateListener_T.cpp" -#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ - -#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) -#pragma message ("UpdateListener_T.cpp template inst") -#pragma implementation ("UpdateListener_T.cpp") -#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ #endif /* UPDATELISTENER_T_H */ diff --git a/dds/InfoRepo/UpdateManager.h b/dds/InfoRepo/UpdateManager.h index ecea4fc133f..0f24282796e 100644 --- a/dds/InfoRepo/UpdateManager.h +++ b/dds/InfoRepo/UpdateManager.h @@ -93,14 +93,7 @@ class OpenDDS_InfoRepoLib_Export Manager : public ACE_Service_Object { OPENDDS_END_VERSIONED_NAMESPACE_DECL -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) #include "UpdateManager_T.cpp" -#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ - -#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) -#pragma message ("UpdateManager_T.cpp template inst") -#pragma implementation ("UpdateManager_T.cpp") -#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL diff --git a/dds/InfoRepo/UpdateProcessor_T.h b/dds/InfoRepo/UpdateProcessor_T.h index 1767562aedd..7369aea01aa 100644 --- a/dds/InfoRepo/UpdateProcessor_T.h +++ b/dds/InfoRepo/UpdateProcessor_T.h @@ -84,13 +84,6 @@ class UpdateProcessor { OPENDDS_END_VERSIONED_NAMESPACE_DECL -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) #include "UpdateProcessor_T.cpp" -#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ - -#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) -#pragma message ("UpdateProcessor_T.cpp template inst") -#pragma implementation ("UpdateProcessor_T.cpp") -#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ #endif /* UPDATEPROCESSOR_T_H */ diff --git a/dds/InfoRepo/UpdateReceiver_T.h b/dds/InfoRepo/UpdateReceiver_T.h index ab29358c1a8..1074c7e1f3a 100644 --- a/dds/InfoRepo/UpdateReceiver_T.h +++ b/dds/InfoRepo/UpdateReceiver_T.h @@ -84,13 +84,6 @@ class UpdateReceiver : public virtual ACE_Task_Base { OPENDDS_END_VERSIONED_NAMESPACE_DECL -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) #include "UpdateReceiver_T.cpp" -#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ - -#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) -#pragma message ("UpdateReceiver_T.cpp template inst") -#pragma implementation ("UpdateReceiver_T.cpp") -#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ #endif /* UPDATE_RECEIVER_T_H */ diff --git a/tests/DCPS/TestFramework/TestFramework_T.h b/tests/DCPS/TestFramework/TestFramework_T.h index ad07e0b9d53..c1825e3dd1f 100644 --- a/tests/DCPS/TestFramework/TestFramework_T.h +++ b/tests/DCPS/TestFramework/TestFramework_T.h @@ -153,13 +153,6 @@ class TestPair : public virtual TestSubscriber, virtual void fini_i(); }; -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) #include "TestFramework_T.cpp" -#endif - -#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) -#pragma message("TestFramework_T.cpp template inst") -#pragma implementation("TestFramework_T.cpp") -#endif #endif /* DCPS_TESTFRAMEWORK_T_H */ diff --git a/tools/modeling/codegen/model/Service_T.h b/tools/modeling/codegen/model/Service_T.h index 85da3375ce4..dcd2d34edf8 100644 --- a/tools/modeling/codegen/model/Service_T.h +++ b/tools/modeling/codegen/model/Service_T.h @@ -130,13 +130,7 @@ namespace OpenDDS { namespace Model { OPENDDS_END_VERSIONED_NAMESPACE_DECL -#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) #include "Service_T.cpp" -#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ - -#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) -#pragma implementation ("Service_T.cpp") -#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ #include /**/ "ace/post.h" From 68797b4e7cebe6fd635522840cdcbc70543fae17 Mon Sep 17 00:00:00 2001 From: Johnny Willemsen Date: Thu, 4 Apr 2024 20:06:04 +0200 Subject: [PATCH 18/37] Update dds/DCPS/TimePoint_T.h Co-authored-by: Fred Hornsey --- dds/DCPS/TimePoint_T.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dds/DCPS/TimePoint_T.h b/dds/DCPS/TimePoint_T.h index 4f59f05909f..783edc8d132 100644 --- a/dds/DCPS/TimePoint_T.h +++ b/dds/DCPS/TimePoint_T.h @@ -158,6 +158,6 @@ OPENDDS_END_VERSIONED_NAMESPACE_DECL # include "TimePoint_T.inl" #endif /* __ACE_INLINE__ */ -# include "TimePoint_T.cpp" +#include "TimePoint_T.cpp" #endif From bd214ba07615b5485e9a08d449c74117656d6078 Mon Sep 17 00:00:00 2001 From: "Justin R. Wilson" Date: Thu, 4 Apr 2024 16:36:53 -0500 Subject: [PATCH 19/37] `gov_gen` fails without useful error message Problem ------- `gov_gen` fails without a useful error message. Solution -------- Print out the error from openssl. --- tests/security/attributes/gov_gen.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/security/attributes/gov_gen.cpp b/tests/security/attributes/gov_gen.cpp index 6a09954de7d..ee1adbdf446 100644 --- a/tests/security/attributes/gov_gen.cpp +++ b/tests/security/attributes/gov_gen.cpp @@ -14,6 +14,7 @@ #include #include +#include size_t find(const std::string& option, const std::string& needle, const std::string arr[], size_t arr_size) { @@ -274,6 +275,13 @@ std::string generate_global_name(size_t aup, size_t ejac, size_t dpk, size_t lpk return result; } +void print_ssl_error() { + const unsigned long ec = ERR_get_error(); + const char* es = ERR_error_string(ec, 0); + std::cerr << "ERROR: " << es << std::endl; +} + + int ACE_TMAIN(int argc, ACE_TCHAR* argv[]) { std::string aup; @@ -355,12 +363,14 @@ int ACE_TMAIN(int argc, ACE_TCHAR* argv[]) BIO* filebuf = BIO_new_file(certpath.c_str(), "r"); if (!filebuf) { std::cerr << "ERROR: could not open " << certpath << std::endl; + print_ssl_error(); return EXIT_FAILURE; } cert = PEM_read_bio_X509(filebuf, NULL, 0, NULL); if (!cert) { std::cerr << "ERROR: could not read " << certpath << std::endl; + print_ssl_error(); return EXIT_FAILURE; } @@ -371,12 +381,14 @@ int ACE_TMAIN(int argc, ACE_TCHAR* argv[]) BIO* filebuf = BIO_new_file(keypath.c_str(), "r"); if (!filebuf) { std::cerr << "ERROR: could not open " << keypath << std::endl; + print_ssl_error(); return EXIT_FAILURE; } key = PEM_read_bio_PrivateKey(filebuf, NULL, NULL, NULL); if (!key) { std::cerr << "ERROR: could not key " << keypath << std::endl; + print_ssl_error(); return EXIT_FAILURE; } @@ -387,24 +399,28 @@ int ACE_TMAIN(int argc, ACE_TCHAR* argv[]) const int buffer_size = static_cast(buffer.str().size()); if (BIO_write(mem, buffer.str().data(), buffer_size) != buffer_size) { std::cerr << "ERROR: could not copy to BIO" << std::endl; + print_ssl_error(); return EXIT_FAILURE; } PKCS7* p7 = PKCS7_sign(cert, key, NULL, NULL, PKCS7_TEXT | PKCS7_DETACHED); if (!p7) { std::cerr << "ERROR: could not sign" << std::endl; + print_ssl_error(); return EXIT_FAILURE; } BIO* out = BIO_new_file(outpath.c_str(), "w"); if (out == NULL) { std::cerr << "ERROR: could not open " << outpath << std::endl; + print_ssl_error(); return EXIT_FAILURE; } if (!SMIME_write_PKCS7(out, p7, mem, PKCS7_TEXT | PKCS7_DETACHED)) { std::cerr << "ERROR: could not write " << outpath << std::endl; + print_ssl_error(); return EXIT_FAILURE; } From 46e7b8eace686aa9fe58891b4c177981cdf66d7e Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Mon, 8 Apr 2024 00:07:43 -0500 Subject: [PATCH 20/37] Rename Configuration Keys to Properties To avoid confusion with config store keys, which are basically the same thing, but it comes across as strange in the documentation to use the same term. --- docs/devguide/built_in_topics.rst | 4 +- .../devguide/content_subscription_profile.rst | 2 +- docs/devguide/dds_security.rst | 2 +- docs/devguide/introduction.rst | 2 +- docs/devguide/run_time_configuration.rst | 82 ++++++++-------- docs/devguide/safety_profile.rst | 2 +- docs/internal/bench.rst | 2 +- docs/internal/docs.rst | 72 +++++++------- docs/news.d/_releases/v3.27.0.rst | 2 +- docs/sphinx_extensions/config_domain.py | 96 ++++++++++--------- 10 files changed, 134 insertions(+), 132 deletions(-) diff --git a/docs/devguide/built_in_topics.rst b/docs/devguide/built_in_topics.rst index 32e338b7054..a94c0d13854 100644 --- a/docs/devguide/built_in_topics.rst +++ b/docs/devguide/built_in_topics.rst @@ -39,7 +39,7 @@ Four separate topics are defined for each domain. Each is dedicated to a particular entity (domain participant :ref:`built_in_topics--dcpsparticipant-topic`, topic :ref:`built_in_topics--dcpsparticipant-topic`, data writer :ref:`built_in_topics--dcpspublication-topic`, data reader :ref:`built_in_topics--dcpssubscription-topic`) and publishes instances describing the state for each entity in the domain. Subscriptions to built-in topics are automatically created for each domain participant. -A participant's support for built-in topics can be toggled via the :cfg:key:`DCPSBit` configuration option. +A participant's support for built-in topics can be toggled via the :cfg:prop:`DCPSBit` configuration option. To view the built-in topic data, simply obtain the built-in Subscriber and then use it to access the Data Reader for the built-in topic of interest. The Data Reader can then be used like any other Data Reader. @@ -285,7 +285,7 @@ OpenDDSInternalThread Topic .. Sect<6.8.3> -The built-in topic ``OpenDDSInternalThread`` is published when OpenDDS is configured with :cfg:key:`DCPSThreadStatusInterval`. +The built-in topic ``OpenDDSInternalThread`` is published when OpenDDS is configured with :cfg:prop:`DCPSThreadStatusInterval`. When enabled, the DataReader for this built-in topic will report the status of threads created and managed by OpenDDS within the current process. The timestamp associated with samples can be used to determine the health (responsiveness) of the thread. diff --git a/docs/devguide/content_subscription_profile.rst b/docs/devguide/content_subscription_profile.rst index c5254b30c42..ac9733055b6 100644 --- a/docs/devguide/content_subscription_profile.rst +++ b/docs/devguide/content_subscription_profile.rst @@ -68,7 +68,7 @@ Once the content-filtered topic has been created, it is used by the subscriber's This data reader is functionally equivalent to a normal data reader except that incoming data samples which do not meet the filter expression's criteria are dropped. Filter expressions are first evaluated at the publisher so that data samples which would be ignored by the subscriber can be dropped before even getting to the transport. -This feature can be turned off by setting :cfg:key:`DCPSPublisherContentFilter` to ``0``. +This feature can be turned off by setting :cfg:prop:`DCPSPublisherContentFilter` to ``0``. The behavior of non-default :ref:`qos-deadline` or :ref:`qos-liveliness` policies may be affected by this policy. Special consideration must be given to how the "missing" samples impact the QoS behavior, see the document in :ghfile:`docs/design/CONTENT_SUBSCRIPTION`. diff --git a/docs/devguide/dds_security.rst b/docs/devguide/dds_security.rst index 46921a59f75..2a4f1bb7cd0 100644 --- a/docs/devguide/dds_security.rst +++ b/docs/devguide/dds_security.rst @@ -150,7 +150,7 @@ The following configuration steps are required to enable OpenDDS Security featur * Via API: ``TheServiceParticipant->set_security(true);`` or - * Via config file: setting :cfg:key:`DCPSSecurity` to ``1``. + * Via config file: setting :cfg:prop:`DCPSSecurity` to ``1``. .. _dds_security--dds-security-configuration-via-propertyqospolicy: diff --git a/docs/devguide/introduction.rst b/docs/devguide/introduction.rst index 0bc41095a60..fe1051a2b6f 100644 --- a/docs/devguide/introduction.rst +++ b/docs/devguide/introduction.rst @@ -360,7 +360,7 @@ It also makes it easier to replace these libraries with custom ones. - :ref:`security ` [#plugins-sec]_ -How to enable and use a particular plugin will differ based on the kind of plugin and the plugin itself, but generally they are enabled by some form of configuration setting, for example using ``[transport]transport_type`` or :cfg:key:`DCPSSecurity` in a configuration file. +How to enable and use a particular plugin will differ based on the kind of plugin and the plugin itself, but generally they are enabled by some form of configuration setting, for example using ``[transport]transport_type`` or :cfg:prop:`DCPSSecurity` in a configuration file. The plugin will also have to be linked and initialized at runtime. For dynamic libraries (``.dll``, ``.dynlib`` or, ``.so`` files) this is done automatically as the OpenDDS will load the dynamic library and then run any initialization the plugin requires. When the plugins are statically linked, then it requires explicit linking and including an initialization header in the application that contains a global object that will initialize the plugin. diff --git a/docs/devguide/run_time_configuration.rst b/docs/devguide/run_time_configuration.rst index 0c87acec434..882ebf8bdcb 100644 --- a/docs/devguide/run_time_configuration.rst +++ b/docs/devguide/run_time_configuration.rst @@ -358,7 +358,7 @@ For example: .. sec:: common - .. key:: DCPSBidirGIOP= + .. prop:: DCPSBidirGIOP= :default: ``1`` (enabled) .. note:: This key is only applicable when using :ref:`inforepo-disc`. @@ -366,26 +366,26 @@ For example: Use TAO's BiDirectional GIOP feature for interaction with the :ref:`inforepo`. With BiDir enabled, fewer sockets are needed since the same socket can be used for both client and server roles. - .. key:: DCPSBit= + .. prop:: DCPSBit= :default: ``1`` (enabled) Controls if :ref:`bit` are enabled. - .. key:: DCPSBitLookupDurationMsec= + .. prop:: DCPSBitLookupDurationMsec= :default: ``2000`` (2 seconds) The maximum duration in milliseconds that the framework will wait for latent :ref:`bit` information when retrieving BIT data given an instance handle. The participant code may get an instance handle for a remote entity before the framework receives and processes the related BIT information. The framework waits for up to the given amount of time before it fails the operation. - .. key:: DCPSBitTransportIPAddress= + .. prop:: DCPSBitTransportIPAddress= :default: ``INADDR_ANY`` .. note:: This key is only applicable when using :ref:`inforepo-disc`. IP address identifying the local interface to be used by :ref:`tcp-transport` for the :ref:`bit`. - .. key:: DCPSBitTransportPort= + .. prop:: DCPSBitTransportPort= :default: ``0`` .. note:: This key is only applicable when using :ref:`inforepo-disc`. @@ -393,28 +393,28 @@ For example: Port used by the :ref:`tcp-transport` for :ref:`bit`. If the default of ``0`` is used, the operating system will choose a port to use. - .. key:: DCPSChunkAssociationMultiplier= + .. prop:: DCPSChunkAssociationMultiplier= :default: ``10`` - Multiplier for the :key:`DCPSChunks` or the ``max_samples`` value in :ref:`qos-resource-limits` to determine the total number of shallow copy chunks that are preallocated. + Multiplier for the :prop:`DCPSChunks` or the ``max_samples`` value in :ref:`qos-resource-limits` to determine the total number of shallow copy chunks that are preallocated. Set this to a value greater than the number of connections so the preallocated chunk handles do not run out. A sample written to multiple data readers will not be copied multiple times but there is a shallow copy handle to that sample used to manage the delivery to each data reader. The size of the handle is small so there is not great need to set this value close to the number of connections. - .. key:: DCPSChunks= + .. prop:: DCPSChunks= :default: ``20`` Configurable number of chunks that a data writer's and reader's cached allocators will preallocate when the :ref:`qos-resource-limits` value is infinite. When all of the preallocated chunks are in use, OpenDDS allocates from the heap. This feature of allocating from the heap when the preallocated memory is exhausted provides flexibility but performance will decrease when the preallocated memory is exhausted. - .. key:: DCPSDebugLevel= + .. prop:: DCPSDebugLevel= :default: ``0`` (disabled) Integer value that controls the amount of :ref:`debug information the DCPS layer logs `. Valid values are ``0`` through ``10``. - .. key:: DCPSDefaultAddress= + .. prop:: DCPSDefaultAddress= :default: ``0.0.0.0`` Default value for the host portion of ``local_address`` in transport instances and some other host address values: @@ -423,13 +423,13 @@ For example: - ``[transport]local_address`` (udp) - ``[transport]local_address`` (multicast) - ``[transport]local_address`` (rtps_udp) - - ``[transport]ipv6_local_address`` (rstp_udp) + - ``[transport]ipv6_local_address`` (rtps_udp) - ``[transport]multicast_interface`` (rtps_udp) - ``[rtps_discovery]SedpLocalAddress`` - ``[rtps_discovery]SpdpLocalAddress`` - ``[rtps_discovery]MulticastInterface`` - .. key:: DCPSDefaultDiscovery=DEFAULT_REPO|DEFAULT_RTPS|DEFAULT_STATIC| + .. prop:: DCPSDefaultDiscovery=DEFAULT_REPO|DEFAULT_RTPS|DEFAULT_STATIC| :default: :val:`DEFAULT_REPO` Specifies a discovery configuration to use for any domain not explicitly configured. @@ -453,7 +453,7 @@ For example: See :ref:`config-disc` for details about configuring discovery. - .. key:: DCPSGlobalTransportConfig=|$file + .. prop:: DCPSGlobalTransportConfig=|$file :default: The default configuration is used as described in :ref:`run_time_configuration--overview`. The :ref:`transport configuration ` that should be used as the global default one. @@ -466,20 +466,20 @@ For example: ``$file`` uses a transport configuration that includes all transport instances defined in the configuration file. - .. key:: DCPSInfoRepo= + .. prop:: DCPSInfoRepo= :default: ``file://repo.ior`` Object reference for locating the :ref:`inforepo` in :ref:`inforepo-disc`. This value is passed to ``CORBA::ORB::string_to_object()`` and can be any Object URL type understandable by :term:`TAO` (file, IOR, corbaloc, corbaname). A simplified endpoint description of the form ``:`` is also accepted, which is equivalent to ``corbaloc:::/DCPSInfoRepo``. - .. key:: DCPSLivelinessFactor= + .. prop:: DCPSLivelinessFactor= :default: ``80`` Percent of the :ref:`qos-liveliness` lease duration after which a liveliness message is sent. A value of ``80`` implies a 20% cushion of latency from the last detected heartbeat message. - .. key:: DCPSLogLevel=none|error|warning|notice|info|debug + .. prop:: DCPSLogLevel=none|error|warning|notice|info|debug :default: :val:`warning` General logging control. @@ -510,30 +510,30 @@ For example: See :ref:`run_time_configuration--logging` for details. - .. key:: DCPSMonitor= + .. prop:: DCPSMonitor= :default: ``0`` Use the Monitor library to publish data on monitoring topics (see :ghfile:`dds/monitor/README`). - .. key:: DCPSPendingTimeout= + .. prop:: DCPSPendingTimeout= :default: ``0`` The maximum duration in seconds a data writer will block to allow unsent samples to drain on deletion. The default, ``0``, blocks indefinitely. - .. key:: DCPSPersistentDataDir= + .. prop:: DCPSPersistentDataDir= :default: ``OpenDDS-durable-data-dir`` The path to a directory on where durable data will be stored for :ref:`PERSISTENT_DURABILITY_QOS `. If the directory does not exist it will be created automatically. - .. key:: DCPSPublisherContentFilter= + .. prop:: DCPSPublisherContentFilter= :default: ``1`` Controls the filter expression evaluation policy for :ref:`content filtered topics `. When the value is ``1`` the publisher may drop any samples, before handing them off to the transport when these samples would have been ignored by all subscribers. - .. key:: DCPSSecurity= + .. prop:: DCPSSecurity= :default: ``0`` This setting is only available when OpenDDS is compiled with :ref:`dds_security`. @@ -542,37 +542,37 @@ For example: See :ref:`dds_security` for more information. - .. key:: DCPSSecurityDebug=[,]... + .. prop:: DCPSSecurityDebug=[,]... :default: ``0`` (No security logging) This setting is only available when OpenDDS is compiled with :ref:`dds_security` enabled. This controls the :ref:`security debug logging ` granularity by category. - .. key:: DCPSSecurityDebugLevel= + .. prop:: DCPSSecurityDebugLevel= :default: ``0`` (No security logging) This setting is only available when OpenDDS is compiled with :ref:`dds_security` enabled. This controls the :ref:`security debug logging ` granularity by debug level. - .. key:: DCPSSecurityFakeEncryption= + .. prop:: DCPSSecurityFakeEncryption= :default: ``0`` (Real encryption when that's setup) This setting is only available when OpenDDS is compiled with :ref:`dds_security` enabled. This option, when set to ``1``, disables all encryption by making encryption and decryption no-ops. OpenDDS still generates keys and performs other security bookkeeping, so this option is useful for debugging the security infrastructure by making it possible to manually inspect all messages. - .. key:: DCPSThreadStatusInterval= + .. prop:: DCPSThreadStatusInterval= :default: ``0`` (disabled) Enable :ref:`internal thread status reporting ` using the specified reporting interval, in seconds. - .. key:: DCPSTransportDebugLevel= + .. prop:: DCPSTransportDebugLevel= :default: ``0`` (disabled) Integer value that controls the amount of :ref:`debug information the transport layer logs `. Valid values are ``0`` through ``5``. - .. key:: DCPSTypeObjectEncoding=Normal|WriteOldFormat|ReadOldFormat + .. prop:: DCPSTypeObjectEncoding=Normal|WriteOldFormat|ReadOldFormat :default: :val:`Normal` From when :term:`XTypes` was first implemented in OpenDDS from 3.16.0 until 3.18.0, there was a bug in the encoding and decoding of ``TypeObject`` and related data types for :ref:`representing user types `. @@ -593,12 +593,12 @@ For example: The default, correct encoding is used. Once all applications are using both OpenDDS 3.18 or later and ``ReadOldFormat``, then ``Normal`` can be used. - .. key:: ORBLogFile= + .. prop:: ORBLogFile= :default: Output to standard error stream on most platforms Change :ref:`log ` message destination to the file specified, which is opened in appending mode. [#orbprefix]_ - .. key:: ORBVerboseLogging=0|1|2 + .. prop:: ORBVerboseLogging=0|1|2 :default: ``0`` Add a prefix to each :ref:`log ` message, using a format defined by the :term:`ACE` library: [#orbprefix]_ @@ -615,18 +615,18 @@ For example: Verbose, in addition to "lite" has host name, PID, program name - .. key:: pool_size= + .. prop:: pool_size= :default: ``41943040`` bytes (40 MiB) Size of :ref:`safety_profile` memory pool, in bytes. - .. key:: pool_granularity= + .. prop:: pool_granularity= :default: ``8`` Granularity of :ref:`safety_profile` memory pool in bytes. Must be multiple of 8. - .. key:: Scheduler=SCHED_RR|SCHED_FIFO|SCHED_OTHER + .. prop:: Scheduler=SCHED_RR|SCHED_FIFO|SCHED_OTHER :default: :val:`SCHED_OTHER` Selects the scheduler to use for transport sending threads. @@ -650,10 +650,10 @@ For example: :ref:`qos-transport-priority` - .. key:: scheduler_slice= + .. prop:: scheduler_slice= :default: ``0`` - Some operating systems require a time slice value to be set when selecting a :key:`Scheduler` other than the default. + Some operating systems require a time slice value to be set when selecting a :prop:`Scheduler` other than the default. For those systems, this option can be used to set a value in microseconds. .. _config-disc: @@ -754,9 +754,9 @@ For example, if an OpenDDS application assigns a domain ID of 3 to its participa [repository/DiscoveryConfig1] RepositoryIor=host1.mydomain.com:12345 -The ``DCPSDefaultDiscovery`` property tells the application to assign any participant that doesn't have a domain id found in the configuration file to use a discovery type of ``DEFAULT_REPO`` which means "use a ``DCPSInfoRepo`` service" and that ``DCPSInfoRepo`` service can be found at ``host3.mydomain.com:12345``. +The :prop:`DCPSDefaultDiscovery` and :prop:`DCPSInfoRepo` properties tell the application that every participant that doesn't have a domain id found in the configuration file to use the :ref:`inforepo` at ``host3.mydomain.com:12345``. -As shown in :ref:`run_time_configuration--common-configuration-options` the ``DCPSDefaultDiscovery`` property has three other values that can be used. +As shown in :ref:`config-common` the ``DCPSDefaultDiscovery`` property has three other values that can be used. The ``DEFAULT_RTPS`` constant value informs participants that don't have a domain configuration to use RTPS discovery to find other participants. Similarly, the ``DEFAULT_STATIC`` constant value informs the participants that don't have a domain configuration to use static discovery to find other participants. @@ -3668,7 +3668,7 @@ DCPS Layer Debug Logging .. Sect<7.6.1> -Debug logging in the DCPS layer of OpenDDS is controlled by the :key:`DCPSDebugLevel` configuration option and command-line option. +Debug logging in the DCPS layer of OpenDDS is controlled by the :prop:`DCPSDebugLevel` configuration option and command-line option. It can also be set in application code using: .. code-block:: cpp @@ -3699,7 +3699,7 @@ Transport Layer Debug Logging .. Sect<7.6.2> -OpenDDS transport debug layer logging is controlled via the :key:`DCPSTransportDebugLevel` configuration option. +OpenDDS transport debug layer logging is controlled via the :prop:`DCPSTransportDebugLevel` configuration option. For example, to add transport layer logging to any OpenDDS application that uses ``TheParticipantFactoryWithArgs``, add the following option to the command line: .. code-block:: bash @@ -3764,8 +3764,8 @@ Security Debug Logging .. Sect<7.6.3> -When OpenDDS is compiled with security enabled, debug logging for security can be enabled using :key:`DCPSSecurityDebug`. -Security logging is divided into categories, although :key:`DCPSSecurityDebugLevel` is also provided, which controls the categories in a similar manner and using the same scale as :key:`DCPSDebugLevel`. +When OpenDDS is compiled with security enabled, debug logging for security can be enabled using :prop:`DCPSSecurityDebug`. +Security logging is divided into categories, although :prop:`DCPSSecurityDebugLevel` is also provided, which controls the categories in a similar manner and using the same scale as :prop:`DCPSDebugLevel`. .. _run_time_configuration--reftable28: @@ -3889,6 +3889,6 @@ All the following are equivalent: .. rubric:: Footnotes -.. [#orbprefix] :key:`ORBLogFile` and :key:`ORBVerboseLogging` start with "ORB" because they are inherited from :term:`TAO`. +.. [#orbprefix] :prop:`ORBLogFile` and :prop:`ORBVerboseLogging` start with "ORB" because they are inherited from :term:`TAO`. They are implemented directly by OpenDDS (not passed to TAO) and are supported either on the command line (using a "-" prefix) or in the configuration file. Other command-line options that begin with ``-ORB`` are passed to TAO's ``ORB_init`` if :ref:`inforepo-disc` is used. diff --git a/docs/devguide/safety_profile.rst b/docs/devguide/safety_profile.rst index 0abf6d9dda6..eb1598b738e 100644 --- a/docs/devguide/safety_profile.rst +++ b/docs/devguide/safety_profile.rst @@ -96,7 +96,7 @@ Run-time Configurable Options Sect<13.4> The memory pool used by OpenDDS can be configured by setting values in the ``[common]`` section of the configuration file. -See :cfg:key:`pool_size` and :cfg:key:`pool_granularity`. +See :cfg:prop:`pool_size` and :cfg:prop:`pool_granularity`. .. _safety_profile--running-ace-and-opendds-tests: diff --git a/docs/internal/bench.rst b/docs/internal/bench.rst index 6862e6713a3..1f2deb12258 100644 --- a/docs/internal/bench.rst +++ b/docs/internal/bench.rst @@ -439,7 +439,7 @@ with configuration of OpenDDS. The elements of this section are functionally identical to the :ref:`config` sections of an OpenDDS ``.ini`` file with the same name. Each config section is created programmatically within the worker process using the name provided and made available to the OpenDDS ``ServiceParticipant`` during entity creation. -The example here sets the value of both the :cfg:key:`DCPSSecurity` and :cfg:key:`DCPSDebugLevel` keys to ``0``. +The example here sets the value of both the :cfg:prop:`DCPSSecurity` and :cfg:prop:`DCPSDebugLevel` keys to ``0``. :: diff --git a/docs/internal/docs.rst b/docs/internal/docs.rst index 1df6b46e98c..4e767927d26 100644 --- a/docs/internal/docs.rst +++ b/docs/internal/docs.rst @@ -473,8 +473,8 @@ For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphin .. rst:directive:: .. cfg:sec:: [@][/] - Use to document a configuration section that can contain :rst:dir:`cfg:key` and most other RST content. - ```` is an optional extension of the name to document cases where the available keys depend on something. + Use to document a configuration section that can contain :rst:dir:`cfg:prop` and most other RST content. + ```` is an optional extension of the name to document cases where the available properties depend on something. Using discriminators requires separate :rst:dir:`cfg:sec` entires. ```` is just for display and has no restrictions on the contents. @@ -485,9 +485,9 @@ For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphin Do not include arguments if it has arguments in the directive. The possible formats are ```` and ``@``. -.. rst:directive:: .. cfg:key:: = +.. rst:directive:: .. cfg:prop:: = - Use to document a configuration key that can contain :rst:dir:`cfg:val` and most other RST content. + Use to document a configuration property that can contain :rst:dir:`cfg:val` and most other RST content. Must be in a :rst:dir:`cfg:sec`. ```` describe what sort of text is accepted. It is just for display and has no restrictions on the contents, but should follow the following conventions to describe the accepted values: @@ -495,37 +495,37 @@ For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphin - ``|`` indicates an OR - ``[]`` indicates an optional part of the value - ``...`` indicates the previous part can be repeated - - Words surrounded angle brackets (ex: ````) indicate placeholders. + - Words surrounded angle brackets (ex: ````) indicate placeholders. - Everything else should be considered literal. For example: ``log_level=none|error|warn|debug``, ``memory_limit=``, ``addresses=[:],...``. .. rst:directive:option:: required - Indicates the key is required for the section + Indicates the property is required for the section .. rst:directive:option:: default - The default value of the key if omitted + The default value of the property if omitted -.. rst:role:: cfg:key +.. rst:role:: cfg:prop - Use to reference a :rst:dir:`cfg:key` by name. + Use to reference a :rst:dir:`cfg:prop` by name. Do not include values if it has values in the directive. The possible formats are: - - ```` + - ```` - Inside of a :rst:dir:`cfg:sec`, it refers to a key in that section. - Outside of a :rst:dir:`cfg:sec`, the key is assumed to be ``common``. + Inside of a :rst:dir:`cfg:sec`, it refers to a property in that section. + Outside of a :rst:dir:`cfg:sec`, the property is assumed to be ``common``. - - ``[]`` - - ``[@]`` + - ``[]`` + - ``[@]`` .. rst:directive:: .. cfg:val:: [<][>] - Use to document a part of what a configuration key accepts. - Must be in a :rst:dir:`cfg:key`. + Use to document a part of what a configuration property accepts. + Must be in a :rst:dir:`cfg:prop`. The optional angle brackets (``<>``) are just for display and are meant to help distinguish between the value being a literal and a placeholder. .. rst:role:: cfg:val @@ -536,15 +536,15 @@ For :doc:`/devguide/run_time_configuration` there's a custom configuration Sphin - ```` - This must be inside a :rst:dir:`cfg:key`. + This must be inside a :rst:dir:`cfg:prop`. - - ``=`` + - ``=`` - Inside of a :rst:dir:`cfg:sec`, it refers to a value of a key in that section. - Outside of a :rst:dir:`cfg:sec`, the key is assumed to be ``common``. + Inside of a :rst:dir:`cfg:sec`, it refers to a value of a property in that section. + Outside of a :rst:dir:`cfg:sec`, the property is assumed to be ``common``. - - ``[]=`` - - ``[@]=`` + - ``[]=`` + - ``[@]=`` Example ^^^^^^^ @@ -562,35 +562,35 @@ This is a example made up for the following INI file: .. code-block:: rst - Outside their sections, references to keys and values must be complete: :cfg:val:`[server]os=linux`, :cfg:key:`[server@linux]distro` + Outside their sections, references to properties and values must be complete: :cfg:val:`[server]os=linux`, :cfg:prop:`[server@linux]distro` Otherwise the ``common`` section will be assumed. .. cfg:sec:: server/ - A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os=windows` + A property or value's section can be omitted from references within their sections: :cfg:prop:`os`, :cfg:val:`os=windows` - .. cfg:key:: os=windows|linux + .. cfg:prop:: os=windows|linux :required: - A value's key can be omitted from references within their keys: :cfg:val:`linux` + A value's property can be omitted from references within their properties: :cfg:val:`linux` .. cfg:val:: windows - Implied titles will be shortened within their scopes: :cfg:key:`[server]os`, :cfg:val:`[server]os=windows` + Implied titles will be shortened within their scopes: :cfg:prop:`[server]os`, :cfg:val:`[server]os=windows` .. cfg:val:: linux - Sections with discriminators require them in the reference targets: :cfg:sec:`server@linux`, :cfg:key:`[server@linux]distro` + Sections with discriminators require them in the reference targets: :cfg:sec:`server@linux`, :cfg:prop:`[server@linux]distro` .. cfg:sec:: server@linux/ - .. cfg:key:: distro= + .. cfg:prop:: distro= :default: ``Ubuntu`` Turns into: - Outside their sections, references to keys and values must be complete: :cfg:val:`[server]os=linux`, :cfg:key:`[server@linux]distro` + Outside their sections, references to properties and values must be complete: :cfg:val:`[server]os=linux`, :cfg:prop:`[server@linux]distro` Otherwise the ``common`` section will be assumed. @@ -598,32 +598,32 @@ Turns into: :no-contents-entry: :no-index-entry: - A key or value's section can be omitted from references within their sections: :cfg:key:`os`, :cfg:val:`os=windows` + A property or value's section can be omitted from references within their sections: :cfg:prop:`os`, :cfg:val:`os=windows` - .. cfg:key:: os=windows|linux + .. cfg:prop:: os=windows|linux :required: :no-contents-entry: :no-index-entry: - A value's key can be omitted from references within their keys: :cfg:val:`linux` + A value's property can be omitted from references within their properties: :cfg:val:`linux` .. cfg:val:: windows :no-contents-entry: :no-index-entry: - Implied titles will be shortened within their scopes: :cfg:key:`[server]os`, :cfg:val:`[server]os=windows` + Implied titles will be shortened within their scopes: :cfg:prop:`[server]os`, :cfg:val:`[server]os=windows` .. cfg:val:: linux :no-contents-entry: :no-index-entry: - Sections with discriminators require them in the reference targets: :cfg:sec:`server@linux`, :cfg:key:`[server@linux]distro` + Sections with discriminators require them in the reference targets: :cfg:sec:`server@linux`, :cfg:prop:`[server@linux]distro` .. cfg:sec:: server@linux/ :no-contents-entry: :no-index-entry: - .. cfg:key:: distro= + .. cfg:prop:: distro= :default: ``Ubuntu`` :no-contents-entry: :no-index-entry: diff --git a/docs/news.d/_releases/v3.27.0.rst b/docs/news.d/_releases/v3.27.0.rst index 1a40fd1feba..46628901c1a 100644 --- a/docs/news.d/_releases/v3.27.0.rst +++ b/docs/news.d/_releases/v3.27.0.rst @@ -41,7 +41,7 @@ Fixes - Fixed a bug where compiling IDL with ``-Lc++11 -Gequality`` produced code outside of a namespace that didn't compile. (:ghpr:`4450`) -- ``SedpLocalAddress`` now defaults to :cfg:key:`DCPSDefaultAddress` to behave like ``SpdpLocalAddress`` and ``local_address``. (:ghpr:`4451`) +- ``SedpLocalAddress`` now defaults to :cfg:prop:`DCPSDefaultAddress` to behave like ``SpdpLocalAddress`` and ``local_address``. (:ghpr:`4451`) Notes ===== diff --git a/docs/sphinx_extensions/config_domain.py b/docs/sphinx_extensions/config_domain.py index 1d551750ddc..6728b076426 100644 --- a/docs/sphinx_extensions/config_domain.py +++ b/docs/sphinx_extensions/config_domain.py @@ -91,7 +91,7 @@ def parse_sig(self, ctx, sig): r'(' + id_re + r'(?:@' + id_re + r')?)(?:/(.*))?', sig, self) sec_name, sec_disc = parse_section_name(name) ctx.push(self, name, f'[{name}]', - sec_name=sec_name, sec_disc=sec_name, arguments=arguments, keys=[]) + sec_name=sec_name, sec_disc=sec_name, arguments=arguments, props=[]) return (sec_name, sec_disc, arguments) def create_signode(self, ctx, name, signode, sec_name, sec_disc, arguments): @@ -106,19 +106,19 @@ def create_signode(self, ctx, name, signode, sec_name, sec_disc, arguments): signode += addnodes.desc_annotation(text, text) -# cfg:key ===================================================================== +# cfg:prop ==================================================================== -key_name_re = id_re + r'(?:\.' + id_re + r')*' -key_re = r'(?:\[(?P' + section_re + r')\])?(?P' + key_name_re + r')' +prop_name_re = id_re + r'(?:\.' + id_re + r')*' +prop_re = r'(?:\[(?P' + section_re + r')\])?(?P' + prop_name_re + r')' -def parse_key_name(full_name, node=None): - return parse(ConfigKey._full_name, key_re, full_name, node, - 'sec', 'sec_name', 'sec_disc', 'key_name') +def parse_prop_name(full_name, node=None): + return parse(ConfigProp._full_name, prop_re, full_name, node, + 'sec', 'sec_name', 'sec_disc', 'prop_name') -def key_text(sec_name, sec_disc, key_name, insert=''): - text = key_name + insert +def prop_text(sec_name, sec_disc, prop_name, insert=''): + text = prop_name + insert if sec_name is not None: text = section_text(sec_name, sec_disc, ' ' + text) return text @@ -139,30 +139,30 @@ def name_canonicalize(name): return name.strip('_').upper() -def key_canonicalize(sec_name, sec_args, key_name): +def key_canonicalize(sec_name, sec_args, prop_name): sec = name_canonicalize(sec_name) if sec_args: sec += '_' + sec_args - return sec + '_' + name_canonicalize(key_name) + return sec + '_' + name_canonicalize(prop_name) -class ConfigKeyRefRole(XRefRole): +class ConfigPropRefRole(XRefRole): def process_link(self, env: BuildEnvironment, refnode: Element, has_explicit_title: bool, title: str, target: str) -> tuple[str, str]: ctx = ContextWrapper(env, 'cfg') target = target.strip() # Normalize target for the current scope - sec, sec_name, sec_disc, key_name = parse_key_name(target, self) + sec, sec_name, sec_disc, prop_name = parse_prop_name(target, self) scope_kind = len(ctx.stack) if sec is not None: - # [sec]key anywhere + # [sec]prop anywhere pass elif scope_kind == 0 and sec is None: - # Assume key outside section should be in [common] + # Assume prop outside section should be in [common] target = f'[common]{target}' elif scope_kind >= 1: - # key anywhere in a section + # prop anywhere in a section prefix = ctx.get_full_name(0) target = f'{prefix}{target}' else: @@ -171,45 +171,46 @@ def process_link(self, env: BuildEnvironment, refnode: Element, if not has_explicit_title: # Reparse target and hide parts of title that are in the current scope - sec, sec_name, sec_disc, key_name = parse_key_name(target, self) + sec, sec_name, sec_disc, prop_name = parse_prop_name(target, self) scope = ctx.get_all_names() scope = scope + [None] * (2 - len(scope)) if scope[0] == sec: sec_name = None - title = key_text(sec_name, sec_disc, key_name) + title = prop_text(sec_name, sec_disc, prop_name) return title, target @ConfigDomain.add_type -class ConfigKey(CustomDomainObject): +class ConfigProp(CustomDomainObject): option_spec: OptionSpec = CustomDomainObject.option_spec.copy() option_spec.update({ 'required': directives.flag, 'default': directives.unchanged, }) - our_name = 'key' + our_name = 'prop' our_parent_required = True our_parent_type = ConfigSection - our_ref_role_type = ConfigKeyRefRole + our_ref_role_type = ConfigPropRefRole def get_index_text(self, name, full_name): - sec, sec_name, sec_disc, key = parse_key_name(full_name) - return f'{key} (config key)' + sec, sec_name, sec_disc, prop = parse_prop_name(full_name) + return f'{prop} (config property)' def parse_sig(self, ctx, sig): - name, arguments = parse(self._full_name, r'(' + key_name_re + r')(?:=(.*))?', sig, self) + name, arguments = parse(self._full_name, r'(' + prop_name_re + r')(?:=(.*))?', sig, self) sec = ctx.get_full_name() ctx.push(self, name, f'{sec}{name}', arguments=arguments) - sec_ctx = ctx.get(-2, 'keys') + sec_ctx = ctx.get(-2, 'props') if sec_ctx is not None: sec_ctx.append((name, self.get_location())) return (arguments,) def create_signode(self, ctx, name, signode, arguments): signode += addnodes.desc_name(name, name) + print(ctx.get(-2, 'sec_name'), name) if arguments is not None: text = '=' + arguments signode += addnodes.desc_addname(text, text) @@ -246,18 +247,18 @@ def transform_content(self, contentnode: addnodes.desc_content) -> None: value_sep = '=' value_sep_re = re.escape(value_sep) -value_re = r'(?:(?P' + key_re + r')' + value_sep_re + r')?(?P' + id_re + r')' +value_re = r'(?:(?P' + prop_re + r')' + value_sep_re + r')?(?P' + id_re + r')' def parse_value_name(full_name, node=None): return parse(ConfigValue._full_name, value_re, full_name, node, - 'sec', 'sec_name', 'sec_disc', 'key', 'key_name', 'val_name') + 'sec', 'sec_name', 'sec_disc', 'prop', 'prop_name', 'val_name') -def value_text(sec_name, sec_disc, key_name, val_name): +def value_text(sec_name, sec_disc, prop_name, val_name): text = val_name - if key_name is not None: - text = key_text(sec_name, sec_disc, key_name, value_sep + text) + if prop_name is not None: + text = prop_text(sec_name, sec_disc, prop_name, value_sep + text) return text @@ -268,19 +269,19 @@ def process_link(self, env: BuildEnvironment, refnode: Element, target = target.strip() # Normalize target for the current scope - sec, sec_name, sec_disc, key, key_name, val_name = parse_value_name(target, self) + sec, sec_name, sec_disc, prop, prop_name, val_name = parse_value_name(target, self) scope_kind = len(ctx.stack) if sec is not None: - # [sec]key=val anywhere + # [sec]prop=val anywhere pass elif scope_kind == 0 and sec is None: - # key=val outside section + # prop=val outside section target = f'[common]{target}' - elif scope_kind >= 1 and key is not None: - # key=val anywhere in a section + elif scope_kind >= 1 and prop is not None: + # prop=val anywhere in a section target = ctx.get_full_name(0) + target - elif scope_kind >= 2 and key is None: - # val anywhere in a key + elif scope_kind >= 2 and prop is None: + # val anywhere in a prop target = ctx.get_full_name(1) + value_sep + target else: ConfigDomain.logger.warning(f'{repr(target)} is an invalid target here', @@ -288,15 +289,15 @@ def process_link(self, env: BuildEnvironment, refnode: Element, if not has_explicit_title: # Reparse target and hide parts of title that are in the current scope - sec, sec_name, sec_disc, key, key_name, val_name = parse_value_name(target, self) + sec, sec_name, sec_disc, prop, prop_name, val_name = parse_value_name(target, self) scope = ctx.get_all_names() scope = scope + [None] * (3 - len(scope)) if scope[0] == sec: sec_name = None - if scope[1] == key_name: - key_name = None + if scope[1] == prop_name: + prop_name = None - title = value_text(sec_name, sec_disc, key_name, val_name) + title = value_text(sec_name, sec_disc, prop_name, val_name) return title, target @@ -305,7 +306,7 @@ def process_link(self, env: BuildEnvironment, refnode: Element, class ConfigValue(CustomDomainObject): our_name = 'val' our_parent_required = True - our_parent_type = ConfigKey + our_parent_type = ConfigProp our_ref_role_type = ConfigValueRefRole def run(self): @@ -315,7 +316,7 @@ def run(self): return super().run() def get_index_text(self, name, full_name): - sec, sec_name, sec_disc, key, key_name, val_name = parse_value_name(full_name, self) + sec, sec_name, sec_disc, prop, prop_name, val_name = parse_value_name(full_name, self) return f'{val_name} (config value)' def parse_sig(self, ctx, sig): @@ -345,6 +346,7 @@ def setup(app: Sphinx) -> dict[str, Any]: 'parallel_write_safe': True, } + class TestConfigDomain(unittest.TestCase): def test_parse_section_name(self): @@ -357,9 +359,9 @@ def test_parse_section_name(self): for ref, expected in cases.items(): self.assertEqual(parse_section_name(ref), expected) - def test_parse_key_name(self): + def test_parse_prop_name(self): cases = { - # sec, sec_name, sec_disc, key_name + # sec, sec_name, sec_disc, prop_name 'kn': (None, None, None, 'kn'), 'kn.a.b.c': (None, None, None, 'kn.a.b.c'), '[sn]kn': ('sn', 'sn', None, 'kn'), @@ -369,11 +371,11 @@ def test_parse_key_name(self): } for ref, expected in cases.items(): - self.assertEqual(parse_key_name(ref), expected, f'On key {repr(ref)}') + self.assertEqual(parse_prop_name(ref), expected, f'On prop {repr(ref)}') def test_parse_value_name(self): cases = { - # sec, sec_name, sec_disc, key, key_name, val_name + # sec, sec_name, sec_disc, prop, prop_name, val_name 'vn': (None, None, None, None, None, 'vn'), 'kn=vn': (None, None, None, 'kn', 'kn', 'vn'), 'kn.a.b.c=vn': (None, None, None, 'kn.a.b.c', 'kn.a.b.c', 'vn'), From 1eebceccc330d3708e55d112a8a884bffbd1df0c Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Mon, 8 Apr 2024 00:47:06 -0500 Subject: [PATCH 21/37] Fix :cfg:prop: and :cmake:prop: being confused This was data accidentally shared between the custom Sphinx domains. --- docs/devguide/run_time_configuration.rst | 2 ++ docs/sphinx_extensions/config_domain.py | 10 ++++++++-- docs/sphinx_extensions/custom_domain.py | 19 ++++++++++--------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/docs/devguide/run_time_configuration.rst b/docs/devguide/run_time_configuration.rst index 882ebf8bdcb..65f358d36d8 100644 --- a/docs/devguide/run_time_configuration.rst +++ b/docs/devguide/run_time_configuration.rst @@ -25,6 +25,8 @@ OpenDDS configuration is concerned with three main areas: Each pluggable transport can be configured separately. See :ref:`config-transport` for details. +.. _config-store-keys: + ********************** Configuration Approach ********************** diff --git a/docs/sphinx_extensions/config_domain.py b/docs/sphinx_extensions/config_domain.py index 6728b076426..a405df42132 100644 --- a/docs/sphinx_extensions/config_domain.py +++ b/docs/sphinx_extensions/config_domain.py @@ -224,8 +224,14 @@ def transform_content(self, contentnode: addnodes.desc_content) -> None: rst = ViewList() # Config store key - key = key_canonicalize(ctx.get(-2, 'sec_name'), ctx.get(-2, 'arguments'), ctx.get_name()) - rst.append(f'| **Config store key**: ``{key}``', f'{__name__}', 1) + try: + key = key_canonicalize( + ctx.get(-2, 'sec_name'), ctx.get(-2, 'arguments'), ctx.get_name()) + rst.append(f'| :ref:`Config store key `: ``{key}``', + f'{__name__}', 1) + except Exception as e: + e = ValueError(f'Something went wrong with key_canonicalize: {e}') + ConfigDomain.logger.warning(e, location=self.get_location()) # :required: flag required = 'required' in self.options diff --git a/docs/sphinx_extensions/custom_domain.py b/docs/sphinx_extensions/custom_domain.py index 6d6147a2647..2c7d4100597 100644 --- a/docs/sphinx_extensions/custom_domain.py +++ b/docs/sphinx_extensions/custom_domain.py @@ -187,15 +187,16 @@ class CustomDomain(Domain): label = None logger = None - object_types = { - } - directives = { - } - roles = { - } - initial_data: dict[str, dict[tuple[str, str], str]] = { - 'objects': {}, # fullname -> docname, objtype - } + def __init_subclass__(cls): + cls.object_types = { + } + cls.directives = { + } + cls.roles = { + } + cls.initial_data = { + 'objects': {}, # fullname -> docname, objtype + } @property def objects(self) -> dict[tuple[str, str], tuple[str, str]]: From 6ba78e39583c743f21ea8f36075660200c6b18a8 Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Mon, 8 Apr 2024 00:51:46 -0500 Subject: [PATCH 22/37] Change more terms --- docs/devguide/run_time_configuration.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/devguide/run_time_configuration.rst b/docs/devguide/run_time_configuration.rst index 65f358d36d8..0d3e224d3bd 100644 --- a/docs/devguide/run_time_configuration.rst +++ b/docs/devguide/run_time_configuration.rst @@ -363,7 +363,7 @@ For example: .. prop:: DCPSBidirGIOP= :default: ``1`` (enabled) - .. note:: This key is only applicable when using :ref:`inforepo-disc`. + .. note:: This property is only applicable when using :ref:`inforepo-disc`. Use TAO's BiDirectional GIOP feature for interaction with the :ref:`inforepo`. With BiDir enabled, fewer sockets are needed since the same socket can be used for both client and server roles. @@ -383,14 +383,14 @@ For example: .. prop:: DCPSBitTransportIPAddress= :default: ``INADDR_ANY`` - .. note:: This key is only applicable when using :ref:`inforepo-disc`. + .. note:: This property is only applicable when using :ref:`inforepo-disc`. IP address identifying the local interface to be used by :ref:`tcp-transport` for the :ref:`bit`. .. prop:: DCPSBitTransportPort= :default: ``0`` - .. note:: This key is only applicable when using :ref:`inforepo-disc`. + .. note:: This property is only applicable when using :ref:`inforepo-disc`. Port used by the :ref:`tcp-transport` for :ref:`bit`. If the default of ``0`` is used, the operating system will choose a port to use. From e6f2b43febfa5ec1c1d39c03b69ea04a706a71e0 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Tue, 9 Apr 2024 17:51:51 +0000 Subject: [PATCH 23/37] Enabled CLOCK_BOOTTIME timers for Multi/Periodic/SporadicTask --- dds/CMakeLists.txt | 4 + dds/DCPS/Definitions.h | 4 + dds/DCPS/MultiTask.cpp | 88 +++++++++++++++ dds/DCPS/MultiTask.h | 92 +++------------- dds/DCPS/PeriodicTask.cpp | 67 ++++++++++++ dds/DCPS/PeriodicTask.h | 79 ++++---------- dds/DCPS/SporadicTask.cpp | 88 +++++++++++++++ dds/DCPS/SporadicTask.h | 87 ++------------- dds/DCPS/Timers.cpp | 121 +++++++++++++++++++++ dds/DCPS/Timers.h | 42 +++++++ tests/unit-tests/dds/DCPS/SporadicTask.cpp | 2 +- tests/unit-tests/dds/DCPS/Timers.cpp | 38 +++++++ 12 files changed, 502 insertions(+), 210 deletions(-) create mode 100644 dds/DCPS/MultiTask.cpp create mode 100644 dds/DCPS/PeriodicTask.cpp create mode 100644 dds/DCPS/SporadicTask.cpp create mode 100644 dds/DCPS/Timers.cpp create mode 100644 dds/DCPS/Timers.h create mode 100644 tests/unit-tests/dds/DCPS/Timers.cpp diff --git a/dds/CMakeLists.txt b/dds/CMakeLists.txt index e6b7aa21138..81c114a47cb 100644 --- a/dds/CMakeLists.txt +++ b/dds/CMakeLists.txt @@ -55,6 +55,7 @@ add_library(OpenDDS_Dcps DCPS/MessageBlock.cpp DCPS/MessageTracker.cpp DCPS/MonitorFactory.cpp + DCPS/MultiTask.cpp DCPS/MultiTopicDataReaderBase.cpp DCPS/MultiTopicImpl.cpp DCPS/MulticastManager.cpp @@ -65,6 +66,7 @@ add_library(OpenDDS_Dcps DCPS/Observer.cpp DCPS/OwnershipManager.cpp DCPS/PeriodicEvent.cpp + DCPS/PeriodicTask.cpp DCPS/PublisherImpl.cpp DCPS/Qos_Helper.cpp DCPS/QueryConditionImpl.cpp @@ -91,6 +93,7 @@ add_library(OpenDDS_Dcps DCPS/ServiceEventDispatcher.cpp DCPS/Service_Participant.cpp DCPS/SporadicEvent.cpp + DCPS/SporadicTask.cpp DCPS/StaticDiscovery.cpp DCPS/StatusConditionImpl.cpp DCPS/SubscriberImpl.cpp @@ -99,6 +102,7 @@ add_library(OpenDDS_Dcps DCPS/ThreadStatusManager.cpp DCPS/TimeDuration.cpp DCPS/Time_Helper.cpp + DCPS/Timers.cpp DCPS/TopicDescriptionImpl.cpp DCPS/TopicImpl.cpp DCPS/Transient_Kludge.cpp diff --git a/dds/DCPS/Definitions.h b/dds/DCPS/Definitions.h index b57b6854bef..56803c12928 100644 --- a/dds/DCPS/Definitions.h +++ b/dds/DCPS/Definitions.h @@ -110,6 +110,10 @@ # define OPENDDS_DO_MANUAL_STATIC_INCLUDES 0 #endif +#ifndef OPENDDS_CONFIG_BOOTTIME_TIMERS +# define OPENDDS_CONFIG_BOOTTIME_TIMERS 0 +#endif + OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL namespace OpenDDS { diff --git a/dds/DCPS/MultiTask.cpp b/dds/DCPS/MultiTask.cpp new file mode 100644 index 00000000000..cea1ad8af76 --- /dev/null +++ b/dds/DCPS/MultiTask.cpp @@ -0,0 +1,88 @@ +/* + * Distributed under the OpenDDS License. + * See: http://www.opendds.org/license.html + */ + +#include "DCPS/DdsDcps_pch.h" //Only the _pch include should start with DCPS/ + +#include "MultiTask.h" + +#include "Timers.h" + +OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace OpenDDS { +namespace DCPS { + +void MultiTask::enable(const TimeDuration& delay) +{ + bool worth_passing_along = false; + { + ACE_Guard guard(mutex_); + worth_passing_along = (timer_ == Timers::InvalidTimerId) || + ((MonotonicTimePoint::now() + delay + cancel_estimate_) < next_time_); + } + if (worth_passing_along) { + RcHandle interceptor = interceptor_.lock(); + if (interceptor) { + interceptor->execute_or_enqueue(make_rch(rchandle_from(this), delay)); + } + } +} + +void MultiTask::enable_i(const TimeDuration& per) +{ + ACE_Guard guard(mutex_); + const MonotonicTimePoint now = MonotonicTimePoint::now(); + if (timer_ == Timers::InvalidTimerId) { + timer_ = Timers::schedule(reactor(), *this, 0, per, delay_); + + if (timer_ == Timers::InvalidTimerId) { + ACE_ERROR((LM_ERROR, "(%P|%t) MultiTask::enable_i" + " failed to schedule timer %p\n", ACE_TEXT(""))); + } else { + next_time_ = now + per; + } + } else { + const MonotonicTimePoint estimated_next_time = now + per + cancel_estimate_; + if (estimated_next_time < next_time_) { + Timers::cancel(reactor(), timer_); + const MonotonicTimePoint now2 = MonotonicTimePoint::now(); + timer_ = Timers::schedule(reactor(), *this, 0, per, delay_); + cancel_estimate_ = now2 - now; + + if (timer_ == Timers::InvalidTimerId) { + ACE_ERROR((LM_ERROR, "(%P|%t) MultiTask::enable_i" + " failed to reschedule timer %p\n", ACE_TEXT(""))); + } else { + next_time_ = now2 + per; + } + } + } +} + +int MultiTask::handle_timeout(const ACE_Time_Value& tv, const void*) +{ + ThreadStatusManager::Event ev(TheServiceParticipant->get_thread_status_manager()); + + const MonotonicTimePoint now(tv); + { + ACE_Guard guard(mutex_); + next_time_ = now + delay_; + } + execute(now); + return 0; +} + +void MultiTask::disable_i() +{ + ACE_Guard guard(mutex_); + if (timer_ != Timers::InvalidTimerId) { + Timers::cancel(reactor(), timer_); + timer_ = Timers::InvalidTimerId; + } +} + +} +} +OPENDDS_END_VERSIONED_NAMESPACE_DECL diff --git a/dds/DCPS/MultiTask.h b/dds/DCPS/MultiTask.h index ade981ca519..c431585a1f9 100644 --- a/dds/DCPS/MultiTask.h +++ b/dds/DCPS/MultiTask.h @@ -10,17 +10,17 @@ #include "RcEventHandler.h" #include "ReactorInterceptor.h" -#include "TimeTypes.h" #include "Service_Participant.h" +#include "TimeTypes.h" OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL namespace OpenDDS { namespace DCPS { -class MultiTask : public virtual RcEventHandler { +class OpenDDS_Dcps_Export MultiTask : public virtual RcEventHandler { public: - explicit MultiTask(RcHandle interceptor, const TimeDuration& delay) + MultiTask(RcHandle interceptor, const TimeDuration& delay) : interceptor_(interceptor) , delay_(delay) , timer_(-1) @@ -32,20 +32,7 @@ class MultiTask : public virtual RcEventHandler { virtual ~MultiTask() {} - void enable(const TimeDuration& delay) - { - bool worth_passing_along = false; - { - ACE_Guard guard(mutex_); - worth_passing_along = (timer_ == -1) || ((MonotonicTimePoint::now() + delay + cancel_estimate_) < next_time_); - } - if (worth_passing_along) { - RcHandle interceptor = interceptor_.lock(); - if (interceptor) { - interceptor->execute_or_enqueue(make_rch(rchandle_from(this), delay)); - } - } - } + void enable(const TimeDuration& delay); void disable() { @@ -58,7 +45,7 @@ class MultiTask : public virtual RcEventHandler { virtual void execute(const MonotonicTimePoint& now) = 0; private: - WeakRcHandle interceptor_; + const WeakRcHandle interceptor_; const TimeDuration delay_; long timer_; MonotonicTimePoint next_time_; @@ -67,8 +54,9 @@ class MultiTask : public virtual RcEventHandler { struct ScheduleEnableCommand : public ReactorInterceptor::Command { ScheduleEnableCommand(WeakRcHandle multi_task, const TimeDuration& delay) - : multi_task_(multi_task), delay_(delay) - { } + : multi_task_(multi_task) + , delay_(delay) + {} virtual void execute() { @@ -78,14 +66,14 @@ class MultiTask : public virtual RcEventHandler { } } - WeakRcHandle const multi_task_; + const WeakRcHandle multi_task_; const TimeDuration delay_; }; struct ScheduleDisableCommand : public ReactorInterceptor::Command { explicit ScheduleDisableCommand(WeakRcHandle multi_task) : multi_task_(multi_task) - { } + {} virtual void execute() { @@ -95,62 +83,14 @@ class MultiTask : public virtual RcEventHandler { } } - WeakRcHandle const multi_task_; + const WeakRcHandle multi_task_; }; - int handle_timeout(const ACE_Time_Value& tv, const void*) - { - ThreadStatusManager::Event ev(TheServiceParticipant->get_thread_status_manager()); - - const MonotonicTimePoint now(tv); - { - ACE_Guard guard(mutex_); - next_time_ = now + delay_; - } - execute(now); - return 0; - } + int handle_timeout(const ACE_Time_Value& tv, const void*); - void enable_i(const TimeDuration& per) - { - ACE_Guard guard(mutex_); - const MonotonicTimePoint now = MonotonicTimePoint::now(); - if (timer_ == -1) { - timer_ = reactor()->schedule_timer(this, 0, per.value(), delay_.value()); - - if (timer_ == -1) { - ACE_ERROR((LM_ERROR, "(%P|%t) MultiTask::enable" - " failed to schedule timer %p\n", ACE_TEXT(""))); - } else { - next_time_ = now + per; - } - } else { - const MonotonicTimePoint estimated_next_time = now + per + cancel_estimate_; - if (estimated_next_time < next_time_) { - reactor()->cancel_timer(timer_); - const MonotonicTimePoint now2 = MonotonicTimePoint::now(); - timer_ = reactor()->schedule_timer(this, 0, per.value(), delay_.value()); - cancel_estimate_ = now2 - now; - - if (timer_ == -1) { - ACE_ERROR((LM_ERROR, "(%P|%t) MultiTask::enable" - " failed to reschedule timer %p\n", ACE_TEXT(""))); - } else { - next_time_ = now2 + per; - } - } - } - } + void enable_i(const TimeDuration& per); - void - disable_i() - { - ACE_Guard guard(mutex_); - if (timer_ != -1) { - reactor()->cancel_timer(timer_); - timer_ = -1; - } - } + void disable_i(); }; template @@ -167,8 +107,8 @@ class PmfMultiTask : public MultiTask { , function_(function) {} private: - WeakRcHandle delegate_; - PMF function_; + const WeakRcHandle delegate_; + const PMF function_; void execute(const MonotonicTimePoint& now) { diff --git a/dds/DCPS/PeriodicTask.cpp b/dds/DCPS/PeriodicTask.cpp new file mode 100644 index 00000000000..b2e046bb3ee --- /dev/null +++ b/dds/DCPS/PeriodicTask.cpp @@ -0,0 +1,67 @@ +/* + * Distributed under the OpenDDS License. + * See: http://www.opendds.org/license.html + */ + +#include "DCPS/DdsDcps_pch.h" //Only the _pch include should start with DCPS/ + +#include "PeriodicTask.h" + +#include "Timers.h" + +OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace OpenDDS { +namespace DCPS { + +void PeriodicTask::enable(bool reenable, const TimeDuration& period) +{ + { + ACE_GUARD(ACE_Thread_Mutex, g, mutex_); + user_enabled_ = true; + } + RcHandle interceptor = interceptor_.lock(); + if (interceptor) { + interceptor->execute_or_enqueue(make_rch(rchandle_from(this), reenable, period)); + } +} + +void PeriodicTask::disable() +{ + { + ACE_GUARD(ACE_Thread_Mutex, g, mutex_); + user_enabled_ = false; + } + RcHandle interceptor = interceptor_.lock(); + if (interceptor) { + interceptor->execute_or_enqueue(make_rch(rchandle_from(this))); + } +} + +void PeriodicTask::enable_i(bool reenable, const TimeDuration& per) +{ + if (!enabled_) { + timer_ = Timers::schedule(reactor(), *this, 0, TimeDuration(), per); + if (timer_ == Timers::InvalidTimerId) { + ACE_ERROR((LM_ERROR, "(%P|%t) PeriodicTask::enable_i" + " failed to schedule timer %p\n", ACE_TEXT(""))); + } else { + enabled_ = true; + } + } else if (reenable) { + disable_i(); + enable_i(false, per); + } +} + +void PeriodicTask::disable_i() +{ + if (enabled_) { + Timers::cancel(reactor(), timer_); + enabled_ = false; + } +} + +} +} +OPENDDS_END_VERSIONED_NAMESPACE_DECL diff --git a/dds/DCPS/PeriodicTask.h b/dds/DCPS/PeriodicTask.h index 117eea97f75..c4c00228c70 100644 --- a/dds/DCPS/PeriodicTask.h +++ b/dds/DCPS/PeriodicTask.h @@ -8,6 +8,7 @@ #ifndef OPENDDS_DCPS_PERIODIC_TASK_H #define OPENDDS_DCPS_PERIODIC_TASK_H +#include "Service_Participant.h" #include "RcEventHandler.h" #include "ReactorInterceptor.h" @@ -16,41 +17,22 @@ OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL namespace OpenDDS { namespace DCPS { -class PeriodicTask : public virtual RcEventHandler { +class OpenDDS_Dcps_Export PeriodicTask : public virtual RcEventHandler { public: explicit PeriodicTask(RcHandle interceptor) : user_enabled_(false) - , interceptor_(interceptor) , enabled_(false) + , interceptor_(interceptor) + , timer_(-1) { reactor(interceptor->reactor()); } virtual ~PeriodicTask() {} - void enable(bool reenable, const TimeDuration& period) - { - { - ACE_GUARD(ACE_Thread_Mutex, g, mutex_); - user_enabled_ = true; - } - RcHandle interceptor = interceptor_.lock(); - if (interceptor) { - interceptor->execute_or_enqueue(make_rch(rchandle_from(this), reenable, period)); - } - } + void enable(bool reenable, const TimeDuration& period); - void disable() - { - { - ACE_GUARD(ACE_Thread_Mutex, g, mutex_); - user_enabled_ = false; - } - RcHandle interceptor = interceptor_.lock(); - if (interceptor) { - interceptor->execute_or_enqueue(make_rch(rchandle_from(this))); - } - } + void disable(); bool enabled() const { @@ -63,13 +45,16 @@ class PeriodicTask : public virtual RcEventHandler { private: mutable ACE_Thread_Mutex mutex_; bool user_enabled_; - WeakRcHandle interceptor_; bool enabled_; + const WeakRcHandle interceptor_; + long timer_; struct ScheduleEnableCommand : public ReactorInterceptor::Command { ScheduleEnableCommand(WeakRcHandle hb, bool reenable, const TimeDuration& period) - : periodic_task_(hb), reenable_(reenable), period_(period) - { } + : periodic_task_(hb) + , reenable_(reenable) + , period_(period) + {} virtual void execute() { @@ -79,7 +64,7 @@ class PeriodicTask : public virtual RcEventHandler { } } - WeakRcHandle const periodic_task_; + const WeakRcHandle periodic_task_; const bool reenable_; const TimeDuration period_; }; @@ -87,7 +72,7 @@ class PeriodicTask : public virtual RcEventHandler { struct ScheduleDisableCommand : public ReactorInterceptor::Command { explicit ScheduleDisableCommand(WeakRcHandle hb) : periodic_task_(hb) - { } + {} virtual void execute() { @@ -97,7 +82,7 @@ class PeriodicTask : public virtual RcEventHandler { } } - WeakRcHandle const periodic_task_; + const WeakRcHandle periodic_task_; }; int handle_timeout(const ACE_Time_Value& tv, const void*) @@ -109,32 +94,9 @@ class PeriodicTask : public virtual RcEventHandler { return 0; } - void enable_i(bool reenable, const TimeDuration& per) - { - if (!enabled_) { - const long timer = - reactor()->schedule_timer(this, 0, ACE_Time_Value::zero, per.value()); - - if (timer == -1) { - ACE_ERROR((LM_ERROR, "(%P|%t) PeriodicTask::enable" - " failed to schedule timer %p\n", ACE_TEXT(""))); - } else { - enabled_ = true; - } - } else if (reenable) { - disable_i(); - enable_i(false, per); - } - } + void enable_i(bool reenable, const TimeDuration& per); - void - disable_i() - { - if (enabled_) { - reactor()->cancel_timer(this); - enabled_ = false; - } - } + void disable_i(); }; template @@ -145,11 +107,12 @@ class PmfPeriodicTask : public PeriodicTask { PmfPeriodicTask(RcHandle interceptor, const Delegate& delegate, PMF function) : PeriodicTask(interceptor) , delegate_(delegate) - , function_(function) {} + , function_(function) + {} private: - WeakRcHandle delegate_; - PMF function_; + const WeakRcHandle delegate_; + const PMF function_; void execute(const MonotonicTimePoint& now) { diff --git a/dds/DCPS/SporadicTask.cpp b/dds/DCPS/SporadicTask.cpp new file mode 100644 index 00000000000..99a00a4a1cc --- /dev/null +++ b/dds/DCPS/SporadicTask.cpp @@ -0,0 +1,88 @@ +/* + * Distributed under the OpenDDS License. + * See: http://www.opendds.org/license.html + */ + +#include "DCPS/DdsDcps_pch.h" //Only the _pch include should start with DCPS/ + +#include "SporadicTask.h" + +#include "Timers.h" + +OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace OpenDDS { +namespace DCPS { + +void SporadicTask::schedule(const TimeDuration& delay) +{ + const MonotonicTimePoint next_time = time_source_.monotonic_time_point_now() + delay; + { + ACE_Guard guard(mutex_); + if (!desired_scheduled_ || next_time < desired_next_time_) { + desired_scheduled_ = true; + desired_next_time_ = next_time; + desired_delay_ = delay; + } else { + return; + } + } + + const RcHandle interceptor = interceptor_.lock(); + if (interceptor) { + interceptor->execute_or_enqueue(sporadic_command_); + } else if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: SporadicTask::schedule: " + "failed to receive ReactorInterceptor handle\n")); + } +} + +void SporadicTask::cancel() +{ + { + ACE_Guard guard(mutex_); + if (!desired_scheduled_) { + return; + } + + desired_scheduled_ = false; + } + + const RcHandle interceptor = interceptor_.lock(); + if (interceptor) { + interceptor->execute_or_enqueue(sporadic_command_); + } else if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: SporadicTask::cancel: " + "failed to receive ReactorInterceptor handle\n")); + } +} + +void SporadicTask::execute_i() +{ + ACE_Guard guard(mutex_); + + if ((!desired_scheduled_ && timer_id_ != -1) || + (desired_scheduled_ && timer_id_ != -1 && desired_next_time_ != actual_next_time_)) { + Timers::cancel(reactor(), timer_id_); + timer_id_ = -1; + } + + if (desired_scheduled_ && timer_id_ == -1) { + timer_id_ = Timers::schedule(reactor(), *this, 0, desired_delay_); + if (timer_id_ == Timers::InvalidTimerId) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: SporadicTask::execute_i: " + "failed to schedule timer %p\n", "")); + } + } else { + actual_next_time_ = desired_next_time_; + } + } +} + +} +} +OPENDDS_END_VERSIONED_NAMESPACE_DECL diff --git a/dds/DCPS/SporadicTask.h b/dds/DCPS/SporadicTask.h index 7fde443ffff..456aec5dfc6 100644 --- a/dds/DCPS/SporadicTask.h +++ b/dds/DCPS/SporadicTask.h @@ -18,7 +18,7 @@ OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL namespace OpenDDS { namespace DCPS { -class SporadicTask : public virtual RcEventHandler { +class OpenDDS_Dcps_Export SporadicTask : public virtual RcEventHandler { public: SporadicTask(const TimeSource& time_source, RcHandle interceptor) @@ -33,61 +33,20 @@ class SporadicTask : public virtual RcEventHandler { virtual ~SporadicTask() {} - void schedule(const TimeDuration& delay) - { - const MonotonicTimePoint next_time = time_source_.monotonic_time_point_now() + delay; - { - ACE_Guard guard(mutex_); - if (!desired_scheduled_ || next_time < desired_next_time_) { - desired_scheduled_ = true; - desired_next_time_ = next_time; - desired_delay_ = delay; - } else { - return; - } - } - - RcHandle interceptor = interceptor_.lock(); - if (interceptor) { - interceptor->execute_or_enqueue(sporadic_command_); - } else if (log_level >= LogLevel::Error) { - ACE_ERROR((LM_ERROR, - "(%P|%t) ERROR: SporadicTask::schedule: " - "failed to receive ReactorInterceptor handle\n")); - } - } - - void cancel() - { - { - ACE_Guard guard(mutex_); - if (!desired_scheduled_) { - return; - } + void schedule(const TimeDuration& delay); - desired_scheduled_ = false; - } - - RcHandle interceptor = interceptor_.lock(); - if (interceptor) { - interceptor->execute_or_enqueue(sporadic_command_); - } else if (log_level >= LogLevel::Error) { - ACE_ERROR((LM_ERROR, - "(%P|%t) ERROR: SporadicTask::cancel: " - "failed to receive ReactorInterceptor handle\n")); - } - } + void cancel(); virtual void execute(const MonotonicTimePoint& now) = 0; protected: - long get_timer_id() { return timer_id_; } + long get_timer_id() const { return timer_id_; } private: - struct SporadicCommand : public ReactorInterceptor::Command { + struct SporadicCommand : ReactorInterceptor::Command { explicit SporadicCommand(WeakRcHandle sporadic_task) : sporadic_task_(sporadic_task) - { } + {} virtual void execute() { @@ -97,42 +56,20 @@ class SporadicTask : public virtual RcEventHandler { } } - WeakRcHandle sporadic_task_; + const WeakRcHandle sporadic_task_; }; const TimeSource& time_source_; - WeakRcHandle interceptor_; + const WeakRcHandle interceptor_; bool desired_scheduled_; MonotonicTimePoint desired_next_time_; TimeDuration desired_delay_; long timer_id_; MonotonicTimePoint actual_next_time_; - RcHandle sporadic_command_; + const RcHandle sporadic_command_; mutable ACE_Thread_Mutex mutex_; - void execute_i() - { - ACE_Guard guard(mutex_); - - if ((!desired_scheduled_ && timer_id_ != -1) || - (desired_scheduled_ && timer_id_ != -1 && desired_next_time_ != actual_next_time_)) { - reactor()->cancel_timer(timer_id_); - timer_id_ = -1; - } - - if (desired_scheduled_ && timer_id_ == -1) { - timer_id_ = reactor()->schedule_timer(this, 0, desired_delay_.value()); - if (timer_id_ == -1) { - if (log_level >= LogLevel::Error) { - ACE_ERROR((LM_ERROR, - "(%P|%t) ERROR: SporadicTask::execute_i: " - "failed to schedule timer %p\n", "")); - } - } else { - actual_next_time_ = desired_next_time_; - } - } - } + void execute_i(); int handle_timeout(const ACE_Time_Value& tv, const void*) { @@ -164,8 +101,8 @@ class PmfSporadicTask : public SporadicTask { {} private: - WeakRcHandle delegate_; - PMF function_; + const WeakRcHandle delegate_; + const PMF function_; void execute(const MonotonicTimePoint& now) { diff --git a/dds/DCPS/Timers.cpp b/dds/DCPS/Timers.cpp new file mode 100644 index 00000000000..7ccbae446af --- /dev/null +++ b/dds/DCPS/Timers.cpp @@ -0,0 +1,121 @@ +/* + * Distributed under the OpenDDS License. + * See: http://www.opendds.org/license.html + */ + +#include "DCPS/DdsDcps_pch.h" //Only the _pch include should start with DCPS/ + +#include "Timers.h" + +#include "debug.h" + +#include + +#if OPENDDS_CONFIG_BOOTTIME_TIMERS +# if defined __linux__ && __linux__ +# include +# else +# error Unsupported platform for OPENDDS_CONFIG_BOOTTIME_TIMERS +# endif +# include "RcHandle_T.h" +#endif + +OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace OpenDDS { +namespace DCPS { +namespace Timers { + +const TimerId InvalidTimerId = -1; + +#if OPENDDS_CONFIG_BOOTTIME_TIMERS + +// CLOCK_BOOTTIME timers on Linux can be set using the timerfd_* functions. +// The file descriptor created by timerfd_ can be used with ACE's reactor so +// that events generated by these timers can be demultiplexed along with other +// events on the same thread. +// To maintain the ACE timers abstraction for users of the OpenDDS::DCPS::Timers +// functions, we'll translate the timerfd's input/read event to handle_timeout. + +struct TimerFdHandler : RcEventHandler { + TimerFdHandler(RcEventHandler& userHandler, ACE_HANDLE fd, const void* context) + : userHandler_(userHandler) + , fd_(fd) + , context_(context) + {} + + int handle_input(ACE_HANDLE) + { + const MonotonicTimePoint now = MonotonicTimePoint::now(); + uint64_t unused; + const ssize_t readReturned = read(fd_, &unused, sizeof unused); + if (readReturned != sizeof unused) { + if (log_level >= LogLevel::Warning) { + ACE_ERROR((LM_WARNING, "(%P|%t) WARNING: TimerFdHandler::handle_input: read %m\n")); + } + return -1; + } + const RcHandle user = userHandler_.lock(); + return user ? user->handle_timeout(now.value(), context_) : -1; + } + + int handle_close(ACE_HANDLE, ACE_Reactor_Mask) { close(fd_); return 0; } + + ACE_HANDLE get_handle() const { return fd_; } + + const WeakRcHandle userHandler_; + const ACE_HANDLE fd_; + const void* const context_; +}; +#endif + +TimerId schedule(ACE_Reactor* reactor, + RcEventHandler& handler, + const void* arg, + const TimeDuration& delay, + const TimeDuration& interval) +{ +#if OPENDDS_CONFIG_BOOTTIME_TIMERS + const ACE_HANDLE fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC); + if (fd == -1) { + if (log_level >= LogLevel::Notice) { + ACE_ERROR((LM_NOTICE, "(%P|%t) NOTICE: Timers::schedule: timerfd_create %m\n")); + } + return InvalidTimerId; + } + itimerspec ts; + ts.it_interval = interval.value(); + ts.it_value = delay.value(); + if (timerfd_settime(fd, 0, &ts, 0) == -1) { + if (log_level >= LogLevel::Notice) { + ACE_ERROR((LM_NOTICE, "(%P|%t) NOTICE: Timers::schedule: timerfd_settime %m\n")); + } + return InvalidTimerId; + } + const RcHandle fdHandler = make_rch(ref(handler), fd, arg); + if (reactor->register_handler(fdHandler.get(), ACE_Event_Handler::READ_MASK) == -1) { + if (log_level >= LogLevel::Notice) { + ACE_ERROR((LM_NOTICE, "(%P|%t) NOTICE: Timers::schedule: register_handler %m\n")); + } + return InvalidTimerId; + } + return fd; +#else + return reactor->schedule_timer(&handler, arg, delay.value(), interval.value()); +#endif +} + +void cancel(ACE_Reactor* reactor, TimerId timer) +{ +#if OPENDDS_CONFIG_BOOTTIME_TIMERS + reactor->remove_handler(static_cast(timer), ACE_Event_Handler::ALL_EVENTS_MASK); +#else + reactor->cancel_timer(timer); +#endif +} + +} +} +} + +OPENDDS_END_VERSIONED_NAMESPACE_DECL diff --git a/dds/DCPS/Timers.h b/dds/DCPS/Timers.h new file mode 100644 index 00000000000..654bedb61a5 --- /dev/null +++ b/dds/DCPS/Timers.h @@ -0,0 +1,42 @@ +/* + * Distributed under the OpenDDS License. + * See: http://www.opendds.org/license.html + */ + +#ifndef OPENDDS_DCPS_TIMERS_H +#define OPENDDS_DCPS_TIMERS_H + +#include "Definitions.h" +#include "RcEventHandler.h" +#include "TimeTypes.h" + +#include "dcps_export.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +class ACE_Reactor; +ACE_END_VERSIONED_NAMESPACE_DECL + +OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace OpenDDS { +namespace DCPS { +namespace Timers { + +typedef long TimerId; // from ACE_Reactor +extern OpenDDS_Dcps_Export const TimerId InvalidTimerId; + +OpenDDS_Dcps_Export TimerId schedule(ACE_Reactor* reactor, + RcEventHandler& handler, + const void* arg, + const TimeDuration& delay, + const TimeDuration& interval = TimeDuration()); + +OpenDDS_Dcps_Export void cancel(ACE_Reactor* reactor, TimerId timer); + +} +} +} + +OPENDDS_END_VERSIONED_NAMESPACE_DECL + +#endif diff --git a/tests/unit-tests/dds/DCPS/SporadicTask.cpp b/tests/unit-tests/dds/DCPS/SporadicTask.cpp index c1112cb8e00..ec9010457ca 100644 --- a/tests/unit-tests/dds/DCPS/SporadicTask.cpp +++ b/tests/unit-tests/dds/DCPS/SporadicTask.cpp @@ -42,7 +42,7 @@ namespace { RcHandle interceptor) : SporadicTask(time_source, interceptor) {} - long timer_id() { return get_timer_id(); } + long timer_id() const { return get_timer_id(); } MOCK_METHOD1(execute, void(const MonotonicTimePoint&)); }; diff --git a/tests/unit-tests/dds/DCPS/Timers.cpp b/tests/unit-tests/dds/DCPS/Timers.cpp new file mode 100644 index 00000000000..be751b39334 --- /dev/null +++ b/tests/unit-tests/dds/DCPS/Timers.cpp @@ -0,0 +1,38 @@ +#include + +#include + +#include + +using namespace OpenDDS::DCPS; + +struct TestEventHandler : RcEventHandler { + TestEventHandler() + : calls_(0) + {} + + int handle_timeout(const ACE_Time_Value&, const void*) + { + ACE_DEBUG((LM_DEBUG, "%T timeout\n")); + ++calls_; + return 0; + } + + int calls_; +}; + +TEST(dds_DCPS_Timers, test) +{ + RcHandle handler = make_rch(); + ACE_Reactor* const reactor = ACE_Reactor::instance(); + + ACE_DEBUG((LM_DEBUG, "%T schedule\n")); + const Timers::TimerId id = Timers::schedule(reactor, *handler, 0, TimeDuration::from_msec(10)); + ASSERT_NE(id, Timers::InvalidTimerId); + + ACE_Time_Value one_sec(1, 0); + reactor->handle_events(one_sec); + + ASSERT_EQ(handler->calls_, 1); + Timers::cancel(reactor, id); +} From 5733f3ad66da2e22b8be79089b83ade896c1afe0 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Tue, 9 Apr 2024 18:11:46 +0000 Subject: [PATCH 24/37] Updated docs --- docs/news.d/boottime.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/news.d/boottime.rst b/docs/news.d/boottime.rst index 903024e2c94..41130e2e808 100644 --- a/docs/news.d/boottime.rst +++ b/docs/news.d/boottime.rst @@ -1,7 +1,7 @@ -.. news-prs: TODO +.. news-prs: 4568 .. news-start-section: Additions - Allow compile-time configuration of CLOCK_BOOTTIME as the clock used for timers - - When the platform supports it, this can be done using ``--boottime`` when building with the configure script or :cmake:var:`OPENDDS_BOOTTIME_TIMERS` when building with CMake. + - If the platform supports it, this can be done using ``--boottime`` when building with the configure script or :cmake:var:`OPENDDS_BOOTTIME_TIMERS` when building with CMake. .. news-end-section From 02bb45af9a65a8b4a5bd730f8879eda832eafe8f Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Tue, 9 Apr 2024 18:18:51 +0000 Subject: [PATCH 25/37] Use the Timers::InvalidTimerId constant --- dds/DCPS/SporadicTask.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dds/DCPS/SporadicTask.cpp b/dds/DCPS/SporadicTask.cpp index 99a00a4a1cc..2c5ec5119e7 100644 --- a/dds/DCPS/SporadicTask.cpp +++ b/dds/DCPS/SporadicTask.cpp @@ -63,19 +63,19 @@ void SporadicTask::execute_i() { ACE_Guard guard(mutex_); - if ((!desired_scheduled_ && timer_id_ != -1) || - (desired_scheduled_ && timer_id_ != -1 && desired_next_time_ != actual_next_time_)) { + if ((!desired_scheduled_ && timer_id_ != Timers::InvalidTimerId) || + (desired_scheduled_ && timer_id_ != Timers::InvalidTimerId && desired_next_time_ != actual_next_time_)) { Timers::cancel(reactor(), timer_id_); - timer_id_ = -1; + timer_id_ = Timers::InvalidTimerId; } - if (desired_scheduled_ && timer_id_ == -1) { + if (desired_scheduled_ && timer_id_ == Timers::InvalidTimerId) { timer_id_ = Timers::schedule(reactor(), *this, 0, desired_delay_); if (timer_id_ == Timers::InvalidTimerId) { if (log_level >= LogLevel::Error) { ACE_ERROR((LM_ERROR, - "(%P|%t) ERROR: SporadicTask::execute_i: " - "failed to schedule timer %p\n", "")); + "(%P|%t) ERROR: SporadicTask::execute_i: " + "failed to schedule timer %p\n", ACE_TEXT(""))); } } else { actual_next_time_ = desired_next_time_; From 805596b15803b36daf2e6833472c92cfd23198dd Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Tue, 9 Apr 2024 18:33:18 +0000 Subject: [PATCH 26/37] Update unit test for SporadicTask --- tests/unit-tests/dds/DCPS/SporadicTask.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unit-tests/dds/DCPS/SporadicTask.cpp b/tests/unit-tests/dds/DCPS/SporadicTask.cpp index ec9010457ca..ea6fdd53754 100644 --- a/tests/unit-tests/dds/DCPS/SporadicTask.cpp +++ b/tests/unit-tests/dds/DCPS/SporadicTask.cpp @@ -15,6 +15,8 @@ using namespace OpenDDS::DCPS; +#if !OPENDDS_CONFIG_BOOTTIME_TIMERS + namespace { class MyTimeSource : public TimeSource { public: @@ -253,3 +255,4 @@ TEST(dds_DCPS_SporadicTask, cancel_no_interceptor) reactor_interceptor.reset(); sporadic_task->cancel(); } +#endif From 45dec5b4a0060da9c189920f09bced6cb2f4a7ba Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Tue, 9 Apr 2024 15:23:26 -0500 Subject: [PATCH 27/37] GitHub Actions: build Wireshark libs without the GUI --- .github/workflows/Wireshark_CMakePresets.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/Wireshark_CMakePresets.json b/.github/workflows/Wireshark_CMakePresets.json index 782c1041623..b54e714ce0f 100644 --- a/.github/workflows/Wireshark_CMakePresets.json +++ b/.github/workflows/Wireshark_CMakePresets.json @@ -6,6 +6,7 @@ "generator": "Ninja", "binaryDir": "$env{WIRESHARK_BUILD_DIR}", "cacheVariables": { + "BUILD_wireshark": "OFF", "LEX_EXECUTABLE": "$env{WINFLEXBISON_ROOT}/bin/Debug/win_flex.exe" } } From a3f3123544a263540e67a102782a91599f7ce719 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Tue, 9 Apr 2024 16:06:24 -0500 Subject: [PATCH 28/37] Wireshark CI: vcpkg may not be needed here --- .github/workflows/build_and_test.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index c92fdd0b81e..83bb8b76a32 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -9618,17 +9618,6 @@ jobs: with: path: ${{ github.job }}.tar.xz key: c02_${{ github.job }}_${{ env.WIRESHARK_COMMIT }}_${{ env.COMPILER_VERSION }} - - name: setup for run-vcpkg - shell: bash - run: | - echo '{ "name": "opendds", "version-string": "github-actions", "dependencies": [ "qt5-winextras", "qt5-tools", "qt5-svg", "qt5-multimedia", "qt5-declarative" ] }' > vcpkg.json - - name: install vcpkg packages - if: steps.cache-artifact.outputs.cache-hit != 'true' - id: runvcpkg - uses: lukka/run-vcpkg@v11 - with: - vcpkgGitCommitId: '${{ env.VCPKG_GIT_COMMIT }}' - runVcpkgInstall: true - name: checkout WinFlexBison if: steps.cache-artifact.outputs.cache-hit != 'true' uses: actions/checkout@v4 From d9cd76cfe17a23620fb225189b1b9cd7058946bd Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Tue, 9 Apr 2024 16:36:06 -0500 Subject: [PATCH 29/37] More Wireshark CMake settings - to avoid warnings --- .github/workflows/Wireshark_CMakePresets.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/Wireshark_CMakePresets.json b/.github/workflows/Wireshark_CMakePresets.json index b54e714ce0f..ff120e967c2 100644 --- a/.github/workflows/Wireshark_CMakePresets.json +++ b/.github/workflows/Wireshark_CMakePresets.json @@ -7,6 +7,8 @@ "binaryDir": "$env{WIRESHARK_BUILD_DIR}", "cacheVariables": { "BUILD_wireshark": "OFF", + "MAKENSIS_EXECUTABLE": "OFF", + "WIX_CANDLE_EXECUTABLE": "OFF", "LEX_EXECUTABLE": "$env{WINFLEXBISON_ROOT}/bin/Debug/win_flex.exe" } } From 8ecb6205c8d74322c4d9ca791dc960ae57db9365 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Tue, 9 Apr 2024 16:37:25 -0500 Subject: [PATCH 30/37] Unit test for timers: use the same ACE_Reactor impl on all platforms --- tests/unit-tests/dds/DCPS/Timers.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unit-tests/dds/DCPS/Timers.cpp b/tests/unit-tests/dds/DCPS/Timers.cpp index be751b39334..59fbda0ffa7 100644 --- a/tests/unit-tests/dds/DCPS/Timers.cpp +++ b/tests/unit-tests/dds/DCPS/Timers.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include @@ -24,15 +24,15 @@ struct TestEventHandler : RcEventHandler { TEST(dds_DCPS_Timers, test) { RcHandle handler = make_rch(); - ACE_Reactor* const reactor = ACE_Reactor::instance(); + ACE_Reactor reactor(new ACE_Select_Reactor, true); ACE_DEBUG((LM_DEBUG, "%T schedule\n")); - const Timers::TimerId id = Timers::schedule(reactor, *handler, 0, TimeDuration::from_msec(10)); + const Timers::TimerId id = Timers::schedule(&reactor, *handler, 0, TimeDuration::from_msec(10)); ASSERT_NE(id, Timers::InvalidTimerId); - ACE_Time_Value one_sec(1, 0); - reactor->handle_events(one_sec); + ACE_Time_Value one_sec(1); + reactor.handle_events(one_sec); ASSERT_EQ(handler->calls_, 1); - Timers::cancel(reactor, id); + Timers::cancel(&reactor, id); } From 0e791e020ddbc37987d61ed316c0b060c93d9e59 Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Wed, 10 Apr 2024 08:29:50 -0500 Subject: [PATCH 31/37] Convert Disc. Config Tables to Use Config Domain --- docs/devguide/built_in_topics.rst | 2 +- docs/devguide/internet_enabled_rtps.rst | 142 +-- docs/devguide/quality_of_service.rst | 2 +- docs/devguide/run_time_configuration.rst | 1163 ++++++++-------------- docs/devguide/xtypes.rst | 2 +- docs/news.d/spdp-user-tag.rst | 3 +- 6 files changed, 493 insertions(+), 821 deletions(-) diff --git a/docs/devguide/built_in_topics.rst b/docs/devguide/built_in_topics.rst index a94c0d13854..18b41983f51 100644 --- a/docs/devguide/built_in_topics.rst +++ b/docs/devguide/built_in_topics.rst @@ -252,7 +252,7 @@ The topic type ParticipantLocationBuiltinTopicData is defined in :ghfile:`dds/Op * ``local6_addr``, ``local6_timestamp``, ``ice6_addr``, ``ice6_timestamp``, ``relay6_addr``, and ``relay6_timestamp`` -- Are the IPV6 equivalents. -* ``lease_duration`` -- The remote participant's lease duration (see Lease Duration in :ref:`run_time_configuration--rtps-disc-config-options`) +* ``lease_duration`` -- The remote participant's :cfg:prop:`[rtps_discovery]LeaseDuration` .. _built_in_topics--openddsconnectionrecord-topic: diff --git a/docs/devguide/internet_enabled_rtps.rst b/docs/devguide/internet_enabled_rtps.rst index caf80af6e51..7539b422b66 100644 --- a/docs/devguide/internet_enabled_rtps.rst +++ b/docs/devguide/internet_enabled_rtps.rst @@ -31,6 +31,7 @@ Adding ICE to RTPS is an optimization that allows participants that are behind f ICE requires a back channel for distributing discovery information and is typically used with the RtpsRelay. .. _internet_enabled_rtps--the-rtpsrelay: +.. _rtpsrelay: ************* The RtpsRelay @@ -39,6 +40,8 @@ The RtpsRelay .. Sect<15.2> +.. program:: RtpsRelay + The RtpsRelay is designed to allow participants to exchange RTPS datagrams when separated by a firewall that performs network address translation (NAT) and/or a network that does not support multicast like the public Internet. The RtpsRelay supports both IPv4 and IPv6. A participant that uses an RtpsRelay Instance is a *client* of that instance. @@ -77,7 +80,7 @@ Using the RtpsRelay Sect<15.2.1> Support for the RtpsRelay is activated via configuration. -See :ref:`RTPS Discovery Configuration Options ` and :ref:`RTPS_UDP Configuration Options `. +See :cfg:sec:`rtps_discovery` and :cfg:sec:`transport@rtps_udp` for details. As an example: .. code-block:: ini @@ -111,7 +114,7 @@ Usage Sect<15.2.2> The RtpsRelay itself is an OpenDDS application. -The source code is located in ``tools/rtpsrelay``. +The source code is located in :ghfile:`tools/rtpsrelay`. Security must be enabled to build the RtpsRelay. See :ref:`dds_security--building-opendds-with-security-enabled`. Each RtpsRelay process has a set of ports for exchanging RTPS messages with the participants called the "vertical" ports and a set of ports for exchanging RTPS messages with other relays called the "horizontal" ports. @@ -127,143 +130,159 @@ The webserver has the following endpoints: * ``/healthcheck`` - Responds with HTTP 200 (OK) or 503 (Service Unavailable) if thread monitoring is enabled and the RtpsRelay is not admitting new client participants. + Responds with HTTP 200 (OK) or 503 (Service Unavailable) if :cfg:prop:`thread monitoring is enabled ` and the RtpsRelay is not admitting new client participants. Load balancers can use this endpoint to route new client participants to an available RtpsRelay instance. The command-line options for the RtpsRelay: -* ``-Id STRING`` +.. option:: -Id - The Id option is mandatory and is a unique id associated with all topics published by the relay. + This option is mandatory and is a unique id associated with all topics published by the relay. -* ``-HorizontalAddress ADDRESS`` +.. option:: -HorizontalAddres
Determines the base network address used for receiving RTPS message from other relays. By default, the relay listens on the first IP network and uses port 11444 for SPDP messages, 11445 for SEDP messages, and 11446 for data messages. -* ``-VerticalAddress ADDRESS`` +.. option:: -VerticalAddress
Determines the base network address used for receiving RTPS messages from the participants. By default, the relay listens on 0.0.0.0:4444 for SPDP messages, 0.0.0.0:4445 for SEDP messages, and 0.0.0.0.4446 for data messages. -* ``-RelayDomain DOMAIN`` +.. option:: -RelayDomain Sets the DDS domain used by the Relay Participant. The default is 0. -* ``-ApplicationDomain DOMAIN`` +.. option:: -ApplicationDomain Sets the DDS domain used by the Application Participant. The default is 1. -* ``-UserData STRING`` +.. option:: -UserData - Set the contents of the Application Participant's UserData QoS policy to the provided string. + Set the contents of the Application Participant's :ref:`UserData QoS policy ` to the provided string. -* ``-BufferSize INTEGER`` +.. option:: -BufferSize Send of send and receive buffers in bytes -* ``-Lifespan SECONDS`` +.. option:: -Lifespan RtpsRelay will only forward a datagram to a client if it has received a datagram from the client in this amount of time. Otherwise, participant is marked as not alive. The default is 60 seconds. -* ``-InactivePeriod SECONDS`` +.. option:: -InactivePeriod RtpsRelay will mark participant as not active if does not receive a datagram from the client in this amount of time. The default is 60 seconds. -* ``-AllowEmptyPartitions 0|1`` +.. option:: -AllowEmptyPartition 0|1 Allow client participants with no partitions. Defaults to 1 (true). -* ``-IdentityCA PATH`` +.. option:: -IdentityCA + + Provide identity CA file for :ref:`sec`. + +.. option:: -PermissionsCA + + Provide permissions CA file for :ref:`sec`. + +.. option:: -IdentityCertificate + + Provide identity certificate file for :ref:`sec`. - ``-PermissionsCA PATH`` +.. option:: -IdentityKey - ``-IdentityCertificate PATH`` + Provide identity key file for :ref:`sec`. - ``-IdentityKey PATH`` +.. option:: -Governance - ``-Governance PATH`` + Provide governance file for :ref:`sec`. - ``-Permissions PATH`` +.. option:: -Permissions - Provide paths to the DDS Security documents. + Provide permissions file for :ref:`sec`. -* ``-RestartDetection 0|1`` +.. option:: -RestartDetection 0|1 - Setting RestartDetction to 1 causes the relay to track clients by the first 6 bytes of their RTPS GUID and source IP address and clean up older sessions with the same key. + Setting to 1 causes the relay to track clients by the first 6 bytes of their RTPS GUID and source IP address and clean up older sessions with the same key. The default is 0 (false). -* ``-LogWarnings 0|1`` +.. option:: -LogWarnings 0|1 - ``-LogDiscovery 0|1`` + Enable/disable logging of warning events. - ``-LogActivity 0|1`` +.. option:: -LogDiscovery 0|1 - Enable/disable logging of the various event types. + Enable/disable logging of discovery events. -* ``-LogRelayStatistics SECONDS`` +.. option:: -LogActivity 0|1 - ``-LogHandlerStatistics SECONDS`` + Enable/disable logging of activity events. - ``-LogParticipantStatistics SECONDS`` +.. option:: -LogRelayStatistics + +.. option:: -LogHandlerStatistics + +.. option:: -LogParticipantStatistics Write statistics for the various event types to the log at the given interval, defaults to 0 (disabled). -* ``-PublishRelayStatistics SECONDS`` +.. option:: -PublishRelayStatistics - ``-PublishHandlerStatistics SECONDS`` +.. option:: -PublishHandlerStatistics - ``-PublishParticipantStatistics SECONDS`` +.. option:: -PublishParticipantStatistics Configure the relay to publish usage statistics on DDS topics at the given interval, defaults to 0 (disabled). -* ``-LogThreadStatus 0|1`` +.. option:: -LogThreadStatus 0|1 + + If :cfg:prop:`thread monitoring is enabled `, log the status of the threads in the RtpsRelay, defaults to 0 (disabled). - Log the status of the threads in the RtpsRelay, defaults to 0 (disabled). +.. option:: -ThreadStatusSafetyFactor -* ``-ThreadStatusSafetyFactor INTEGER`` + Restart if :cfg:prop:`thread monitoring is enabled ` and a thread has not checked in for this many reporting intervals, default 3. - Restart if thread monitoring is enabled and a thread has not checked in for this many reporting intervals, default 3. +.. option:: -UtilizationLimit -* ``-UtilizationLimit DECIMAL`` + If :cfg:prop:`thread monitoring is enabled `, the RtpsRelay will not accept to new client participants if the CPU utilization of any thread is above this limit, default .95. - If thread monitoring is enabled, the RtpsRelay will not accept to new client participants if the CPU utilization of any thread is above this limit, default .95. +.. option:: -PublishRelayStatus -* ``-PublishRelayStatus SECONDS`` + Setting this to a positive integer causes the relay to publish its status at that interval. - ``-PublishRelayStatusLiveliness SECONDS`` +.. option:: -PublishRelayStatusLiveliness - Setting PublishRelayStatus to a positive integer causes the relay to publish its status at that interval. - Setting PublishRelayStatusLiveliness to a positive integer causes the relay to set the liveliness QoS on the relay status topic. + Setting this to a positive integer causes the relay to set the :ref:`qos-liveliness` on the relay status topic. -* ``-MetaDiscoveryAddress ADDRESS`` +.. option:: -MetaDiscoveryAddress : - Listening address for the meta discovery server, default 0.0.0.0:8080. + Listening address for the meta discovery server, default is ``0.0.0.0:8080``. -* ``-MetaDiscoveryContentType CONTENT-TYPE`` +.. option:: -MetaDiscoveryContentType - The HTTP content type to report for the meta discovery config endpoint, default application/json. + The HTTP content type to report for the meta discovery config endpoint, default is ``application/json``. -* ``-MetaDiscoveryContentPath PATH`` +.. option:: -MetaDiscoveryContentPath - ``-MetaDiscoveryContent CONTENT`` +.. option:: -MetaDiscoveryContent - The content returned by the meta discovery config endpoint, default {}. + The content returned by the meta discovery config endpoint, default ``{}``. If a path is specified, the content of the file will be used. -* ``-MaxIpsPerClient INTEGER`` +.. option:: -MaxIpsPerClient The maximum number of IP addresses that the RtpsRelay will maintain for a client participant, defaults to 0 (infinite). -* ``-RejectedAddressDuration SECONDS`` +.. option:: -RejectedAddressDuration - Amount of time to reject messages from client participants that show suspicious behavior, e.g., those that send messages from the RtpsRelay back to the RtpsRelay. The default is 0 (disabled). + Amount of time to reject messages from client participants that show suspicious behavior, e.g., those that send messages from the RtpsRelay back to the RtpsRelay. + The default is 0 (disabled). .. _internet_enabled_rtps--deployment-considerations: @@ -286,6 +305,7 @@ These simple web servers would be exposed via a centralized load balancer. A participant, then, could access the HTTP load balancer to select a relay. .. _internet_enabled_rtps--interactive-connectivity-establishment-ice-for-rtps: +.. _ice: ***************************************************** Interactive Connectivity Establishment (ICE) for RTPS @@ -316,8 +336,8 @@ ICE utilizes the STUN protocol that is defined in :rfc:`5389`. The ICE implementation in OpenDDS does not use TURN servers. ICE is enabled through configuration. -The minimum configuration involves setting the ``UseIce`` flag and providing addresses for the STUN servers. -See :ref:`RTPS Discovery Configuration Options ` and :ref:`RTPS_UDP Configuration Options ` for details. +The minimum configuration involves setting the :cfg:prop:`[rtps_discovery]UseIce` and ``[transport@rtps_udp]UseIce`` flags and providing addresses for the STUN servers. +See :cfg:sec:`rtps_discovery` and ``transport@rtps_udp`` for details. .. code-block:: ini @@ -333,6 +353,7 @@ See :ref:`RTPS Discovery Configuration Options ` + * See :cfg:prop:`[rtps_discovery]CheckSourceIp` * Use the participant lease time from secure discovery and bound it otherwise. By default, OpenDDS will attempt authentication for the participant lease duration specified in the SPDP message. However, this data can't be trusted so a smaller maximum lease time can be specified to force authentication or discovery to terminate before the lease time. - * See ``MaxAuthTime`` in :ref:`RTPS Discovery Configuration Options ` + * See :cfg:prop:`[rtps_discovery]MaxAuthTime` * Limit the number of outstanding secure discoveries. The number of discovered but not-yet-authenticated participants is capped when using secure discovery. - * See ``MaxParticipantsInAuthentication`` in :ref:`RTPS Discovery Configuration Options ` + * See :cfg:prop:`[rtps_discovery]MaxParticipantsInAuthentication` .. _internet_enabled_rtps--run-participants-in-a-secure-network: @@ -419,4 +440,3 @@ One approach to a secure application without DDS Security is to secure it at the A physically secure network satisfies this by construction. Another approach is to use a virtual private network (VPN) or a secure overlay. These approaches have a simple security model when compared to DDS Security and are not interoperable. - diff --git a/docs/devguide/quality_of_service.rst b/docs/devguide/quality_of_service.rst index d5e0390afe8..ee134063e41 100644 --- a/docs/devguide/quality_of_service.rst +++ b/docs/devguide/quality_of_service.rst @@ -761,7 +761,7 @@ For example, the application could attach security credentials via the policy th .. warning:: When using :ref:`dds_security`, the user data of a participant can be leaked in unsecured discovery messages. - Enabling ``[rtps_discovery]SecureParticipantUserData`` will only send and provide the real user data when it can be securely sent. + Enabling :cfg:prop:`[rtps_discovery]SecureParticipantUserData` will only send and provide the real user data when it can be securely sent. This is an OpenDDS-specific extension. .. _qos-topic-data: diff --git a/docs/devguide/run_time_configuration.rst b/docs/devguide/run_time_configuration.rst index 0d3e224d3bd..ab41769c708 100644 --- a/docs/devguide/run_time_configuration.rst +++ b/docs/devguide/run_time_configuration.rst @@ -53,7 +53,7 @@ Sections, instances, and properties can contain underscores meaning that undersc This ambiguity is resolved by the following rules: * Sections are known by OpenDDS. - For example, OpenDDS will look for :ref:`DDSI-RTPS Discovery` instances under keys prefixed by ``RTPS_DISCOVERY``. + For example, OpenDDS will look for :ref:`RTPS Discovery ` instances under keys prefixed by ``RTPS_DISCOVERY``. * Instances must be introduced by a special key-value pair where the value is prefixed by ``@``. For example, ``RTPS_DISCOVERY_MY_DISCOVERY=@MY_DISCOVERY`` introduces an instance named ``MY_DISCOVERY`` under the ``RTPS_DISCOVERY`` section. @@ -182,22 +182,21 @@ This is accomplished by using the ``TheParticipantFactoryWithArgs`` macro: Command-line arguments are parsed in two phases. The following arguments are parse in the first phase: -#. ``-ORBLogFile PATH`` - Causes logging output to be written to the file indicated by ``PATH``. +#. :prop:`ORBLogFile` -#. ``-ORBVerboseLogging [0|1]`` - Enables/disables verbose logging (default 0). - Verbose logging causes each log message to be prefixed with a timestamp. +#. :prop:`ORBVerboseLogging` -#. ``-DCPSSingleConfigFile [0|1]`` - Enables/disables the legacy behavior of a single configuration file that is processed after environment variables and command-line arguments and does not overwrite existing configuration (default 1). +#. ``-DCPSSingleConfigFile 0|1`` - Enables/disables the legacy behavior of a single configuration file that is processed after environment variables and command-line arguments and does not overwrite existing configuration (default 1). When disabled, arguments processed in the second phase are processed as they are encountered and overwrite existing configuration. The following arguments are processed in the second phase: -#. ``-DCPSConfigFile PATH`` - Causes configuration to be read from the file indicated by ``PATH``. +#. ``-DCPSConfigFile `` - Causes configuration to be read from the file indicated by ````. It is processed immediately if ``-DCPSSingleConfigFile 0`` and deferred to the end of argument processing, otherwise. #. ``-OpenDDSKEY VALUE`` - Causes ``KEY=VALUE`` to be saved in the configuration store. The key ``KEY`` is canonicalized before being stored. - To set the ``ResendPeriod`` on an ``rtps_discovery`` instance named ``MyDiscovery`` to 5 seconds using environment variables, one could use the following arguments: + To set the :prop:`[rtps_discovery]ResendPeriod` on an :sec:`rtps_discovery` instance named ``MyDiscovery`` to 5 seconds using environment variables, one could use the following arguments: * ``-OpenDDS_rtps_discovery_MyDiscovery @MY_DISCOVERY`` * ``-OpenDDS_rtps_discovery_MyDiscovery_ResendPeriod 5`` @@ -213,7 +212,7 @@ The following arguments are processed in the second phase: Configuration with a File ========================= -The ``-DCPSConfigFile PATH`` argument described above causes OpenDDS to read configuration from a human-readable ini-style text file. +The ``-DCPSConfigFile `` argument described above causes OpenDDS to read configuration from a human-readable ini-style text file. For example: .. tab:: Linux, macOS, BSDs, etc. @@ -288,8 +287,10 @@ See :ghfile:`dds/DdsDcpsInfrastructure.idl` and :ghfile:`dds/DCPS/ConfigStoreImp int main(int argc, char* argv[]) { // ... - TheServiceParticipant->config_store()->set_string("RTPS_DISCOVERY_MY_DISCOVERY", "@MY_DISCOVERY"); - TheServiceParticipant->config_store()->set_string("RTPS_DISCOVERY_MY_DISCOVERY_RESEND_PERIOD", "5"); + TheServiceParticipant->config_store()->set_string( + "RTPS_DISCOVERY_MY_DISCOVERY", "@MY_DISCOVERY"); + TheServiceParticipant->config_store()->set_string( + "RTPS_DISCOVERY_MY_DISCOVERY_RESEND_PERIOD", "5"); // ... } @@ -427,9 +428,9 @@ For example: - ``[transport]local_address`` (rtps_udp) - ``[transport]ipv6_local_address`` (rtps_udp) - ``[transport]multicast_interface`` (rtps_udp) - - ``[rtps_discovery]SedpLocalAddress`` - - ``[rtps_discovery]SpdpLocalAddress`` - - ``[rtps_discovery]MulticastInterface`` + - :prop:`[rtps_discovery]SedpLocalAddress` + - :prop:`[rtps_discovery]SpdpLocalAddress` + - :prop:`[rtps_discovery]MulticastInterface` .. prop:: DCPSDefaultDiscovery=DEFAULT_REPO|DEFAULT_RTPS|DEFAULT_STATIC| :default: :val:`DEFAULT_REPO` @@ -451,7 +452,7 @@ For example: .. val:: Name of a user-defined discovery configuration. - This can either be a ``repository`` or ``rtps_discovery`` section + This can either be a :sec:`repository` or :sec:`rtps_discovery` section See :ref:`config-disc` for details about configuring discovery. @@ -682,6 +683,7 @@ Except for static discovery, each mechanism uses default values if no configurat The following sections show how to configure the advanced discovery capabilities. For example, some deployments may need to use multiple ``DCPSInfoRepo`` services or DDSI-RTPS discovery to satisfy interoperability requirements. +.. _config-domain: .. _run_time_configuration--domain-configuration: Domain Configuration @@ -692,12 +694,9 @@ Domain Configuration An OpenDDS configuration file uses the ``[domain]`` section type to configure one or more discovery domains with each domain pointing to a discovery configuration in the same file or a default discovery configuration. OpenDDS applications can use a centralized discovery approach using the ``DCPSInfoRepo`` service or a peer-to-peer discovery approach using the RTPS discovery protocol standard or a combination of the two in the same deployment. -The section type for the ``DCPSInfoRepo`` method is ``[repository]`` and the section type for an RTPS discovery configuration is ``[rtps_discovery]``. -The static discovery mechanism does not have a dedicated section. -Instead, users are expected to refer to the ``DEFAULT_STATIC`` instance. A single domain can refer to only one type of discovery section. -See :ref:`run_time_configuration--configuring-applications-for-dcpsinforepo` for configuring InfoRepo Discovery, :ref:`run_time_configuration--configuring-for-ddsi-rtps-discovery` for configuring RTPS Discovery, and :ref:`run_time_configuration--configuring-for-static-discovery` for configuring Static Discovery. +See :ref:`inforepo-disc-config` for configuring InfoRepo Discovery, :ref:`rtps-disc-config` for configuring RTPS Discovery, and :ref:`static-disc-config` for configuring Static Discovery. Ultimately a domain is assigned an integer value and a configuration file can support this in two ways. The first is to simply make the instance value the integer value assigned to the domain as shown here: @@ -708,9 +707,9 @@ The first is to simply make the instance value the integer value assigned to the DiscoveryConfig=DiscoveryConfig1 (more properties...) -Our example configures a single domain identified by the domain keyword and followed by an instance value of ``/1``. +Our example configures a single domain identified by the ``domain`` keyword and followed by an instance value of ``/1``. The instance value after the slash in this case is the integer value assigned to the domain. -An alternative syntax for this same content is to use a more recognizable (friendly) name instead of a number for the domain name and then add the ``DomainId`` property to the section to give the integer value. +An alternative syntax for this same content is to use a more recognizable (friendly) name instead of a number for the domain name and then add the :prop:`[domain]DomainId` property to the section to give the integer value. Here is an example: .. code-block:: ini @@ -720,13 +719,13 @@ Here is an example: DiscoveryConfig=DiscoveryConfig1 The domain is given a friendly name of books. -The ``DomainId`` property assigns the integer value of ``1`` needed by a DDS application reading the configuration. +The :prop:`[domain]DomainId` property assigns the integer value of ``1`` needed by a DDS application reading the configuration. Multiple domain instances can be identified in a single configuration file in this format. Once one or more domain instances are established, the discovery properties must be identified for that domain. -The ``DiscoveryConfig`` property must either point to another section that holds the discovery configuration or specify one of the internal default values for discovery (e.g. ``DEFAULT_REPO``, ``DEFAULT_RTPS``, or ``DEFAULT_STATIC``). +The :prop:`[domain]DiscoveryConfig` property must either point to another section that holds the discovery configuration or specify one of the internal default values for discovery. The instance name in our example is ``DiscoveryConfig1``. -This instance name must be associated with a section type of either ``[repository]`` or ``[rtps_discovery]``. +This instance name must be associated with a section type of either :sec:`repository` or :sec:`rtps_discovery`. Here is an extension of our example: @@ -739,7 +738,7 @@ Here is an extension of our example: RepositoryIor=host1.mydomain.com:12345 In this case our domain points to a ``[repository]`` section which is used for an OpenDDS ``DCPSInfoRepo`` service. -See :ref:`run_time_configuration--configuring-applications-for-dcpsinforepo` for more details. +See :ref:`inforepo-disc-config` for more details. There are going to be occasions when specific domains are not identified in the configuration file. For example, if an OpenDDS application assigns a domain ID of 3 to its participants and the above example does not supply a configuration for domain id of 3 then the following can be used: @@ -785,35 +784,29 @@ Here is an example: By adding the ``DCPSDefaultDiscovery`` property to the ``[common]`` section, any participant that hasn't been assigned to a domain id of ``1`` or ``2`` will use the configuration of ``DiscoveryConfig2``. For more explanation of a similar configuration for RTPS discovery see :ref:`run_time_configuration--configuring-for-ddsi-rtps-discovery`. -Here are the available properties for the ``[domain]`` section: +.. sec:: domain/ -.. list-table:: Domain Section Configuration Properties - :header-rows: 1 - - * - Option - - - Description - - * - ``DomainId=n`` + .. prop:: DomainId= + :required: - - An integer value representing a Domain being associated with a repository. + An integer value representing a domain being associated with a repository. - * - ``DomainRepoKey=k`` + .. prop:: DomainRepoKey= - - Key value of the mapped repository + Key value of the mapped repository - (Deprecated. - Provided for backward compatibility). + .. deprecated:: Provided for backward compatibility. - * - ``DiscoveryConfig=config instance name`` + .. prop:: DiscoveryConfig= + :default: :prop:`[common]DCPSDefaultDiscovery` - - A user-defined string that refers to the instance name of a ``[repository]`` or ``[rtps_discovery]`` section in the same configuration file or one of the internal default values (``DEFAULT_REPO``, ``DEFAULT_RTPS``, or ``DEFAULT_STATIC``). - (Also see the ``DCPSDefaultDiscovery`` property in :ref:`run_time_configuration--common-configuration-options`) + Sets the discovery configuration for this domain. + It uses the same values as :prop:`[common]DCPSDefaultDiscovery`. - * - ``DefaultTransportConfig=config`` + .. prop:: DefaultTransportConfig= - - A user-defined string that refers to the instance name of a ``[config]`` section. - See :ref:`run_time_configuration--transport-configuration`. + A user-defined string that refers to the instance name of a ``[config]`` section. + See :ref:`config-transport`. .. _inforepo-disc-config: .. _run_time_configuration--configuring-applications-for-dcpsinforepo: @@ -886,7 +879,7 @@ The command line to start our executable would now change to the following: publisher -DCSPConfigFile pub.ini A configuration file can specify domains with discovery configuration assigned to those domains. -In this case the ``RepositoryIor`` property is used to take the same information that would be supplied on a command line to point to a running ``DCPSInfoRepo`` service. +In this case the :prop:`[repository]RepositoryIor` property is used to take the same information that would be supplied on a command line to point to a running ``DCPSInfoRepo`` service. Two domains are configured here: .. code-block:: ini @@ -903,7 +896,7 @@ Two domains are configured here: [repository/DiscoveryConfig2] RepositoryIor=host2.mydomain.com:12345 -The ``DiscoveryConfig`` property under ``[domain/1]`` instructs all participants in domain ``1`` to use the configuration defined in an instance called ``DiscoveryConfig1``. +The :prop:`[domain]DiscoveryConfig` property under ``[domain/1]`` instructs all participants in domain ``1`` to use the configuration defined in an instance called ``DiscoveryConfig1``. In the above, this is mapped to a ``[repository]`` section that gives the ``RepositoryIor`` value of ``myhost.mydomain.com:12345``. Finally, when configuring a ``DCPSInfoRepo`` the ``DiscoveryConfig`` property under a domain instance entry can also contain the value of ``DEFAULT_REPO`` which instructs a participant using this instance to use the definition of the property ``DCPSInfoRepo`` wherever it has been supplied. @@ -923,7 +916,7 @@ Consider the following configuration file as an example: [domain/2] DiscoveryConfig=DEFAULT_REPO -In this case any participant in domain 2 would be instructed to refer to the discovery property of ``DCPSInfoRepo``, which is defined in the ``[common]`` section of our example. +In this case any participant in domain 2 would be instructed to refer to the discovery property of :prop:`DCPSInfoRepo`, which is defined in the ``[common]`` section of our example. If the ``DCPSInfoRepo`` value is not supplied in the ``[common]`` section, it could alternatively be supplied as a parameter to the command line like so: .. code-block:: bash @@ -983,7 +976,7 @@ For this example we will only show the discovery aspects of the configuration an RepositoryIor=host2.mydomain.com:12345 When Process ``E`` reads in the above configuration it finds the occurrence of multiple domain sections. -As described in :ref:`run_time_configuration--domain-configuration` each domain has an instance integer and a property of ``DiscoveryConfig`` defined. +As described in :ref:`run_time_configuration--domain-configuration` each domain has an instance integer and a property of :prop:`[domain]DiscoveryConfig` defined. For the first domain (``[domain/1]``), the ``DiscoveryConfig`` property is supplied with the user-defined name of ``DiscoveryConfig1`` value. This property causes the OpenDDS implementation to find a section title of either ``repository`` or ``rtps_discovery`` and an instance name of ``DiscoveryConfig1``. @@ -1001,22 +994,17 @@ There may be any number of repository or domain sections within a single configu Here are the valid properties for a ``[repository]`` section: -.. list-table:: Multiple repository configuration sections - :header-rows: 1 +.. sec:: repository/ - * - Option + .. prop:: RepositoryIor= - - Description + Repository IOR or host:port - * - ``RepositoryIor=ior`` + .. prop:: RepositoryKey= - - Repository IOR or host:port. + Unique key value for the repository - * - ``RepositoryKey=key`` - - - Unique key value for the repository. - (Deprecated. - Provided for backward compatibility) + .. deprecated:: Provided for backward compatibility. .. _rtps-disc-config: .. _run_time_configuration--configuring-for-ddsi-rtps-discovery: @@ -1064,7 +1052,7 @@ The following example uses the ``[common]`` section to point to an instance of a ResendPeriod=5 The instance ``[rtps_discovery/TheRTPSConfig]`` is now the location where properties that vary the default DDSI-RTPS settings get specified. -In our example the ``ResendPeriod=5`` entry sets the number of seconds between periodic announcements of available data readers / data writers and to detect the presence of other data readers / data writers on the network. +In our example the :prop:`ResendPeriod=5 <[rtps_discovery]ResendPeriod>` entry sets the number of seconds between periodic announcements of available data readers / data writers and to detect the presence of other data readers / data writers on the network. This would override the default of 30 seconds. If your OpenDDS deployment uses multiple domains, the following configuration approach combines the use of the ``[domain]`` section title with ``[rtps_discovery]`` to allow a user to specify particular settings by domain. @@ -1093,411 +1081,333 @@ Some important implementation notes regarding DDSI-RTPS discovery in OpenDDS are #. Domain IDs should be between 0 and 231 (inclusive) due to the way UDP ports are assigned to domain IDs. In each OpenDDS process, up to 120 domain participants are supported in each domain. -#. OpenDDS's multicast transport (:ref:`run_time_configuration--ip-multicast-transport-configuration-options`) does not work with RTPS Discovery due to the way GUIDs are assigned (a warning will be issued if this is attempted). +#. The :ref:`multicast-transport` does not work with RTPS Discovery due to the way GUIDs are assigned (a warning will be issued if this is attempted). The OMG DDSI-RTPS specification details several properties that can be adjusted from their defaults that influence the behavior of DDSI-RTPS discovery. Those properties, along with options specific to OpenDDS's RTPS Discovery implementation, are listed below. -.. _run_time_configuration--rtps-disc-config-options: - -.. list-table:: RTPS Discovery Configuration Options - :header-rows: 1 - - * - Option - - - Description - - - Default - - * - ``ResendPeriod=sec`` - - - The number of seconds that a process waits between the announcement of participants (see :omgspec:`rtps:8.5.3`). - - - ``30`` - - * - ``MinResendDelay=msec`` +.. sec:: rtps_discovery/ - - The minimum time in milliseconds between participant announcements. + .. prop:: ResendPeriod= + :default: ``30`` - - ``100`` + The number of seconds that a process waits between the announcement of participants (see :omgspec:`rtps:8.5.3`). - * - ``QuickResendRatio=frac`` + .. prop:: MinResendDelay= + :default: ``100`` - - Tuning parameter that configures local SPDP resends as a fraction of the resend period. + The minimum time in milliseconds between participant announcements. - - ``0.1`` + .. prop:: QuickResendRatio= + :default: ``0.1`` - * - ``LeaseDuration=sec`` + Tuning parameter that configures local SPDP resends as a fraction of the resend period. - - Sent as part of the participant announcement. - It tells the peer participants that if they don't hear from this participant for the specified duration, then this participant can be considered "not alive." + .. prop:: LeaseDuration= + :default: ``300`` (5 minutes) - - ``300`` + Sent as part of the participant announcement. + It tells the peer participants that if they don't hear from this participant for the specified duration, then this participant can be considered "not alive". - * - ``LeaseExtension=sec`` - - - Extends the lease of discovered participants by the set amount of seconds. - Useful on spotty connections to reduce load on the RtpsRelay. - - - ``0`` - - * - ``PB=port`` - - - Port Base number. - This number sets the starting point for deriving port numbers used for Simple Endpoint Discovery Protocol (SEDP). - This property is used in conjunction with ``DG``, ``PG``, ``D0`` (or ``DX``), and ``D1`` to construct the necessary Endpoints for RTPS discovery communication. - See :omgspec:`rtps:9.6.1.1` for how these Endpoints are constructed. - - - ``7400`` - - * - ``DG=n`` - - - An integer value representing the Domain Gain. - This is a multiplier that assists in formulating Multicast or Unicast ports for RTPS. - - - ``250`` - - * - ``PG=n`` - - - An integer that assists in configuring SPDP Unicast ports and serves as an offset multiplier as participants are assigned addresses using the formula: - - ``PB + DG * domainId + d1 + PG * participantId`` - - See :omgspec:`rtps:9.6.1.1` for how these Endpoints are constructed. - - - 2 - - * - ``D0=n`` - - - An integer value that assists in providing an offset for calculating an assignable port in SPDP Multicast configurations. - The formula used is: - - PB + DG * domainId + d0 - - See :omgspec:`rtps:9.6.1.1` for how these Endpoints are constructed. - - - ``0`` - - * - ``D1=n`` - - - An integer value that assists in providing an offset for calculating an assignable port in SPDP Unicast configurations. - The formula used is: - - ``PB + DG * domainId + d1 + PG * participantId`` - - See :omgspec:`rtps:9.6.1.1` for how these Endpoints are constructed. - - - ``10`` - - * - ``SpdpRequestRandomPort=[0|1]`` - - - Use a random port for SPDP. - - - ``0`` - - * - ``SedpMaxMessageSize=n`` - - - Set the maximum SEDP message size. - The default is the maximum UDP message size. - See max_message_size in table 7-17. - - - ``65466`` - - * - ``SedpMulticast=[0|1]`` - - - A boolean value (0 or 1) that determines whether Multicast is used for the SEDP traffic. - When set to 1, Multicast is used. - When set to zero (0) Unicast for SEDP is used. - - - ``1`` - - * - ``SedpLocalAddress=addr:[port]`` - - - Configure the transport instance created and used by SEDP to bind to the specified local address and port. - In order to leave the port unspecified, it can be omitted from the setting but the trailing : must be present. - - - System default address - - * - ``SpdpLocalAddress=addr[:port]`` - - - Address of a local interface, which will be used by SPDP to bind to that specific interface. - - - DCPSDefaultAddress or ``0.0.0.0`` - - * - ``SedpAdvertisedLocalAddress= addr:[port]`` - - - Sets the address advertised by SEDP. - Typically used when the participant is behind a firewall or NAT. - In order to leave the port unspecified, it can be omitted from the setting but the trailing : must be present. - - - - - * - ``SedpSendDelay=msec`` - - - Time in milliseconds for a built-in (SEDP) Writer to wait before sending data. - - - ``10`` - - * - ``SedpHeartbeatPeriod=msec`` - - - Time in milliseconds for a built-in (SEDP) Writer to announce the availability of data. + .. prop:: LeaseExtension= + :default: ``0`` - - ``200`` + Extends the lease of discovered participants by the set amount of seconds. + Useful on spotty connections to reduce load on the RtpsRelay. - * - ``SedpNakResponseDelay=msec`` + .. prop:: PB= + :default: ``7400`` - - Time in milliseconds for a built-in (SEDP) Writer to delay the response to a negative acknowledgment. + This number sets the starting point for deriving port numbers used for Simple Endpoint Discovery Protocol (SEDP). + This property is used in conjunction with :prop:`DG`, :prop:`PG`, :prop:`D0` (or :prop:`DX`), and :prop:`D1` to construct the necessary Endpoints for RTPS discovery communication. + See :omgspec:`rtps:9.6.1.1` for how these Endpoints are constructed. - - ``100`` + .. prop:: DG= + :default: ``250`` - * - ``DX=n`` + An integer value representing the Domain Gain. + This is a multiplier that assists in formulating Multicast or Unicast ports for RTPS. - - An integer value that assists in providing an offset for calculating a port in SEDP Multicast configurations. - The formula used is: + .. prop:: PG= + :default: ``2`` - ``PB + DG * domainId + dx`` + An integer that assists in configuring SPDP Unicast ports and serves as an offset multiplier. + Participants are assigned addresses using the formula: - This is only valid when ``SedpMulticast=1``. - This is an OpenDDS extension and not part of the OMG DDSI-RTPS specification. + .. math:: - - ``2`` + \mathit{PB} + DG \times \mathit{domainId} + \mathit{d}1 + \mathit{PG} \times \mathit{participantId} - * - ``SpdpSendAddrs=`` + See :omgspec:`rtps:9.6.1.1` for how these Endpoints are constructed. - ``[host:port],[host:port]...`` + .. prop:: D0= + :default: The value of the ``OPENDDS_RTPS_DEFAULT_D0`` environment variable if set, else ``0`` - - A list (comma or whitespace separated) of host:port pairs used as destinations for SPDP content. - This can be a combination of Unicast and Multicast addresses. + An integer value that assists in providing an offset for calculating an assignable port in SPDP Multicast configurations. + The formula used is: - - + .. math:: - * - ``MaxSpdpSequenceMsgResetChecks=n`` + \mathit{PB} + \mathit{DG} \times \mathit{domainId} + \mathit{d0} - - Remove a discovered participant after this number of SPDP messages with earlier sequence numbers. + See :omgspec:`rtps:9.6.1.1` for how these Endpoints are constructed. - - ``3`` + .. prop:: D1= + :default: ``10`` - * - ``PeriodicDirectedSpdp=[0|1]`` + An integer value that assists in providing an offset for calculating an assignable port in SPDP Unicast configurations. + The formula used is: - - A boolean value that determines whether directed SPDP messages are sent to all participants once every resend period. - This setting should be enabled for participants that cannot use multicast to send SPDP announcements, e.g., an RtpsRelay. + .. math:: - - ``0`` + \mathit{PB} + \mathit{DG} \times \mathit{domainId} + \mathit{d1} + \mathit{PG} \times \mathit{participantId} - * - ``UndirectedSpdp=[0|1]`` + See :omgspec:`rtps:9.6.1.1` for how these Endpoints are constructed. - - A boolean value that determines whether undirected SPDP messages are sent. - This setting should be disabled for participants that cannot use multicast to send SPDP announcements, e.g., an RtpsRelay. + .. prop:: DX= + :default: ``2`` - - ``1`` + An integer value that assists in providing an offset for calculating a port in SEDP Multicast configurations. + This is only valid when :prop:`SedpMulticast=1 `. + The formula used is: - * - ``InteropMulticastOverride=group_address`` + .. math:: - - A network address specifying the multicast group to be used for SPDP discovery. - This overrides the interoperability group of the specification. - It can be used, for example, to specify use of a routed group address to provide a larger discovery scope. + \mathit{PB} + \mathit{DG} \times \mathit{domainId} + \mathit{dx} - - ``239.255.0.1`` + This is an OpenDDS extension and not part of the OMG DDSI-RTPS specification. - * - ``TTL=n`` + .. prop:: SpdpRequestRandomPort= + :default: ``0`` - - The value of the Time-To-Live (TTL) field of multicast datagrams sent as part of discovery. - This value specifies the number of hops the datagram will traverse before being discarded by the network. - The default value of 1 means that all data is restricted to the local network subnet. + Use a random port for SPDP. - - ``1`` + .. prop:: SedpMaxMessageSize= + :default: ``65466`` (maximum worst-case UDP payload size) - * - ``MulticastInterface=iface`` + Set the maximum SEDP message size. - - Specifies the network interface to be used by this discovery instance. - This uses a platform-specific format that identifies the network interface. - On Linux systems this would be something like eth ``0``. + See ``[transport@rtps_udp]max_message_size``. - If this value is not configured, the Common Configuration value ``DCPSDefaultAddress`` is used to set the multicast interface. + .. prop:: SedpMulticast= + :default: ``1`` - - The system default interface is used + Determines whether Multicast is used for the SEDP traffic. + When set to ``1``, Multicast is used. + When set to ``0``, Unicast is used. - * - ``GuidInterface=iface`` + .. prop:: SedpLocalAddress=:[] + :default: :prop:`[common]DCPSDefaultAddress` - - Specifies the network interface to use when determining which local MAC address should appear in a GUID generated by this node. + Configure the transport instance created and used by SEDP to bind to the specified local address and port. + In order to leave the port unspecified, it can be omitted from the setting but the trailing ``:`` must be present. - - The system / ACE library default is used + .. prop:: SpdpLocalAddress=[:] + :default: :prop:`[common]DCPSDefaultAddress` - * - ``SpdpRtpsRelayAddress=host:port`` + Address of a local interface, which will be used by SPDP to bind to that specific interface. - - Specifies the address of the RtpsRelay for SPDP messages. - See :ref:`internet_enabled_rtps--the-rtpsrelay`. + .. prop:: SedpAdvertisedLocalAddress=:[] - - + Sets the address advertised by SEDP. + Typically used when the participant is behind a firewall or NAT. + In order to leave the port unspecified, it can be omitted from the setting but the trailing ``:`` must be present. - * - ``SpdpRtpsRelaySendPeriod=period`` + .. prop:: SedpSendDelay= + :default: ``10`` - - Specifies the interval between SPDP announcements sent to the RtpsRelay. - See :ref:`internet_enabled_rtps--the-rtpsrelay`. + Time in milliseconds for a built-in SEDP Writer to wait before sending data. - - 30 seconds + .. prop:: SedpHeartbeatPeriod= + :default: ``200`` - * - ``SedpRtpsRelayAddress=host:port`` + Time in milliseconds for a built-in SEDP Writer to announce the availability of data. - - Specifies the address of the RtpsRelay for SEDP messages. - See :ref:`internet_enabled_rtps--the-rtpsrelay`. + .. prop:: SedpNakResponseDelay= + :default: ``100`` - - + Time in milliseconds for a built-in SEDP Writer to delay the response to a negative acknowledgment. - * - ``RtpsRelayOnly=[0|1]`` + .. prop:: SpdpSendAddrs=:[,:]... - - Only send RTPS message to the RtpsRelay (for debugging). - See :ref:`internet_enabled_rtps--the-rtpsrelay`. + A list (comma or whitespace separated) of ``:`` pairs used as destinations for SPDP content. + This can be a combination of Unicast and Multicast addresses. - - ``0`` + .. prop:: MaxSpdpSequenceMsgResetChecks= + :default: ``3`` - * - ``UseRtpsRelay=[0|1]`` + Remove a discovered participant after this number of SPDP messages with earlier sequence numbers. - - Send messages to the RtpsRelay. - Messages will only be sent if SpdpRtpsRelayAddress and/or SedpRtpsRelayAddress is set. - See :ref:`internet_enabled_rtps--the-rtpsrelay`. + .. prop:: PeriodicDirectedSpdp= + :default: ``0`` (disabled) - - ``0`` + A boolean value that determines whether directed SPDP messages are sent to all participants once every resend period. + This setting should be enabled for participants that cannot use multicast to send SPDP announcements, e.g., an RtpsRelay. - * - ``SpdpStunServerAddress=host:port`` + .. prop:: UndirectedSpdp= + :default: ``1`` (enabled) - - Specifies the address of the STUN server to use for SPDP when using ICE. - See :ref:`internet_enabled_rtps--interactive-connectivity-establishment-ice-for-rtps` + A boolean value that determines whether undirected SPDP messages are sent. + This setting should be disabled for participants that cannot use multicast to send SPDP announcements, e.g., an RtpsRelay. - - + .. prop:: InteropMulticastOverride= - * - ``SedpStunServerAddress=host:port`` + A network address specifying the multicast group to be used for SPDP discovery. + This overrides the interoperability group of the specification, ``239.255.0.1`` + It can be used, for example, to specify use of a routed group address to provide a larger discovery scope. - - Specifies the address of the STUN server to use for SEDP when using ICE. - See :ref:`internet_enabled_rtps--interactive-connectivity-establishment-ice-for-rtps`. + .. prop:: TTL=n + :default: ``1`` (all data is restricted to the local network) - - + The value of the Time-To-Live (TTL) field of multicast datagrams sent as part of discovery. + This value specifies the number of hops the datagram will traverse before being discarded by the network. - * - ``UseIce=[0|1]`` + .. prop:: MulticastInterface= + :default: :prop:`[common]DCPSDefaultAddress` - - Enable or disable ICE for both SPDP and SEDP. - See :ref:`internet_enabled_rtps--interactive-connectivity-establishment-ice-for-rtps`. + Specifies the network interface to be used by this discovery instance. + This uses a platform-specific format that identifies the network interface, but can be address assigned to that interface on most platforms. - - 0 + .. prop:: GuidInterface= + :default: The system / ACE library default is used - * - ``MaxAuthTime=sec`` + Specifies the network interface to use when determining which local MAC address should appear in a GUID generated by this node. - - Set the maximum time for authentication with DDS Security. + .. prop:: SpdpRtpsRelayAddress=: - - 300 + Specifies the address of :ref:`rtpsrelay` for SPDP messages. - * - ``AuthResendPeriod=sec`` + .. prop:: SpdpRtpsRelaySendPeriod= + :default: ``30`` seconds - - Resend authentication messages after this amount of time. - It is a floating point value, so fractions of a second can be specified. + Specifies the interval between SPDP announcements sent to :ref:`rtpsrelay`. - - 1 + .. prop:: SedpRtpsRelayAddress=host:port - * - ``SecureParticipantUserData=[0|1]`` + Specifies the address of :ref:`rtpsrelay` for SEDP messages. - - If DDS Security is enabled, the Participant's :ref:`qos-user-data` is omitted from unsecured discovery messages. - - - ``0`` + .. prop:: RtpsRelayOnly= + :default: ``0`` (disabled) - * - .. _run_time_configuration--usextypes: + Only send RTPS message to :ref:`rtpsrelay` (for debugging). - ``UseXTypes=[`` + .. prop:: UseRtpsRelay= + :default: ``0`` (disabled) - ``no|0|`` + Send messages to :ref:`rtpsrelay`. + Messages will only be sent if :prop:`SpdpRtpsRelayAddress` and/or :prop:`SedpRtpsRelayAddress` are set. - ``minimal|1|`` + .. prop:: SpdpStunServerAddress=: - ``complete|2`` + Specifies the address of the STUN server to use for SPDP when using :ref:`ICE `. - ``]`` + .. prop:: SedpStunServerAddress=: - - Enables discovery extensions from the XTypes specification. - Participants exchange top-level type information in endpoint announcements and extended type information using the Type Lookup Service. + Specifies the address of the STUN server to use for SEDP when using :ref:`ICE `. - ``minimal`` or ``1`` uses ``MinimalTypeObject`` and ``complete`` or ``2`` uses ``CompleteTypeObject`` if available. - See :ref:`xtypes--representing-types-with-typeobject-and-dynamictype` for more information on ``CompleteTypeObject`` and its use in the dynamic binding. + .. prop:: UseIce= + :default: ``0`` (disabled) - - ``minimal`` + Enable or disable :ref:`ICE ` for both SPDP and SEDP. - * - ``TypeLookupServiceReplyTimeout=msec`` + .. prop:: MaxAuthTime= + :default: ``300`` seconds (5 minutes) - - If a request is sent to a peer's Type Lookup Service (see UseXTypes above), wait up to this duration (in milliseconds) for a reply. + Set the maximum time for authentication with :ref:`dds_security`. - - ``5000`` + .. prop:: AuthResendPeriod= + :default: ``1`` second - ``(5 seconds)`` + Resend authentication messages for :ref:`dds_security` after this amount of seconds. + It is a floating point value, so fractions of a second can be specified. - * - ``SedpResponsiveMode=[0|1]`` + .. prop:: SecureParticipantUserData= + :default: ``0`` (disabled) - - Causes the built-in SEDP endpoints to send additional messages which may reduce latency. + If :ref:`dds_security` is enabled, the :ref:`Participant's USER_DATA QoS ` is omitted from unsecured discovery messages. - - 0 + .. prop:: UseXTypes=no|minimal|complete + :default: :val:`no` - * - ``SedpPassiveConnectDuration=msec`` + Enables discovery extensions from the XTypes specification. + Participants exchange topic type information in endpoint announcements and extended type information using the Type Lookup Service. - - Sets the duration that a passive endpoint will wait for a connection. + See :ref:`xtypes--representing-types-with-typeobject-and-dynamictype` for more information on ``CompleteTypeObject`` and its use in the dynamic binding. - - 60000 + .. val:: no - (1 minute) + XTypes isn't taken into consideration during discovery. + ``0`` can also be used for backwards compatibility. - * - ``SendBufferSize=bytes`` + .. val:: minimal - - Socket send buffer size for both SPDP and SEDP. - A value of zero indicates that the system default value is used. + XTypes is used for discovery when possible and only the ``MinimalTypeObject`` is provided to remote participants if available. + ``1`` can also be used for backwards compatibility. - - 0 + .. val:: complete - * - ``RecvBufferSize=bytes`` + XTypes is used for discovery when possible and only the ``CompleteTypeObject`` is provided to remote participants if available. + This requires that :option:`opendds_idl -Gxtypes-complete` was used when compiling the IDL. + ``2`` can also be used for backwards compatibility. - - Socket receive buffer size for both SPDP and SEDP. - A value of zero indicates that the system default value is used. + .. prop:: TypeLookupServiceReplyTimeout= + :default: ``5000`` milliseconds (5 seconds). - - 0 + If :prop:`UseXTypes` is enabled, then this sets the timeout for waiting for replies to remote Type Lookup Service requests. - * - ``MaxParticipantsInAuthentication=n`` + .. prop:: SedpResponsiveMode= + :default: ``0`` (disabled) - - If DDS Security is enabled, this option (when set to a positive number) limits the number of peer participants that can be concurrently in the process of authenticating -- that is, not yet completed authentication. + Causes the built-in SEDP endpoints to send additional messages which may reduce latency. - - 0 (unlimited) + .. prop:: SedpPassiveConnectDuration= + :default: ``60000`` milliseconds (1 minute) - * - ``SedpReceivePreallocatedMessageBlocks=n`` + Sets the duration that a passive endpoint will wait for a connection. - - Configure the receive_preallocated_message_blocks attribute of SEDP's transport. - See :ref:`run_time_configuration--configuration-options-common-to-all-transports`. + .. prop:: SendBufferSize= + :default: ``0`` (system default value is used) - - 0 (use default) + Socket send buffer size for both SPDP and SEDP. - * - ``SedpReceivePreallocatedDataBlocks=n`` + .. prop:: RecvBufferSize= + :default: ``0`` (system default value is used) - - Configure the receive_preallocated_data_blocks attribute of SEDP's transport. - See :ref:`run_time_configuration--configuration-options-common-to-all-transports`. + Socket receive buffer size for both SPDP and SEDP. - - 0 (use default) + .. prop:: MaxParticipantsInAuthentication= + :default: ``0`` (no limit) - * - ``CheckSourceIp=[0|1]`` + This setting is only available when OpenDDS is compiled with :ref:`dds_security` enabled. + Limits the number of peer participants that can be concurrently in the process of authenticating -- that is, not yet completed authentication. - - Incoming participant announcements (SPDP) are checked to verify that their source IP address matches one of: + .. prop:: SedpReceivePreallocatedMessageBlocks= + :default: ``0`` (use ``[transport]receive_preallocated_message_blocks``'s default) - * An entry in the metatraffic locator list + Configure the ``[transport]receive_preallocated_message_blocks`` attribute of SEDP's transport. - * The configured RtpsRelay (if any) + .. prop:: SedpReceivePreallocatedDataBlocks= + :default: ``0`` (use ``[transport]receive_preallocated_data_blocks``'s default) - * An ICE AgentInfo parameter + Configure the ``[transport]receive_preallocated_data_blocks`` attribute of SEDP's transport. - Announcements that don't match any of these are dropped if this check is enabled. + .. prop:: CheckSourceIp= + :default: ``1`` (enabled) - - 1 (enabled) + Incoming participant announcements (SPDP) are checked to verify that their source IP address matches one of: - * - ``SpdpUserTag=i`` + - An entry in the metatraffic locator list + - The configured :ref:`RtpsRelay ` (if any) + - An :ref:`ICE ` AgentInfo parameter - - Add the OpenDDS-specific UserTag RTPS submessage to the start of SPDP messages. - If i is 0 (the default), the submessage is not added. - Otherwise this submessage's contents is the 4-byte unsigned integer i. + Announcements that don't match any of these are dropped if this check is enabled. - - 0 (disabled) + .. prop:: SpdpUserTag= + :default: ``0`` (disabled) -.. note:: If the environment variable ``OPENDDS_RTPS_DEFAULT_D0`` is set, its value is used as the ``D0`` default value. + Add the OpenDDS-specific UserTag RTPS submessage to the start of SPDP messages. + If ```` is 0 (the default), the submessage is not added. + Otherwise this submessage's contents is the 4-byte unsigned integer ````. .. _run_time_configuration--additional-ddsi-rtps-discovery-features: @@ -1525,16 +1435,17 @@ Using only the configuration file, the static discovery mechanism must be able t The static discovery mechanism uses this information to determine all potential associations between readers and writers. A domain participant learns about the existence of an endpoint through hints supplied by the underlying transport. -.. note:: Currently, static discovery can only be used for endpoints using the RTPS UDP transport. +.. note:: Currently, static discovery can only be used for endpoints using the :ref:`rtps-udp-transport`. -Static discovery introduces the following configuration file sections: ``[topic/*]``, ``[datawriterqos/*]``, ``[datareaderqos/*]``, ``[publisherqos/*]``, ``[subscriberqos/*]``, and ``[endpoint/*]``. -The :ref:`topic ` section is used to introduce a topic. -The :ref:`datawriterqos `, :ref:`datareaderqos `, :ref:`publisherqos `, and :ref:`subscriberqos ` sections are used to describe a QoS of the associated type. -The :ref:`endpoint ` section describes a data reader or writer. +Static discovery introduces the following configuration file sections: -Data reader and writer objects must be identified by the user so that the static discovery mechanism can associate them with the correct ``[endpoint/*]`` section in the configuration file. -This is done by setting the ``user_data`` of the ``DomainParticipantQos`` to an octet sequence of length 6. -The representation of this octet sequence occurs in the ``participant`` value of an ``[endpoint/*]`` section as a string with two hexadecimal digits per octet. +- The :sec:`topic` section is used to introduce a topic. +- The :sec:`datawriterqos`, :sec:`datareaderqos`, :sec:`publisherqos`, and :sec:`subscriberqos` sections are used to describe a QoS of the associated type. +- The :sec:`endpoint` section describes a data reader or writer. + +Data reader and writer objects must be identified by the user so that the static discovery mechanism can associate them with the correct :sec:`endpoint` section in the configuration file. +This is done by setting the :ref:`qos-user-data` of the ``DomainParticipantQos`` to an octet sequence of length 6. +The representation of this octet sequence occurs in the :prop:`[endpoint]participant` as a string with two hexadecimal digits per octet. Similarly, the ``user_data`` of the ``DataReaderQos`` or ``DataWriterQos`` must be set to an octet sequence of length 3 corresponding to the ``entity`` value in the ``[endpoint/*]`` section. For example, suppose the configuration file contains the following: @@ -1587,553 +1498,295 @@ The code to configure the DataReaderQos is similar: The domain id, which is 34 in the example, should be passed to the call to ``create_participant``. In the example, the endpoint configuration for ``MyReader`` references ``MyConfig`` which in turn references ``MyTransport``. -Transport configuration is described in :ref:`run_time_configuration--transport-configuration`. +Transport configuration is described in :ref:`config-transport`. The important detail for static discovery is that at least one of the transports contains a known network address (``1.2.3.4:30000``). An error will be issued if an address cannot be determined for an endpoint. The static discovery implementation also checks that the QoS of a data reader or data writer object matches the QoS specified in the configuration file. -.. _run_time_configuration--reftable13: - -.. list-table:: [topic/\*] Configuration Options - :header-rows: 1 - - * - Option - - - Description - - - Default - - * - ``name=string`` - - - The name of the topic. - - - ``Instance name of section`` - - * - ``type_name=string`` - - - Identifier which uniquely defines the sample type. - This is typically a CORBA interface repository type name. - - - ``Required`` - -.. _run_time_configuration--reftable14: - -.. list-table:: [datawriterqos/\*] Configuration Options - :header-rows: 1 - - * - Option - - - Description - - - Default - - * - ``durability.kind=[`` - - ``VOLATILE|TRANSIENT_LOCAL]`` - - - See :ref:`quality_of_service--durability`. - - - - - * - ``deadline.period.sec=[`` - - ``numeric|DURATION_INFINITE_SEC]`` - - - See :ref:`quality_of_service--deadline`. - - - - - * - ``deadline.period.nanosec=[`` - - ``numeric|DURATION_INFINITE_NANOSEC]`` - - - See :ref:`quality_of_service--deadline`. +.. sec:: topic/ - - - - * - ``latency_budget.duration.sec=[`` + .. prop:: name= + :default: The ```` of the topic section - ``numeric|DURATION_INFINITE_SEC]`` + Use this to override the name of the topic in the DDS API. - - See :ref:`quality_of_service--latency-budget`. + .. prop:: type_name= + :required: - - + Identifier which uniquely defines the sample type. + This is typically a CORBA interface repository type name. - * - ``latency_budget.duration.nanosec=[`` +.. sec:: datawriterqos/ - ``numeric|DURATION_INFINITE_NANOSEC]`` + .. prop:: durability.kind=VOLATILE|TRANSIENT_LOCAL - - See :ref:`quality_of_service--latency-budget`. + See :ref:`quality_of_service--durability`. - - + .. prop:: deadline.period.sec=|DURATION_INFINITE_SEC - * - ``liveliness.kind=[`` + See :ref:`quality_of_service--deadline`. - ``AUTOMATIC|`` + .. prop:: deadline.period.nanosec=|DURATION_INFINITE_NANOSEC - ``MANUAL_BY_TOPIC|`` + See :ref:`quality_of_service--deadline`. - ``MANUAL_BY_PARTICIPANT]`` + .. prop:: latency_budget.duration.sec=|DURATION_INFINITE_SEC - - See :ref:`quality_of_service--liveliness`. + See :ref:`quality_of_service--latency-budget`. - - + .. prop:: latency_budget.duration.nanosec=|DURATION_INFINITE_NANOSEC - * - ``liveliness.lease_duration.sec=[`` + See :ref:`quality_of_service--latency-budget`. - ``numeric|DURATION_INFINITE_SEC]`` + .. prop:: liveliness.kind=AUTOMATIC|MANUAL_BY_TOPIC|MANUAL_BY_PARTICIPANT - - See :ref:`quality_of_service--liveliness`. + See :ref:`qos-liveliness`. - - - - * - ``liveliness.lease_duration.nanosec=[`` - - ``numeric|DURATION_INFINITE_NANOSEC]`` - - - See :ref:`quality_of_service--liveliness`. - - - + .. prop:: liveliness.lease_duration.sec=|DURATION_INFINITE_SEC - * - ``reliability.kind=[BEST_EFFORT|RELIABILE]`` + See :ref:`qos-liveliness`. - - See :ref:`quality_of_service--reliability`. + .. prop:: liveliness.lease_duration.nanosec=|DURATION_INFINITE_NANOSEC - - + See :ref:`qos-liveliness`. - * - ``reliability.max_blocking_time.sec=[`` + .. prop:: reliability.kind=BEST_EFFORT|RELIABILE - ``numeric|DURATION_INFINITE_SEC]`` + See :ref:`quality_of_service--reliability`. - - See :ref:`quality_of_service--reliability`. + .. prop:: reliability.max_blocking_time.sec=|DURATION_INFINITE_SEC - - + See :ref:`quality_of_service--reliability`. - * - ``reliability.max_blocking_time.nanosec=[`` + .. prop:: reliability.max_blocking_time.nanosec=|DURATION_INFINITE_NANOSEC - ``numeric|DURATION_INFINITE_NANOSEC]`` + See :ref:`quality_of_service--reliability`. - - See :ref:`quality_of_service--reliability`. + .. prop:: destination_order.kind=BY_SOURCE_TIMESTAMP|BY_RECEPTION_TIMESTAMP - - + See :ref:`quality_of_service--destination-order`. - * - ``destination_order.kind=[`` + .. prop:: history.kind=KEEP_LAST|KEEP_ALL - ``BY_SOURCE_TIMESTAMP|`` + See :ref:`quality_of_service--history`. - ``BY_RECEPTION_TIMESTAMP]`` + .. prop:: history.depth= - - See :ref:`quality_of_service--destination-order`. + See :ref:`quality_of_service--history`. - - + .. prop:: resource_limits.max_samples= - * - ``history.kind=[KEEP_LAST|KEEP_ALL]`` + See :ref:`quality_of_service--resource-limits`. - - See :ref:`quality_of_service--history`. + .. prop:: resource_limits.max_instances= - - + See :ref:`quality_of_service--resource-limits`. - * - ``history.depth=numeric`` + .. prop:: resource_limits.max_samples_per_instance= - - See :ref:`quality_of_service--history`. + See :ref:`quality_of_service--resource-limits`. - - + .. prop:: transport_priority.value= - * - ``resource_limits.max_samples=numeric`` + See :ref:`quality_of_service--transport-priority`. - - See :ref:`quality_of_service--resource-limits`. + .. prop:: lifespan.duration.sec=|DURATION_INFINITE_SEC - - + See :ref:`quality_of_service--lifespan`. - * - ``resource_limits.max_instances=numeric`` + .. prop:: lifespan.duration.nanosec=|DURATION_INFINITE_NANOSEC - - See :ref:`quality_of_service--resource-limits`. + See :ref:`quality_of_service--lifespan`. - - + .. prop:: ownership.kind=SHARED|EXCLUSIVE - * - ``resource_limits.max_samples_per_instance=`` + See :ref:`quality_of_service--ownership`. - ``numeric`` + .. prop:: ownership_strength.value= - - See :ref:`quality_of_service--resource-limits`. + See :ref:`quality_of_service--ownership-strength`. - - +.. sec:: datareaderqos/ - * - ``transport_priority.value=numeric`` + .. prop:: durability.kind=VOLATILE|TRANSIENT_LOCAL - - See :ref:`quality_of_service--transport-priority`. + See :ref:`quality_of_service--durability`. - - + .. prop:: deadline.period.sec=|DURATION_INFINITE_SEC - * - ``lifespan.duration.sec=[`` + See :ref:`quality_of_service--deadline`. - ``numeric|DURATION_INFINITE_SEC]`` + .. prop:: deadline.period.nanosec=|DURATION_INFINITE_NANOSEC - - See :ref:`quality_of_service--lifespan`. + See :ref:`quality_of_service--deadline`. - - + .. prop:: latency_budget.duration.sec=|DURATION_INFINITE_SEC - * - ``lifespan.duration.nanosec=[`` + See :ref:`quality_of_service--latency-budget`. - ``numeric|DURATION_INFINITE_NANOSEC]`` + .. prop:: latency_budget.duration.nanosec=|DURATION_INFINITE_NANOSEC - - See :ref:`quality_of_service--lifespan`. + See :ref:`quality_of_service--latency-budget`. - - + .. prop:: liveliness.kind=AUTOMATIC|MANUAL_BY_TOPIC|MANUAL_BY_PARTICIPANT - * - ``ownership.kind=[SHARED|EXCLUSIVE]`` + See :ref:`qos-liveliness`. - - See :ref:`quality_of_service--ownership`. + .. prop:: liveliness.lease_duration.sec=|DURATION_INFINITE_SEC - - + See :ref:`qos-liveliness`. - * - ``ownership_strength.value=numeric`` + .. prop:: liveliness.lease_duration.nanosec=|DURATION_INFINITE_NANOSEC - - See :ref:`quality_of_service--ownership-strength`. + See :ref:`qos-liveliness`. - - + .. prop:: reliability.kind=BEST_EFFORT|RELIABILE -.. _run_time_configuration--reftable15: + See :ref:`quality_of_service--reliability`. -.. list-table:: [datareaderqos/\*] Configuration Options - :header-rows: 1 + .. prop:: reliability.max_blocking_time.sec=|DURATION_INFINITE_SEC - * - Option + See :ref:`quality_of_service--reliability`. - - Description + .. prop:: reliability.max_blocking_time.nanosec=|DURATION_INFINITE_NANOSEC - - Default + See :ref:`quality_of_service--reliability`. - * - ``durability.kind=[`` + .. prop:: destination_order.kind=BY_SOURCE_TIMESTAMP|BY_RECEPTION_TIMESTAMP - ``VOLATILE|TRANSIENT_LOCAL]`` + See :ref:`quality_of_service--destination-order`. - - See :ref:`quality_of_service--durability`. + .. prop:: history.kind=KEEP_LAST|KEEP_ALL - - + See :ref:`quality_of_service--history`. - * - ``deadline.period.sec=[`` + .. prop:: history.depth= - ``numeric|DURATION_INFINITE_SEC]`` + See :ref:`quality_of_service--history`. - - See :ref:`quality_of_service--deadline`. + .. prop:: resource_limits.max_samples= - - + See :ref:`quality_of_service--resource-limits`. - * - ``deadline.period.nanosec=[`` + .. prop:: resource_limits.max_instances= - ``numeric|DURATION_INFINITE_NANOSEC]`` + See :ref:`quality_of_service--resource-limits`. - - See :ref:`quality_of_service--deadline`. + .. prop:: resource_limits.max_samples_per_instance= - - + See :ref:`quality_of_service--resource-limits`. - * - ``latency_budget.duration.sec=[`` + .. prop:: time_based_filter.minimum_separation.sec=|DURATION_INFINITE_SEC - ``numeric|DURATION_INFINITE_SEC]`` + See :ref:`quality_of_service--time-based-filter`. - - See :ref:`quality_of_service--latency-budget`. + .. prop:: time_based_filter.minimum_separation.nanosec=|DURATION_INFINITE_NANOSEC - - + See :ref:`quality_of_service--time-based-filter`. - * - ``latency_budget.duration.nanosec=[`` + .. prop:: reader_data_lifecycle.autopurge_nowriter_samples_delay.sec=|DURATION_INFINITE_SEC - ``numeric|DURATION_INFINITE_NANOSEC]`` + See :ref:`quality_of_service--reader-data-lifecycle`. - - See :ref:`quality_of_service--latency-budget`. + .. prop:: reader_data_lifecycle.autopurge_nowriter_samples_delay.nanosec=|DURATION_INFINITE_NANOSEC - - + See :ref:`quality_of_service--reader-data-lifecycle`. - * - ``liveliness.kind=[`` + .. prop:: reader_data_lifecycle.autopurge_dispose_samples_delay.sec=|DURATION_INFINITE_SEC - ``AUTOMATIC|`` + See :ref:`quality_of_service--reader-data-lifecycle`. - ``MANUAL_BY_TOPIC|`` + .. prop:: reader_data_lifecycle.autopurge_dispose_samples_delay.nanosec=|DURATION_INFINITE_NANOSEC - ``MANUAL_BY_PARTICIPANT]`` + See :ref:`quality_of_service--reader-data-lifecycle`. - - See :ref:`quality_of_service--liveliness`. +.. sec:: publisherqos/ - - + .. prop:: presentation.access_scope=INSTANCE|TOPIC|GROUP - * - ``liveliness.lease_duration.sec=[`` + See :ref:`quality_of_service--presentation`. - ``numeric|DURATION_INFINITE_SEC]`` + .. prop:: presentation.coherent_access=true|false - - See :ref:`quality_of_service--liveliness`. + See :ref:`quality_of_service--presentation`. - - + .. prop:: presentation.ordered_access=true|false - * - ``liveliness.lease_duration.nanosec=[`` + See :ref:`quality_of_service--presentation`. - ``numeric|DURATION_INFINITE_NANOSEC]`` + .. prop:: partition.name=[,]... - - See :ref:`quality_of_service--liveliness`. + See :ref:`quality_of_service--partition`. - - +.. sec:: subscriberqos/ - * - ``reliability.kind=[BEST_EFFORT|RELIABILE]`` + .. prop:: presentation.access_scope=INSTANCE|TOPIC|GROUP - - See :ref:`quality_of_service--reliability`. + See :ref:`quality_of_service--presentation`. - - + .. prop:: presentation.coherent_access=true|false - * - ``reliability.max_blocking_time.sec=[`` + See :ref:`quality_of_service--presentation`. - ``numeric|DURATION_INFINITE_SEC]`` + .. prop:: presentation.ordered_access=true|false - - See :ref:`quality_of_service--reliability`. + See :ref:`quality_of_service--presentation`. - - + .. prop:: partition.name=[,]... - * - ``reliability.max_blocking_time.nanosec=[`` + See :ref:`quality_of_service--partition`. - ``numeric|DURATION_INFINITE_NANOSEC]`` +.. sec:: endpoint/ - - See :ref:`quality_of_service--reliability`. + .. prop:: domain= + :required: - - + Domain id for endpoint in range 0-231. + Used to form GUID of endpoint. - * - ``destination_order.kind=[`` + .. prop:: participant= + :required: - ``BY_SOURCE_TIMESTAMP|`` + String of 12 hexadecimal digits. + Used to form GUID of endpoint. + All endpoints with the same domain/participant combination should be in the same process. - ``BY_RECEPTION_TIMESTAMP]`` + .. prop:: entity= + :required: - - See :ref:`quality_of_service--destination-order`. + String of 6 hexadecimal digits. + Used to form GUID of endpoint. + The combination of domain/participant/entity should be unique. - - + .. prop:: type=reader|writer + :required: - * - ``history.kind=[KEEP_LAST|KEEP_ALL]`` + Determines if the entity is a data reader or data writer. - - See :ref:`quality_of_service--history`. + .. prop:: topic= + :required: - - + The :sec:`topic` to use. - * - ``history.depth=numeric`` + .. prop:: datawriterqos= - - See :ref:`quality_of_service--history`. + The :sec:`datawriterqos` to use. - - + .. prop:: datareaderqos= - * - ``resource_limits.max_samples=numeric`` + The :sec:`datareaderqos` to use. - - See :ref:`quality_of_service--resource-limits`. + .. prop:: publisherqos= - - + The :sec:`publisherqos` to use. - * - ``resource_limits.max_instances=numeric`` + .. prop:: subscriberqos= - - See :ref:`quality_of_service--resource-limits`. + The :sec:`subscriberqos` to use. - - - - * - ``resource_limits.max_samples_per_instance=`` - - ``numeric`` - - - See :ref:`quality_of_service--resource-limits`. - - - - - * - ``time_based_filter.minimum_separation.sec=[`` - - ``numeric|DURATION_INFINITE_SEC]`` - - - See :ref:`quality_of_service--time-based-filter`. - - - - - * - ``time_based_filter.minimum_separation.nanosec=[`` - - ``numeric|DURATION_INFINITE_NANOSEC]`` - - - See :ref:`quality_of_service--time-based-filter`. - - - - - * - ``reader_data_lifecycle.`` - ``autopurge_nowriter_samples_delay.sec=[`` - - ``numeric|DURATION_INFINITE_SEC]`` - - - See :ref:`quality_of_service--reader-data-lifecycle`. - - - - - * - ``reader_data_lifecycle.`` - ``autopurge_nowriter_samples_delay.nanosec=[`` - - ``numeric|DURATION_INFINITE_NANOSEC]`` - - - See :ref:`quality_of_service--reader-data-lifecycle`. - - - - - * - ``reader_data_lifecycle.`` - ``autopurge_dispose_samples_delay.sec=[`` - - ``numeric|DURATION_INFINITE_SEC]`` - - - See :ref:`quality_of_service--reader-data-lifecycle`. - - - - - * - ``reader_data_lifecycle.`` - ``autopurge_dispose_samples_delay.nanosec=[`` - - ``numeric|DURATION_INFINITE_NANOSEC]`` - - - See :ref:`quality_of_service--reader-data-lifecycle`. - - - - -.. _run_time_configuration--reftable16: - -.. list-table:: [publisherqos/\*] Configuration Options - :header-rows: 1 - - * - Option - - - Description + .. prop:: config= - - Default - - * - ``presentation.access_scope=[INSTANCE|TOPIC|GROUP]`` - - - See :ref:`quality_of_service--presentation`. - - - - - * - ``presentation.coherent_access=[true|false]`` - - - See :ref:`quality_of_service--presentation`. - - - - - * - ``presentation.ordered_access=[true|false]`` - - - See :ref:`quality_of_service--presentation`. - - - - - * - ``partition.name=name0,name1,...`` - - - See :ref:`quality_of_service--partition`. - - - - -.. _run_time_configuration--reftable17: - -.. list-table:: [subscriberqos/\*] Configuration Options - :header-rows: 1 - - * - Option - - - Description - - - Default - - * - ``presentation.access_scope=[INSTANCE|TOPIC|GROUP]`` - - - See :ref:`quality_of_service--presentation`. - - - - - * - ``presentation.coherent_access=[true|false]`` - - - See :ref:`quality_of_service--presentation`. - - - - - * - ``presentation.ordered_access=[true|false]`` - - - See :ref:`quality_of_service--presentation`. - - - - - * - ``partition.name=name0,name1,...`` - - - See :ref:`quality_of_service--partition`. - - - - -.. _run_time_configuration--reftable18: - -.. list-table:: [endpoint/\*] Configuration Options - :header-rows: 1 - - * - Option - - - Description - - - Default - - * - ``domain=numeric`` - - - Domain id for endpoint in range 0-231. - Used to form GUID of endpoint. - - - Required - - * - ``participant=hexstring`` - - - String of 12 hexadecimal digits. - Used to form GUID of endpoint. - All endpoints with the same domain/participant combination should be in the same process. - - - Required - - * - ``entity=hexstring`` - - - String of 6 hexadecimal digits. - Used to form GUID of endpoint. - The combination of domain/participant/entity should be unique. - - - Required - - * - ``type=[reader|writer]`` - - - Determines if the entity is a data reader or data writer. - - - Required - - * - ``topic=name`` - - - Refers to a ``[topic/*]`` section. - - - Required - - * - ``datawriterqos=name`` - - - Refers to a ``[datawriterqos/*]`` section. - - - - - * - ``datareaderqos=name`` - - - Refers to a ``[datareaderqos/*]`` section. - - - - - * - ``publisherqos=name`` - - - Refers to a ``[publisherqos/*]`` section. - - - - - * - ``subscriberqos=name`` - - - Refers to a ``[subscriberqos/*]`` section. - - - - - * - ``config`` - - - Refers to a transport configuration in a ``[config/*]`` section. - This is used to determine a network address for the endpoint. - - - + The transport configuration to use. .. _config-transport: .. _run_time_configuration--transport-configuration: diff --git a/docs/devguide/xtypes.rst b/docs/devguide/xtypes.rst index 742013addd2..1fcd6ce4e32 100644 --- a/docs/devguide/xtypes.rst +++ b/docs/devguide/xtypes.rst @@ -894,7 +894,7 @@ To do the same for CMake: ) Once set up to be generated, OpenDDS has to be configured to send and receive the ``CompleteTypeObject``\s. -This can be done by setting the :ref:`UseXTypes ` RTPS discovery configuration option (:ref:`run_time_configuration--configuring-for-ddsi-rtps-discovery`) or programmatically using the ``OpenDDS::RTPS::RtpsDiscovery::use_xtypes()`` setter methods. +This can be done by setting :cfg:prop:`[rtps_discovery]UseXTypes` or programmatically using the ``OpenDDS::RTPS::RtpsDiscovery::use_xtypes()`` setter methods. .. _xtypes--interpreting-data-samples-with-dynamicdata: diff --git a/docs/news.d/spdp-user-tag.rst b/docs/news.d/spdp-user-tag.rst index 0b6294fff05..59ba92c0942 100644 --- a/docs/news.d/spdp-user-tag.rst +++ b/docs/news.d/spdp-user-tag.rst @@ -1,6 +1,5 @@ .. news-prs: 4533 .. news-start-section: Additions -- DDSI-RTPS Discovery has a new configuration option: SpdpUserTag. - +- Added :cfg:prop:`[rtps_discovery]SpdpUserTag`. .. news-end-section From c4dbd3b941ed9b021fb68f9554d37b196c534fa3 Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Wed, 10 Apr 2024 11:08:57 -0500 Subject: [PATCH 32/37] Remove Two Accidentally Committed Things --- docs/devguide/internet_enabled_rtps.rst | 2 +- docs/sphinx_extensions/config_domain.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/devguide/internet_enabled_rtps.rst b/docs/devguide/internet_enabled_rtps.rst index 7539b422b66..21b3383872b 100644 --- a/docs/devguide/internet_enabled_rtps.rst +++ b/docs/devguide/internet_enabled_rtps.rst @@ -80,7 +80,7 @@ Using the RtpsRelay Sect<15.2.1> Support for the RtpsRelay is activated via configuration. -See :cfg:sec:`rtps_discovery` and :cfg:sec:`transport@rtps_udp` for details. +See :cfg:sec:`rtps_discovery` and ``transport@rtps_udp`` for details. As an example: .. code-block:: ini diff --git a/docs/sphinx_extensions/config_domain.py b/docs/sphinx_extensions/config_domain.py index a405df42132..3b0d306dc89 100644 --- a/docs/sphinx_extensions/config_domain.py +++ b/docs/sphinx_extensions/config_domain.py @@ -210,7 +210,6 @@ def parse_sig(self, ctx, sig): def create_signode(self, ctx, name, signode, arguments): signode += addnodes.desc_name(name, name) - print(ctx.get(-2, 'sec_name'), name) if arguments is not None: text = '=' + arguments signode += addnodes.desc_addname(text, text) From f3fa995f1ba1f730681a6174fbc9cd2e2f63ee25 Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Wed, 10 Apr 2024 12:54:18 -0500 Subject: [PATCH 33/37] Apply suggestions from code review Co-authored-by: Justin Wilson --- docs/devguide/internet_enabled_rtps.rst | 2 +- docs/devguide/run_time_configuration.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/devguide/internet_enabled_rtps.rst b/docs/devguide/internet_enabled_rtps.rst index 21b3383872b..53fe6c700d0 100644 --- a/docs/devguide/internet_enabled_rtps.rst +++ b/docs/devguide/internet_enabled_rtps.rst @@ -250,7 +250,7 @@ The command-line options for the RtpsRelay: .. option:: -UtilizationLimit - If :cfg:prop:`thread monitoring is enabled `, the RtpsRelay will not accept to new client participants if the CPU utilization of any thread is above this limit, default .95. + If :cfg:prop:`thread monitoring is enabled `, the RtpsRelay will not accept new client participants if the CPU utilization of any thread is above this limit, default .95. .. option:: -PublishRelayStatus diff --git a/docs/devguide/run_time_configuration.rst b/docs/devguide/run_time_configuration.rst index ab41769c708..a79902c2b90 100644 --- a/docs/devguide/run_time_configuration.rst +++ b/docs/devguide/run_time_configuration.rst @@ -1738,7 +1738,7 @@ The static discovery implementation also checks that the QoS of a data reader or .. sec:: endpoint/ - .. prop:: domain= + .. prop:: domain= :required: Domain id for endpoint in range 0-231. From 57c37cb3d2f3b8c5d8a2c2974e087007c5fe9ed8 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Wed, 10 Apr 2024 19:24:38 +0000 Subject: [PATCH 34/37] updates from testing --- dds/DCPS/SporadicTask.cpp | 2 +- dds/DCPS/SporadicTask.h | 4 +- dds/DCPS/Timers.cpp | 16 ++++---- .../transport/framework/TransportClient.cpp | 40 +++++++++++++++++-- .../transport/framework/TransportClient.h | 39 ++++-------------- 5 files changed, 55 insertions(+), 46 deletions(-) diff --git a/dds/DCPS/SporadicTask.cpp b/dds/DCPS/SporadicTask.cpp index 2c5ec5119e7..8405f87cc63 100644 --- a/dds/DCPS/SporadicTask.cpp +++ b/dds/DCPS/SporadicTask.cpp @@ -59,7 +59,7 @@ void SporadicTask::cancel() } } -void SporadicTask::execute_i() +void SporadicTask::update_schedule() { ACE_Guard guard(mutex_); diff --git a/dds/DCPS/SporadicTask.h b/dds/DCPS/SporadicTask.h index 456aec5dfc6..22b9775dce6 100644 --- a/dds/DCPS/SporadicTask.h +++ b/dds/DCPS/SporadicTask.h @@ -52,7 +52,7 @@ class OpenDDS_Dcps_Export SporadicTask : public virtual RcEventHandler { { RcHandle st = sporadic_task_.lock(); if (st) { - st->execute_i(); + st->update_schedule(); } } @@ -69,7 +69,7 @@ class OpenDDS_Dcps_Export SporadicTask : public virtual RcEventHandler { const RcHandle sporadic_command_; mutable ACE_Thread_Mutex mutex_; - void execute_i(); + void update_schedule(); int handle_timeout(const ACE_Time_Value& tv, const void*) { diff --git a/dds/DCPS/Timers.cpp b/dds/DCPS/Timers.cpp index 7ccbae446af..210b0271744 100644 --- a/dds/DCPS/Timers.cpp +++ b/dds/DCPS/Timers.cpp @@ -83,19 +83,19 @@ TimerId schedule(ACE_Reactor* reactor, } return InvalidTimerId; } - itimerspec ts; - ts.it_interval = interval.value(); - ts.it_value = delay.value(); - if (timerfd_settime(fd, 0, &ts, 0) == -1) { + const RcHandle fdHandler = make_rch(ref(handler), fd, arg); + if (reactor->register_handler(fdHandler.get(), ACE_Event_Handler::READ_MASK) == -1) { if (log_level >= LogLevel::Notice) { - ACE_ERROR((LM_NOTICE, "(%P|%t) NOTICE: Timers::schedule: timerfd_settime %m\n")); + ACE_ERROR((LM_NOTICE, "(%P|%t) NOTICE: Timers::schedule: register_handler %m\n")); } return InvalidTimerId; } - const RcHandle fdHandler = make_rch(ref(handler), fd, arg); - if (reactor->register_handler(fdHandler.get(), ACE_Event_Handler::READ_MASK) == -1) { + itimerspec ts; + ts.it_interval = interval.value(); + ts.it_value = (delay == TimeDuration()) ? interval.value() : delay.value(); + if (timerfd_settime(fd, 0, &ts, 0) == -1) { if (log_level >= LogLevel::Notice) { - ACE_ERROR((LM_NOTICE, "(%P|%t) NOTICE: Timers::schedule: register_handler %m\n")); + ACE_ERROR((LM_NOTICE, "(%P|%t) NOTICE: Timers::schedule: timerfd_settime %m\n")); } return InvalidTimerId; } diff --git a/dds/DCPS/transport/framework/TransportClient.cpp b/dds/DCPS/transport/framework/TransportClient.cpp index fc6f258ecd3..cc6bfe16fa1 100644 --- a/dds/DCPS/transport/framework/TransportClient.cpp +++ b/dds/DCPS/transport/framework/TransportClient.cpp @@ -14,9 +14,11 @@ #include "TransportReceiveListener.h" #include -#include -#include #include +#include +#include +#include + #include #include @@ -341,17 +343,47 @@ TransportClient::associate(const AssociationData& data, bool active) } void -TransportClient::PendingAssoc::reset_client() { +TransportClient::PendingAssoc::reset_client() +{ ACE_Guard guard(mutex_); client_.reset(); } bool -TransportClient::PendingAssoc::safe_to_remove() { +TransportClient::PendingAssoc::safe_to_remove() +{ ACE_Guard guard(mutex_); return !client_ && !scheduled_; } +void +TransportClient::PendingAssocTimer::ScheduleCommand::execute() +{ + if (timer_->reactor()) { + const TransportClient_rch client = transport_client_.lock(); + if (client) { + ACE_Guard guard(assoc_->mutex_); + assoc_->scheduled_ = true; + const Timers::TimerId id = Timers::schedule(timer_->reactor(), *assoc_, client.in(), + client->passive_connect_duration_); + if (id != Timers::InvalidTimerId) { + timer_->set_id(id); + } + } + } +} + +void +TransportClient::PendingAssocTimer::CancelCommand::execute() +{ + if (timer_->reactor() && timer_->get_id() != Timers::InvalidTimerId) { + ACE_Guard guard(assoc_->mutex_); + timer_->reactor()->cancel_timer(timer_->get_id()); + timer_->set_id(-1); + assoc_->scheduled_ = false; + } +} + int TransportClient::PendingAssoc::handle_timeout(const ACE_Time_Value&, const void* arg) diff --git a/dds/DCPS/transport/framework/TransportClient.h b/dds/DCPS/transport/framework/TransportClient.h index ef589098efe..747404fbb9d 100644 --- a/dds/DCPS/transport/framework/TransportClient.h +++ b/dds/DCPS/transport/framework/TransportClient.h @@ -268,8 +268,8 @@ class OpenDDS_Dcps_Export TransportClient public: CommandBase(PendingAssocTimer* timer, const PendingAssoc_rch& assoc) - : timer_ (timer) - , assoc_ (assoc) + : timer_(timer) + , assoc_(assoc) { } protected: PendingAssocTimer* timer_; @@ -279,41 +279,18 @@ class OpenDDS_Dcps_Export TransportClient ScheduleCommand(PendingAssocTimer* timer, TransportClient_rch transport_client, const PendingAssoc_rch& assoc) - : CommandBase (timer, assoc) - , transport_client_ (transport_client) + : CommandBase(timer, assoc) + , transport_client_(transport_client) { } - virtual void execute() - { - if (timer_->reactor()) { - TransportClient_rch client = transport_client_.lock(); - if (client) { - ACE_Guard guard(assoc_->mutex_); - assoc_->scheduled_ = true; - long id = timer_->reactor()->schedule_timer(assoc_.in(), - client.in(), - client->passive_connect_duration_.value()); - if (id != -1) { - timer_->set_id(id); - } - } - } - } - WeakRcHandle transport_client_; + virtual void execute(); + const WeakRcHandle transport_client_; }; struct CancelCommand : public CommandBase { CancelCommand(PendingAssocTimer* timer, const PendingAssoc_rch& assoc) - : CommandBase (timer, assoc) + : CommandBase(timer, assoc) { } - virtual void execute() - { - if (timer_->reactor() && timer_->get_id()) { - ACE_Guard guard(assoc_->mutex_); - timer_->reactor()->cancel_timer(timer_->get_id()); - timer_->set_id(-1); - assoc_->scheduled_ = false; - } - } + virtual void execute(); }; long timer_id_; }; From 2816ccf75c3bd9d812d99d286fa446c85b2f2c87 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Wed, 10 Apr 2024 19:51:23 +0000 Subject: [PATCH 35/37] extended test --- tests/unit-tests/dds/DCPS/Timers.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/unit-tests/dds/DCPS/Timers.cpp b/tests/unit-tests/dds/DCPS/Timers.cpp index 59fbda0ffa7..9fb400fdde8 100644 --- a/tests/unit-tests/dds/DCPS/Timers.cpp +++ b/tests/unit-tests/dds/DCPS/Timers.cpp @@ -13,7 +13,6 @@ struct TestEventHandler : RcEventHandler { int handle_timeout(const ACE_Time_Value&, const void*) { - ACE_DEBUG((LM_DEBUG, "%T timeout\n")); ++calls_; return 0; } @@ -21,12 +20,11 @@ struct TestEventHandler : RcEventHandler { int calls_; }; -TEST(dds_DCPS_Timers, test) +TEST(dds_DCPS_Timers, test_oneshot) { RcHandle handler = make_rch(); ACE_Reactor reactor(new ACE_Select_Reactor, true); - ACE_DEBUG((LM_DEBUG, "%T schedule\n")); const Timers::TimerId id = Timers::schedule(&reactor, *handler, 0, TimeDuration::from_msec(10)); ASSERT_NE(id, Timers::InvalidTimerId); @@ -36,3 +34,18 @@ TEST(dds_DCPS_Timers, test) ASSERT_EQ(handler->calls_, 1); Timers::cancel(&reactor, id); } + +TEST(dds_DCPS_Timers, test_repeat) +{ + RcHandle handler = make_rch(); + ACE_Reactor reactor(new ACE_Select_Reactor, true); + + const Timers::TimerId id = Timers::schedule(&reactor, *handler, 0, TimeDuration(), TimeDuration::from_msec(10)); + ASSERT_NE(id, Timers::InvalidTimerId); + + ACE_Time_Value one_sec(1); + reactor.run_reactor_event_loop(one_sec); + + ASSERT_GT(handler->calls_, 10); + Timers::cancel(&reactor, id); +} From 4cd620ecb562c6935b7b8e6a16f0f4d282ab1ee3 Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Wed, 10 Apr 2024 20:46:23 +0000 Subject: [PATCH 36/37] Updated TransportClient::PendingAssocTimer::CancelCommand::execute() --- dds/DCPS/transport/framework/TransportClient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dds/DCPS/transport/framework/TransportClient.cpp b/dds/DCPS/transport/framework/TransportClient.cpp index cc6bfe16fa1..9fd7f358585 100644 --- a/dds/DCPS/transport/framework/TransportClient.cpp +++ b/dds/DCPS/transport/framework/TransportClient.cpp @@ -378,8 +378,8 @@ TransportClient::PendingAssocTimer::CancelCommand::execute() { if (timer_->reactor() && timer_->get_id() != Timers::InvalidTimerId) { ACE_Guard guard(assoc_->mutex_); - timer_->reactor()->cancel_timer(timer_->get_id()); - timer_->set_id(-1); + Timers::cancel(timer_->reactor(), timer_->get_id()); + timer_->set_id(Timers::InvalidTimerId); assoc_->scheduled_ = false; } } From fa24b14f10a98ae955387f3ed2fcd0f806ed439b Mon Sep 17 00:00:00 2001 From: Adam Mitz Date: Thu, 11 Apr 2024 13:34:17 +0000 Subject: [PATCH 37/37] Updated logging to use log_level Fixed usage in configure script --- configure | 2 +- dds/DCPS/MultiTask.cpp | 12 ++++++++---- dds/DCPS/PeriodicTask.cpp | 6 ++++-- dds/DCPS/SporadicTask.cpp | 10 ++++------ 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/configure b/configure index e8e25f6d95d..a8c21f4753d 100755 --- a/configure +++ b/configure @@ -227,7 +227,7 @@ my @specs = # Array of array-refs, each inner array is an option group which 'macros=s@', 'Extra text for platform_macros.GNU', 'features=s@', 'Extra text for default.features', 'mpcopts=s@', 'Extra command-line args for MPC', - 'boottime|boottime!', 'Use CLOCK_BOOTTIME for timers (no)', + 'boottime!', 'Use CLOCK_BOOTTIME for timers (no)', ], ['Optional dependencies for OpenDDS (disabled by default unless noted otherwise):', 'java:s', 'Java development kit (use JAVA_HOME)', diff --git a/dds/DCPS/MultiTask.cpp b/dds/DCPS/MultiTask.cpp index cea1ad8af76..5814ab22509 100644 --- a/dds/DCPS/MultiTask.cpp +++ b/dds/DCPS/MultiTask.cpp @@ -38,8 +38,10 @@ void MultiTask::enable_i(const TimeDuration& per) timer_ = Timers::schedule(reactor(), *this, 0, per, delay_); if (timer_ == Timers::InvalidTimerId) { - ACE_ERROR((LM_ERROR, "(%P|%t) MultiTask::enable_i" - " failed to schedule timer %p\n", ACE_TEXT(""))); + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, "(%P|%t) MultiTask::enable_i: " + "failed to schedule timer %p\n", ACE_TEXT(""))); + } } else { next_time_ = now + per; } @@ -52,8 +54,10 @@ void MultiTask::enable_i(const TimeDuration& per) cancel_estimate_ = now2 - now; if (timer_ == Timers::InvalidTimerId) { - ACE_ERROR((LM_ERROR, "(%P|%t) MultiTask::enable_i" - " failed to reschedule timer %p\n", ACE_TEXT(""))); + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, "(%P|%t) MultiTask::enable_i: " + "failed to reschedule timer %p\n", ACE_TEXT(""))); + } } else { next_time_ = now2 + per; } diff --git a/dds/DCPS/PeriodicTask.cpp b/dds/DCPS/PeriodicTask.cpp index b2e046bb3ee..330b7da5e77 100644 --- a/dds/DCPS/PeriodicTask.cpp +++ b/dds/DCPS/PeriodicTask.cpp @@ -43,8 +43,10 @@ void PeriodicTask::enable_i(bool reenable, const TimeDuration& per) if (!enabled_) { timer_ = Timers::schedule(reactor(), *this, 0, TimeDuration(), per); if (timer_ == Timers::InvalidTimerId) { - ACE_ERROR((LM_ERROR, "(%P|%t) PeriodicTask::enable_i" - " failed to schedule timer %p\n", ACE_TEXT(""))); + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, "(%P|%t) PeriodicTask::enable_i: " + "failed to schedule timer %p\n", ACE_TEXT(""))); + } } else { enabled_ = true; } diff --git a/dds/DCPS/SporadicTask.cpp b/dds/DCPS/SporadicTask.cpp index 8405f87cc63..78b4a11f644 100644 --- a/dds/DCPS/SporadicTask.cpp +++ b/dds/DCPS/SporadicTask.cpp @@ -32,9 +32,8 @@ void SporadicTask::schedule(const TimeDuration& delay) if (interceptor) { interceptor->execute_or_enqueue(sporadic_command_); } else if (log_level >= LogLevel::Error) { - ACE_ERROR((LM_ERROR, - "(%P|%t) ERROR: SporadicTask::schedule: " - "failed to receive ReactorInterceptor handle\n")); + ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: SporadicTask::schedule: " + "failed to receive ReactorInterceptor handle\n")); } } @@ -53,9 +52,8 @@ void SporadicTask::cancel() if (interceptor) { interceptor->execute_or_enqueue(sporadic_command_); } else if (log_level >= LogLevel::Error) { - ACE_ERROR((LM_ERROR, - "(%P|%t) ERROR: SporadicTask::cancel: " - "failed to receive ReactorInterceptor handle\n")); + ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: SporadicTask::cancel: " + "failed to receive ReactorInterceptor handle\n")); } }