barrel_att_store_none (barrel_docdb v1.9.0)

View Source

Attachment backend that stores nothing.

For databases that structurally never accept attachments -- barrel's own _barrel_system and _replication_tasks (see barrel_docdb.erl's ensure_system_db/0 and barrel_rep_tasks.erl's ensure_tasks_db/0), which only ever call put_local_doc/3. barrel_db_server opens an attachment store unconditionally for every database (see its init/8), and the default backend, barrel_att_store_blob, is a real RocksDB instance: even completely empty, RocksDB preallocates its WAL file (~1.1x write_buffer_size -- 64MB default -> ~70.4MB) and its MANIFEST (4MB), a fixed ~74MB floor paid once per database regardless of whether a single attachment is ever stored. Measured on a real deployment (hecate-agora, 2026-09-05): two internal databases that only ever hold a handful of small local docs were paying this floor TWICE each (once for docs, once for attachments) -- ~298MB of a 455MB total, dwarfing the actual content by two orders of magnitude.

Select this backend via att_opts => #{backend => none} on barrel_docdb:create_db/2. Every mutating call returns {error, attachments_disabled}; every read call returns the same "nothing here" result a real backend would return for a document that happens to have zero attachments (not_found from get/4, {error, not_found} from get_info/4, the accumulator unchanged from fold/5), so a caller that never writes an attachment cannot tell the difference. checkpoint/2 and destroy/2 are deliberately not exported (like barrel_att_s3_store and the test-only minimal backend): barrel_att_store degrades those to {error, unsupported} / a no-op respectively -- a none-backed database cannot be forked via timeline branching, which is fine for _barrel_system and _replication_tasks (neither is ever branched) but is a real limitation for anyone else opting into this backend.

purge_existing => true removes an attachments/ directory left by a previous backend on open. Only for databases known to never hold attachments: it deletes whatever is there.

Summary

Functions

Replicated delete: exported so callers that skip the supports_sync check get an error, not undef.

Deleting all (zero) attachments a document has is trivially successful, same as a real backend would report for a document that never had any.

Nothing to fold over; the accumulator passes through unchanged, same as a real backend would do for a document with zero attachments.

Same shape as a real backend asked for an attachment that was never stored: not_found, not an error.

No RocksDB instance, no directory. With purge_existing => true, a stale store left at Path by a previous backend is removed.

Exported for the same reason as delete/5.

Functions

abort_stream(Stream)

-spec abort_stream(map()) -> ok.

close(AttRef)

-spec close(map()) -> ok.

close_stream(Stream)

-spec close_stream(map()) -> ok.

delete(AttRef, DbName, DocId, AttName)

-spec delete(map(), binary(), binary(), binary()) -> {error, attachments_disabled}.

delete(AttRef, DbName, DocId, AttName, Opts)

-spec delete(map(), binary(), binary(), binary(), map()) -> {error, attachments_disabled}.

Replicated delete: exported so callers that skip the supports_sync check get an error, not undef.

delete_all(AttRef, DbName, DocId)

-spec delete_all(map(), binary(), binary()) -> ok.

Deleting all (zero) attachments a document has is trivially successful, same as a real backend would report for a document that never had any.

finish_stream(Stream)

-spec finish_stream(map()) -> {error, attachments_disabled}.

fold(AttRef, DbName, DocId, Fun, Acc)

-spec fold(map(), binary(), binary(), fun(), term()) -> term().

Nothing to fold over; the accumulator passes through unchanged, same as a real backend would do for a document with zero attachments.

get(AttRef, DbName, DocId, AttName)

-spec get(map(), binary(), binary(), binary()) -> not_found.

Same shape as a real backend asked for an attachment that was never stored: not_found, not an error.

get_info(AttRef, DbName, DocId, AttName)

-spec get_info(map(), binary(), binary(), binary()) -> {error, not_found}.

get_stream(AttRef, DbName, DocId, AttName)

-spec get_stream(map(), binary(), binary(), binary()) -> {error, not_found}.

open(Path, Options)

-spec open(string(), map()) -> {ok, map()} | {error, term()}.

No RocksDB instance, no directory. With purge_existing => true, a stale store left at Path by a previous backend is removed.

put(AttRef, DbName, DocId, AttName, Data)

-spec put(map(), binary(), binary(), binary(), binary()) -> {error, attachments_disabled}.

put(AttRef, DbName, DocId, AttName, Data, Opts)

-spec put(map(), binary(), binary(), binary(), binary(), map()) -> {error, attachments_disabled}.

put_stream(AttRef, DbName, DocId, AttName, ContentType)

-spec put_stream(map(), binary(), binary(), binary(), binary()) -> {error, attachments_disabled}.

put_stream(AttRef, DbName, DocId, AttName, ContentType, Opts)

-spec put_stream(map(), binary(), binary(), binary(), binary(), map()) -> {error, attachments_disabled}.

read_chunk(Stream)

-spec read_chunk(map()) -> eof.

rebuild_feed(AttRef, DbName)

-spec rebuild_feed(map(), binary()) -> {error, attachments_disabled}.

Exported for the same reason as delete/5.

write_chunk(Stream, Data)

-spec write_chunk(map(), binary()) -> {error, attachments_disabled}.