diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-12 00:17:32 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-12 00:17:32 +0200 |
| commit | 14911aae21ec4975f7a805b91e3c4867cb41974b (patch) | |
| tree | 8c00230a88053905fd77938f3a9539efeb4c3094 /docs | |
| parent | f6f107e02c7a4aa7326c9a82310a239327d81ed6 (diff) | |
| download | meshbay-14911aae21ec4975f7a805b91e3c4867cb41974b.tar.gz | |
feat: let the operator pause and resume a root's indexing (MNP 6.2)
A whole-root walk now checks its root before every file: removed or
ejected, it stops instead of reading the drive to the end; paused, it
finishes from the hash cache alone. A paused root is not watched, not
swept by reconcile and survives a restart (roster), its indexed files
stay served. Resume runs the reconcile sweep over the root, so entries
and their enrichment are kept.
Signed root_pause / root_resume over MNP, loopback routes, CLI
`root pause|resume`, a pause button on the indexing dock and
pause/resume in the roots table of Group settings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/MESHBAY_DESIGN.md | 35 | ||||
| -rw-r--r-- | docs/MESHBAY_HTTP_API.md | 2 | ||||
| -rw-r--r-- | docs/MESHBAY_NODE_PROTOCOL.md | 21 | ||||
| -rw-r--r-- | docs/USERGUIDE.md | 8 |
4 files changed, 55 insertions, 11 deletions
diff --git a/docs/MESHBAY_DESIGN.md b/docs/MESHBAY_DESIGN.md index 9c63c52..d0b5475 100644 --- a/docs/MESHBAY_DESIGN.md +++ b/docs/MESHBAY_DESIGN.md @@ -16,7 +16,7 @@ > them — it names the invariant that holds today, not the incident that produced > it. §13 is the register of those labels. > -> Wire versions at the time of writing: **MNP 6.1** (oldest peer accepted 4.0), +> Wire versions at the time of writing: **MNP 6.2** (oldest peer accepted 4.0), > **MHP 0.1**, packages **0.19.0**. The normative source for the wire format is > `MESHBAY_NODE_PROTOCOL.md`; this document states the design the protocol > serves, not its byte layout. @@ -1231,7 +1231,7 @@ from anything in the response. | `invite_link_create`, `invite_cancel` | the operator | | group key init and rotation | **local admin API or CLI only**; the node generates the key itself | | root add, root `writable`/`removable`, hosting a group, transfer limits | **local admin API or CLI only** (MNP 6.0) | -| root remove/eject/plug, `apps_enabled`, app directories | operator-signed | +| root remove/eject/plug/pause/resume, `apps_enabled`, app directories | operator-signed | | ~~`gek_bundle_store`~~ | **the message does not exist.** No member ever hands the node key material | `gek_bundle_store` was deleted rather than gated. The operator's X25519 public key @@ -1641,8 +1641,9 @@ A signed op proves that the operator's key signed, not that they meant it: in a browser that key is driven by code the hub serves (T3), and in the desktop application by a renderer that parses content from nodes. Either could otherwise have shared any folder on the machine, writable, from anywhere. The operator still -sees every root and its flags from any browser; removing, ejecting and plugging stay -signed ops, because they narrow what is shared or restore what already was. +sees every root and its flags from any browser; removing, ejecting, plugging, pausing +and resuming stay signed ops, because they narrow what is shared or restore what +already was. > **There is one answer to "may this member write", and it is the root.** A single > flag over the group cannot express "this library is published read-only and that @@ -1670,6 +1671,12 @@ states: - **`available`** — computed as `not ejected and is_live()`. This is what clients and the indexer see. +A third, **`paused`**, is the operator's alone and independent of both: the root is +readable and served, and its indexing is stopped (§6.3). Persisted in `roster.db` +beside `ejected`, for the same reason: a pause that a restart undid would start the +scan the operator stopped. Removing a root forgets its pause, so a directory added +back under the same name starts indexed. + The distinction matters: between clicking eject and physically unplugging, `is_live()` is still true, and without `ejected` the availability sweep would immediately flip the root back. @@ -1755,6 +1762,24 @@ reason to show progress. `index_progress` is deliberately **not** sealed: counters only, every 2 s. +**A walk looks at its root before every file.** A root removed from the set or +ejected while it is walked is not read to the end: its entries are dropped, or +frozen on a drive that is leaving. The walk reads the root from the current set, +not the object it started with, because a reload replaces every root. + +**A pause outlasts the walk it stops.** Reconcile indexes every file the index +lacks, so a walk that was merely cancelled is redone at the next tick. A paused +root is therefore not watched, not swept by reconcile, and not hashed by any walk: + +- **A walk that meets a pause finishes from the hash cache alone.** What the node + already hashed stays listed; nothing new is read. Stopping dead is not enough, + because the index is rebuilt at every start and a rescan drops the root's + entries before it walks — either would leave a paused root half empty. +- **Resuming runs the reconcile sweep over that root, never a scan.** A scan + replaces every entry it meets, and with them what the enrichment passes put + there; the sweep indexes only what the index lacks. The request returns once + the walk is queued, and the progress band shows it. + ### 6.4 Uploads Five protections, and they are the substance: @@ -1989,7 +2014,7 @@ before its key is linked or a group exists. ``` meshbay-node status meshbay-node group list|add|remove -meshbay-node root list|add|remove|set|eject|plug +meshbay-node root list|add|remove|set|eject|plug|pause|resume meshbay-node gek init|rotate meshbay-node operator pair meshbay-node member list|invite [--link]|cancel|revoke|unpin diff --git a/docs/MESHBAY_HTTP_API.md b/docs/MESHBAY_HTTP_API.md index 1bcb55d..73d079d 100644 --- a/docs/MESHBAY_HTTP_API.md +++ b/docs/MESHBAY_HTTP_API.md @@ -229,6 +229,8 @@ draws a new one at each start and deletes the file when it stops. | PATCH | `/api/groups/{group_id}/roots/{root_name}` | Make a folder writable or removable, or not. | | PUT | `/api/groups/{group_id}/roots/{root_name}/eject` | Eject a removable folder so its disk can be unplugged. | | PUT | `/api/groups/{group_id}/roots/{root_name}/plug` | Bring an ejected folder back. | +| PUT | `/api/groups/{group_id}/roots/{root_name}/pause` | Stop indexing a folder. | +| PUT | `/api/groups/{group_id}/roots/{root_name}/resume` | Index a paused folder again, from where it stopped. | | DELETE | `/api/groups/{group_id}/roots/{root_name}` | Remove a folder from a group. | | GET | `/api/groups/{group_id}/index-status` | One group's indexing progress. | | GET | `/api/index-status` | Every group's indexing progress. | diff --git a/docs/MESHBAY_NODE_PROTOCOL.md b/docs/MESHBAY_NODE_PROTOCOL.md index 994c908..207d640 100644 --- a/docs/MESHBAY_NODE_PROTOCOL.md +++ b/docs/MESHBAY_NODE_PROTOCOL.md @@ -1168,6 +1168,7 @@ broadcast, every connected peer in the group learns the change without reconnect | `musicbrainz_enabled` | `enabled` | operator | `musicbrainz_enabled_ack{enabled}` | yes | | `root_remove` | the root name | operator | `root_remove_ack` | no | | `root_eject`, `root_plug` | the root name | operator | `root_eject_ack` / `root_plug_ack` | yes | +| `root_pause`, `root_resume` | the root name | operator | `root_pause_ack` / `root_resume_ack` | yes | | `app_directories` | `<app>:<dir>,<dir>,...` | operator | `app_directories_ack{app, dirs}` | yes | | `chat_directory` | the path | operator | `chat_directory_ack{path}` | yes | | `chat_link_preview` | `on\|off` | operator | `chat_link_preview_ack{enabled}` | yes | @@ -1189,7 +1190,8 @@ proves that the operator's key signed, not that the operator meant it: in a brow that key is driven by code the hub serves (T3), and in the desktop application by a renderer that parses content from nodes. Either could have shared any folder on the operator's machine, writable, from anywhere. What is left here narrows (`root_remove`, -`root_eject`) or restores what the operator already shared (`root_plug`). The +`root_eject`, `root_pause`) or restores what the operator already shared (`root_plug`, +`root_resume`). The operator still sees the table from any browser: it rides in `index_sync` and `index_delta`, which is also how a change made on the node's machine reaches every open page. @@ -1327,11 +1329,13 @@ folder just created, or one emptied, does not exist as far as the UI is concerne a member cannot tell "the drive is unplugged" from "it is all still there" — an unavailable root is listed, with its content frozen rather than hidden. -Each root is described as `{name, kind, available, writable, removable, ejected}` — and -never a path: a member is told what exists and whether it is readable, never where on -the operator's disk it lives. `roots` rides on `index_delta` as well as `index_sync`, +Each root is described as `{name, kind, available, writable, removable, ejected, +paused}` — and never a path: a member is told what exists and whether it is readable, +never where on the operator's disk it lives. `paused` is the operator having stopped +the root's indexing: its files are served as before, and nothing new is indexed until +it is resumed. `roots` rides on `index_delta` as well as `index_sync`, because a full index is only ever sent on request: without it, a root added, removed, -ejected or plugged would leave every connected client's directory table stale until +ejected, plugged or paused would leave every connected client's directory table stale until somebody reloaded the page, and the delta that tells them something changed would be the one message unable to say what. @@ -2138,6 +2142,7 @@ it back (§3.5). | `chat_link_preview` / `_ack` | C→N / N⇒C | signed | whether the node unfurls posted links | | `search_listed` / `_ack` | C→N / N⇒C | signed | whether members' cross-group Search lists this group | | `root_eject` / `_ack`, `root_plug` / `_ack` | C→N / N⇒C | signed | take a removable root offline, put it back | +| `root_pause` / `_ack`, `root_resume` / `_ack` | C→N / N⇒C | signed | stop a root's indexing, start it again from where it stopped (6.2) | | `apps_enabled` / `_ack` | C→N / N⇒C | signed | which group apps are shown | | `set_scan_settings` / `_ack` | C→N / N⇒C | signed | reconcile interval and debounce | | `tmdb_config` / `_ack` | C→N / N⇒C | signed | node-wide TMDB token and language | @@ -2182,7 +2187,7 @@ message: ## 13. Versioning and compatibility -MNP versions independently of the package version. Current: **`6.1`**; oldest peer +MNP versions independently of the package version. Current: **`6.2`**; oldest peer accepted: **`4.0`**. 4.0 is the floor: a member presents a short-lived node-audience token bound to one node @@ -2208,6 +2213,10 @@ script in its page either. 6.1 adds the signed `chat_purge` (§10.4), additively: a 6.0 node gives no answer, as for any unknown type, and nothing else changes. +6.2 adds the signed `root_pause` and `root_resume` (§10.4) and `paused` on each root of +the roots table, additively: a 6.1 node gives no answer to either message, and a client +that ignores `paused` shows a paused root as an ordinary one. + The two numbers are separate on purpose. `MNP_VERSION` says what this build speaks; `MNP_MIN_SUPPORTED` says what it will talk to, and moving the second is a decision about whether an older peer can still do anything useful: diff --git a/docs/USERGUIDE.md b/docs/USERGUIDE.md index 5649b30..42103d6 100644 --- a/docs/USERGUIDE.md +++ b/docs/USERGUIDE.md @@ -695,6 +695,13 @@ catalogued. Group → Settings has the re-check interval and how long the node waits after a file changes before indexing it. Members see indexing progress while it runs. +**Pausing.** Indexing a large drive takes hours. The pause button on the +indexing band, or **Pause indexing** beside the directory in Group → Settings, +stops it at the next file. The files already indexed stay visible to members. +Nothing else in that directory is indexed until you click **Resume indexing**, +not even a file a member uploads into it, and the pause survives a restart. +Resuming picks up where it stopped: files already indexed are not read again. + One thing that surprises people: **two identical files in one group are one entry**, because a file is identified by its content. A scan that reports ten files and indexes nine has not lost anything. @@ -1058,6 +1065,7 @@ meshbay-node reset erase all node state (destructive) meshbay-node group list|add|remove groups this node hosts meshbay-node root list|add|remove|set directories in a group meshbay-node root eject|plug removable drives +meshbay-node root pause|resume stop and restart a directory's indexing meshbay-node gek init|rotate the group's encryption key meshbay-node operator pair authorise a browser |