Menu

#15 so_5_transport transactions

2014_01
open
nobody
5
2013-12-19
2013-12-19
No

On practice messages of binary protocols often can be treated as a pair of a header and a payload. Header usually contains some technical information about subsequent payload, like message type and payload size. To do the output of such protocols one can do the following: start an output-trx and write payload to it, so that the size of the payload becomes known. When all the necessary meta-information about the payload is known a new output-trx is started and the header is created and written to a header trx. Then the header transaction must be committed first, and then the payload transaction. This approach has several disadvantages:
1. Header usually has significantly smaller size than the payload has. And for example scattered_buffer_stream_t with 5Kb block size makes bad usage of a single block (the one that the header is written to).
2. Committing header transaction often leads to handling of output block in TCP-channel svc-handler on the reactor before the payload transaction finishes its commit. That means that the data that could have been sent via single call to socket api (ACE_SOCK_Stream::send_n()) would be sent via two calls. And Wireshark shows that short TCP-packets (containing only header image) are not a rare thing.

Please publish your ideas on the topic in this thread.

Discussion

  • Yauheni Akhotnikau

    • Group: 2013_12 --> 2014_01
     
  • Nicolai Grodzitski

    Some ideas how to avoid mentioned disadvantages.

    Calculate payload size before writing it to output stream, so that header and payload can be written under single transaction and use no extra poorly used block. Lets call such case a predictable-payload.
    But it is not applicable in all cases.
    First example when the payload size is unknown until it is written to a stream (oess serializable object for example). One can use buffer for writing payload so that the size of the payload would be known and then to handle the case as a predictable-payload one. But the extra step is introduced and extra space is allocated.
    The second example when the following strategy is used: the data is accumulated until the specific timeout expires or the size of accumulated data exceeds specific max-size. This makes impossible to predict the final size even if the size of each single item is known.

    A possible solution to a 2nd disadvantages is to give user a possibility to merge user transactions for example:

    payload_trx->merge_to_front( std::move( header_trx ) );
    
    payload_trx->commit(); // payload_trx->checkpoint();
    

    or

    header_trx->merge_to_back( std::move( payload_trx ) );
    header_trx->commit(); // header_trx->checkpoint();
    
     
  • Yauheni Akhotnikau

    I think there could be used something like reservation, substreams or nested transactions (but the last term is not good). May be the situation with header/body could be rewritten as such:

    auto reply_pkg_trx = msg.m_io.begin_output_trx();
    auto header_substream = reply_pkg_trx.start_substream();
    auto payload_substream = reply_pkg_trx.start_substream();
    ... // Write to payload_substream.
    payload_substream.commit() // Also closes substream.
    header_substream << payload_size;
    header_substream.commit();
    reply_pkg_trx.commit();
    

    Method start_substream could have several forms, like:

    // For the case when size of substream is unknown and unlimited.
    some_stream_type_t start_substream();
    // For the case when size of substream is known and fixed.
    some_stream_type_t start_fixed_size_substream( size_t size );
    // For the case when size of substream is unknown but limited.
    some_stream_type_t start_limited_size_substream( size_t max_size );
    

    With different start_*substream method scattered_buffer_stream_t could preallocate data buffers appropriatelly. And those buffers could be taken into account when calling ACE_OS::send or send_n functions.

     
    • Nicolai Grodzitski

      How trx->checkpoint() would be handled under substream facility?

       
      • Yauheni Akhotnikau

        How trx->checkpoint() would be handled under substream facility?

        All substream must be commited before calling commit on parent stream.

         

Log in to post a comment.