Merge branch 'stable-3.11' into stable-3.12 * stable-3.11: Fix pull replication filtering for deleted refs Revert "Do not filter out refs removals when filtering pull-replication fetches" Change-Id: Ib85084ac3496992dc089215982f43ba4eed34e37
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationFetchFilter.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationFetchFilter.java index 8423d2e..a620dce 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationFetchFilter.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationFetchFilter.java
@@ -23,6 +23,7 @@ import com.google.common.collect.Sets; import com.google.common.flogger.FluentLogger; import com.google.gerrit.entities.Project; +import com.google.gerrit.entities.Project.NameKey; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -86,6 +87,28 @@ ref, oid.getName())); + try { + Ref localRef = refDb.exactRef(ref); + if (localRef == null + && foundAsZeroInSharedRefDb(Project.nameKey(projectName), ref)) { + repLog.info( + "{}:{} was removed locally and is set to zeros in the shared-refdb and thus" + + " will NOT BE fetched", + projectName, + ref); + return false; + } + } catch (IOException ioe) { + String message = + String.format( + "Cannot dereference ref '%s' for project '%s' therefore will NOT BE" + + " fetched", + ref, projectName); + repLog.error(message); + logger.atSevere().withCause(ioe).log("%s", message); + return false; + } + return !localRefOid.isPresent(); }) .collect(Collectors.toSet()); @@ -133,6 +156,31 @@ return refLocks; } + /* If the ref to fetch has been set to all zeros on the global-refdb, it means + * that whatever is the situation locally, we do not need to fetch it: + * - If the remote still has it, fetching it will be useless because the global + * state is that the ref should be removed. + * - If the remote doesn't have it anymore, trying to fetch the ref won't do + * anything because you can't just remove local refs by fetching. + */ + private boolean hasBeenRemovedFromGlobalRefDb(String projectName, String ref) { + if (foundAsZeroInSharedRefDb(Project.nameKey(projectName), ref)) { + repLog.info( + "{}:{} is found as zeros (removed) in shared-refdb thus will NOT BE fetched", + projectName, + ref); + return true; + } + return false; + } + + private boolean foundAsZeroInSharedRefDb(NameKey projectName, String ref) { + return sharedRefDb + .get(projectName, ref, String.class) + .map(r -> ZERO_ID_NAME.equals(r)) + .orElse(false); + } + private Optional<ObjectId> getLocalSha1IfEqualsToExistingGlobalRefDb( Repository repository, String projectName,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationFetchFilterTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationFetchFilterTest.java index b9ec588..2216544 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationFetchFilterTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationFetchFilterTest.java
@@ -201,6 +201,23 @@ } @Test + public void shouldNotFilterOutWhenRefIsMissingOnlyInTheLocalRepository() throws Exception { + String refObjectId = "0000000000000000000000000000000000000001"; + String nonExistingLocalRef = "refs/heads/temporaryOutdated"; + + Set<String> refsToFetch = Set.of(nonExistingLocalRef); + doReturn(Optional.of(refObjectId)) + .when(sharedRefDatabaseMock) + .get(eq(projectName), any(), any()); + + MultisiteReplicationFetchFilter fetchFilter = + new MultisiteReplicationFetchFilter(sharedRefDatabaseMock, gitRepositoryManager, config); + Set<String> filteredRefsToFetch = fetchFilter.filter(project, refsToFetch); + + assertThat(filteredRefsToFetch).hasSize(1); + } + + @Test public void shouldNotFilterOutRefThatDoesntExistLocallyOrInSharedRefDb() throws Exception { String nonExisting = "refs/heads/non-existing-ref"; @@ -213,6 +230,23 @@ assertThat(filteredRefsToFetch).hasSize(1); } + @Test + public void shouldFilterOutRefMissingInTheLocalRepositoryAndDeletedInSharedRefDb() + throws Exception { + String nonExistingLocalRef = "refs/heads/temporaryOutdated"; + + Set<String> refsToFetch = Set.of(nonExistingLocalRef); + doReturn(Optional.of(ObjectId.zeroId().getName())) + .when(sharedRefDatabaseMock) + .get(eq(projectName), any(), any()); + + MultisiteReplicationFetchFilter fetchFilter = + new MultisiteReplicationFetchFilter(sharedRefDatabaseMock, gitRepositoryManager, config); + Set<String> filteredRefsToFetch = fetchFilter.filter(project, refsToFetch); + + assertThat(filteredRefsToFetch).hasSize(0); + } + private RevCommit newRef(String refName) throws Exception { return repo.branch(refName).commit().create(); }