diff --git a/docs/manual/config/config_file_reference.rst b/docs/manual/config/config_file_reference.rst index 8e68a65772..567c33032f 100644 --- a/docs/manual/config/config_file_reference.rst +++ b/docs/manual/config/config_file_reference.rst @@ -843,11 +843,23 @@ The default value is: ``writers`` //CycloneDDS/Domain/Internal/BurstSize -------------------------------------- -Children: `//CycloneDDS/Domain/Internal/BurstSize/MaxInitTransmit`_, `//CycloneDDS/Domain/Internal/BurstSize/MaxRexmit`_ +Children: `//CycloneDDS/Domain/Internal/BurstSize/MaxFragsRexmitSample`_, `//CycloneDDS/Domain/Internal/BurstSize/MaxInitTransmit`_, `//CycloneDDS/Domain/Internal/BurstSize/MaxRexmit`_ Setting for controlling the size of transmitting bursts. +.. _`//CycloneDDS/Domain/Internal/BurstSize/MaxFragsRexmitSample`: + +//CycloneDDS/Domain/Internal/BurstSize/MaxFragsRexmitSample +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Text + +This element controls the maximum number of fragments of a sample that are retransmit in response to a NACK of the entire sample (as opposed to what is sent in response to a NACKFRAG requesting specific fragments). + +The default value is: ``1`` + + .. _`//CycloneDDS/Domain/Internal/BurstSize/MaxInitTransmit`: //CycloneDDS/Domain/Internal/BurstSize/MaxInitTransmit @@ -2628,10 +2640,10 @@ The categorisation of tracing output is incomplete and hence most of the verbosi The default value is: ``none`` .. - generated from ddsi_config.h[eae21b4181f3fdd23b2514a089c43b0e36357066] + generated from ddsi_config.h[570f67bd3080674a4bad53d9580a8bb7ad1e6e4d] generated from ddsi__cfgunits.h[bd22f0c0ed210501d0ecd3b07c992eca549ef5aa] - generated from ddsi__cfgelems.h[0d5a3d2063031f4b47f53cc007d2703bcdefdfa1] - generated from ddsi_config.c[7b5f868237256aa44f09a4ef5b411a21a5ca8024] + generated from ddsi__cfgelems.h[13337a006d5313519c88c3f3643f27992840cfd3] + generated from ddsi_config.c[efeae198a5e12ca8977a655216470564b5c44b64] generated from _confgen.h[e32eabfc35e9f3a7dcb63b19ed148c0d17c6e5fc] generated from _confgen.c[237308acd53897a34e8c643e16e05a61d73ffd65] generated from generate_rnc.c[b50e4b7ab1d04b2bc1d361a0811247c337b74934] diff --git a/docs/manual/options.md b/docs/manual/options.md index 141b020a84..1071cd05f1 100644 --- a/docs/manual/options.md +++ b/docs/manual/options.md @@ -566,11 +566,19 @@ The default value is: `writers` #### //CycloneDDS/Domain/Internal/BurstSize -Children: [MaxInitTransmit](#cycloneddsdomaininternalburstsizemaxinittransmit), [MaxRexmit](#cycloneddsdomaininternalburstsizemaxrexmit) +Children: [MaxFragsRexmitSample](#cycloneddsdomaininternalburstsizemaxfragsrexmitsample), [MaxInitTransmit](#cycloneddsdomaininternalburstsizemaxinittransmit), [MaxRexmit](#cycloneddsdomaininternalburstsizemaxrexmit) Setting for controlling the size of transmitting bursts. +##### //CycloneDDS/Domain/Internal/BurstSize/MaxFragsRexmitSample +Text + +This element controls the maximum number of fragments of a sample that are retransmit in response to a NACK of the entire sample (as opposed to what is sent in response to a NACKFRAG requesting specific fragments). + +The default value is: `1` + + ##### //CycloneDDS/Domain/Internal/BurstSize/MaxInitTransmit Number-with-unit @@ -1836,10 +1844,10 @@ While none prevents any message from being written to a DDSI2 log file. The categorisation of tracing output is incomplete and hence most of the verbosity levels and categories are not of much use in the current release. This is an ongoing process and here we describe the target situation rather than the current situation. Currently, the most useful verbosity levels are config, fine and finest. The default value is: `none` - + - - + + diff --git a/etc/cyclonedds.rnc b/etc/cyclonedds.rnc index 6670c0fd6a..b1e1438071 100644 --- a/etc/cyclonedds.rnc +++ b/etc/cyclonedds.rnc @@ -407,6 +407,12 @@ CycloneDDS configuration""" ] ]

Setting for controlling the size of transmitting bursts.

""" ] ] element BurstSize { [ a:documentation [ xml:lang="en" """ +

