Strata: storage you choose
Oxygen Strata lets a repository's data live wherever its owner chooses: this disk, a shared directory, or a bucket in your own Amazon S3, Google Cloud Storage or Azure account, in your region, under your keys. Any of them can be a remote, and a repository can also be kept on one directly.
flowchart TB
subgraph Code[One Store interface]
T["has, get, get_range, put_new,<br/>list, delete<br/>read_ref, write_ref (compare-and-swap)"]
end
Code --> L[(Local directory)]
Code --> M[(Memory, for tests)]
Code --> S3[(Amazon S3)]
Code --> GCS[(Google Cloud Storage)]
Code --> AZ[(Azure Blob Storage)]
A store has two halves:
- Objects are written once and never change. Any store can hold them safely.
- References are the one record that changes. It is updated only by compare-and-swap on a version the store issues (an ETag on S3, a generation on GCS), so two writers can share a bucket with no lock server.
A bucket as a remote
oxy remote add cloud s3://my-bucket/repos/project --profile work # or gs://, az://, dir://
oxy remote check cloud # reachable, what it holds, and that it behaves correctly
oxy push cloud
oxy clone s3://my-bucket/repos/project?profile=work
sequenceDiagram
participant You
participant Mirror as Local mirror of the bucket
participant Bucket
You->>Mirror: bring level: read refs, import new bundles
You->>Mirror: run the same checks a hub would (policy, fast-forward)
You->>Bucket: upload one bundle for this push
You->>Bucket: write refs, if still at the version read
alt someone pushed first
Bucket-->>You: conflict
You->>Mirror: read again, merge, try again
end
A bucket cannot run code, so each client does what a hub would: it keeps a mirror, checks policy and attestations itself, and only then moves the bucket's refs record.
A repository kept on a store
oxy init project --store s3://my-bucket/repos/project?region=eu-west-2
oxy config storage.cache 10G # the local cache's size (2 GiB by default)
--store is new on main and arrives with the next release. Here the bucket is not a copy: it is the repository. The objects and the operation head live in the bucket, and this machine keeps a cache.
flowchart LR
oxy[oxy] --> Cache["Caching store<br/>.oxy/cache"]
Cache -->|"reads: kept on first use<br/>writes: to the bucket first"| Bucket[(Your bucket)]
oxy -->|"operation head:<br/>always the bucket's, by compare-and-swap"| Bucket
- Reads are kept in
.oxy/cache; writes go to the bucket first, then the cache. The bucket always holds everything, so the cache can be deleted at any time. - The cache stays within
storage.cache, removing what was used least recently. - The operation head is the bucket's own record, moved by compare-and-swap, so two machines can share one repository.
Measured against real buckets with small commits: about half a second to a second per commit, and about half a second to open with an empty cache.
On OxygenHub
A repository on OxygenHub can live in its owner's bucket too. The New repository form has a Storage section; the bucket is checked before anything is made, and the hub keeps the credentials sealed. An organisation can require every new repository to live in its own buckets, so its data stays where those buckets are.
The design record is docs/stores.md, and the user guide is docs/strata.md.