Skip to content

Unify filesystem storage accounting - #3728

Draft
kmatasfp wants to merge 35 commits into
mainfrom
kaurmatas/gol-416-unify-filesystem-storage-accounting
Draft

Unify filesystem storage accounting#3728
kmatasfp wants to merge 35 commits into
mainfrom
kaurmatas/gol-416-unify-filesystem-storage-accounting

Conversation

@kmatasfp

@kmatasfp kmatasfp commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Implements GOL-416.

Summary

  • replace logical filesystem byte deltas, storage permits, and custom hard-link accounting with one AgentFilesystems / AgentFilesystem lifecycle
  • use managed XFS project quotas as the authority for per-agent allocated-byte usage, filesystem-object usage, and limits, while using fresh statvfs observations for physical node capacity
  • route WASI P2 and P3 direct operations and asynchronous streams through shared lifecycle admission and failure classification
  • move filesystem creation, initial-file materialization, replay settlement, and cleanup under the AgentFilesystem lifecycle
  • meter authoritative allocated-byte observations over the same ConcurrentAgentPermit window as linear memory

Behavior

AgentFilesystem now owns each resident agent's ephemeral filesystem across creation, initial-file materialization, oplog replay, execution, and unload. Startup removes and verifies stale local resources before creating an unmanaged directory or managed XFS project. Replay-owned filesystem effects settle before startup publishes the runtime. Unload seals new filesystem work, tears down runtime resources, deletes the filesystem, and verifies cleanup before publishing Unloaded.

Managed XFS validates project-quota support, project identity and inheritance, reflink support, permissions, and exclusive ownership of the managed root. Project observations supply authoritative allocated bytes and filesystem-object counts. The executor installs the public allocated-byte limit together with an internally derived object limit. Read-only and read-write initial files both count toward quota and billing. Reducing either limit below current usage suspends and unloads the agent until reconstruction fits the current policy.

Physical capacity remains separate from project usage. The executor obtains available bytes and filesystem objects from fresh statvfs observations. On physical exhaustion it may unload only eligible loaded-idle agents, and recognizes reclaimed capacity only after deletion and another observation. Agent quota exhaustion never triggers pressure eviction.

P2 and P3 preserve errno, completed prefixes, and effect evidence until classification. Retries are bounded and apply only to a proven unwritten suffix or an operation whose postcondition proves no effect. Unknown effects and terminal infrastructure failures invalidate the disposable local runtime while leaving durable work available for reconstruction. XFS reports ENOSPC for both project-quota and physical exhaustion, so classification uses fresh quota, capacity, and backend-health observations instead of errno alone.

Storage billing integrates ordered absolute allocated_bytes observations prospectively. Storage and memory start and stop together at one monotonic timestamp while the worker owns its concurrent-agent permit. Active execution, host calls, host I/O waits, and replay are billable while retaining the permit. Loaded-idle, unloaded, and durably sleeping workers accrue nothing. Unload and filesystem deletion happen outside the billing window.

The superseded logical accounting path has been removed across oplog types, protobuf, WIT, CLI schemas, SDK bindings, documentation, and the built-in OTLP exporter. ConcurrentAgentPermit remains because it defines the execution and billing window; it is unrelated to the removed filesystem byte permits.

@kmatasfp
kmatasfp requested a review from a team August 7, 2026 23:04
@netlify

netlify Bot commented Aug 7, 2026

Copy link
Copy Markdown

Deploy Preview for golemcloud canceled.

Name Link
🔨 Latest commit 014562b
🔍 Latest deploy log https://app.netlify.com/projects/golemcloud/deploys/6a86b73648fe3e000810f43f

@vigoo

vigoo commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

You need to rebuild the built-in plugins (cargo make build-plugins) because of the WIT change

@vigoo

vigoo commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Both filesystem APIs (p2 and p3) expose hard-link creation without charging another copy (link_at), which is correct because both names refer to one inode, but unlink releases the file's entire size after any successful unlink without tracking reference counts.

@vigoo

vigoo commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

One more review finding to check:

Read-write provisioning writes directly to the destination:

  • Cache hits use tokio::fs::copy
  • Cache misses File::create the final path and stream into it

Either operation can fail after leaving a partial regular file. On a revision-update retry, update_filesystem accepts any existing regular file as NoChanges, without validating its expected size or content.

The resulting sequence is:

  1. A revision update reserves N bytes for a new read-write file.
  2. The download writes K < N bytes and fails.
  3. The reservation is rolled back because no successful growth was reported.
  4. The partial K-byte destination remains.
  5. Retry sees a regular file and reports NoChanges.
  6. The update can succeed with those K bytes absent from quota, capacity, billing, and recovery accounting.

Required fix: write/copy into a sibling temporary file, delete it on failure, and atomically rename it only after complete success. Do not accept an arbitrary pre-existing regular destination without validating that it represents a completed provisioning operation.

@kmatasfp

kmatasfp commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

All of the above you mentioned @vigoo plus some other things I ran into myself reviewing this are the reason I changed the direction and abandoned the golem internal quota/disk usage tracking/management and now building out a proper FS support I mentioned during the standup. GOL-416 issue description contains details of the new approach

@kmatasfp
kmatasfp marked this pull request as draft August 13, 2026 03:42
kmatasfp and others added 14 commits August 13, 2026 12:09
The in-process reservation, oplog delta, and storage-permit model is superseded by backend-authoritative filesystem usage and capacity accounting planned under GOL-416.
Coordinate filesystem effects during shutdown and retry cleanup of unmanaged agent storage.

Refs GOL-429
Use XFS project quotas for authoritative per-agent usage and lifecycle cleanup. Fail closed when the managed backend cannot guarantee isolation or accounting.
Route initial file creation and revision updates through the owned agent filesystem so storage accounting, immutable-path policy, and cleanup share one authoritative lifecycle.
Make managed XFS project quotas authoritative for byte and object limits across initial files and P2/P3 mutations. Suspend and reconstruct workers when downgraded limits no longer fit.
Integrate managed-XFS allocated bytes over the concurrent-agent permit window and settle storage atomically with memory. Keep control-plane limit updates serialized across billing transitions.
…fy-filesystem-storage-accounting

# Conflicts:
#	golem-common/src/model/oplog/protobuf.rs
#	golem-worker-executor-test-utils/src/lib.rs
#	golem-worker-executor/src/durable_host/mod.rs
#	golem-worker-executor/src/model/public_oplog/mod.rs
#	golem-worker-executor/src/model/public_oplog/wit.rs
#	golem-worker-executor/tests/lib.rs
#	plugins/otlp-exporter.wasm
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown

📖 Docs preview: https://docs-q2xjslwb4-golem-cloud.vercel.app

Built from commit 014562b588675856d0edaed8b40ee6f2d1499d81 by docs.yaml.

@blacksmith-sh

This comment has been minimized.

Keep malformed durable invocations on the current worker generation, ignore stale status wakeups before permit acquisition, and treat startup suspension as a successful parked state.
Move provisioning, quota, capacity, and cleanup behind backend interfaces. Preserve lifecycle ownership across cancellation and fallback cleanup.

Refs GOL-416
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.

2 participants