CodamAIDocs
Topicdone

Concurrent changes

There is no save, and normal models have no optimistic locking: the last change wins. Only file models detect a conflict.

Variants
normal model: last write winsPATCH instead of PUT makes conflicts smallerfile model: 409 on overlapping requestsclient decides create/update based on the id

What this is about

Two people open the same object, both change something, both save. What happens?

Last write wins

sequenceDiagram
    participant A as Anna (Client)
    participant C as CDMS
    participant B as Ben (Client)
    A->>C: reads customer (email = alt@…, phone = 111)
    B->>C: reads customer (email = alt@…, phone = 111)
    A->>C: PUT { email: anna@…, phone: 111 }
    C-->>A: 200
    B->>C: PUT { email: alt@…, phone: 222 }
    C-->>B: 200
    Note over C: email = alt@… (Anna's change is gone)<br/>phone = 222

Ben never saw Anna’s new email. His PUT describes the whole target state, so it also contains the old email. CDMS does not check whether the object changed since Ben read it, and it saves Ben’s version.

PATCH makes the conflict smaller

With PATCH, each person only sends what they changed. Then two people only overwrite each other if they change the same field.

Anna changes the email, Ben the phone
both with PUTboth with PATCH
Anna sendsemail and phoneonly email
Ben sendsemail and phoneonly phone
ResultAnna's email is lostboth changes stay

If both change the same field, the last request wins with PATCH too. See PUT or PATCH? The null trap

File models: 409 on overlapping requests

A file model has an internal system field _version, a counter. The client does not see it and does not send it. CDMS uses it to detect two requests that write the same object at the same time:

Two concurrent uploads into the same file object
  1. 1
    Client→CDMS
    Request 1: PUT /update/{id}/upload with a new file
  2. 2
    Client→CDMS
    Request 2, shortly after: also an upload into the same object
  3. 3
    CDMS→Database
    Request 1 claims the object and increases _version before it writes the file
  4. 4
    CDMS→Database
    Request 2 wants the same, but already finds a higher _version
  5. 5
    CDMS→Client
    Request 2 → 409 CDMS_OPTIMISTIC_LOCK_CONFLICT, its file is not accepted
  6. 6
    CDMS→Client
    Request 1 → 200
The response to the second request
Response 409
{
  "error": "CodamaiPersistenceException",
  "messageKey": "CDMS_OPTIMISTIC_LOCK_CONFLICT",
  "code": "409",
  "layer": "database"
}
What the client should do
Read the object again,
check whether the upload is still needed,
then send it again.

This also applies to overlapping changes of the other fields of a file object. It does not detect two requests one after the other: if there is a pause between reading and saving, the last one wins here too.

Normal model and file model compared

Protection against concurrent changes
Normal modelFile model
Version fieldnone_version, internal
Client sends something alongnono
two overlapping requeststhe later one winsthe second one gets 409
read 10 minutes ago, saved nowthe later one winsthe later one wins

The client decides: create or update

There is no endpoint that decides by itself whether to create or update (save, “upsert”). The client decides based on the id:

Saving in the client
Object has an idRequest
noPOST /create, then remember the id from the response
yesPUT or PATCH /update/{id}

If someone clicks “Save” twice before the first response arrives, two objects are created. Disable the button until the response arrives. For singletons, CDMS prevents a second object itself: the second create returns 400 object-already-exists|use-update.

Pitfalls

Where to go next

Sources in the code and the knowledge base
  • CDMS/cdms-generator – EntityProcessor (@Version _version only for file models), ApiProcessor (endpoint list, no save)
  • CDMS/cdms-persistence-database – AbstractDatabasePersistence.lockForUpdate (PESSIMISTIC_FORCE_INCREMENT), flush; OptimisticLockMultiTest
  • commons-persistence – OptimisticLockTranslator, PersistenceErrorCode (CDMS_OPTIMISTIC_LOCK_CONFLICT)
  • CDMS/cdms-system-layer – AbstractLayer.recursivePrepare (lockForUpdate before saveFile)
  • documentation/05-api-guide/06-schreiben.md
Search