From 20626e7b8429882f64a4dc0ae26193ff8fabf8e7 Mon Sep 17 00:00:00 2001
From: Carsten  Rose <carsten.rose@math.uzh.ch>
Date: Fri, 20 Dec 2019 23:29:52 +0100
Subject: [PATCH] Update Developer doc for record locking.

---
 Documentation-develop/RECORD_LOCK.md  | 42 +++++++++++++++++++++++++++
 Documentation/Manual.rst              |  2 +-
 extension/Classes/Core/Constants.php  |  2 +-
 extension/Classes/Core/Form/Dirty.php |  2 +-
 4 files changed, 45 insertions(+), 3 deletions(-)
 create mode 100644 Documentation-develop/RECORD_LOCK.md

diff --git a/Documentation-develop/RECORD_LOCK.md b/Documentation-develop/RECORD_LOCK.md
new file mode 100644
index 000000000..0b811f49d
--- /dev/null
+++ b/Documentation-develop/RECORD_LOCK.md
@@ -0,0 +1,42 @@
+<!-- -*- markdown -*- -->
+
+# Record locking
+
+## Concept: Late locking
+
+* A lock is required on first modification.
+* Multiple forms might open the same record, all seems to have write access. The first one who modifies the record
+  get the lock, all following will switch to form=readonly on their first try to modify the record.
+  
+## Lock mode: Exclusive 
+
+* A lock can't be overwritten.
+
+## Lock mode: Advisory 
+
+* A lock can be ignored.
+* Last save win's.
+
+## Lock mode: None
+
+* No locking at all.
+
+# Workarounds
+
+* At least one Browser (FF 71, maybe other in the future too), do not allow to wrap the 'leave page' dialog anymore.
+  This might result in stale lock files (modified record, click on browser tab close or any link), cause the lock 
+  logic does not know that the user leaves the page. 
+  
+  * Workaround: before 'do you want to leave the page' appears, the lock is released, independent if the user answers 'no'.
+    As soon as the users modifies the record again, a new lock is acquired. This is better than a stale record lock.
+    
+* Reload a page (F5) on a modified record, opens the form in readonly mode (record lock found).
+
+  * Reason: the lock release is fired by the browser AFTER form load - than the lock-logic reports 'record is already locked'.
+  * Workaround: with the above workaround, this does not happen anymore. Nevertheless, a 'tabUniqId' has been implemented.
+    That one is saved as record lock and a page reload origin can be identified as the same tab as where the lock has been
+    acquired.  
+
+= State Diagram =
+
+See `Documentation-develop/diagram` for a state diagram.
diff --git a/Documentation/Manual.rst b/Documentation/Manual.rst
index 227ea5b7a..7a854f273 100644
--- a/Documentation/Manual.rst
+++ b/Documentation/Manual.rst
@@ -2255,7 +2255,7 @@ If a timeout expires, the lock becomes invalid. During the next change in a form
 
 A lock is assigned to a record of a table. Multiple forms, with the same primary table, uses the same lock for a given record.
 
-If a `Form` acts on further records (e.g. via FE action), those records are not protected by this basic record locking.
+If a `Form` acts on further records (e.g. via FE action), those further records are not protected by this basic record locking.
 
 If a user tries to delete a record and another user already owns a lock on that record, the delete action is denied.
 
diff --git a/extension/Classes/Core/Constants.php b/extension/Classes/Core/Constants.php
index a6fb4f89f..c4bcc9a0f 100644
--- a/extension/Classes/Core/Constants.php
+++ b/extension/Classes/Core/Constants.php
@@ -1816,7 +1816,7 @@ const DIRTY_API_ACTION_EXTEND = 'extend';
 const LOCK_NOT_FOUND = 0;
 const LOCK_FOUND_OWNER = 1;
 const LOCK_FOUND_CONFLICT = 2;
-const TAB_UNIQ_ID = 'tabUniqId'; // Currently only only a uniq identifier: no values stored behind the identifier - might change.
+const TAB_UNIQ_ID = 'tabUniqId'; // Uniq identifier per tab: no values stored behind the identifier - might change.
 
 // AutoCron
 const AUTOCRON_MAX_AGE_MINUTES = 10;
diff --git a/extension/Classes/Core/Form/Dirty.php b/extension/Classes/Core/Form/Dirty.php
index 970f68fb6..b8039fa2a 100644
--- a/extension/Classes/Core/Form/Dirty.php
+++ b/extension/Classes/Core/Form/Dirty.php
@@ -146,7 +146,7 @@ class Dirty {
     }
 
     /**
-     * Tries to get a 'DirtyRecord'. Returns an array (becomes JSON) about success or failure.
+     * Tries to get a lock ('dirty record'). Returns an array (becomes JSON) about success or failure.
      *
      * @param int $recordId
      * @param array $tableVars
-- 
GitLab