Ankit Sinha · Backend EngineerTechnical Report 001Issue No. 01 · 27 SEP 2026

Ankit Sinha



Content-Addressable Storage

Storing the same bytes once, and deleting them exactly when nobody needs them.

Issue 01 · July 2026 · Filed under: Storage · Distributed Systems

CLIENT01SHA-25602API03DEDUP?04S305

§1 Address by content, not by name

In HashVault a file is not its bytes. A file is a row that points at a storage object, and a storage object is keyed by the SHA-256 of its contents: objects/{checksum}. Two users uploading the same PDF produce two file rows and one object.

Because the key is derived from the content, re-uploading identical bytes always resolves to the same key. There is nothing to look up by filename and nothing to reconcile.

§2 The upload path

The client hashes the file and asks to upload. If the checksum already exists, the API answers deduplicated: true and skips issuing a presigned URL altogether — the upload round trip disappears.

Otherwise the client receives a presigned PUT, sends bytes straight to S3, and confirms. The Go server only ever sees metadata. It lives on the control plane.

§3 Reference counting is the hard part

Each object carries a ref count. Confirming an upload increments it; deleting a file decrements it; the object is purged from S3 and Postgres only when the count reaches zero. Both operations are atomic SQL, never read-modify-write in Go.

The failure that matters is concurrency: fifty clients confirming the same checksum at the same moment must yield exactly one object with a count of fifty. That is a property of the database, so it is tested against a real Postgres rather than a mock.

§4 Quota without surprises

Quota is checked at init and again at confirm. A deduplicated file still counts against the uploader's quota — storage is shared underneath, but accounting is per user.