Refuse convert-ref-storage to reftable when usePerRequestRefCache is set Reftable is unservable while core.usePerRequestRefCache is enabled (the per-request ref cache assumes a RefDirectory), so refuse converting a repository to reftable via the convert-ref-storage SSH command instead of producing an unservable repository. Release-Notes: convert-ref-storage SSH command refuses converting to reftable when core.usePerRequestRefCache is enabled Change-Id: I81c9daa3157647f61f2592ff3c211b2726358de5
diff --git a/Documentation/cmd-convert-ref-storage.txt b/Documentation/cmd-convert-ref-storage.txt index cbb5457..d5f5507 100644 --- a/Documentation/cmd-convert-ref-storage.txt +++ b/Documentation/cmd-convert-ref-storage.txt
@@ -21,6 +21,10 @@ == DESCRIPTION Convert ref storage to reftable. +Converting to `reftable` additionally requires the server to run with +link:config-gerrit.html#core.usePerRequestRefCache[core.usePerRequestRefCache] +set to `false` (reftable is otherwise unservable); the command fails otherwise. + == ACCESS Administrators
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index 5054b66..6efa1db 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt
@@ -2670,6 +2670,10 @@ (lazily) if needed. This helps reduce the overhead of checking if the packed-refs file is outdated. + +Repositories using the reftable format cannot be served while this cache +is enabled. Set this option to `false` and restart Gerrit before serving +reftable repositories. ++ Default is `true`. [[core.useFileKeyByProjectCache]]core.useFileKeyByProjectCache::
diff --git a/java/com/google/gerrit/sshd/commands/ConvertRefStorage.java b/java/com/google/gerrit/sshd/commands/ConvertRefStorage.java index 56cf5c8..511339a 100644 --- a/java/com/google/gerrit/sshd/commands/ConvertRefStorage.java +++ b/java/com/google/gerrit/sshd/commands/ConvertRefStorage.java
@@ -20,6 +20,7 @@ import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.entities.Project; import com.google.gerrit.extensions.annotations.RequiresCapability; +import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.git.DelegateRepository; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.project.ProjectState; @@ -29,6 +30,7 @@ import java.io.IOException; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.internal.storage.file.FileRepository; +import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Repository; import org.kohsuke.args4j.Option; import org.kohsuke.args4j.spi.ExplicitBooleanOptionHandler; @@ -41,6 +43,8 @@ public class ConvertRefStorage extends SshCommand { @Inject private GitRepositoryManager repoManager; + @Inject @GerritServerConfig private Config cfg; + private enum StorageFormatOption { reftable, refdir, @@ -74,6 +78,11 @@ @Override public void run() throws Exception { enableGracefulStop(); + // reftable is unservable with core.usePerRequestRefCache; refuse converting to it. + if (storageFormat == StorageFormatOption.reftable + && cfg.getBoolean("core", null, "usePerRequestRefCache", true)) { + throw die("Converting to reftable requires core.usePerRequestRefCache=false"); + } Project.NameKey projectName = projectState.getNameKey(); try (Repository repo = repoManager.openRepository(projectName)) { if (repo instanceof DelegateRepository delegateRepository) {
diff --git a/javatests/com/google/gerrit/acceptance/ssh/ConvertRefStorageIT.java b/javatests/com/google/gerrit/acceptance/ssh/ConvertRefStorageIT.java new file mode 100644 index 0000000..dadbc69 --- /dev/null +++ b/javatests/com/google/gerrit/acceptance/ssh/ConvertRefStorageIT.java
@@ -0,0 +1,34 @@ +// Copyright (C) 2026 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.acceptance.ssh; + +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.NoHttpd; +import com.google.gerrit.acceptance.UseSsh; +import com.google.gerrit.acceptance.config.GerritConfig; +import org.junit.Test; + +@NoHttpd +@UseSsh +public class ConvertRefStorageIT extends AbstractDaemonTest { + @Test + @GerritConfig(name = "core.usePerRequestRefCache", value = "true") + public void refusesConversionToReftableWhenPerRequestRefCacheEnabled() throws Exception { + adminSshSession.exec( + "gerrit convert-ref-storage --project " + project.get() + " --format reftable"); + adminSshSession.assertFailure( + "Converting to reftable requires core.usePerRequestRefCache=false"); + } +}