tarasko · GitHub

Bug report

Bug description:

asyncio.loop.sendfile() does not reliably report native sendfile unavailability when fallback=False.

The documentation says:

Raise SendfileNotAvailableError if the system does not support the sendfile syscall and fallback is False.

However, the actual exception depends on the transport mode:

  • TRY_NATIVE transport where native sendfile fails:
    raises SendfileNotAvailableError
  • FALLBACK transport, such as SSL/TLS:
    raises RuntimeError("fallback is disabled and native sendfile is not supported ...")
  • unsupported transport:
    raises RuntimeError("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

Linked PRs

Read the original on github.com ↗