We can't just replay the SQL commands, that's too low-level: if we do
INSERT, then use the resulting ID into e.g. another INSERT command, at replay
time we might get a different ID from the first command, and then insert
the wrong ID in the second one...
So instead we want to re-run the entire handler's parseStream(), which we
do by throwing a DbDeadlockException (from QueryBuilder), and catching that
in the caller (Connection) using a helper class (DbDeadlockCatcher, unittested)
which retries up to 5 times.
For this to work, it means:
- we must also rollback any chances made to in-memory caches (done by
clearing those caches, good enough since DB deadlocks are rare)
- ItemModifyJob which sends parts on demand, shouldn't delete after
sending (it might be asked again) -- this was hit by GidTest (fetchAndSetGid).
- delaying the updating of intervalChecker and cacheCleaner by NotificationCollector until commit time;
- checking other users of QueryBuilder (who now can get a DbDeadlockException...)