What this is about
A file model has two parts: the record in the database and the content in the file storage. See What a file model is.
The database has a transaction, the file storage does not. CDMS therefore lets the file storage follow the database: while the request runs, every change to the content is only prepared. It takes effect once the database has committed the record. If the request fails before that, CDMS throws away what it prepared.
Preparing and taking effect
Every change to content has two steps:
| Step | when | what happens | visible? |
|---|---|---|---|
| Prepare | while the request runs | Uploaded content is placed under a private name next to its final place. For a rollback, the requested version is copied there. A deletion is only noted. fileSize, mimeType and fileVersion are known from here on. | no |
| Take effect | after the commit | For audited models the previous content is kept as a version, then the prepared content is moved into place with a single rename. A noted deletion removes the content and its versions. | yes |
The record needs fileSize, mimeType and fileVersion when it is saved. CDMS therefore reads them from the prepared content, which is byte for byte the content that becomes current later.
How an upload runs
sequenceDiagram
participant C as Client
participant D as CDMS
participant F as File storage
participant DB as Database
C->>D: POST /fileasset/create/upload (record + file)
D->>D: check role
D->>F: prepare content (private name, not visible yet)
D->>D: before hooks, validation
D->>DB: save record, flush
D->>DB: read back
D->>DB: COMMIT
D->>F: make content take effect (rename)
D-->>C: 200 with the record
The rename happens in one step. So anyone downloading the file at that moment always gets a complete content, never a half-written one.
Where it can fail
When: All steps succeed.
-
1CDMS→File storageprepares the content
-
2CDMS→Databasesaves the record, commit
-
3CDMS→File storagemakes the content take effect
Result: Record and content match.
When: The file storage cannot take the content over, for example because the volume is full.
-
1CDMS→File storagepreparing fails
-
2CDMS→Client500
file-not-saved, the database is rolled back
Result: Nothing is saved, neither record nor content.
When: The content is prepared, then something else fails: validation (422), a child's role (403), a hook, a database rule.
-
1CDMS→File storageprepares the content
-
2CDMSa later step fails
-
3CDMS→Databaserolls back
-
4CDMS→File storagethrows the prepared content away
-
5CDMS→Clienterror response
Result: Database and file storage are unchanged. When replacing, the previous content is still current.
When: The record is committed, but the rename in the file storage fails. This is very rare, because all that is left is a rename within one directory.
-
1CDMS→Databasecommit
-
2CDMS→File storagerename fails
-
3CDMS→Client500
file-not-saved
Result: The record is saved, the content is still the old one. The prepared content stays in the storage, it is the only copy. Sending the request again brings both back together.
Decision table
| Operation | Request successful? | State afterwards |
|---|---|---|
| create with file | yes | record and content present |
| create with file | no | neither record nor content |
| replace content | yes | new content current, for audited models the old one as a version |
| replace content | no | record and previous content unchanged |
| delete | yes | record and content including versions gone |
| delete | no | record, content and versions stay |
| any of the three | commit yes, rename or delete in the storage no | error response; the record is new, the storage still old |
For deleting see Deleting file models, for restoring Rollback for files. Both follow the same pattern.
Concurrent uploads
Two requests that write new content to the same record at the same time would rename one after the other in the storage, and the later content would silently win. That is why CDMS locks the record before it prepares the content. The second request gets 409 and has not placed anything in the storage yet. See Concurrent changes.
How to deal with it
What comes next
- The bracket around the database: One request, one transaction
- Uploading in detail: Uploading
- Storage layout: Storage layout and tenant isolation in storage