blob: 6a4553a415814c1aeb1537465cf36b64a7dce361 [file] [log] [blame]
// 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.
import com.google.common.flogger.FluentLogger
import com.google.gerrit.entities.Project
import com.google.gerrit.extensions.annotations.*
import com.google.gerrit.extensions.events.LifecycleListener
import com.google.gerrit.lifecycle.LifecycleModule
import com.google.gerrit.metrics.*
import com.google.gerrit.server.config.*
import com.google.gerrit.server.git.LocalDiskRepositoryManager
import com.google.inject.Singleton
import org.eclipse.jgit.lib.Constants
import javax.inject.Inject
import java.util.concurrent.TimeUnit
import static groovy.io.FileType.FILES
@Singleton
@Listen
class RepoRepackTracker implements LifecycleListener {
private static final FluentLogger logger = FluentLogger.forEnclosingClass()
private static final NAME = "is_repack_running_per_project"
private static final DESCRIPTION = "Check repack running for the project"
private static final GIT_PACK_FOLDER = "objects/pack"
private static final TMP_PREFIX = "tmp_"
private static final TMP_SUFFIX = ".tmp"
@Inject
@PluginName
String pluginName
@Inject
PluginConfigFactory configFactory
@Inject
MetricMaker metrics
@Inject
LocalDiskRepositoryManager repoMgr
private def tmpFilter = ~/^(${TMP_PREFIX}.*|.*${TMP_SUFFIX})$/
private long considerStaleAfterMs
CallbackMetric1<String, Long> projectsAndGcMetric
List<String> projects
@Override
void start() {
PluginConfig pluginConfig = configFactory.getFromGerritConfig(pluginName)
long considerStaleAfter = ConfigUtil.getTimeUnit(
pluginConfig.getString("considerStaleAfter", "60 minutes"),
60L,
TimeUnit.MINUTES)
considerStaleAfterMs = TimeUnit.MILLISECONDS.convert(considerStaleAfter, TimeUnit.MINUTES)
projects = pluginConfig.getStringList("project")
projectsAndGcMetric = createCallbackMetric(NAME, DESCRIPTION)
addMetricsTrigger(projectsAndGcMetric, projects)
logger.atInfo().log("Plugin %s started (staleAfter %d minutes)",
pluginName,
considerStaleAfter)
}
CallbackMetric1<String, Long> createCallbackMetric(String name, String description) {
metrics.newCallbackMetric(
name,
Long.class,
new Description(description).setGauge(),
Field.ofProjectName("repository_name")
.description(description)
.build()
)
}
void addMetricsTrigger(CallbackMetric1<String, Long> projectsAndGcMetric, List<String> projects) {
metrics.newTrigger(
projectsAndGcMetric, {
if (projects.isEmpty()) {
projectsAndGcMetric.forceCreate("")
} else {
projects.each { e ->
projectsAndGcMetric.set(e, checkRepackingRunningForProject(e))
}
projectsAndGcMetric.prune()
}
})
}
long checkRepackingRunningForProject(String projectName) {
def isRepackRunning = 0L
try {
def repoDir = getRepoDir(projectName)
def packDir = new File(repoDir, GIT_PACK_FOLDER)
if (packDir.exists() && hasRepackTmpFiles(packDir)) {
isRepackRunning = 1L
}
} catch (Exception e) {
logger.atSevere().withCause(e).log("Could not check project %s", projectName)
}
isRepackRunning
}
File getRepoDir(String projectName) {
def name = Project.nameKey(projectName)
def path = repoMgr.getBasePath(name)
return path.resolve("${name.get()}${Constants.DOT_GIT_EXT}").toFile()
}
boolean hasRepackTmpFiles(folder) {
def modifiedCutoffTime = System.currentTimeMillis() - considerStaleAfterMs
def tmpFileFound = false
folder.traverse(type: FILES, nameFilter: tmpFilter) { file ->
if (file.lastModified() >= modifiedCutoffTime) {
tmpFileFound = true
}
}
return tmpFileFound
}
@Override
void stop() {}
}
class RepoRepackTrackerModule extends LifecycleModule {
protected void configure() {
listener().to(RepoRepackTracker)
}
}
modules = [RepoRepackTrackerModule]