This element controls the maximum number of fragments of a sample that are retransmit in response to a NACK of the entire sample (as opposed to what is sent in response to a NACKFRAG requesting specific fragments).

+

The default value is: 1

""" ] ] + element MaxFragsRexmitSample { + text + }? + & [ a:documentation [ xml:lang="en" """

This element specifies how much more than the (presumed or discovered) receive buffer size may be sent when transmitting a sample for the first time, expressed as a percentage; the remainder will then be handled via retransmits. Usually, the receivers can keep up with the transmitter, at least on average, so generally it is better to hope for the best and recover. Besides, the retransmits will be unicast, and so any multicast advantage will be lost as well.

The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

The default value is: 4294967295

""" ] ] @@ -1277,10 +1283,10 @@ MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==
duration_inf = xsd:token { pattern = "inf|0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([num]?s|min|hr|day)" } memsize = xsd:token { pattern = "0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([kMG]i?)?B" } } -# generated from ddsi_config.h[eae21b4181f3fdd23b2514a089c43b0e36357066] +# generated from ddsi_config.h[570f67bd3080674a4bad53d9580a8bb7ad1e6e4d] # generated from ddsi__cfgunits.h[bd22f0c0ed210501d0ecd3b07c992eca549ef5aa] -# generated from ddsi__cfgelems.h[0d5a3d2063031f4b47f53cc007d2703bcdefdfa1] -# generated from ddsi_config.c[7b5f868237256aa44f09a4ef5b411a21a5ca8024] +# generated from ddsi__cfgelems.h[13337a006d5313519c88c3f3643f27992840cfd3] +# generated from ddsi_config.c[efeae198a5e12ca8977a655216470564b5c44b64] # generated from _confgen.h[e32eabfc35e9f3a7dcb63b19ed148c0d17c6e5fc] # generated from _confgen.c[237308acd53897a34e8c643e16e05a61d73ffd65] # generated from generate_rnc.c[b50e4b7ab1d04b2bc1d361a0811247c337b74934] diff --git a/etc/cyclonedds.xsd b/etc/cyclonedds.xsd index f3ba8e487a..0ecd10e6ab 100644 --- a/etc/cyclonedds.xsd +++ b/etc/cyclonedds.xsd @@ -682,11 +682,19 @@ CycloneDDS configuration + + + + +<p>This element controls the maximum number of fragments of a sample that are retransmit in response to a NACK of the entire sample (as opposed to what is sent in response to a NACKFRAG requesting specific fragments).</p> +<p>The default value is: <code>1</code></p> + + @@ -1931,10 +1939,10 @@ MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==<br> - + - - + + diff --git a/src/core/ddsi/defconfig.c b/src/core/ddsi/defconfig.c index 3285361098..e25ff0df1c 100644 --- a/src/core/ddsi/defconfig.c +++ b/src/core/ddsi/defconfig.c @@ -83,6 +83,7 @@ void ddsi_config_init_default (struct ddsi_config *cfg) cfg->whc_adaptive = INT32_C (1); cfg->max_rexmit_burst_size = UINT32_C (1048576); cfg->init_transmit_extra_pct = UINT32_C (4294967295); + cfg->max_frags_in_rexmit_of_sample = UINT32_C (1); cfg->tcp_nodelay = INT32_C (1); cfg->tcp_port = INT32_C (-1); cfg->tcp_read_timeout = INT64_C (2000000000); @@ -98,10 +99,10 @@ void ddsi_config_init_default (struct ddsi_config *cfg) cfg->ssl_min_version.minor = 3; #endif /* DDS_HAS_SSL */ } -/* generated from ddsi_config.h[eae21b4181f3fdd23b2514a089c43b0e36357066] */ +/* generated from ddsi_config.h[570f67bd3080674a4bad53d9580a8bb7ad1e6e4d] */ /* generated from ddsi__cfgunits.h[bd22f0c0ed210501d0ecd3b07c992eca549ef5aa] */ -/* generated from ddsi__cfgelems.h[0d5a3d2063031f4b47f53cc007d2703bcdefdfa1] */ -/* generated from ddsi_config.c[7b5f868237256aa44f09a4ef5b411a21a5ca8024] */ +/* generated from ddsi__cfgelems.h[13337a006d5313519c88c3f3643f27992840cfd3] */ +/* generated from ddsi_config.c[efeae198a5e12ca8977a655216470564b5c44b64] */ /* generated from _confgen.h[e32eabfc35e9f3a7dcb63b19ed148c0d17c6e5fc] */ /* generated from _confgen.c[237308acd53897a34e8c643e16e05a61d73ffd65] */ /* generated from generate_rnc.c[b50e4b7ab1d04b2bc1d361a0811247c337b74934] */ diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_config.h b/src/core/ddsi/include/dds/ddsi/ddsi_config.h index 48ac7b7dc2..f3be421a94 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_config.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_config.h @@ -322,6 +322,7 @@ struct ddsi_config uint32_t max_rexmit_msg_size; uint32_t init_transmit_extra_pct; uint32_t max_rexmit_burst_size; + uint32_t max_frags_in_rexmit_of_sample; int publish_uc_locators; /* Publish discovery unicast locators */ int enable_uc_locators; /* If false, don't even try to create a unicast socket */ diff --git a/src/core/ddsi/src/ddsi__cfgelems.h b/src/core/ddsi/src/ddsi__cfgelems.h index 96406bc71c..aaa64fa0da 100644 --- a/src/core/ddsi/src/ddsi__cfgelems.h +++ b/src/core/ddsi/src/ddsi__cfgelems.h @@ -1003,6 +1003,13 @@ static struct cfgelem internal_burstsize_cfgelems[] = { "Besides, the retransmits will be unicast, and so any multicast advantage " "will be lost as well.

"), UNIT("memsize")), + STRING("MaxFragsRexmitSample", NULL, 1, "1", + MEMBER(max_frags_in_rexmit_of_sample), + FUNCTIONS(0, uf_pos_uint, 0, pf_uint), + DESCRIPTION( + "

This element controls the maximum number of fragments of a sample that " + "are retransmit in response to a NACK of the entire sample (as opposed to " + "what is sent in response to a NACKFRAG requesting specific fragments).

")), END_MARKER }; diff --git a/src/core/ddsi/src/ddsi_config.c b/src/core/ddsi/src/ddsi_config.c index 7910b67eae..52c9d624b9 100644 --- a/src/core/ddsi/src/ddsi_config.c +++ b/src/core/ddsi/src/ddsi_config.c @@ -162,6 +162,7 @@ DUPF(uint32); #endif DU(natint); DU(natint_255); +DU(pos_uint); DUPF(participantIndex); DU(dyn_port); DUPF(memsize); @@ -1418,6 +1419,16 @@ static enum update_result uf_uint (struct ddsi_cfgst *cfgst, void *parent, struc return URES_SUCCESS; } +static enum update_result uf_pos_uint (struct ddsi_cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + uint32_t * const elem = cfg_address (cfgst, parent, cfgelem); + int64_t x; + if (uf_int64_unit (cfgst, &x, value, NULL, 1, 1, UINT32_MAX) != URES_SUCCESS) + return URES_ERROR; + *elem = (uint32_t) x; + return URES_SUCCESS; +} + static void pf_uint (struct ddsi_cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) { uint32_t const * const p = cfg_address (cfgst, parent, cfgelem); diff --git a/src/core/ddsi/src/ddsi_transmit.c b/src/core/ddsi/src/ddsi_transmit.c index c6d65dd187..4312702faf 100644 --- a/src/core/ddsi/src/ddsi_transmit.c +++ b/src/core/ddsi/src/ddsi_transmit.c @@ -486,8 +486,15 @@ int ddsi_enqueue_sample_wrlock_held (struct ddsi_writer *wr, ddsi_seqno_t seq, s /* end-of-transaction messages are empty, but still need to be sent */ nfrags = 1; } - if (!isnew && nfrags > 1) - nfrags = 1; + if (!isnew && nfrags > gv->config.max_frags_in_rexmit_of_sample) + { + /* Implementations that never use NACKFRAG are allowed by the specification and for such a peer, + we must always respond with the full sample on a NACK. For all other implementations (and + certainly for Cyclone) it makes much more sense to do a small initial retransmit. + + (I am not aware of any implementations that never use NACKFRAG.) */ + nfrags = gv->config.max_frags_in_rexmit_of_sample; + } for (i = 0; i < nfrags && enqueued != DDSI_QXEV_MSG_REXMIT_DROPPED; i++) { struct ddsi_xmsg *fmsg = NULL; @@ -508,7 +515,11 @@ int ddsi_enqueue_sample_wrlock_held (struct ddsi_writer *wr, ddsi_seqno_t seq, s } else { - /* Implementations that never use NACKFRAG are allowed by the specification, and for such a peer, we must always force out the full sample on a retransmit request. I am not aware of any such implementations so leaving the override flag in, but not actually using it at the moment. Should set force = (i != 0) for "known bad" implementations. */ + /* For implementations that never use NACKFRAG if we enqueue the first fragment, we must enqueue + everything, because dropping the tail is guaranteed to result in another full NACK anyway. + + I am not aware of any such implementations so leaving the override flag in, if it turns out they do + exist, set force = (i != 0) for "known bad" implementations. */ const int force = 0; if(fmsg) {