Content-addressable heap with typed digest
README.md

cas #

A content-addressable heap with typed digests, for OCaml.

Git, Irmin and the AT Protocol all store immutable blocks under the hash of their contents, and keep a few mutable names (branches, heads) that point at those hashes. cas provides that layer once. Cas.Hash gives SHA-1 and SHA-256 digests distinct types, so a Git object id cannot be used where an ATProto block key is expected. Cas.Heap stores blocks under their hashes, binds names to hashes with refs that support compare-and-set, and composes heaps with combinators. layer top bottom reads from top first and falls back to bottom, writes to top, and copies into top every block it finds in bottom, as a cache in front of a store. recording heap behaves as heap and also keeps every block a find returned; a proof collects the blocks one computation read this way. It interprets neither the contents of a block nor any file path: a codec above it decides what a block means, and a backend below it decides where blocks live.

The cas library is pure. A storage backend implements Cas.Heap.BACKEND, and Cas.Heap.Make (Backend).v turns a backend handle into a heap. The companion package cas-eio provides Cas_eio.Fs, a durable SHA-256 heap in a directory, which refuses a write whose key is not the digest of its block and checks stored bytes on every read.

Installation #

$ opam install cas cas-eio

If opam cannot find the packages, they may not yet be released in the public opam-repository. Add the overlay repository, then install them:

$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install cas cas-eio

Usage #

Store a block in an in-memory heap under its SHA-256 digest:

Cas.Heap.read_only ~name heap preserves reads while refusing every mutating operation with an error that names the store. The cas-eio package provides Cas_eio.Fs.read_only ~dir to open a filesystem heap without creating a missing store or modifying an existing one.

module Memory = Cas.Heap.Mem (struct
  type hash = Cas.Hash.sha256
  type block = string

  let equal = Cas.Hash.equal
  let hash = Cas.Hash.hash
end)

let heap = Memory.v ()
let block = "hello"
let key = Cas.Hash.sha256 block
let () = Cas.Heap.put heap key block

Cas.Heap.Content_addressed wraps any heap so that a put whose key differs from the digest of its block is refused, and a find that reads a block stored under the wrong key raises Cas.Heap.Integrity_error.

API #

  • Cas.Hash provides typed SHA-1 and SHA-256 digests, their raw and hexadecimal forms, comparison, and Cas.Hash.any for stores that mix both algorithms.
  • Cas.Heap provides block lookup, insertion and enumeration, named refs with compare-and-set, the combinators layer, recording and of_list, the Content_addressed check and the in-memory heap Mem.
  • Cas_eio.Fs provides the filesystem heap.

Licence #

ISC. See LICENSE.md.