A Transaction Processing Monitor
Basic Model
Applications that execute transactions are referred to as server processes; those that request transactions from other processes are called requestor processes. In general, a server manages a set of objects such as databases or machines and implements all transactions that operate on these objects.
Any application running in the system can, at any time, request a transaction or offer to execute one. Thus, the terms "server" and "requestor" should always be interpreted as being relative to a particular transaction.
In order to guarantee atomicity of events, a two-phase commit protocol is used. Once the system finds one server per related transaction, the first (prepare) phase begins: the system sends each one a transaction request. Each server determines if the part of the event that its transaction performs can be done correctly. If so, the server is expected to set up an intermediate state from which either the original state or the new state can be obtained even if the system crashes. It then sends a commit outcome of the transaction to the system; otherwise, it sends an abort. The second (complete) phase then begins. If all of the other transactions in the event also {commit}ed, the event commits and the system will send a FinalCommit message, telling the server to make the transaction permanent. Otherwise, the event aborts and the system will send a FinalAbort message telling the server to discard any effects of the transaction. In either case, the second phase message is sent to the requestor at the same time as the servers.
When an event commits its return code and output data buffer is that of one of its one transactions known as the selected transaction. Otherwise, the return code is that of the first transaction in the event to abort.
The event mechanism allows atomically-executing entities (events) to be made up of independent entities (transactions) and this buys a fair amount of flexibility, especially for incremental modification of events. For example, if the programmer wanted to add some functionality to an event e{1}, she could do so by writing a new transaction, tx{i}, that performed the new actions and then add tx{i} to the definition of e{1} in the event table. The alternative to this would be to write an entirely new transaction that contained the code that implements the functionality of e{1} plus the code that would have been in tx{i}. The advantage of the event-based solution is that it doesn't require any rewriting of (presumably) working code.
Like the event mechanism itself, this method of passing parameters provides flexibility. If it is determined that one of the transactions included in an event requires more information, a new symbol can be added to the message and be passed with the data buffer. Since each transaction explicitly asks for the data by symbol name, other transactions in the same event are not affected by this change.