Bug report
Bug description:
asyncio.loop.sendfile() does not reliably report native sendfile unavailability when fallback=False.
The documentation says:
Raise
SendfileNotAvailableErrorif the system does not support the sendfile syscall and fallback isFalse.
However, the actual exception depends on the transport mode:
TRY_NATIVEtransport where native sendfile fails:
raisesSendfileNotAvailableErrorFALLBACKtransport, such as SSL/TLS:
raisesRuntimeError("fallback is disabled and native sendfile is not supported ...")- unsupported transport:
raisesRuntimeError("sendfile is not supported ...")
This makes it hard for callers to reliably detect that native sendfile is unavailable. Catching RuntimeError is too broad, because it can also indicate unrelated states such as a closing transport or an unsupported
transport object.
For example, in aiohttp there is a project specific sendfile fallback implementation, which is more efficient than asyncio's fallback.
I did a small PR aio-libs/aiohttp#12945
which illustrates performance difference but there is no reliable way to detect that loop.sendfile can't be used with a particular transport. So I had to use private members from asyncio to do that.
It would be nice to just have the following logic:
try:
loop.sendfile(transport, ..., fallback=False)
except asyncio.SendfileNotAvailableError:
_sendfile_fallback(...)
But, it doesn't work for at least SSL transports.
Suggested fix:
Always raise SendfileNotAvailableError when native sendfile for transport can't be used and fallback=False
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux