erllama_cache_disk_srv (erllama v0.1.0)

View Source

Disk tier server (read_write mode).

One server per disk root directory. Owns no ETS tables; the disk itself is the source of truth for slabs. Reads, writes, and deletes all funnel through the gen_server, which keeps file ordering sequential per directory.

Save pipeline (save/3):

  1. Build framed bytes via erllama_cache_kvc:build/2.
  2. Open writer-unique temp file <hex>.kvc.<writer_id>.tmp with O_EXCL.
  3. prim_file:write/2 an iolist of [Prefix, Payload]. Multi-GB payloads are not concatenated in BEAM memory; the IO subsystem uses writev under the hood.
  4. prim_file:datasync/1, then close.
  5. prim_file:make_link/2 to publish at <hex>.kvc. EEXIST is handled: if the existing file is a valid KVC for this Key, we adopt it (delete our temp). Otherwise we delete the corrupt file and retry once.
  6. erllama_nif:fsync_dir/1 on the root.
  7. Reopen the published file and parse it (validation belt-and- braces against FS bugs).

Returns {ok, Header, Size} on success. The caller is responsible for the meta_srv:reserve_save -> check_reservation -> mark_published -> announce_saved protocol around this call (the writer pool in step 10 wires that up).

On startup, the server scans its directory: deletes any *.tmp files (interrupted writes; safe to drop), parses every <hex>.kvc header, and registers each valid file with the meta server. Files that fail to parse are deleted.

Summary

Types

state()

-type state() :: #state{name :: atom(), tier :: disk | ram_file, root :: file:name()}.

write_out()

-type write_out() ::
          #{key := erllama_cache:cache_key(),
            tmp := file:name(),
            final := file:name(),
            prefix := binary(),
            payload := binary(),
            root := file:name()}.

Functions

abort_tmp/1

-spec abort_tmp(write_out()) -> ok.

delete(SrvName, Key)

-spec delete(atom(), erllama_cache:cache_key()) -> ok.

dir(SrvName)

-spec dir(atom()) -> file:name().

handle_call/3

handle_cast(Msg, S)

-spec handle_cast(term(), state()) -> {noreply, state()}.

init/1

-spec init([term()]) -> {ok, state()}.

load(SrvName, Key)

-spec load(atom(), erllama_cache:cache_key()) ->
              {ok, erllama_cache_kvc:info(), binary()} | miss | {error, term()}.

publish/1

-spec publish(write_out()) ->
                 {ok, erllama_cache:cache_key(), binary(), non_neg_integer()} | {error, term()}.

publish(Root, TmpPath, FinalPath, Key)

-spec publish(file:name(), file:name(), file:name(), erllama_cache:cache_key()) ->
                 {ok, erllama_cache:cache_key(), binary(), non_neg_integer()} | {error, term()}.

save(SrvName, BuildMeta, Payload)

-spec save(atom(), erllama_cache_kvc:build_meta(), binary()) ->
              {ok, erllama_cache:cache_key(), binary(), non_neg_integer()} | {error, term()}.

scan(SrvName)

-spec scan(atom()) -> [{erllama_cache:cache_key(), binary(), non_neg_integer()}].

start_link(Name, RootDir)

-spec start_link(atom(), file:name()) -> {ok, pid()} | {error, term()}.

start_link(Name, Tier, RootDir)

-spec start_link(atom(), disk | ram_file, file:name()) -> {ok, pid()} | {error, term()}.

touch_hits(Path, Hits)

-spec touch_hits(file:name(), non_neg_integer()) -> ok.

write_tmp(Root, BuildMeta, Payload)

-spec write_tmp(file:name(), erllama_cache_kvc:build_meta(), binary()) ->
                   {ok, write_out()} | {error, term()}.