Reverse the order of storing commit, tree and blobs Apply-object inserts commits, trees and blobs into the repository. These writes are not transactional this means that if any of these writes fails previous ones are not reverted. This can cause repository corruption because we end up with a commit pointing to a non existing tree or blob. The revised logic safeguards the repository from corruption by mandating the order of insertion as follows: 1. Blobs 2. Trees 3. Commits With this order even if the insertion fails it will keep the repository healthy and the git GC will clean up dangling objects. Bug: Issue 306464772 Change-Id: I761e84d5e518e3c3b8ab9c151996149e5d466378
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/ApplyObject.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/ApplyObject.java index 36356e9..05033b4 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/ApplyObject.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/ApplyObject.java
@@ -61,10 +61,6 @@ throw new MissingParentObjectException(name, refSpec.getSource(), parent.getId()); } } - refHead = newObjectID = oi.insert(commitObject.getType(), commitObject.getContent()); - - RevisionObjectData treeObject = revisionData.getTreeObject(); - oi.insert(treeObject.getType(), treeObject.getContent()); } for (RevisionObjectData rev : revisionData.getBlobs()) { @@ -75,6 +71,13 @@ refHead = newObjectID; } + if (commitObject != null) { + RevisionObjectData treeObject = revisionData.getTreeObject(); + oi.insert(treeObject.getType(), treeObject.getContent()); + + refHead = oi.insert(commitObject.getType(), commitObject.getContent()); + } + oi.flush(); if (commitObject == null) {