Nesting Transactions
The ability to roll back a single function is okay, but what about functions that need to call other functions? For instance:
void f() { g(); h(); }
If h() throws an exception, how do you roll back g(), if g() could do something such as detonate a bomb? The answer is that you can't. But if g() and h() only use transactional operations, then they can be rolled back by a transaction in f(); for example:
void f() { atomic::transaction t1; ... g(); ... h(); .. t1.commit(); } g() { atomic::transaction t2; ... t2.commit(); } h() { atomic::transaction t3; ... t3.commit(); }
g() is atomic because of the transaction t2. h() is atomic because of the transaction t3. And f() is atomic because the transaction t1 can roll back anything in f(), g(), or h(). Even when t2.commit() has been called in g(), t2 can still be rolled back.
Transactions can be nested to any depth. Transaction objects must always be nested, which is guaranteed by the C++ scoping rules.
Transactional Containers
The Atomic Library has a variety of containers that can be used in transactions:
- atomic::list, the atomic equivalent of std::list.
- atomic::map, the atomic equivalent of std::map.
- atomic::vector, the atomic equivalent of std::vector. This container only supports the push_back() operation.
- atomic::set, the atomic equivalent of std::set.
- atomic::multimap, the atomic equivalent of std::multimap.
- atomic::multiset, the atomic equivalent of std::multiset.
In general, these containers behave exactly as their std equivalents, but they can be rolled back by atomic::transaction. For example:
atomic::set<Item> pending; atomic::list<Item> processed; void process() { atomic::transaction tr; while(!pending.empty()) { Item &i = pending.front(); i.process(); processed.push_back(i); pending.pop_front(); } tr.commit(); }
When the function encounters an exception in process(), the entire function is rolled back as if no items had been moved from pending to processed.
All functions on atomic containers are guaranteed to be strongly exception safe, unlike the C++ Standard Library.