Pushing an item onto two lists. A failure in list2.push_back() undoes list1.push_back().
atomic::vector<std::string> list1, list2;
void f(const std::string &s)
{
atomic::auto_transaction tr;
list1.push_back(s);
list2.push_back(s);
}
This example inserts one set into another. A normal std::set implementation would not make this operation atomic. But all operations on atomic containers are atomic.
atomic::set<Order> orders;
void addOrders(const atomic::set<Order> &x)
{
orders.insert(x.begin(), x.end());
}
Process items on a list. Any exception in processing will restore pending and processed to their initial states.
atomic::list<Item> pending, processed;
void processAll()
{
atomic::auto_transaction tr;
while(!pending.empty())
{
Item &item = pending.front();
process(item); processed.push_back(item); pending.pop_front();
} }
Knights tour. This uses transactions to "roll back" the dead-ends in a depth-first search.
Recovering complex processing. The point is that at any point in the process, an exception should undo all of the actions prior to the exception. For example, a failure to deliver should result in all payments being rolled back, all stock being unreserved, and all logs being rolled back.
void processOrder(Order &order)
{
atomic::transaction tr;
checkStockAndReserveItems(order);
// throws out_of_stock exception
if(usingVouchers(order))
{
useVouchers(order);
// Throws voucher_invalid exception,
// voucher_already_used exception
// insufficient_funds
}
else if(usingCreditCard(order))
{
chargeCreditCard(order);
// Throws invalid_credit_card, insufficient_funds etc etc
}
else
{
throw unrecognised_payment_method();
}
invoicingSystem.logInvoice(order);
invoicingSystem.sendReceipt(order);
salesteam.increaseChristmasBonus();
dispatchingSystem.dispatchOrder(order);
// throws: staff_on_strike, invalid_delivery_address,
// out_of_boxes, fire_at_the_warehouse etc etc.
tr.commit();
}