Skip to content

A handle is where a store is made, not only where it is found - #153

Open
torstei wants to merge 1 commit into
mainfrom
feature/create-in-the-forest
Open

A handle is where a store is made, not only where it is found#153
torstei wants to merge 1 commit into
mainfrom
feature/create-in-the-forest

Conversation

@torstei

@torstei torstei commented Aug 31, 2026

Copy link
Copy Markdown
Owner

timberfs create nginx made a store in whatever directory it was run from,
which timberfs query nginx then could not find — the two halves of the same
name disagreed.

A bare token (no /) is now a handle for a destination too: create,
append --into and import --into resolve one exactly as reading does, and
where nothing holds that handle yet the store is made in the forest, at
<forest>/<handle>/<handle>.log — the layout every intake already writes.

$ cd /some/scratch/dir
$ timberfs create --index nginx
timberfs: created /var/log/timberfs/nginx/nginx.log (indexed) with manifest …
$ cd / && echo 'line' | timberfs append --into nginx
$ timberfs query nginx          # the same store, from anywhere

append --into had the same split and gets the same rule: had only create
learned the forest, the two commands would have disagreed about what nginx
means, and append would have gone on creating shadow stores in the cwd.

Refusals, not a fallback

With no forest declared, or with several, a bare destination is refused
and says which:

Error: `nginx` is a handle and no forest is declared to create it in
(declarations live in /etc/timberfs/forests.d) — `timberfs forest create
/var/log/timberfs` declares one, or write the path out: ./nginx

Resolving it to the working directory is the answer that reads as success and
leaves a store no handle finds. Only the directory handle is matched —
never a declared name or an id prefix, since either can name several stores and
a write destination may not be a guess.

The same bug from the other side

is_existing_store no longer counts a directory. <forest>/nginx is the
ordinary shape of a store, so from inside the forest root the token nginx
meant that directory. Measured on the current build, before the fix:

  • query nginx there failed with no index file ./nginx.rings — there and
    nowhere else;
  • create nginx wrote a flat nginx.trunk/nginx.rings beside the nested
    store, after which the handle matched both and query nginx was ambiguous
    from everywhere.

A plain file still counts, so a path that is not a store keeps producing the
error it always did instead of turning into a handle.

Tests

Six new unit tests in src/forest.rs (destination in the forest, .log
stripped once, an existing handle is the destination itself, paths still pass
through, no-forest/several-forests refused, an ambiguous handle refused, and a
directory is not a store) — 346 pass.

One new VM test, forest: a bare destination is created in the forest, not the cwd: it is the shipped default.conf that decides, which the env-var unit
tests cannot exercise. It creates from a foreign cwd, appends to the same
handle from /, reads it back, re-runs create --if-not-exists, does all of
it again from inside /var/log/timberfs (asserting no flat store appears
beside the nested one), and declares a second forest to check the refusal.

Docs

timberfs(1) (a new DEST paragraph under create, and the destination
half of the rule in FORESTS), the three --into/DEST help strings,
README.md, and docs/concepts.md (forest, handle).

`timberfs create nginx` made a store in whatever directory it was run from,
which `timberfs query nginx` then could not find — the two halves of the same
name disagreed. A bare token (no `/`) is a HANDLE for a destination too now:
`create`, `append --into` and `import --into` resolve one exactly as reading
does, and where nothing holds that handle yet the store is made in the forest,
at <forest>/<handle>/<handle>.log — the layout every intake already writes.

So `create nginx` then `query nginx` are one store whichever directory either
ran in, and a provisioning unit re-running `create --if-not-exists nginx` from
a different working directory lands on the store it made last boot instead of
making a second one beside it. `append --into nginx` had the same split and
gets the same rule, or the two commands would disagree about what `nginx`
means the moment create learned the forest.

With NO forest declared, or with several, a bare destination is refused and
says which. Resolving it to the working directory is the answer that reads as
success and leaves a store no handle finds. Only the directory handle is
matched — never a declared name or an id prefix, since either can name several
stores and a write destination may not be a guess.

`is_existing_store` no longer counts a DIRECTORY, which is the same bug seen
from the other side: <forest>/nginx is the ordinary shape of a store, so from
inside the forest root the token `nginx` meant that directory. Measured before
the fix: `query nginx` there failed with "no index file ./nginx.rings" — there
and nowhere else — and `create nginx` wrote a flat nginx.trunk/.rings beside
the nested store, after which the handle matched both and resolved to neither.
A plain file still counts, so a path that is not a store keeps producing the
error it always did rather than turning into a handle.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant