blob: 011740303964037e2b5f27c3554b15ef21e591a0 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# =============================================================================
# The byte-range source interface: what a remote (or any byte-addressable)
# object must provide for `Arrow.Table` to read it with exact range requests.
# =============================================================================
"""
Arrow.AbstractArrowSource
A byte-addressable object of known length — an object in cloud storage, an
HTTP resource, an in-memory buffer — that [`Arrow.Table`](@ref) reads with
exact byte-range requests instead of downloading whole. With a
`Tables.Scan`, Arrow reads the file-format footer from the tail. It prunes
batches by the footer's statistics and — without a filter — by the scan's
window. It then requests only the surviving batches' buffers for the
selected and filter-referenced columns, coalesced into a few ranges issued
in one round. A filtered limit stops decoding, not fetching.
An implementation defines two methods:
Arrow.sourcelength(src)::Integer # total length in bytes
Arrow.readrange(src, offset, len)::Vector{UInt8} # `len` bytes from 0-based `offset`
and may override
Arrow.concurrentreads(src)::Int # default 1
to let Arrow issue planned ranges through `readrange` concurrently. One
read handle samples that preference once, clamps it by
`Limits.max_concurrent_reads`, and uses one semaphore across every operation
on that handle (Arrow places each result by its request, so completion order
never matters). Separate read handles are independent; a transport that
needs one process-wide cap must enforce it inside `readrange`.
Every returned vector must have exactly the requested length. Arrow
validates lengths and offsets and refuses violations with a
`ValidationError`. Arrow cannot authenticate the bytes themselves: the
source is trusted to return what lives at the requested range.
```julia
struct BytesSource <: Arrow.AbstractArrowSource
data::Vector{UInt8}
end
Arrow.sourcelength(s::BytesSource) = length(s.data)
Arrow.readrange(s::BytesSource, offset, len) = s.data[(offset + 1):(offset + len)]
tbl = Arrow.Table(BytesSource(bytes); scan=Tables.Scan(select=(:a, :b)))
```
The `CloudStore.jl` extension makes a `CloudStore.Object` a source, so
`Arrow.Table(CloudStore.Object(bucket, key); scan=…)` reads just the needed
column bytes from S3 or Azure Blob Storage. Stream-format objects have
no footer and are read whole.
"""
abstract type AbstractArrowSource end
"""
Arrow.sourcelength(src::AbstractArrowSource) -> Integer
The source's total length in bytes. Required of every implementation.
"""
function sourcelength end
"""
Arrow.readrange(src::AbstractArrowSource, offset, len) -> Vector{UInt8}
`len` bytes starting at 0-based `offset`; the result must have exactly `len`
elements. Required of every implementation.
"""
function readrange end
"""
Arrow.concurrentreads(src::AbstractArrowSource) -> Int
How many [`Arrow.readrange`](@ref) calls Arrow may have in flight at once
through one `SourceFile` handle. The default, `1`, reads them one at a time;
a transport whose requests are independent (HTTP range GETs) returns a bound
suited to it. The handle samples the value once, clamps it by
`Limits.max_concurrent_reads`, and stores every result by request index.
Separate handles are independent.
"""
concurrentreads(::AbstractArrowSource) = 1