]> mj.ucw.cz Git - libucw.git/blob - ucw/doc/trans.txt
Trans: Documented naming of exceptions
[libucw.git] / ucw / doc / trans.txt
1 Transactions and resource tracking
2 ==================================
3
4 LibUCW is equipped with a general system for keeping track of resources
5 (allocated memory, open files, ...) and freeing them when requested to.
6
7 The resource tracker can be used either separately (in the form of explicitly
8 managed resource pools) or within a transactional layer, which offers
9 exceptions similar to those in higher-level languages. An exception
10 then rolls back the transaction, freeing all temporary resources allocated
11 within the transaction.
12
13 - <<respools,Resource pools>>
14 - <<trans,Transactions>>
15 - <<exc,Exceptions>>
16 - <<excnames,Exception names>>
17
18 Resource pools: ucw/respool.h [[respools]]
19 ------------------------------------------
20
21 A resource pool contains a stack of resources. When a new resource
22 is created, it is pushed onto the stack. When freeing the pool, the
23 resources are freed in the opposite order, which allows a resource
24 refer to data of previously created resources.
25
26 A resource can be also freed separately (which unlinks it from the pool),
27 or *detached* from the pool (which keeps the real resource, but forgets
28 its meta-data, so the resource is no longer tracked).
29
30 In many cases, a combination of both methods is needed: some resources
31 are marked as temporary, while some others are permanent. When the
32 an operation is completed successfully (and @rp_commit() is called),
33 all temporary resources are freed and the permanent ones detached.
34 When the operation fails, @rp_delete() deletes all resources. By default,
35 all resources are created as temporary. You can make a resource permanent
36 by calling @res_permanent(), or change the default in `resource->default_res_flags`.
37
38 For each thread, LibUCW remembers the currently active resource pool.
39 One pool can be used for at most one thread at a time. All functions
40 which create resources do so in the active pool. All other functions
41 operating on resources work on both active and in-active pools.
42
43 !!ucw/respool.h
44
45 Transactions: ucw/trans.h [[trans]]
46 -----------------------------------
47
48 Upon the resource pools, a transactional mechanism is built. A transaction
49 consists of a piece of code and a resource pool for temporary objects created
50 by the code. Whenever the transaction is running, this pool is set as current.
51 You are allowed to switch to a different pool, but please do so carefully.
52
53 When a transaction ends, the pool is destroyed and the previous active
54 pool is popped off the transaction stack. The fate of the resources
55 inside the pool depends on the operation used to end the transaction:
56
57 * *commit* -- permanent resources are detached from the pool, temporary
58   resources are freed
59 * *rollback* -- all resources are freed
60 * *fold* -- instead of destroying the pool, it is added as a subpool
61   to the parent transaction (which must exist)
62
63 A transaction is tied to a thread which has created it. A transaction
64 can create a sub-transaction, so every thread keeps a stack of running
65 transactions in its per-thread data. Calling @trans_init() is optional,
66 but @trans_cleanup() should be used before a thread exits in order to
67 free resources used by transaction system.
68
69 Each transaction also includes a memory pool, from which all temporary
70 structures (including all resources created by the transaction) are
71 allocated. Feel free to allocate your temporary data from this pool, too;
72 they will be freed when the transaction is committed or rolled back.
73 When the transaction ends with a fold, this pool gets included inside
74 the parent transaction's pool.
75
76 (More precisely, there is actually a shared transaction pool per thread
77 and the transaction logic uses @mp_push() and @mp_pop() to keep a stack
78 of per-transaction data.)
79
80 === Exceptions [[exc]] ===
81
82 Transactions are commonly used together with exceptions (which are similar
83 to how exceptions work in other languages, but they differ in subtle details,
84 so please read carefully). When a failure condition of some kind is detected,
85 an exception is *raised* ("*thrown*" is also sometimes used). It involves
86 creating an exception object and jumping out of the transaction by
87 a `longjmp()`. The exception object (`struct exception`) contains an
88 identification of the error and possibly additional data.
89
90 Usually, creation of an transaction and handling of exceptions is done
91 using *helper macros* (it is not strictly necessary, but highly recommended):
92
93         TRANS_TRY
94           {
95             // Code that runs inside the transaction.
96           }
97         TRANS_CATCH(x)
98           {
99             // When an exception is raised, execution continues here.
100           }
101         TRANS_END;
102
103 The code inside the transaction ends with an implicit @trans_commit().
104 If you want to end the transaction in a different way, you can do so,
105 but you need to use a `break` statement to skip the implicit commit.
106
107 The exception handling code gets a local variable `x` pointing to the
108 exception object. When the exception is handled (for example, an error
109 message is logged), @trans_caught() is called automatically, which rolls
110 back the transaction and frees all its resources. Again, you can use the
111 `break` statement to skip this.
112
113 Alternatively, when you are in a *nested transaction*, you can throw a different
114 exception or re-throw the original one. This raises an exception in the
115 context of the parent transaction. In this case, the child transaction is
116 not rolled back, but its pools are folded as sub-pools of the parent transaction
117 and kept until @trans_caught() is called finally.
118
119 When an exception is thrown *outside a transaction*, it is converted to
120 a plain @die().
121
122 *Memory management* and lifetime of various objects and pools deserve special
123 attention, as usually when non-local jumps are taking place. When an exception
124 is raised, the exception structure is allocated from the memory pool of the
125 current transaction. When the exception is propagated through the stack of
126 transactions, no transaction is ever rolled back -- all of them are folded
127 and their pools remain accessible until @trans_caught() is called at the end.
128 Therefore exceptions can carry pointers to the objects which have failed
129 without a risk of the object becoming invalid. However, you need to avoid
130 pointing to on-stack data like local variables of functions, because these
131 are of course destroyed during the `longjmp()`.
132
133 === Functions and structures ===
134
135 !!ucw/trans.h
136
137 == Exception names [[excnames]] ==
138
139 Exception identifiers form a hierarchy. Each identifier consists of dot-separated
140 components with the most general component at the beginning.
141
142 All exceptions raised by LibUCW reside in the `ucw` subtree. So far, the
143 following exception types are defined:
144
145 `ucw.fb`:: <<fastbuf:fbexc,Fastbufs>>
146
147 == FIXME's ==
148
149 - Unit tests
150 - Resourcification of more libucw objects.
151 - More exceptions
152 - Do we want to allow res_alloc() when no pool is active?