From d87f689b9227062126f3c902ad967d6a0571739c Mon Sep 17 00:00:00 2001
From: Daniel Hornung <d.hornung@indiscale.com>
Date: Thu, 3 Jun 2021 15:37:16 +0200
Subject: [PATCH] DOC ENH: Transactions and Schedules section added.

---
 src/doc/development/structure.rst | 74 +++++++++++++++++++++++++++++--
 1 file changed, 71 insertions(+), 3 deletions(-)

diff --git a/src/doc/development/structure.rst b/src/doc/development/structure.rst
index 41fd3324..f5d5cb8b 100644
--- a/src/doc/development/structure.rst
+++ b/src/doc/development/structure.rst
@@ -57,13 +57,15 @@ main packages which handle the backend:
 
 :java:ref:`backend.implementation.MySQL<MySQL>`
     MySQL implementations of the interfaces.  Typical "simple" implementations create a prepared SQL
-    statement from the arguments to ``execute(...)`` and send it to the SQL server.
+    statement from the arguments to ``execute(...)`` and send it to the SQL server.  They may also
+    have methods for undoing and cleanup, using an :java:ref:`UndoHandler`.
 
 :java:ref:`backend.transaction<backend.transaction>` classes
     Subclasses of the abstract :java:ref:`BackendTransaction` which implement the ``execute()``
     method.  These classes may use specific backend implementations (like for example the MySQL
     implementations) to interact with the backend database.
 
+For example, the structure when getting an Entity ID by name looks like this:
 
 .. uml::
 
@@ -71,7 +73,7 @@ main packages which handle the backend:
   together {
     abstract BackendTransaction {
       HashMap impl // stores all implementations
-      abstract execute()
+      {abstract} execute()
     }
     note left of BackendTransaction::impl
       Stores the
@@ -81,7 +83,7 @@ main packages which handle the backend:
     end note
     package ...backend.interfaces {
       interface GetIDByNameImpl {
-        abstract execute(String name, String role, String limit)
+        {abstract} execute(String name, String role, String limit)
       }
     }
   }
@@ -106,5 +108,71 @@ main packages which handle the backend:
 Transactions and Schedules
 --------------------------
 
+In CaosDB, several client requests may be handled concurrently.  This poses no problem as long as
+only read-only requests are processed, but writing transactions need to block other requests.
+Therefore all transactions (between their first and last access) block write transactions other than
+themselves from writing to the backend, while read transactions may happen at any time, except when
+a write transaction actually writes to the backend.
+
+.. note::
+
+  There is a fine distinction between write transactions on the CaosDB server and actually writing
+  to the backend, since even transactions which need only very short write access to the backend may
+  require extensive read access before, for example to check for permissions or to check if the
+  intended write action makes sense (linked entities must exist, they may need to be of the correct
+  RecordType, etc.).
+
+The request handling in CaosDB is organized in the following way:
+
+- HTTP resources usually create a :java:ref:`Transaction` object and call its
+  :java:ref:`Transaction.execute()` method.  Entities are passed to and from the transaction via
+  :java:ref:`TransactionContainers<TransactionContainer>` (basically normal
+  :java:ref:`Containers<Container>`, enriched with some metadata).
+- The Transaction keeps a :java:ref:`Schedule` of related :java:ref:`Jobs<Job>` (each also wrapping
+  a specific Transaction), which may be called at different stages, called
+  :java:ref:`JobExecutionTimes<JobExecutionTime>`.
+- The Transaction's ``execute()`` method, when called, in turn calls a number of methods for
+  initialization, checks, preparations, cleanup etc.  Additionally the scheduled jobs are executed
+  at their specified stages, for example all jobs scheduled for ``INIT`` are executed immediately
+  after calling ``Transaction.init()``.  Please consult the API documentation for
+  :java:ref:`Transaction.execute()` for details.
+
+  Most importantly, the (abstract) method ``transaction()`` is called by ``execute()``, which in
+  inheriting classes typically interacts with the backend via :java:ref:`execute(BackendTransaction,
+  Access)<Transaction.execute(K t, Access access)>`, which in turn calls the
+  ``BackendTransaction``'s :java:ref:`BackendTransaction.executeTransaction()` method (just a thin
+  wrapper around its ``execute()`` method).
+
+Summarized, the classes are connected like this:
 
+.. uml::
+
+  @startuml
+  hide empty members
+
+  class Container
+  class TransactionContainer extends Container
+
+  abstract Transaction {
+    Schedule schedule
+    TransactionContainer container
+    execute()
+    execute(BackendTransaction t, Access access)\n    // -> t.executeTransaction(t)
+  }
+
+  class Schedule
+  class ScheduledJob
+  abstract Job {
+    ExecutionTime time
+    Transaction transaction
+    execute(BackendTransaction t)\n    // -> transaction.execute(t, transaction.access)
+  }
+
+  Schedule "*" *- ScheduledJob
+  ScheduledJob *- Job
+  Job o--d- Transaction
+
+  TransactionContainer -* Transaction::container
+  Transaction::schedule *- Schedule
+  @enduml
 
-- 
GitLab