Allow to re-create a previously removed ref

When removing a ref, the zookeeper path is set with a zeros
ObjectId marking it as tombstone. Automatically detect the tombstones
when re-creating the ref and avoid false split-brain scenarios.

Bug: Issue 11888
Change-Id: Ie58823eab18a870ab8208cad5815d5a5182915fd
diff --git a/src/main/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZkSharedRefDatabase.java b/src/main/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZkSharedRefDatabase.java
index 5378879..835b6e9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZkSharedRefDatabase.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZkSharedRefDatabase.java
@@ -117,7 +117,8 @@
         new DistributedAtomicValue(client, pathFor(projectName, oldRef), retryPolicy);
 
     try {
-      if (oldRef.getObjectId() == null || oldRef.getObjectId().equals(ObjectId.zeroId())) {
+      if ((oldRef.getObjectId() == null || oldRef.getObjectId().equals(ObjectId.zeroId()))
+          && refNotInZk(projectName, oldRef)) {
         return distributedRefValue.initialize(writeObjectId(newRefValue));
       }
       final ObjectId newValue = newRefValue == null ? ObjectId.zeroId() : newRefValue;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseTest.java b/src/test/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseTest.java
index db7024b..8a9ea80 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseTest.java
@@ -92,6 +92,19 @@
   }
 
   @Test
+  public void shouldCompareAndPutPreviouslyRemovedRefSuccessfully() throws Exception {
+    Ref ref = refOf(AN_OBJECT_ID_1);
+    Project.NameKey projectName = A_TEST_PROJECT_NAME_KEY;
+
+    zookeeperContainer.createRefInZk(projectName, ref);
+
+    assertThat(zkSharedRefDatabase.compareAndPut(projectName, ref, ObjectId.zeroId())).isTrue();
+
+    Ref zerosRef = refOf(ObjectId.zeroId());
+    assertThat(zkSharedRefDatabase.compareAndPut(projectName, zerosRef, AN_OBJECT_ID_1)).isTrue();
+  }
+
+  @Test
   public void compareAndPutShouldFailIfTheObjectionHasNotTheExpectedValue() throws Exception {
     Project.NameKey projectName = A_TEST_PROJECT_NAME_KEY;