From: Martin Mares Date: Sun, 17 Apr 2011 16:26:37 +0000 (+0200) Subject: Trans: First bits of documentation X-Git-Tag: v5.0~74^2~27 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=cdaca8c440aae7016d460d332e6016918a854663;p=libucw.git Trans: First bits of documentation I have tried to document the complete logic of transactions, including memory management details. It is however still far from a complete documentation and the AsciiDoc formatting is also somewhat obscure at the moment. --- diff --git a/ucw/doc/Makefile b/ucw/doc/Makefile index 0ceb39ca..81ee2bcc 100644 --- a/ucw/doc/Makefile +++ b/ucw/doc/Makefile @@ -2,7 +2,7 @@ DIRS+=ucw/doc -UCW_DOCS=basics log fastbuf index config configure install basecode hash docsys conf mempool eltpool mainloop generic growbuf unaligned lists chartype unicode prime binsearch heap binheap compress sort hashtable relnotes +UCW_DOCS=basics log fastbuf index config configure install basecode hash docsys conf mempool eltpool mainloop generic growbuf unaligned lists chartype unicode prime binsearch heap binheap compress sort hashtable relnotes trans UCW_INDEX=$(o)/ucw/doc/def_index.html UCW_DOCS_HTML=$(addprefix $(o)/ucw/doc/,$(addsuffix .html,$(UCW_DOCS))) diff --git a/ucw/doc/index.txt b/ucw/doc/index.txt index a9981c5f..3f625e85 100644 --- a/ucw/doc/index.txt +++ b/ucw/doc/index.txt @@ -35,6 +35,7 @@ Modules - <> - <> - <> +- <> Other features -------------- diff --git a/ucw/doc/trans.txt b/ucw/doc/trans.txt new file mode 100644 index 00000000..f56c6c36 --- /dev/null +++ b/ucw/doc/trans.txt @@ -0,0 +1,84 @@ +Transactions and resource tracking +================================== + +Assorted notes: + +- A transaction is tied to a thread which has created it. A transaction + can create a sub-transaction, so every thread keeps a stack of running + transactions in its per-thread data. + +- Every transaction keeps a resource pool containing resources, which + have been created during the transaction. Whenever the transaction is + running, this pool is set as current. You are allowed to switch to + a different pool, but please do so carefully. ++ + When a transaction ends, the pool is destroyed and the previous active + pool is popped off the transaction stack. The fate of the resources + inside the pool depends on the operation used to end the transaction: + * commit -- all resources are detached from the pool + * rollback -- all resources are freed + * fold -- instead of destroying the pool, it is added as a subpool + to the parent transaction (which must exist) + +- Each transaction also includes a memory pool, from which all temporary + structures (including all resources created by the transaction) are + allocated. Feel free to allocate your temporary data from this pool, too; + they will be freed when the transaction is committed or rolled back. + When the transaction ends with a fold, this pool gets included inside + the parent transaction's pool. ++ + (To be true, there is actually a shared transaction pool per thread + and the transaction logic uses @mp_push() and @mp_pop() to keep a stack + of per-transaction data.) + +- Transactions are usually used together with exceptions (which are similar + to how exceptions work in other languages, but they differ in subtle details, + so please read carefully). When a failure condition of some kind is detected, + an exception is raised. It involves creating an exception object and jumping + out of the transaction by a `longjmp()`. The exception object (`struct exception`) + contains an identification of the error and possibly additional data. ++ + Usually, creation of an transaction and handling of exceptions is done + using helper macros (it is not strictly necessary, but highly recommended): ++ + TRANS_TRY + { + // Code that runs inside the transaction. + } + TRANS_CATCH(x) + { + // When an exception is raised, execution continues here. + } + TRANS_END; + + The code inside the transaction ends with an implicit @trans_commit(). + If you want to end the transaction in a different way, you can do so, + but you need to use a `break` statement to skip the implicit commit. + + The exception handling code gets a local variable `x` pointing to the + exception object. When the exception is handled (for example, an error + message is logged), @trans_caught() is called automatically, which rolls + back the transaction and frees all its resources. Again, you can use the + `break` statement to skip this. + + Alternatively, when you are in a nested transaction, you can throw a different + exception or re-throw the original one. This raises an exception in the + context of the parent transaction. In this case, the child transaction is + not rolled back, but its pools are folded as sub-pools of the parent transaction + and kept until @trans_caught() is called finally. + +* When an exception is thrown outside a transaction, it is converted to + a plain @die(). + +* Memory management and lifetime of various objects and pools deserve special + attention, as usually when non-local jumps are taking place. When an exception + is raised, the exception structure is allocated from the memory pool of the + current transaction. When the exception is propagated through the stack of + transactions, no transaction is ever rolled back -- all of them are folded + and their pools remain accessible until @trans_caught() is called at the end. + Therefore exceptions can carry pointers to the objects which have failed + without a risk of the object becoming invalid. However, you need to avoid + pointing to on-stack data like local variables of functions, because these + are of course destroyed during the `longjmp()`. + +FIXME: Interaction between exceptions, pools and other libucw modules.