CodamAIDocs
Themafertig

Dateien und Transaktion

Dateiinhalte werden während der Anfrage nur vorbereitet und erst nach dem Commit wirksam. Scheitert die Anfrage, bleibt der Dateispeicher, wie er war.

Ausprägungen
ErfolgFehler beim Vorbereiten der DateiFehler nach dem VorbereitenFehler nach dem CommitLöschen

Worum es geht

Ein Datei-Modell hat zwei Teile: den Datensatz in der Datenbank und den Inhalt im Dateispeicher. Siehe Was ein Datei-Modell ist.

Die Datenbank hat eine Transaktion, der Dateispeicher nicht. CDMS lässt den Dateispeicher deshalb der Datenbank folgen: Während die Anfrage läuft, wird jede Änderung am Inhalt nur vorbereitet. Wirksam wird sie erst, wenn die Datenbank den Datensatz festgeschrieben hat (Commit). Scheitert die Anfrage vorher, wirft CDMS das Vorbereitete weg.

Vorbereiten und wirksam werden

Jede Änderung am Inhalt hat zwei Schritte:

Schrittwannwas passiertsichtbar?
Vorbereitenwährend der AnfrageEin hochgeladener Inhalt wird unter einem privaten Namen neben seinen Platz gelegt. Für einen Rollback wird die gewünschte Version dorthin kopiert. Ein Löschen wird nur vorgemerkt. fileSize, mimeType und fileVersion stehen danach schon fest.nein
Wirksam werdennach dem CommitDer bisherige Inhalt wird bei auditierten Modellen als Version aufbewahrt, dann wird der vorbereitete Inhalt mit einem einzigen Umbenennen an seinen Platz gehoben. Ein vorgemerktes Löschen entfernt Inhalt und Versionen.ja

Der Datensatz braucht fileSize, mimeType und fileVersion schon beim Speichern. Deshalb liest CDMS sie aus dem vorbereiteten Inhalt, der Byte für Byte dem entspricht, der später aktuell wird.

Der Ablauf eines Uploads

sequenceDiagram
    participant C as Client
    participant D as CDMS
    participant F as Dateispeicher
    participant DB as Datenbank
    C->>D: POST /fileasset/create/upload (Datensatz + Datei)
    D->>D: Rolle prüfen
    D->>F: Inhalt vorbereiten (privater Name, noch nicht sichtbar)
    D->>D: Before-Hooks, Validierung
    D->>DB: Datensatz speichern, flush
    D->>DB: zurücklesen
    D->>DB: COMMIT
    D->>F: Inhalt wirksam machen (umbenennen)
    D-->>C: 200 mit dem Datensatz

Das Umbenennen passiert in einem Schritt. Wer die Datei gerade herunterlädt, bekommt deshalb immer einen vollständigen Inhalt, nie einen halb geschriebenen.

Wo es scheitern kann

Ein Upload mit Fehler

Wann: Alle Schritte gelingen.

  1. 1
    CDMS→File storage
    bereitet den Inhalt vor
  2. 2
    CDMS→Database
    speichert den Datensatz, Commit
  3. 3
    CDMS→File storage
    macht den Inhalt wirksam

Ergebnis: Datensatz und Inhalt passen zusammen.

Wann: Der Dateispeicher kann den Inhalt nicht übernehmen, etwa weil das Volume voll ist.

  1. 1
    CDMS→File storage
    Vorbereiten scheitert
  2. 2
    CDMS→Client
    500 file-not-saved, die Datenbank wird zurückgerollt

Ergebnis: Nichts ist gespeichert, weder Datensatz noch Inhalt.

Wann: Der Inhalt ist vorbereitet, dann scheitert etwas anderes: Validierung (422), Rolle eines Kindes (403), ein Hook, eine Datenbankregel.

  1. 1
    CDMS→File storage
    bereitet den Inhalt vor
  2. 2
    CDMS
    ein späterer Schritt scheitert
  3. 3
    CDMS→Database
    rollt zurück
  4. 4
    CDMS→File storage
    wirft den vorbereiteten Inhalt weg
  5. 5
    CDMS→Client
    Fehlerantwort

Ergebnis: Datenbank und Dateispeicher sind unverändert. Beim Ersetzen ist der bisherige Inhalt weiter aktuell.

Wann: Der Datensatz ist festgeschrieben, aber das Umbenennen im Dateispeicher scheitert. Das ist sehr selten, weil nur noch ein Umbenennen im selben Verzeichnis fehlt.

  1. 1
    CDMS→Database
    Commit
  2. 2
    CDMS→File storage
    Umbenennen scheitert
  3. 3
    CDMS→Client
    500 file-not-saved

Ergebnis: Der Datensatz ist gespeichert, der Inhalt ist noch der alte. Der vorbereitete Inhalt bleibt im Speicher liegen, er ist die einzige Kopie. Die Anfrage erneut zu schicken, bringt beides wieder zusammen.

Entscheidungstabelle

Datenbank und Dateispeicher nach einer Anfrage
OperationAnfrage erfolgreich?Stand danach
Anlegen mit DateijaDatensatz und Inhalt vorhanden
Anlegen mit Dateineinweder Datensatz noch Inhalt
Inhalt ersetzenjaneuer Inhalt aktuell, bei auditierten Modellen der alte als Version
Inhalt ersetzenneinDatensatz und bisheriger Inhalt unverändert
LöschenjaDatensatz und Inhalt samt Versionen weg
LöschenneinDatensatz, Inhalt und Versionen bleiben
eine der dreiCommit ja, Umbenennen oder Löschen im Speicher neinFehlerantwort; der Datensatz ist neu, der Speicher noch alt

Zum Löschen siehe Datei-Modelle löschen, zum Zurücksetzen Rollback bei Dateien. Beide folgen demselben Muster.

Gleichzeitige Uploads

Zwei Anfragen, die gleichzeitig denselben Datensatz mit neuem Inhalt beschreiben, würden im Speicher nacheinander umbenennen, und der spätere Inhalt würde still gewinnen. Deshalb sperrt CDMS den Datensatz, bevor es den Inhalt vorbereitet. Die zweite Anfrage bekommt 409 und hat noch nichts in den Speicher gelegt. Siehe Gleichzeitige Änderungen.

Wie du damit umgehst

Wie es weitergeht

Quellen im Code und in der Wissensdatenbank
  • CDMS/cdms-system-layer – AbstractLayer.recursivePrepare (stageFile vor Hooks, Validierung und Speichern; lockForUpdate), recursivePatch (Dateizweig), recursiveDelete (stageDeletion), rollbackFileContent (stageRollback), followTransaction (onCompletion)
  • CDMS/cdms-localfs-storage – LocalFSFileController.stageFile, stageDeletion, stageRollback, Staged.publish/discard; docs/adr/ADR-016-content-becomes-current-by-atomic-rename.md, ADR-021-content-changes-take-effect-after-the-commit.md
  • commons-persistence – DatabaseRequestContext.onCompletion, commitThreadTransactions, markRollbackOnly, closeEntityManager
  • CDMS/cdms-persistence-database – AbstractDatabasePersistence.rollback (discardCompletions)
  • CDMS/cdms-integrationtest – AbstractFileRollbackTest (aRefusedDeleteKeepsTheContentAndItsHistory, aRefusedReplaceKeepsTheCurrentContent, aRefusedRollbackKeepsTheCurrentContent, aRefusedCreateLeavesNoUploadBehind)
  • documentation/30-daten-und-persistenz/05-dateien-und-storage.md (Konsistenz zwischen Blob und Metadaten)
Suchen