v0.5.0 — Object versioning
The fifth Hamster release: object versioning — the S3 versioning API, served on both the single-node store and the erasure-coded cluster.
Dev preview. Versioning is complete, but the surrounding v0.x limits still hold: on the cluster path the S3 write path commits only on the Raft leader (a non-leader answers
503 SlowDown, clients retry elsewhere), multipart and server-side copy are still not on the cluster path, a single-nodeservestore still cannot become a cluster in place, and on-disk/on-wire formats may still change between v0 releases (they are additively versioned, but nothing is frozen yet). Please don't trust real data to it.
What's in v0.5
The metadata has modeled every key as an ordered list of versions since v0.1 (it is the third load-bearing invariant), so this release is the S3 surface that finally exposes it — and enabling versioning never migrates a schema.
- Per-bucket versioning config.
PutBucketVersioning/GetBucketVersioningover the?versioningsubresource:EnabledandSuspended. An object-lock bucket cannot be suspended (the guard that protects WORM data, ahead of the lock surface in v0.6). MFA Delete is out of scope — object lock is Hamster's WORM mechanism, and an attempt to enable MFA Delete is refused honestly rather than silently dropped. - Version IDs everywhere.
x-amz-version-idon PUT, on versioned GET/HEAD, and on DELETE — the hex ID on an enabled bucket,nullfor the null version under suspension, omitted on a bucket that was never versioned, exactly as S3 does. - Reads and deletes by version.
GetObject/HeadObject/DeleteObjectwith?versionId=(includingversionId=null). ADELETEwith no ID drops a delete marker; with an ID it permanently destroys that one version and frees its data. A GET or HEAD addressing a delete marker is405 MethodNotAllowedwithx-amz-delete-marker; a missing version is404 NoSuchVersion. ListObjectVersions. The?versionssubresource: versions and delete markers across keys in S3 order (key ascending, newest version first), withIsLatest, delimiter-groupedCommonPrefixes, and key-marker + version-id-marker pagination.- All of it on the cluster, too. The same surface runs over
cluster run -s3: a by-version GET fetches that version's shards through the erasure-coded data path, and a permanent version delete reclaims its shards across the cluster. Versions store independent shards — no cross-version sharing.
How it's verified
- Unit tests at every layer: the paged version-keyspace read (ordering,
IsLatestacross pages, mid-key resume, prefix filtering) in the metadata model, and the full HTTP surface in the gateway (config round trip, the two-version lifecycle, delete markers, delimiter-grouped listing with pagination). - A cluster end-to-end test over real processes and loopback mTLS: enable versioning, store two erasure-coded versions of one key, read the current and each prior version by ID through the data path, list versions, drop a delete marker (current read 404s, old versions still read), and permanently delete a version — freeing its shards while its sibling survives.
- The real
awsCLI undertask compat:put-bucket-versioning,get-bucket-versioning, version IDs onput-object,list-object-versions,get-object --version-id, anddelete-objectwith and without a version id. rclone, restic, and s3cmd keep passing, as does the race detector and the deterministic simulation harness.
Binaries below are static (CGO_ENABLED=0), version-stamped (hamster version), with SHA-256 checksums in SHA256SUMS. Next up, v0.6: object lock — GOVERNANCE and COMPLIANCE retention and legal holds, building directly on the versioning this release ships. The metadata already carries the lock fields and the apply-layer guard that no delete path may bypass; v0.6 adds the S3 surface over it.