Bedrock.ObjectStorage behaviour (bedrock v0.5.2)
View SourceBehaviour and API for object storage backends.
ObjectStorage provides a simple key-value interface for storing and retrieving binary data objects. It supports multiple backends (local filesystem, S3, GCS) through a common behaviour.
Operations
put/4- Store an objectget/2- Retrieve an objectdelete/2- Remove an objectlist/2- List objects with a prefix (returns lazy stream)put_if_not_exists/4- Store an object only if it doesn't exist (conditional create)get_with_version/2- Retrieve an object with version tokenput_if_version_matches/5- Store an object only if version matches (conditional update)
Canonical Error Reasons
Backends may return storage-specific errors. The public API normalizes known errors to canonical reasons:
:not_found:already_exists:version_mismatch:access_denied
Path Structure
Object keys follow a hierarchical structure:
- Cluster state:
/{cluster}/state - Chunks:
/{cluster}/shards/{tag}/chunks/{inverted_version} - Snapshots:
/{cluster}/shards/{tag}/snapshots/{inverted_version}
Inverted Version Keys
Object stores list in ascending order only. To get newest objects first,
use inverted version numbers: (2^64 - 1) - version
See Bedrock.ObjectStorage.Keys for key formatting helpers.
Summary
Callbacks
Delete an object by key.
Retrieve an object by key.
Retrieve an object with its version token for conditional updates.
List objects with the given prefix.
Store an object at the given key.
Store an object only if it doesn't already exist (conditional write).
Store an object only if its version matches the expected token.
Functions
Creates an opaque backend reference for the given module and config.
Delete an object by key.
Retrieve an object by key.
Retrieve an object with its version token.
List objects with the given prefix.
Normalizes backend-specific error reasons to canonical ObjectStorage reasons.
Store an object at the given key.
Store an object only if it doesn't already exist.
Store an object only if its version matches.
Types
Callbacks
Delete an object by key.
Deletion is idempotent - deleting a non-existent object succeeds.
Returns
:ok- Object deleted (or didn't exist){:error, reason}- Deletion failed
Retrieve an object by key.
Returns
{:ok, data}- Object data{:error, :not_found}- Object does not exist{:error, reason}- Retrieval failed
@callback get_with_version(backend :: term(), key :: key()) :: {:ok, data(), version_token()} | error()
Retrieve an object with its version token for conditional updates.
Returns the object data along with an opaque version token that can be
passed to put_if_version_matches/5 to implement optimistic concurrency.
Returns
{:ok, data, version_token}- Object data and version token{:error, :not_found}- Object does not exist{:error, reason}- Retrieval failed
@callback list(backend :: term(), prefix :: String.t(), opts :: opts()) :: Enumerable.t()
List objects with the given prefix.
Returns a lazy stream that fetches pages as needed. Objects are returned in ascending lexicographic order by key.
Options
:limit- Maximum number of keys to return (default: unlimited)
Returns
A Stream of key strings.
Store an object at the given key.
Options
:content_type- MIME type of the data (default: "application/octet-stream")
Returns
:ok- Object stored successfully{:error, reason}- Storage failed
@callback put_if_not_exists( backend :: term(), key :: key(), data :: data(), opts :: opts() ) :: :ok | error()
Store an object only if it doesn't already exist (conditional write).
This provides atomicity for write operations where concurrent writers might attempt to create the same object. Only one writer will succeed.
Options
Same as put/4.
Returns
:ok- Object stored successfully (was new){:error, :already_exists}- Object already exists{:error, reason}- Storage failed
@callback put_if_version_matches( backend :: term(), key :: key(), version_token :: version_token(), data :: data(), opts :: opts() ) :: :ok | error()
Store an object only if its version matches the expected token.
This implements optimistic locking (compare-and-swap) semantics.
The operation succeeds only if the current version of the object
matches the provided version_token (obtained from get_with_version/2).
Returns
:ok- Object updated successfully{:error, :version_mismatch}- Object was modified since version_token was obtained{:error, :not_found}- Object does not exist{:error, reason}- Update failed
Functions
Creates an opaque backend reference for the given module and config.
Examples
backend = ObjectStorage.backend(ObjectStorage.LocalFilesystem, root: "/tmp/objects")
ObjectStorage.put(backend, "test/key", "data")
Delete an object by key.
Retrieve an object by key.
@spec get_with_version(backend :: {module(), keyword()}, key :: key()) :: {:ok, data(), version_token()} | error()
Retrieve an object with its version token.
@spec list(backend :: {module(), keyword()}, prefix :: String.t(), opts :: opts()) :: Enumerable.t()
List objects with the given prefix.
Normalizes backend-specific error reasons to canonical ObjectStorage reasons.
Canonical reasons:
:not_found:already_exists:version_mismatch:access_denied
@spec put( backend :: {module(), keyword()}, key :: key(), data :: data(), opts :: opts() ) :: :ok | error()
Store an object at the given key.
@spec put_if_not_exists( backend :: {module(), keyword()}, key :: key(), data :: data(), opts :: opts() ) :: :ok | error()
Store an object only if it doesn't already exist.
@spec put_if_version_matches( backend :: {module(), keyword()}, key :: key(), version_token :: version_token(), data :: data(), opts :: opts() ) :: :ok | error()
Store an object only if its version matches.