Merge "Refuse convert-ref-storage to reftable when usePerRequestRefCache is set"
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 ab54297..6521e3b 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -2677,6 +2677,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");
+ }
+}