Executing CherryPick.writeCherryPickCommit() in a transaction.

This would at least allow the partial changes to the
database to rollback and not get users in a bad state when
e.g. in the case of OrmDuplicateKeyException: patch_set_ancestors'.

Bug: issue 2034
Bug: issue 2246
Change-Id: I65e111bedc3cec033299b5b5360aaee733d4b5c6
(cherry picked from commit eb4778d079e7156c82d04c2f26c71ca89d12df16)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/CherryPick.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/CherryPick.java
index 48f62b5..259d939 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/CherryPick.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/CherryPick.java
@@ -161,26 +161,36 @@
     ps.setCreatedOn(TimeUtil.nowTs());
     ps.setUploader(submitAudit.getAccountId());
     ps.setRevision(new RevId(newCommit.getId().getName()));
-    insertAncestors(args.db, ps.getId(), newCommit);
-    args.db.patchSets().insert(Collections.singleton(ps));
 
-    n.change.setCurrentPatchSet(patchSetInfoFactory.get(newCommit, ps.getId()));
-    args.db.changes().update(Collections.singletonList(n.change));
+    final RefUpdate ru;
 
-    final List<PatchSetApproval> approvals = Lists.newArrayList();
-    for (PatchSetApproval a : args.mergeUtil.getApprovalsForCommit(n)) {
-      approvals.add(new PatchSetApproval(ps.getId(), a));
-    }
-    args.db.patchSetApprovals().insert(approvals);
+    args.db.changes().beginTransaction(n.change.getId());
+    try {
+      insertAncestors(args.db, ps.getId(), newCommit);
+      args.db.patchSets().insert(Collections.singleton(ps));
+      n.change
+          .setCurrentPatchSet(patchSetInfoFactory.get(newCommit, ps.getId()));
+      args.db.changes().update(Collections.singletonList(n.change));
 
-    final RefUpdate ru = args.repo.updateRef(ps.getRefName());
-    ru.setExpectedOldObjectId(ObjectId.zeroId());
-    ru.setNewObjectId(newCommit);
-    ru.disableRefLog();
-    if (ru.update(args.rw) != RefUpdate.Result.NEW) {
-      throw new IOException(String.format("Failed to create ref %s in %s: %s",
-          ps.getRefName(), n.change.getDest().getParentKey().get(),
-          ru.getResult()));
+      final List<PatchSetApproval> approvals = Lists.newArrayList();
+      for (PatchSetApproval a : args.mergeUtil.getApprovalsForCommit(n)) {
+        approvals.add(new PatchSetApproval(ps.getId(), a));
+      }
+      args.db.patchSetApprovals().insert(approvals);
+
+      ru = args.repo.updateRef(ps.getRefName());
+      ru.setExpectedOldObjectId(ObjectId.zeroId());
+      ru.setNewObjectId(newCommit);
+      ru.disableRefLog();
+      if (ru.update(args.rw) != RefUpdate.Result.NEW) {
+        throw new IOException(String.format(
+            "Failed to create ref %s in %s: %s", ps.getRefName(), n.change
+                .getDest().getParentKey().get(), ru.getResult()));
+      }
+
+      args.db.commit();
+    } finally {
+      args.db.rollback();
     }
 
     gitRefUpdated.fire(n.change.getProject(), ru);