From: Alain Kermis Date: Thu, 30 Nov 2023 13:16:50 +0000 (+0100) Subject: SONAR-20737 Improve performance of large SARIF imports X-Git-Tag: 10.4.0.87286~380 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=614c53b5f13f2fe09e07e18d3a47747c6532442f;p=sonarqube.git SONAR-20737 Improve performance of large SARIF imports --- diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/LocationMapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/LocationMapper.java index 129d4b61d93..d41de202f89 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/LocationMapper.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/LocationMapper.java @@ -20,14 +20,19 @@ package org.sonar.scanner.externalissue.sarif; import com.google.common.annotations.VisibleForTesting; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import java.io.File; import java.io.IOException; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.Optional; +import java.util.concurrent.TimeUnit; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import org.jetbrains.annotations.NotNull; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.predicates.AbstractFilePredicate; import org.sonar.api.batch.sensor.SensorContext; @@ -43,10 +48,18 @@ import static org.sonar.api.utils.Preconditions.checkArgument; @ScannerSide public class LocationMapper { + private static final int CACHE_SIZE = 500; + private static final int CACHE_EXPIRY = 60; private final SensorContext sensorContext; private final RegionMapper regionMapper; + LoadingCache> inputFileCache = CacheBuilder.newBuilder() + .maximumSize(CACHE_SIZE) + .expireAfterAccess(CACHE_EXPIRY, TimeUnit.SECONDS) + .concurrencyLevel(Runtime.getRuntime().availableProcessors()) + .build(getCacheLoader()); + LocationMapper(SensorContext sensorContext, RegionMapper regionMapper) { this.sensorContext = sensorContext; this.regionMapper = regionMapper; @@ -64,12 +77,13 @@ public class LocationMapper { PhysicalLocation physicalLocation = location.getPhysicalLocation(); String fileUri = getFileUriOrThrow(location); - InputFile file = findFile(sensorContext, fileUri); - if (file == null) { + Optional file = findFile(fileUri); + if (file.isEmpty()) { return null; } - newIssueLocation.on(file); - regionMapper.mapRegion(physicalLocation.getRegion(), file).ifPresent(newIssueLocation::at); + InputFile inputFile = file.get(); + newIssueLocation.on(inputFile); + regionMapper.mapRegion(physicalLocation.getRegion(), inputFile).ifPresent(newIssueLocation::at); return newIssueLocation; } @@ -88,10 +102,23 @@ public class LocationMapper { return Optional.ofNullable(location).map(PhysicalLocation::getArtifactLocation).map(ArtifactLocation::getUri).isPresent(); } - @CheckForNull - private static InputFile findFile(SensorContext context, String filePath) { + private Optional findFile(String filePath) { + return inputFileCache.getUnchecked(filePath); + } + + private CacheLoader> getCacheLoader() { + return new CacheLoader<>() { + @NotNull + @Override + public Optional load(final String filePath) { + return computeInputFile(filePath); + } + }; + } + + private Optional computeInputFile(String key) { // we use a custom predicate (which is not optimized) because fileSystem().predicates().is() doesn't handle symlinks correctly - return context.fileSystem().inputFile(new IsPredicate(getFileFromAbsoluteUriOrPath(filePath).toPath())); + return Optional.ofNullable(sensorContext.fileSystem().inputFile(new LocationMapper.IsPredicate(getFileFromAbsoluteUriOrPath(key).toPath()))); } private static File getFileFromAbsoluteUriOrPath(String filePath) { @@ -120,4 +147,5 @@ public class LocationMapper { } } } + }