All notable changes to zs3 are documented here. The format follows Keep a Changelog, and versioning follows Semantic Versioning.
First release. Distributed mode now replicates across nodes: writes leave the node that receives them, reads fall back to peers, and a gossip round repairs the mesh after restarts and partitions.
- Distributed namespace replication. PUT/DELETE/multipart-complete push
the raw metadata entry (inline data and tombstones included) to all peers
via
POST /_zs3/meta. Bucket create/delete propagate viaPOST /_zs3/bucket[_delete]. Cross-node GET/LIST after an acknowledged write is immediately consistent. - Read fallback. A GET/HEAD miss falls back to
POST /_zs3/meta_get. Blob reads sweep all known peers when provider records are missing. - Bootstrap sync. Joining nodes pull the full index (
GET /_zs3/index) and discover the bootstrap peer's peers, handshaking so links are bidirectional. - Background replication worker. Blob replication, DHT announces, and
bucket-op propagation run on a
PushWorkerthread off the write path, so copying to peers no longer adds to write latency. The ~1KB metadata push stays synchronous. - Peer gossip. A
--gossip-interval-msround (default 30s) pings random peers, refreshinglast_seenand pulling peer lists, so a node that restarts with an empty routing table is rebuilt without re-bootstrapping. - Address gossip.
/_zs3/peersentries now carry a full"addr":"ip:port"field. The port-only form is kept as a fallback. - Clean 4xx errors for filesystem-size limits. Keys that can't fit a
filesystem (
NAME_MAXper component,PATH_MAXtotal) return400 KeyTooLongin both standalone and distributed modes instead of a misleading 500 fromENAMETOOLONG. - 431 for oversized headers, 400 for oversized bodies. Request headers
over 8KB get
431. Bodies over 5GB get400. Neither is truncated or dropped silently.
- Bucket resurrection race. Bucket create/delete are broadcast by
different nodes at different times, so a late-arriving create could
resurrect an already-deleted bucket on replicas (flaky
HEAD <bucket>in the replication suite). A per-bucket last-write-wins registry (BucketOps, persisted indata_dir/.buckets/) keeps create/delete timestamps. Peers apply only newer ops, and on a tie the delete wins, matching the object-metadata tombstone convention. fetchFromPeerEINVAL panic on macOS. A single ~5GBread()is rejected by macOS with EINVAL and panicsstd.Io. Peer responses now read in 16KB chunks.- Hung peers can no longer wedge the event loop. Peer sockets get 5s send/receive timeouts, so a hung peer can't deadlock two nodes mid-request.
- Unauthenticated
/_zs3/endpoints now validate bucket/key names. HeadObjectfor directory prefixes. Directories answer HEAD instead of a miss.
- Position zs3 as "SQLite for objects": new
docs/vision.md,docs/replace-minio.md,docs/deployment.mdupdate, andscripts/verify-clients.sh/scripts/verify_boto3.pyfor reproducing the aws-cli / boto3 / rclone compatibility check.
- New
test_replication.py: a four-node suite (113 checks) covering cross-node reads, LWW overwrites, delete-then-recreate, multipart, pagination, restart catch-up, origin-node death, gossip mesh repair after a routing-table wipe, and peer protocol validation. Unit tests cover the meta-entry parser. - Distributed boto3 suite: 71 → 72 passing.
- Regression tests for the
400 KeyTooLong/431/400error paths intest_client.py.