You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a new storage.FS driver named kvfs to opencloud-eu/reva under pkg/storage/fs/kvfs/. The driver stores authoritative file metadata in NATS JetStream KV buckets and blobs in any S3-compatible object store. It is a peer to decomposed / decomposeds3 / posix, not a replacement.
Companion follow-up PR to opencloud-eu/opencloud would wire the driver into services/storage-users and services/storage-system.
2. Problem
Existing drivers all require some form of authoritative state on a filesystem accessible to every storage pod (xattrs, sidecar files, or POSIX semantics). This forces shared filesystems (RWX PVCs, NFS, CephFS) for any multi-replica deployment, which is operationally expensive and a known source of pain.
"In case of decomposed s3 we could store the upload session information in nats and directly upload the blob to an s3 ... getting rid of the RWM volume for uploads."
kvfs generalises that idea to all metadata, not only upload sessions. The result is genuinely stateless storage pods (no PVCs, only emptyDir), with HA delegated to the NATS cluster (R=3) and the S3 backend.
Data model: seven NATS KV buckets (nodes, children, spaces, trash, versions, uploads, locks), msgpack-encoded values, prefix-namespaced so multiple instances share a NATS cluster. Blobs live at s3://<bucket>/<spaceID>/<pathified-blobID>.
Concurrency: optimistic CAS on NATS KV revisions. All mutations bounded by defaultMaxCASRetries = 10 with exponential backoff and jitter. PutChildren does merge-on-conflict for create races. Tree-size propagation is best-effort with a Prometheus drift counter.
Uploads: two paths, both committing through the same commitFileNode CAS path. Simple PUT streams to S3 with inline SHA-1 hashing. TUS multipart maps each chunk to an S3 part with session state in the uploads bucket.
Garbage collection: distributed lock in the locks bucket, per-space reference set, blob-age guard before deletion, dry-run mode. Also handles expired upload session cleanup (S3 multipart abort).
Observability: 12 Prometheus collectors covering CAS retries, KV / blob latency, in-flight uploads, tree-size drift, and GC outcomes. Eight standard reva storage events emitted (FileUploaded, ItemMoved, etc.).
storage.FS coverage: every method implemented except CreateReference (symlinks) and DenyGrant, both of which return NotSupported. Detailed method-by-method table in the README.
4. Implementation status
Code: ~4400 LOC of driver, ~5400 LOC of tests (169 tests, stdlib testing).
Production deployment: running at sekops on a 3-node bare-metal Kubernetes cluster (NATS R=3, Minio 3-node replicated, opencloud + collaboration at 2 replicas with PDB and topology spread). 2 months production runtime as of 2026-05-09.
Test coverage: full integration suite at 133/133, including LDAP, concurrency / CAS contention, backend state inspection, and storage-system tests. Validated end-to-end with real desktop sync clients.
Rebased on current upstream: the branch is rebased onto opencloud-eu/opencloud@main and includes the recent AddFavorite / RemoveFavorite to AddLabel / RemoveLabel migration.
5. Decisions needed
Five points where we want maintainer guidance before opening the PR:
Niche: opencloud-eu/opencloud#2498 describes pruning to decomposed / decomposeds3 / posix. Is kvfs distinct enough to merit a 4th driver? An alternative would be making decomposeds3's metadata backend pluggable so NATS KV becomes a swap-in, at the cost of a larger refactor.
Test framework: stdlib testing is what we have. pkg/storage/pkg/decomposedfs/... uses Ginkgo / Gomega. Is conversion required for parity, or acceptable as-is?
PR shape: single PR (driver, loader registration, changelog entry, Woodpecker workflow) or split (driver, then CI follow-up)?
1. Proposal
Add a new
storage.FSdriver namedkvfstoopencloud-eu/revaunderpkg/storage/fs/kvfs/. The driver stores authoritative file metadata in NATS JetStream KV buckets and blobs in any S3-compatible object store. It is a peer todecomposed/decomposeds3/posix, not a replacement.Companion follow-up PR to
opencloud-eu/opencloudwould wire the driver intoservices/storage-usersandservices/storage-system.2. Problem
Existing drivers all require some form of authoritative state on a filesystem accessible to every storage pod (xattrs, sidecar files, or POSIX semantics). This forces shared filesystems (RWX PVCs, NFS, CephFS) for any multi-replica deployment, which is operationally expensive and a known source of pain.
The thesis matches opencloud-eu/opencloud#1314:
kvfsgeneralises that idea to all metadata, not only upload sessions. The result is genuinely stateless storage pods (no PVCs, onlyemptyDir), with HA delegated to the NATS cluster (R=3) and the S3 backend.Related signals: opencloud-eu/opencloud#918, opencloud-eu/opencloud#1596.
3. Architecture
Compressed summary. Full design doc with feature-parity table is at vendor/.../kvfs/README.md in our fork.
nodes,children,spaces,trash,versions,uploads,locks), msgpack-encoded values, prefix-namespaced so multiple instances share a NATS cluster. Blobs live ats3://<bucket>/<spaceID>/<pathified-blobID>.defaultMaxCASRetries = 10with exponential backoff and jitter.PutChildrendoes merge-on-conflict for create races. Tree-size propagation is best-effort with a Prometheus drift counter.commitFileNodeCAS path. Simple PUT streams to S3 with inline SHA-1 hashing. TUS multipart maps each chunk to an S3 part with session state in theuploadsbucket.locksbucket, per-space reference set, blob-age guard before deletion, dry-run mode. Also handles expired upload session cleanup (S3 multipart abort).FileUploaded,ItemMoved, etc.).storage.FScoverage: every method implemented exceptCreateReference(symlinks) andDenyGrant, both of which returnNotSupported. Detailed method-by-method table in the README.4. Implementation status
testing).feat/kvfs-driver. It would move to a fresh fork ofopencloud-eu/reva(sekops-ch/reva) for the actual PR.opencloud-eu/opencloud@mainand includes the recentAddFavorite/RemoveFavoritetoAddLabel/RemoveLabelmigration.5. Decisions needed
Five points where we want maintainer guidance before opening the PR:
decomposed/decomposeds3/posix. Iskvfsdistinct enough to merit a 4th driver? An alternative would be makingdecomposeds3's metadata backend pluggable so NATS KV becomes a swap-in, at the cost of a larger refactor.opencloud-eu/revanow, or wait for the reva-into-opencloud repo merge described in add grants to list-spaces cs3org/reva#2498?testingis what we have.pkg/storage/pkg/decomposedfs/...uses Ginkgo / Gomega. Is conversion required for parity, or acceptable as-is?kvfsland first, or does the dataprovider-as-service redesign reshape the driver surface enough that we should wait?Happy to walk through the design synchronously or async, whichever fits your review style. /cc @aduffeck @butonic