# Runtime limits and source consistency

> Working memory, request admission, cancellation and pinned object snapshots.

---

LLMS index: [llms.txt](/llms.txt)

---

## Active work and memory ownership

Default readers, tilers and mosaic pools share `WorkBudget::global()`, a
512 MiB allowance. `WorkBudget::new(bytes)` creates an independent allowance;
clone and inject the same budget through `ReaderConfig::work_budget`,
`Tiler::with_work_budget`, and `MosaicTiler::builder(...).work_budget(...)`
when these objects must share an application limit.

Low-level reservations fail immediately with `AgError::ResourceLimit`. Public
tile/warp/mosaic requests release the failed attempt, wait for exclusive
admission, and retry once under the original deadline. Direct `CogReader` calls
remain fail-fast; individually oversized requests still fail. `used_bytes()`, `peak_bytes()` and `limit_bytes()`
expose the accounting. Cloned reservations stay live until their last owner is
dropped, including an already-running blocking job after its caller cancels.
Managed response buffers retain their byte reservation for the buffer lifetime.

This is an active-work allowance, **not an OS RSS ceiling**. Completed
caller-owned images, resident decoded caches, allocator overhead, runtime/TLS
state and unrelated application allocations have different ownership. Set
`CacheConfig::max_bytes` for decoded-cache residency, share caches deliberately,
and bound how many completed outputs the application retains.

Reader defaults add per-operation validation:

| Setting | Default |
| --- | ---: |
| Source-window pixels | 16 × 1024 × 1024 |
| Window bytes / compressed fetch batch | 256 MiB |
| Blocks per window | 4096 |
| Declared decoded bytes per block | 64 MiB |
| Cumulative metadata bytes while opening | 8 MiB |
| IFDs | 256 |
| Entries per IFD | 4096 |
| Concurrent foreground windows | 8 |

Use `ReaderConfig::default()` and override fields explicitly. Oversized ranges,
metadata and arithmetic overflow fail before the corresponding fetch/allocation.
Background prefetch uses immediate budget acquisition and skips when foreground
work owns the allowance. These guards and a small workload are not a proof of
every codec/backend's behavior on arbitrary input.

The default decoder registration now bounds the output of uncompressed,
Deflate/OldDeflate, LZW, ZSTD and JPEG blocks against the declared block shape.
Typed/planar byte arithmetic and JPEG MCU padding are included in validation
and work estimates. This covers the registered implementations; it does not
make an arbitrary caller-supplied codec implementation safe.

## Request admission, deadlines and cancellation

The default `RequestLimiter` is shared across public tile calls and admits
64 requests. Excess calls return `AgError::Overloaded` immediately. Custom
limiters can be shared using `Tiler::with_request_limiter` and
`MosaicTilerBuilder::request_limiter`. Internal mosaic child work does not
consume a second request admission.

The default request timeout is 30 seconds, including I/O and permit waits.
`TilerConfig` and `MosaicConfig` expose `max_in_flight_requests` and
`request_timeout`; use `..Default::default()` when constructing these configs.
`tile_with_options` (and single-source `warp_tile_with_options`) accepts a
`RequestOptions` containing a per-call timeout and a cloneable
`RequestCancellation`. Calling `cancel()` on any clone ends the request with
`AgError::Cancelled`; expiration returns `AgError::DeadlineExceeded`.

Cancellation is cooperative. It stops later pipeline stages and drops pending
I/O, but does not preempt an arbitrary running CPU instruction or remote server
handler. Blocking work retains its admission/accounting until it finishes.
HTTP client/TLS initialization runs off async workers under a separate bounded
limit; local workload telemetry distinguishes request return from later activity.

The example server exposes:

- `ASYNC_GEOTIFF_MAX_IN_FLIGHT_REQUESTS` (positive integer).
- `ASYNC_GEOTIFF_REQUEST_TIMEOUT_MS` (positive integer milliseconds).

HTTP admission and timeout include dataset lookup/opening. Library callers that
open a `CogReader` directly outside a tile request should apply their own outer
timeout when an application deadline must include that initial open.

The server passes the configured timeout and a shared library request limiter
to default, lazy local, MosaicJSON and STAC tile paths. Raising the HTTP values
does not leave an additional fixed 30-second total request deadline or 64-request
admission cap. Transport connection/read timeouts remain independent. Running
CPU work retains its library admission until it drains after HTTP cancellation.
`ASYNC_GEOTIFF_PREFETCH_RING` applies to default and lazy local single-COG
readers; mosaic asset readers retain their zero-prefetch default.

HTTP mosaic asset error labels remove URL userinfo, query strings and fragments,
including when opening is rejected by the access policy. Store-backed asset
keys retain their existing semantics; they are not interpreted as HTTP URLs.

## Mosaic ordering and selected bands

MosaicJSON assets retain their listed paint order during deduplication. Prefix
lookups traverse matching quadkeys in lexical order and retain the first
occurrence of each asset, preserving each key's list order.

Mosaic selection comes from the Raster Style document, including
`pixel_selection`, `stage`, and the one-based `rank_channel` for Highest/Lowest.
Before channels, the input tuple contains deduplicated source dependencies sorted
by band number; after channels, it contains evaluated output channels. Every
component must be valid for the asset's tuple to participate. Highest/Lowest
keep a complete tuple from the winning asset, with source order breaking ties.

Dependencies are warped independently so unrelated bands' nodata cannot affect
interpolation. Gamma, color mapping and opacity run once after reduction.
Calibration other than `none` currently returns an error; the old `unscale`
parameter is removed. Public `Tiler::warp_tile` returns compact dependencies or,
for `after_channels`, evaluated channels. It no longer returns every source band.

## Pinned object snapshots

Managed `open_http` and `open_object_store` use
`SnapshotPolicy::RequireValidator` by default. A strong ETag or immutable object
version must be available. Conditional reads and decoded-cache identity pin
metadata and pixels to that snapshot; a changed source produces an error
instead of a mixed-version tile. Version-aware stores may continue serving the
pinned old version. LocalFileSystem managed opens supply validators, so the
checked-in fixtures do not need to waive this contract.

An opaque `ObjectReader` does not expose its underlying store for conditional
requests. Passing it to `.open(reader)` therefore requires explicit
`.snapshot_policy(SnapshotPolicy::AssumeImmutable)`. This is a caller guarantee,
not verified snapshot consistency. Use it only for a source the caller keeps
immutable, or migrate to a managed store open.

Validator consistency depends on truthful validators and the backend's atomic
write contract. It cannot detect a server that changes bytes while reusing the
same validator, or raw in-place filesystem writes that violate that contract.

There is no automatic source refresh. Reopen a direct reader to discover the
current validator. For mosaics, call `invalidate_source(key, source_id)` so the
next lookup opens a fresh snapshot, or use a new source version identity.
Invalidation does not mutate an existing reader `Arc`: it retains its original
snapshot, and uncached reads fail if the old version is no longer available.
New reader/cache identities include the validator and size, preventing stale
decoded blocks from being reused as new imagery.

---

Backlinks:

- [Production operation](/docs/guides/production/)
