]> mj.ucw.cz Git - libucw.git/blob - ucw/doc/trans.txt
Trans: First bits of documentation
[libucw.git] / ucw / doc / trans.txt
1 Transactions and resource tracking
2 ==================================
3
4 Assorted notes:
5
6 - A transaction is tied to a thread which has created it. A transaction
7   can create a sub-transaction, so every thread keeps a stack of running
8   transactions in its per-thread data.
9
10 - Every transaction keeps a resource pool containing resources, which
11   have been created during the transaction. Whenever the transaction is
12   running, this pool is set as current. You are allowed to switch to
13   a different pool, but please do so carefully.
14 +
15   When a transaction ends, the pool is destroyed and the previous active
16   pool is popped off the transaction stack. The fate of the resources
17   inside the pool depends on the operation used to end the transaction:
18         * commit -- all resources are detached from the pool
19         * rollback -- all resources are freed
20         * fold -- instead of destroying the pool, it is added as a subpool
21           to the parent transaction (which must exist)
22
23 - Each transaction also includes a memory pool, from which all temporary
24   structures (including all resources created by the transaction) are
25   allocated. Feel free to allocate your temporary data from this pool, too;
26   they will be freed when the transaction is committed or rolled back.
27   When the transaction ends with a fold, this pool gets included inside
28   the parent transaction's pool.
29 +
30   (To be true, there is actually a shared transaction pool per thread
31   and the transaction logic uses @mp_push() and @mp_pop() to keep a stack
32   of per-transaction data.)
33
34 - Transactions are usually used together with exceptions (which are similar
35   to how exceptions work in other languages, but they differ in subtle details,
36   so please read carefully). When a failure condition of some kind is detected,
37   an exception is raised. It involves creating an exception object and jumping
38   out of the transaction by a `longjmp()`. The exception object (`struct exception`)
39   contains an identification of the error and possibly additional data.
40 +
41   Usually, creation of an transaction and handling of exceptions is done
42   using helper macros (it is not strictly necessary, but highly recommended):
43 +
44         TRANS_TRY
45           {
46             // Code that runs inside the transaction.
47           }
48         TRANS_CATCH(x)
49           {
50             // When an exception is raised, execution continues here.
51           }
52         TRANS_END;
53
54   The code inside the transaction ends with an implicit @trans_commit().
55   If you want to end the transaction in a different way, you can do so,
56   but you need to use a `break` statement to skip the implicit commit.
57
58   The exception handling code gets a local variable `x` pointing to the
59   exception object. When the exception is handled (for example, an error
60   message is logged), @trans_caught() is called automatically, which rolls
61   back the transaction and frees all its resources. Again, you can use the
62   `break` statement to skip this.
63
64   Alternatively, when you are in a nested transaction, you can throw a different
65   exception or re-throw the original one. This raises an exception in the
66   context of the parent transaction. In this case, the child transaction is
67   not rolled back, but its pools are folded as sub-pools of the parent transaction
68   and kept until @trans_caught() is called finally.
69
70 * When an exception is thrown outside a transaction, it is converted to
71   a plain @die().
72
73 * Memory management and lifetime of various objects and pools deserve special
74   attention, as usually when non-local jumps are taking place. When an exception
75   is raised, the exception structure is allocated from the memory pool of the
76   current transaction. When the exception is propagated through the stack of
77   transactions, no transaction is ever rolled back -- all of them are folded
78   and their pools remain accessible until @trans_caught() is called at the end.
79   Therefore exceptions can carry pointers to the objects which have failed
80   without a risk of the object becoming invalid. However, you need to avoid
81   pointing to on-stack data like local variables of functions, because these
82   are of course destroyed during the `longjmp()`.
83
84 FIXME: Interaction between exceptions, pools and other libucw modules.