package org.sonar.ce.task.projectanalysis.scm;
import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import javax.annotation.Nonnull;
this.fileHash = fileHash;
}
- public static Optional<DbScmInfo> create(Iterable<DbFileSources.Line> lines, String fileHash) {
+ public static Optional<DbScmInfo> create(List<DbFileSources.Line> lines, String fileHash) {
LineToChangeset lineToChangeset = new LineToChangeset();
- Map<Integer, Changeset> lineChanges = new LinkedHashMap<>();
+ Changeset[] lineChanges = new Changeset[lines.size()];
+
+ boolean lineAdded = false;
for (DbFileSources.Line line : lines) {
Changeset changeset = lineToChangeset.apply(line);
if (changeset == null) {
continue;
}
- lineChanges.put(line.getLine(), changeset);
+ lineChanges[line.getLine() - 1] = changeset;
+ lineAdded = true;
}
- if (lineChanges.isEmpty()) {
+ if (!lineAdded) {
return Optional.empty();
}
return Optional.of(new DbScmInfo(new ScmInfoImpl(lineChanges), fileHash));
}
-
+
public String fileHash() {
return fileHash;
}
}
@Override
- public Map<Integer, Changeset> getAllChangesets() {
+ public Changeset[] getAllChangesets() {
return delegate.getAllChangesets();
}
/**
- * Transforms {@link org.sonar.db.protobuf.DbFileSources.Line} into {@link Changeset}
+ * Transforms {@link org.sonar.db.protobuf.DbFileSources.Line} into {@link Changeset}
*/
private static class LineToChangeset implements Function<DbFileSources.Line, Changeset> {
private final Changeset.Builder builder = Changeset.newChangesetBuilder();
public Changeset apply(@Nonnull DbFileSources.Line input) {
if (input.hasScmDate()) {
Changeset cs = builder
- .setRevision(input.hasScmRevision() ? input.getScmRevision() : null)
- .setAuthor(input.hasScmAuthor() ? input.getScmAuthor() : null)
+ .setRevision(input.hasScmRevision() ? input.getScmRevision().intern() : null)
+ .setAuthor(input.hasScmAuthor() ? input.getScmAuthor().intern() : null)
.setDate(input.getScmDate())
.build();
if (cache.containsKey(cs)) {
*/
package org.sonar.ce.task.projectanalysis.scm;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
import static com.google.common.base.Preconditions.checkState;
public class GeneratedScmInfo implements ScmInfo {
private final ScmInfoImpl delegate;
- public GeneratedScmInfo(Map<Integer, Changeset> changesets) {
- delegate = new ScmInfoImpl(changesets);
+ public GeneratedScmInfo(Changeset[] lineChangeset) {
+ delegate = new ScmInfoImpl(lineChangeset);
}
- public static ScmInfo create(long analysisDate, Set<Integer> lines) {
- checkState(!lines.isEmpty(), "No changesets");
+ public static ScmInfo create(long analysisDate, int lines) {
+ checkState(lines > 0, "No changesets");
Changeset changeset = Changeset.newChangesetBuilder()
.setDate(analysisDate)
.build();
- Map<Integer, Changeset> changesets = lines.stream()
- .collect(Collectors.toMap(x -> x, i -> changeset));
- return new GeneratedScmInfo(changesets);
+ Changeset[] lineChangeset = new Changeset[lines];
+ for (int i = 0; i < lines; i++) {
+ lineChangeset[i] = changeset;
+ }
+ return new GeneratedScmInfo(lineChangeset);
}
public static ScmInfo create(long analysisDate, int[] matches, ScmInfo dbScmInfo) {
.setDate(analysisDate)
.build();
- Map<Integer, Changeset> dbChangesets = dbScmInfo.getAllChangesets();
- Map<Integer, Changeset> changesets = new LinkedHashMap<>(matches.length);
+ Changeset[] dbChangesets = dbScmInfo.getAllChangesets();
+ Changeset[] changesets = new Changeset[matches.length];
for (int i = 0; i < matches.length; i++) {
if (matches[i] > 0) {
- changesets.put(i + 1, dbChangesets.get(matches[i]));
+ changesets[i] = dbChangesets[matches[i]];
} else {
- changesets.put(i + 1, changeset);
+ changesets[i] = changeset;
}
}
return new GeneratedScmInfo(changesets);
}
@Override
- public Map<Integer, Changeset> getAllChangesets() {
+ public Changeset[] getAllChangesets() {
return delegate.getAllChangesets();
}
package org.sonar.ce.task.projectanalysis.scm;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
import javax.annotation.concurrent.Immutable;
-import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.scanner.protocol.output.ScannerReport;
import static com.google.common.base.Preconditions.checkState;
ReportScmInfo(ScannerReport.Changesets changesets) {
requireNonNull(changesets);
this.delegate = convertToScmInfo(changesets);
- checkState(!delegate.getAllChangesets().isEmpty(), "Report has no changesets");
}
private static ScmInfo convertToScmInfo(ScannerReport.Changesets changesets) {
- return new ScmInfoImpl(IntStream.rangeClosed(1, changesets.getChangesetIndexByLineCount())
- .boxed()
- .collect(Collectors.toMap(x -> x, new LineIndexToChangeset(changesets), MoreCollectors.mergeNotSupportedMerger(), LinkedHashMap::new)));
+ Changeset[] lineChangesets = new Changeset[changesets.getChangesetIndexByLineCount()];
+ LineIndexToChangeset lineIndexToChangeset = new LineIndexToChangeset(changesets);
+
+ for (int i = 0; i < changesets.getChangesetIndexByLineCount(); i++) {
+ lineChangesets[i] = lineIndexToChangeset.apply(i);
+ }
+
+ return new ScmInfoImpl(lineChangesets);
}
@Override
}
@Override
- public Map<Integer, Changeset> getAllChangesets() {
+ public Changeset[] getAllChangesets() {
return this.delegate.getAllChangesets();
}
public LineIndexToChangeset(ScannerReport.Changesets changesets) {
this.changesets = changesets;
- changesetCache = new HashMap<>(changesets.getChangesetCount());
+ this.changesetCache = new HashMap<>(changesets.getChangesetCount());
}
@Override
public Changeset apply(Integer lineNumber) {
- int changesetIndex = changesets.getChangesetIndexByLine(lineNumber - 1);
+ int changesetIndex = changesets.getChangesetIndexByLine(lineNumber);
return changesetCache.computeIfAbsent(changesetIndex, idx -> convert(changesets.getChangeset(changesetIndex), lineNumber));
}
checkState(isNotEmpty(changeset.getRevision()), "Changeset on line %s must have a revision", line);
checkState(changeset.getDate() != 0, "Changeset on line %s must have a date", line);
return builder
- .setRevision(changeset.getRevision())
- .setAuthor(isNotEmpty(changeset.getAuthor()) ? changeset.getAuthor() : null)
+ .setRevision(changeset.getRevision().intern())
+ .setAuthor(isNotEmpty(changeset.getAuthor()) ? changeset.getAuthor().intern() : null)
.setDate(changeset.getDate())
.build();
}
/**
* Return all ChangeSets, in order, for all lines that have changesets.
*/
- Map<Integer, Changeset> getAllChangesets();
+ Changeset[] getAllChangesets();
}
*/
package org.sonar.ce.task.projectanalysis.scm;
-import java.util.Collections;
+import java.util.Arrays;
import java.util.Comparator;
-import java.util.Map;
import javax.annotation.concurrent.Immutable;
-import static com.google.common.base.Preconditions.checkState;
+import org.sonar.api.utils.Preconditions;
@Immutable
public class ScmInfoImpl implements ScmInfo {
private final Changeset latestChangeset;
- private final Map<Integer, Changeset> lineChangesets;
+ private final Changeset[] lineChangesets;
- public ScmInfoImpl(Map<Integer, Changeset> lineChangesets) {
- checkState(!lineChangesets.isEmpty(), "A ScmInfo must have at least one Changeset and does not support any null one");
- this.lineChangesets = Collections.unmodifiableMap(lineChangesets);
+ public ScmInfoImpl(Changeset[] lineChangesets) {
+ Preconditions.checkNotNull(lineChangesets);
+ Preconditions.checkState(lineChangesets.length > 0, "ScmInfo cannot be empty");
+ this.lineChangesets = lineChangesets;
this.latestChangeset = computeLatestChangeset(lineChangesets);
}
- private static Changeset computeLatestChangeset(Map<Integer, Changeset> lineChangesets) {
- return lineChangesets.values().stream().max(Comparator.comparingLong(Changeset::getDate))
+ private static Changeset computeLatestChangeset(Changeset[] lineChangesets) {
+ return Arrays.stream(lineChangesets).max(Comparator.comparingLong(Changeset::getDate))
.orElseThrow(() -> new IllegalStateException("Expecting at least one Changeset to be present"));
}
@Override
public Changeset getChangesetForLine(int lineNumber) {
- Changeset changeset = lineChangesets.get(lineNumber);
+ Changeset changeset = lineChangesets[lineNumber - 1];
if (changeset != null) {
return changeset;
}
@Override
public boolean hasChangesetForLine(int lineNumber) {
- return lineChangesets.containsKey(lineNumber);
+ return lineNumber - 1 < lineChangesets.length && lineChangesets[lineNumber - 1] != null;
}
@Override
- public Map<Integer, Changeset> getAllChangesets() {
+ public Changeset[] getAllChangesets() {
return lineChangesets;
}
*/
package org.sonar.ce.task.projectanalysis.scm;
-import java.util.HashMap;
+import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.Component.Status;
import org.sonar.ce.task.projectanalysis.source.SourceHashRepository;
import org.sonar.ce.task.projectanalysis.source.SourceLinesDiff;
+import org.sonar.scanner.protocol.output.ScannerReport;
+import vlsi.utils.CompactHashMap;
import static java.util.Objects.requireNonNull;
private static final Logger LOGGER = Loggers.get(ScmInfoRepositoryImpl.class);
private final BatchReportReader scannerReportReader;
- private final Map<Component, Optional<ScmInfo>> scmInfoCache = new HashMap<>();
+ private final Map<Component, Optional<ScmInfo>> scmInfoCache = new CompactHashMap<>();
private final ScmInfoDbLoader scmInfoDbLoader;
private final AnalysisMetadataHolder analysisMetadata;
private final SourceLinesDiff sourceLinesDiff;
private final SourceHashRepository sourceHashRepository;
public ScmInfoRepositoryImpl(BatchReportReader scannerReportReader, AnalysisMetadataHolder analysisMetadata, ScmInfoDbLoader scmInfoDbLoader,
- SourceLinesDiff sourceLinesDiff, SourceHashRepository sourceHashRepository) {
+ SourceLinesDiff sourceLinesDiff, SourceHashRepository sourceHashRepository) {
this.scannerReportReader = scannerReportReader;
this.analysisMetadata = analysisMetadata;
this.scmInfoDbLoader = scmInfoDbLoader;
if (file.getFileAttributes().getLines() == 0) {
return Optional.empty();
}
- Set<Integer> newOrChangedLines = IntStream.rangeClosed(1, file.getFileAttributes().getLines()).boxed().collect(Collectors.toSet());
- return Optional.of(GeneratedScmInfo.create(analysisMetadata.getAnalysisDate(), newOrChangedLines));
+ return Optional.of(GeneratedScmInfo.create(analysisMetadata.getAnalysisDate(), file.getFileAttributes().getLines()));
}
private static ScmInfo removeAuthorAndRevision(ScmInfo info) {
- Map<Integer, Changeset> cleanedScmInfo = info.getAllChangesets().entrySet().stream()
- .collect(Collectors.toMap(Map.Entry::getKey, e -> removeAuthorAndRevision(e.getValue())));
- return new ScmInfoImpl(cleanedScmInfo);
+ Changeset[] changesets = Arrays.stream(info.getAllChangesets())
+ .map(ScmInfoRepositoryImpl::removeAuthorAndRevision)
+ .toArray(Changeset[]::new);
+ return new ScmInfoImpl(changesets);
}
private static Changeset removeAuthorAndRevision(Changeset changeset) {
}
ScmInfo scmInfo = scmInfoOpt.get();
- Map<Integer, Changeset> allChangesets = scmInfo.getAllChangesets();
+ Changeset[] allChangesets = scmInfo.getAllChangesets();
Set<Integer> lines = new HashSet<>();
// in SLB/PRs, we consider changes introduced in this analysis as new, hence subtracting 1.
long referenceDate = analysisMetadataHolder.isSLBorPR() ? analysisMetadataHolder.getAnalysisDate() - 1 : periodHolder.getPeriod().getSnapshotDate();
- for (Map.Entry<Integer, Changeset> e : allChangesets.entrySet()) {
- if (isLineInPeriod(e.getValue().getDate(), referenceDate)) {
- lines.add(e.getKey());
+ for (int i=0; i<allChangesets.length; i++) {
+ if (isLineInPeriod(allChangesets[i].getDate(), referenceDate)) {
+ lines.add(i+1);
}
}
+
return Optional.of(lines);
}