Tahr.InMemory (tahr v0.1.0)

Copy Markdown View Source

An in-memory read-write filesystem backing the reference Tahr.InMemory.NFSBackend and Tahr.InMemory.MountBackend implementations.

Useful for:

  • Smoke testing with mix tahr.serve — the task defaults to this backend.
  • Studying the backend behaviours — the callbacks are small enough to read end-to-end.
  • Exercising the server in tests that don't need real storage.

The tree lives in an Agent, which serialises all mutations — exactly what NFS's weak cache consistency model wants, and a handy property for a reference implementation.

Not suitable for production

Data is lost when the agent exits. There is no persistence, no multi-node coordination, and no permission checking — every client can do everything.

Summary

Types

One file, directory, or symlink in the tree.

Filesystem state held by the agent.

Functions

Apply an sattr3 to node. nil fields are left unchanged; atime / mtime honour RFC 1813's time_set semantics; ctime always moves to now.

Build the fattr3 for fileid / node.

Returns a specification to start this module under a supervisor.

Resolve a file handle to its {fileid, node} in tree. Any handle that decodes oddly, belongs to another volume, or names a forgotten fileid is refused with NFS3ERR_STALE.

Resolve name inside directory dir to its {fileid, node}.

Read the agent's state without changing it.

Pack fileid into a v1 default-scheme file handle.

A new directory node, with sattr applied.

A new regular-file node, with sattr applied.

A new symlink node pointing at target.

The current wall-clock time as an nfstime3.

The program registry that serves this backend: NFSv3 (100003) and MOUNT v3 (100005) wired to the in-memory backends. Pass it to Tahr.RPC.Server as :programs.

Reset the filesystem to its freshly-seeded state.

The file handle of the root directory.

The byte size NFS attributes report for node.

Start the agent unless it is already running.

Start the filesystem agent.

Read and update the agent's state in one serialised step.

The cookieverf3 for a directory. Derived from its mtime, so any mutation invalidates outstanding READDIR paginations.

Pair a pre-operation WccAttr with the post-operation attributes of fileid as found in tree (nil if the operation removed it).

Capture the pre-operation half of a wcc_data for node.

The per-boot writeverf3 this server instance reports.

Types

file_node()

@type file_node() :: %{
  type: :dir | :reg | :lnk,
  mode: non_neg_integer(),
  nlink: pos_integer(),
  uid: non_neg_integer(),
  gid: non_neg_integer(),
  content: binary(),
  children: %{optional(binary()) => non_neg_integer()},
  target: binary() | nil,
  create_verf: <<_::64>> | nil,
  atime: Tahr.NFSv3.Types.Nfstime3.t(),
  mtime: Tahr.NFSv3.Types.Nfstime3.t(),
  ctime: Tahr.NFSv3.Types.Nfstime3.t()
}

One file, directory, or symlink in the tree.

content is meaningful for :reg, children for :dir, and target for :lnk. create_verf records the verifier of an EXCLUSIVE create so a retried CREATE stays idempotent.

state()

@type state() :: %{
  tree: %{optional(non_neg_integer()) => file_node()},
  next_fileid: pos_integer(),
  writeverf: <<_::64>>
}

Filesystem state held by the agent.

Functions

apply_sattr(node, sattr, now)

Apply an sattr3 to node. nil fields are left unchanged; atime / mtime honour RFC 1813's time_set semantics; ctime always moves to now.

attr(fileid, node)

Build the fattr3 for fileid / node.

child_spec(arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

fetch(tree, fhandle)

@spec fetch(map(), binary()) ::
  {:ok, non_neg_integer(), file_node()} | {:error, :stale}

Resolve a file handle to its {fileid, node} in tree. Any handle that decodes oddly, belongs to another volume, or names a forgotten fileid is refused with NFS3ERR_STALE.

fetch_child(tree, map, name)

@spec fetch_child(map(), file_node(), binary()) ::
  {:ok, non_neg_integer(), file_node()} | {:error, :noent}

Resolve name inside directory dir to its {fileid, node}.

get(fun)

@spec get((state() -> reply)) :: reply when reply: var

Read the agent's state without changing it.

handle_for(fileid)

@spec handle_for(non_neg_integer()) :: binary()

Pack fileid into a v1 default-scheme file handle.

new_dir(sattr, now)

A new directory node, with sattr applied.

new_file(sattr, create_verf, now)

@spec new_file(
  Tahr.NFSv3.Types.Sattr3.t(),
  <<_::64>> | nil,
  Tahr.NFSv3.Types.Nfstime3.t()
) ::
  file_node()

A new regular-file node, with sattr applied.

new_symlink(target, now)

@spec new_symlink(binary(), Tahr.NFSv3.Types.Nfstime3.t()) :: file_node()

A new symlink node pointing at target.

now()

@spec now() :: Tahr.NFSv3.Types.Nfstime3.t()

The current wall-clock time as an nfstime3.

programs()

@spec programs() :: Tahr.RPC.Dispatcher.programs()

The program registry that serves this backend: NFSv3 (100003) and MOUNT v3 (100005) wired to the in-memory backends. Pass it to Tahr.RPC.Server as :programs.

reset()

@spec reset() :: :ok

Reset the filesystem to its freshly-seeded state.

root_handle()

@spec root_handle() :: binary()

The file handle of the root directory.

size_of(arg1)

@spec size_of(file_node()) :: non_neg_integer()

The byte size NFS attributes report for node.

start()

@spec start() :: :ok

Start the agent unless it is already running.

start_link(opts \\ [])

@spec start_link(keyword()) :: Agent.on_start()

Start the filesystem agent.

update(fun)

@spec update((state() -> {reply, state()})) :: reply when reply: var

Read and update the agent's state in one serialised step.

verf_for(map)

@spec verf_for(file_node()) :: <<_::64>>

The cookieverf3 for a directory. Derived from its mtime, so any mutation invalidates outstanding READDIR paginations.

wcc(before, fileid, tree)

Pair a pre-operation WccAttr with the post-operation attributes of fileid as found in tree (nil if the operation removed it).

wcc_pre(node)

@spec wcc_pre(file_node()) :: Tahr.NFSv3.Types.WccAttr.t()

Capture the pre-operation half of a wcc_data for node.

writeverf()

@spec writeverf() :: <<_::64>>

The per-boot writeverf3 this server instance reports.