A Parquet scan does not read a file, it reads a list of spans: the footer,
then one span per column chunk of each row group it kept. Over local storage
that is a list of seeks and costs nothing. Over HTTP it is a list of requests,
and even with connection reuse each one still costs a round trip — so the
useful optimisation is not making requests faster, it is making fewer of them.
Column chunks of the same row group are laid out consecutively, which means the
spans a scan asks for are usually adjacent or separated by the columns it
skipped. Fetching across a small hole and throwing the hole away is cheaper
than a second round trip: this module works out where those holes are.
The bound is max_gap (1 MiB by default), applied per join, so the bytes read
and discarded are at most max_gap times the number of joins — never more than
the caller asked for plus that.
This module deliberately knows nothing about transports; fileio and httpio
execute the plan.