The distilled journey of momo from a file-replication playground to a production-ready, distributed, content-addressed object store with an S3-compatible gateway, P2P gossip ring, quorum durability, and a FUSE/POSIX mount. Every post documents what was built (verified against src/), why (architecture decisions), and the Bolt / Sentinel tradeoffs that shaped it.
R10 Phase 4: S3 Object Lock β WORM That Actually Refuses Deletes
Object Lock is the S3 feature regulated workloads ask for first: write-once-read-many retention that the storage server itself enforces, not a policy the client promises to honor. This phase gives momo bucket-level lock enablement at creation, per-version retention and legal holds, and a delete path that answers 403 instead of quietly removing bytes. Teaches: how COMPLIANCE and GOVERNANCE differ in who can override them, why lock state must live beside the version record rather than inside object metadata, and which parts of AWSβs surface momo deliberately does not pretend to implement.
R10 Phase 3: S3 Notification β Event-Driven Webhooks on CAS
Implemented S3 bucket notification configurations with real webhook delivery, prefix/suffix filtering, exponential-backoff retries, and all six S3 event types β so backup tools and pipelines can react to object changes instead of polling. Teaches: why a notification dispatcher that returns nil without sending is the trap to watch for, and how events stay honest across plain PUT, multipart, and delete paths.
S3 Lifecycle Rules on a Content-Addressed Store: Time as a First-Class Dimension
Lifecycle rules are the first feature that makes momo delete data on a schedule rather than on request β which turns age, storage class, and delete markers into correctness problems. This post walks through the expiration and transition engine, why a background worker is the only safe place to run it, and how expiration composes with versioningβs delete markers.
β‘ Bolt: Zero-Allocation SigV4 Canonical Headers
Every authenticated S3 request rebuilds a SigV4 canonical-headers block β and the two obvious ways to write it (strings.Split and Header.Get) each allocate on the hottest authorization path. This post walks through replacing both with an IndexByte scan and an EqualFold lookup, and the golden-equivalence test that proves the rewrite is byte-identical for every request AWS clients actually send.
S3 Versioning on a Content-Addressed Store: Two Kinds of Identity
Why S3 versioning and content-addressed storage seem to conflict β mutation identity vs content identity β and how momo keeps both: UUIDv4 version records pointing at deduplicated blobs, delete markers that shadow without deleting, and pagination that can only be computed after sorting. Teaches: the real semantics backup tools depend on, and where the version chain deliberately stops being distributed.
β‘ Bolt: Zero-Allocation Parsing of ETag Lists
How we removed the heap allocation from ETag list parsing on the S3 conditional-request path by replacing strings.Split with a strings.IndexByte scan. Teaches: what If-Match/If-None-Match actually carry, why Split allocates per request, and how a microbenchmark proves the win.
π Adaptive Systems: Ant-Colony Routing and Epigenetic Concurrency
How Momo replaces static concurrency limits and rigid replica selection with bio-inspired adaptive mechanisms: Ant Colony pheromone-based replica exploration and Epigenetic host-capacity admission.
Packing Small Objects into Superblocks: O(1) Reads Without Per-Blob Inodes
Why millions of small files per directory collapse a filesystem, and how a SeaweedFS-style volume layout fixes it: append-only superblocks, 8-byte-aligned needles with CRC32C frames, hole-punching deletion, and crash recovery by truncation. Teaches: the real cost of per-blob files, why alignment beats variable-length framing, and how to make crash recovery O(1).
β‘ Bolt: Zero-Allocation Parsing of AWS Chunked Headers
How we removed the last heap allocation from the aws-chunked ingest path by replacing strings.Split and strings.TrimPrefix with a strings.IndexByte scan. Teaches: what a streaming S3 upload body looks like, why Split allocates per chunk, and how a microbenchmark proves the win.
Eliminating Redundant Time Formats: Slicing for Speed
By replacing a second time.Format call with a simple string slice (amzDate[:8]), we eliminated redundant heap allocations and CPU overhead when generating timestamps for AWS SigV4 requests.