Exgit.ObjectStore protocol (exgit v0.1.0)

Copy Markdown View Source

Storage protocol for git objects, keyed by binary SHA-1.

Implemented by Exgit.ObjectStore.Memory (in-heap), Exgit.ObjectStore.Disk (git's on-disk layout), and Exgit.ObjectStore.Promisor (lazy, fetch-on-demand).

Stores are pure values: every write (put/2, import_objects/2, close_write/2) returns the updated store, which the caller must thread forward. Reads never mutate.

Summary

Types

t()

All the types that implement this protocol.

Functions

Abort the write session and release any associated resources (open ports, temp files, etc.) without persisting the object. Always returns :ok.

Finalise the write session: compute the object SHA, persist the object, and return the updated store. Returns {:ok, sha, updated_store}.

Uncompressed byte size of an object WITHOUT materializing its content.

Open a streaming write session for an object of type and expected_size bytes (the declared uncompressed size from the pack header).

Append a chunk of uncompressed content to the in-progress write session. Returns {:ok, updated_handle}.

Types

t()

@type t() :: term()

All the types that implement this protocol.

Functions

cancel_write(store, handle)

@spec cancel_write(t(), term()) :: :ok

Abort the write session and release any associated resources (open ports, temp files, etc.) without persisting the object. Always returns :ok.

close_write(store, handle)

@spec close_write(t(), term()) :: {:ok, binary(), t()} | {:error, term()}

Finalise the write session: compute the object SHA, persist the object, and return the updated store. Returns {:ok, sha, updated_store}.

get(store, sha)

@spec get(t(), binary()) :: {:ok, Exgit.Object.t()} | {:error, term()}

has?(store, sha)

@spec has?(t(), binary()) :: boolean()

import_objects(store, raw_objects)

@spec import_objects(t(), [{atom(), binary(), binary()}]) :: {:ok, t()}

object_size(store, sha)

@spec object_size(t(), binary()) ::
  {:ok, non_neg_integer()} | {:error, :not_found | :not_local | term()}

Uncompressed byte size of an object WITHOUT materializing its content.

The point is a constant-memory size check: callers can decide whether a blob is too large to read before paying to inflate it into the heap.

Returns {:ok, byte_count} when the store can answer, or:

  • {:error, :not_found} — the object is genuinely absent from the store.
  • {:error, :not_local} — a meaningful, non-fatal result for lazy stores (Promisor): it means "knowing this size requires a network fetch", so the caller can opt in rather than have a multi-GB fetch triggered behind a size check.
  • {:error, term()} — store-specific failure (e.g. a corrupt loose object on disk).

open_write(store, type, expected_size)

@spec open_write(t(), Exgit.Object.object_type(), non_neg_integer()) ::
  {:ok, term()} | {:error, term()}

Open a streaming write session for an object of type and expected_size bytes (the declared uncompressed size from the pack header).

Returns {:ok, handle} where handle is an opaque term, or {:error, :not_supported} for stores that do not implement the streaming API.

put(store, object)

@spec put(t(), Exgit.Object.t()) :: {:ok, binary(), t()}

write_chunk(store, handle, chunk)

@spec write_chunk(t(), term(), binary()) :: {:ok, term()} | {:error, term()}

Append a chunk of uncompressed content to the in-progress write session. Returns {:ok, updated_handle}.