Transactions and in-memory data (part 3 of n)

Last time I laid out a little framework for transactional rollback.  It clearly is not sufficient for a real honest-to-goodness persistent transaction but if you can tolerate every ESE failing (due to allocating the rollback log entry) it's pretty compelling.  Pretty much every function can be transactional if it only works with data structures/algorithms which could support this metaphor.  It might look something like...

int do_work(collection_t *collection, int x, int y, int z) {
rollback_record_t *txn = NULL;
int err;
if ((err = collection_insert(&txn, collection, x))) {
do_rollback(txn);
return err;
}
if ((err = collection_remove(&txn, collection, y))) {
do_rollback(txn);
return err;
}
if ((err = collection_do_something_else(&txn, collection, z))) {
do_rollback(txn);
return err;
}
free_rollback(txn);
return 0;
}

Hey, that's kinda cool.  Pretty easy to write a transactional function, eh?  But wait there's more.  With this metaphor it's also easy to be a good transactional citizen!

int do_work(rollback_record_t **parent_txn, collection_t *collection, int x, int y, int z) {
rollback_record_t *txn = NULL;
int err;
if ((err = collection_insert(&txn, collection, x))) {
do_rollback(txn);
return err;
}
if ((err = collection_remove(&txn, collection, y))) {
do_rollback(txn);
return err;
}
if ((err = collection_do_something_else(&txn, collection, z))) {
do_rollback(txn);
return err;
}
merge_rollback(txn, parent_txn);
return 0;
}

Hey, woah maybe we're on to something!

Hmm.. it's going to be hard to use other libraries... what if I don't really need this level of guarantee?  What if people point at the code and say it's weird?  I guess social acceptability is as important as reliability and correctness...