Adapt to the new PersistentCacheBaseFactory on master

Also manage the new v2 format for H2-DB v2 upgrade in Gerrit master and
adapt the way cache tables to files are computed.

Change-Id: I0bdc792f470406cdc4ed4c1f90495a7907fb34b5
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheFactory.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheFactory.java
index 27be43f..60fc7d4 100644
--- a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheFactory.java
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheFactory.java
@@ -18,6 +18,7 @@
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.gerrit.extensions.registration.DynamicMap;
 import com.google.gerrit.metrics.MetricMaker;
@@ -60,11 +61,11 @@
   ChronicleMapCacheFactory(
       MemoryCacheFactory memCacheFactory,
       @GerritServerConfig Config cfg,
-      SitePaths site,
+      @Nullable @ChronicleMapDir Path cacheDir,
       ChronicleMapCacheConfig.Factory configFactory,
       DynamicMap<Cache<?, ?>> cacheMap,
       MetricMaker metricMaker) {
-    super(memCacheFactory, cfg, site);
+    super(memCacheFactory, cfg, cacheDir);
     this.configFactory = configFactory;
     this.metricMaker = metricMaker;
     this.caches = new LinkedList<>();
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheModule.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheModule.java
index a9b3856..a5a05cc 100644
--- a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheModule.java
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheModule.java
@@ -13,14 +13,26 @@
 // limitations under the License.
 package com.googlesource.gerrit.modules.cache.chroniclemap;
 
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.ModuleImpl;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.PersistentCacheFactory;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.eclipse.jgit.lib.Config;
 
 @ModuleImpl(name = CacheModule.PERSISTENT_MODULE)
 public class ChronicleMapCacheModule extends LifecycleModule {
 
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
   @Override
   protected void configure() {
     factory(ChronicleMapCacheConfig.Factory.class);
@@ -28,4 +40,30 @@
     listener().to(ChronicleMapCacheFactory.class);
     bind(CachesWithoutChronicleMapConfigMetric.class).asEagerSingleton();
   }
+
+  @Provides
+  @Singleton
+  @Nullable
+  @ChronicleMapDir
+  Path getChronicleMapDir(SitePaths site, @GerritServerConfig Config config) {
+    String name = config.getString("cache", null, "directory");
+    if (name == null) {
+      return null;
+    }
+    Path loc = site.resolve(name);
+    if (!Files.exists(loc)) {
+      try {
+        Files.createDirectories(loc);
+      } catch (IOException e) {
+        logger.atWarning().log("Can't create disk cache: %s", loc.toAbsolutePath());
+        return null;
+      }
+    }
+    if (!Files.isWritable(loc)) {
+      logger.atWarning().log("Can't write to disk cache: %s", loc.toAbsolutePath());
+      return null;
+    }
+    logger.atInfo().log("Enabling disk cache %s", loc.toAbsolutePath());
+    return loc;
+  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapDir.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapDir.java
new file mode 100644
index 0000000..a1cbef6
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapDir.java
@@ -0,0 +1,24 @@
+// Copyright (C) 2025 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.googlesource.gerrit.modules.cache.chroniclemap;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.BindingAnnotation;
+import java.lang.annotation.Retention;
+
+@Retention(RUNTIME)
+@BindingAnnotation
+public @interface ChronicleMapDir {}
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/H2CacheCommand.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/H2CacheCommand.java
index b956a7b..1522f94 100644
--- a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/H2CacheCommand.java
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/H2CacheCommand.java
@@ -29,10 +29,11 @@
 
 public class H2CacheCommand {
   protected static final FluentLogger logger = FluentLogger.forEnclosingClass();
-  public static final String H2_SUFFIX = "h2.db";
+  public static final String H2_SUFFIX = "-v2.mv.db";
 
   public static String baseName(Path h2File) {
-    return FilenameUtils.removeExtension(FilenameUtils.getBaseName(h2File.toString()));
+    String filename = h2File.toString();
+    return FilenameUtils.getBaseName(filename.substring(0, filename.length() - H2_SUFFIX.length()));
   }
 
   protected static H2AggregateData getStats(Path h2File) throws Exception {
@@ -65,7 +66,7 @@
   protected static String jdbcUrl(Path h2FilePath) {
     final String normalized =
         FilenameUtils.removeExtension(FilenameUtils.removeExtension(h2FilePath.toString()));
-    return "jdbc:h2:" + normalized + ";AUTO_SERVER=TRUE";
+    return "jdbc:h2:" + normalized + ";AUTO_SERVER=TRUE;DATABASE_TO_UPPER=false";
   }
 
   protected static Optional<Path> getCacheDir(Config gerritConfig, SitePaths site)
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/H2MigrationServlet.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/H2MigrationServlet.java
index 0055dd7..c18b0bd 100644
--- a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/H2MigrationServlet.java
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/H2MigrationServlet.java
@@ -280,7 +280,7 @@
   }
 
   private Optional<Path> getH2CacheFile(Path cacheDir, String name) {
-    Path h2CacheFile = cacheDir.resolve(String.format("%s.%s", name, H2_SUFFIX));
+    Path h2CacheFile = cacheDir.resolve(String.format("%s%s", name, H2_SUFFIX));
     if (Files.exists(h2CacheFile)) {
       return Optional.of(h2CacheFile);
     }
diff --git a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheExtendedIT.java b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheExtendedIT.java
index 4735477..4c7ab75 100644
--- a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheExtendedIT.java
+++ b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheExtendedIT.java
@@ -31,10 +31,10 @@
 import com.google.gerrit.server.cache.MemoryCacheFactory;
 import com.google.gerrit.server.cache.serialize.CacheSerializer;
 import com.google.gerrit.server.cache.serialize.StringCacheSerializer;
-import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
 import java.io.File;
 import java.nio.ByteBuffer;
+import java.nio.file.Path;
 import java.time.Duration;
 import java.util.UUID;
 import java.util.concurrent.ExecutionException;
@@ -54,7 +54,6 @@
   @Inject MetricRegistry metricRegistry;
   @Inject MemoryCacheFactory memCacheFactory;
 
-  @Inject SitePaths sitePaths;
   private StoredConfig gerritConfig;
 
   private final String cacheDirectory = ".";
@@ -694,9 +693,11 @@
             expireAfterWrite != null ? expireAfterWrite : Duration.ZERO,
             refreshAfterWrite != null ? refreshAfterWrite : Duration.ZERO);
 
+    Path cacheDir = sitePaths.resolve(cfg.getString("cache", null, "directory"));
+
     ChronicleMapCacheFactory cacheFactory =
         new ChronicleMapCacheFactory(
-            memCacheFactory, new Config(), sitePaths, null, null, metricMaker);
+            memCacheFactory, new Config(), cacheDir, null, null, metricMaker);
 
     if (withLoader) {
       return (ChronicleMapCacheImpl<String, String>)
diff --git a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/MigrateH2CachesLocalDiskIT.java b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/MigrateH2CachesLocalDiskIT.java
index c8d42b0..798cf3f 100644
--- a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/MigrateH2CachesLocalDiskIT.java
+++ b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/MigrateH2CachesLocalDiskIT.java
@@ -320,7 +320,7 @@
             cacheDirectory,
             persistentDef,
             H2CacheCommand.getStats(
-                cacheDirectory.resolve(String.format("%s.%s", cacheName, H2_SUFFIX))),
+                cacheDirectory.resolve(String.format("%s%s", cacheName, H2_SUFFIX))),
             DEFAULT_SIZE_MULTIPLIER,
             DEFAULT_MAX_BLOAT_FACTOR);