Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

One Large PUT, Fully Traced

handle_put first parses metadata, checksum expectations, and encryption parameters. It converts the Hyper body into a stream and delegates to save_stream. The handler does not buffer the whole object.

save_stream reads the first block while fetching existing object metadata. If the body fits below the inline threshold, Garage encrypts it and stores it inside the object table. A large object takes the more interesting path.

Before transferring bytes, Garage writes an Uploading object version and an empty version-table entry. These are durable breadcrumbs: later block references always point at a known version, and interrupted work can be found and cleaned.

The body then passes through four cooperating futures:

HTTP body → fixed-size chunks → checksums → encrypt + content hash → replica writes
             channel(2)         channel(1)          channel(1)

Hashing and encryption use spawn_blocking; bounded Tokio channels keep those CPU stages from running arbitrarily far ahead of network writes. The final stage also caps the number of concurrent block writes for this request.

For every block, put_block_and_meta concurrently performs three obligations:

  • replicate immutable block bytes to their placement set;
  • add the block and offset to the version table;
  • add a reference from the version to the block hash.

Only after all blocks finish, checksums and quotas pass, and metadata is ready does Garage merge a Complete object version. A Drop guard remains armed until that point. On error or cancellation it schedules cleanup for the incomplete upload.

The HTTP response therefore means more than “the body was received.” It means the final object metadata reached its configured write quorum after the byte and reference obligations completed.