FOLIO OL protocol is based on exchanging the value of _version field between the client and the server during record(s) retrieval (GET) and subsequent record update (PUT or POST in the batch update case), The ides is based on how HTTP ETAGs work: server generates a _version value during initial record creation and inserts it into the designated _version field in the record body. The _version value is then returned to the client (during GET) as a regular field in the record. Client is required is to provide the exact same value in the _version field for a subsequent update (PUT). Server then checks if the provided value matches the value stored on the server and if true accepts the update. If the provided value does not match stored value, server responds with 409 Conflict response code.
The _version should be added as a top-level field to the entity's JSON schema. See example in mod-inventory-storage's instance record: https://github.com/folio-org/mod-inventory-storage/blob/master/ramls/instance.json
OL is enabled by providing a withOptimisticLocking table configuration property in the schema.json with the following values:
- off disables optimisticLocking for this table. If a "version" property exists it is ignored,
removed on save,and no "version" is generated.
- logOnConflict in case of version conflict detection a WARN log message is logged to the standard log with the UUID of the record and the conflicting versions but the update is allowed. Uses PostgreSQL's RAISE WARNING that gets logged in the module log: https://www.postgresql.org/docs/current/plpgsql-errors-and-messages.html
- failOnConflict in case of version conflict detection a 409 Conflict HTTP error is returned to the client and the update is prevented
. Uses PostgreSQL's RAISE EXCEPTION that usually rolls back the current transaction: https://www.postgresql.org/docs/current/plpgsql-errors-and-messages.html
For phase 1 the default will be off for all tables without a withOptimisticLocking entry.
On module install and module upgrade RMB installs or changes the triggers to match the off, logOnConflict or failOnConflict option in schema.json:
an INSERT trigger that populates the initial value for the "version" property
an UPDATE trigger that compares NEW value with the OLD value and if they match updates the NEW value to a new generated value and allows the update; the trigger warns or fails on mismatch
Proof-of-concept: https://issues.folio.org/browse/RMB-719?focusedCommentId=86211&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-86211 Note: per comments, magic value "-1" in POC will not be implemented for now
RMB tasks for phase 2 (Per comments, not in scope of this ticket. Most likely will be handled in
RMB-769) TenantLoading needs to be changed to pass the "version" property of the records in the database when upgrading reference and sample data.
PgUtil.postSync (when upsert=true) and PgUtil.put need to handle optimistic locking failures by responding with HTTP 409 status code.
Use a simple (to calculate and update) increment counter.
RMB-719 why other options have issues without clear benefits: hashing is more computationally complex and a random UUID has issues related to replication/clustering.