asio-tr2 icon indicating copy to clipboard operation
asio-tr2 copied to clipboard

Reconsider use of CompletionCondition as way to limit maximum transfer size

Open chriskohlhoff opened this issue 10 years ago • 1 comments

E.g. to limit use of non-paged memory.

chriskohlhoff avatar Feb 26 '15 09:02 chriskohlhoff

Pre-Lenexa Summary

[buffer.transfer.all], [buffer.transfer.at.least], [buffer.transfer.exactly]

These completion condition types are defined in terms of an unspecified non-zero value, which is used to determine the maximum number of bytes transferred in a single underlying operation.

This value is intended for operating systems where transferring a large number of bytes in a single operation can have a detrimental effect. For example, on Windows buffers may require non-paged memory (a limited resource) until the operation is complete.

For example, a user is writing a simple file server where they send large files directly using memory-mapped files. They can conveniently transfer a 1 GB file using a single async_write() operation, but if the operation consumed 1 GB of non-paged memory until complete then the server would not scale very well.

Asio's implementation sets the default transfer size to 64KB as a reasonable estimate for common use cases. Implementations are free to use whatever value suits their platform best.

The suggestion in Cologne was that the sensible value for the transfer size depends on the I/O object type. E.g. a TCP socket may differ from a named pipe or an asynchronous file. The proposal was that this transfer size should therefore be part of the underlying object's read_some(), async_read_some(), async_read_some() or async_write_some() behaviour.

I am opposed a change in this area as I believe the operations on the underlying object should trust the user knows what they want. I.e. the underlying socket operations should map their behaviour directly to system calls.

However, the higher level algorithms like async_read and async_write should provide a reasonable default (selected by the library) as well as a way to choose a different value -- which they can do by specifying a custom CompletionCondition. In my view the sensible value depends on both the OS and the specific application requirements. If for a particular application we know that 1MB per transfer is optimal, we should be able to specify that behaviour. The current design allows that.

What we could consider doing is making the maximum transfer size part of the transfer_all, transfer_exactly and transfer_at_least constructors. For example:

class transfer_all
{
public:
  explicit transfer_all(size_t max_size_per_transfer = unspecified);
  size_t operator()(const error_code& ec, size_t) const;

};

where the default is something sensible for the platform.

chriskohlhoff avatar May 05 '15 10:05 chriskohlhoff