Skip to content

Commit b6c4d38

Browse files
ghislainpiotsonartech
authored andcommitted
SONARPY-2888 Refactor the Scanner implementations to have a single implementation of sequential/parallel analysis (#238)
GitOrigin-RevId: 1d27f34b0457c5af7fed2668b152d1390cf9cb03
1 parent c8382dc commit b6c4d38

3 files changed

Lines changed: 34 additions & 61 deletions

File tree

python-commons/src/main/java/org/sonar/plugins/python/PythonScanner.java

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,10 @@
3131
import java.util.Optional;
3232
import java.util.Set;
3333
import java.util.concurrent.ConcurrentHashMap;
34-
import java.util.concurrent.ForkJoinPool;
3534
import java.util.concurrent.atomic.AtomicBoolean;
3635
import java.util.concurrent.atomic.AtomicInteger;
3736
import java.util.function.Supplier;
3837
import java.util.regex.Pattern;
39-
import java.util.stream.Stream;
4038
import javax.annotation.CheckForNull;
4139
import org.slf4j.Logger;
4240
import org.slf4j.LoggerFactory;
@@ -120,26 +118,8 @@ protected String name() {
120118
}
121119

122120
@Override
123-
protected void processFiles(List<PythonInputFile> files, SensorContext context, MultiFileProgressReport progressReport,
124-
AtomicInteger numScannedWithoutParsing) {
125-
var numberOfThreads = getNumberOfThreads(context);
126-
if (numberOfThreads == 1) {
127-
super.processFiles(files, context, progressReport, numScannedWithoutParsing);
128-
return;
129-
}
130-
var pool = new ForkJoinPool(numberOfThreads);
131-
try {
132-
LOG.debug("Scanning files in {} threads", numberOfThreads);
133-
pool.submit(() -> super.processFiles(files, context, progressReport, numScannedWithoutParsing))
134-
.join();
135-
} finally {
136-
pool.shutdown();
137-
}
138-
}
139-
140-
@Override
141-
protected Stream<PythonInputFile> getFilesStream(List<PythonInputFile> files) {
142-
return getNumberOfThreads(context) == 1 ? files.stream() : files.stream().parallel();
121+
protected void logStart(int numThreads) {
122+
LOG.debug("Scanning files in {} threads", numThreads);
143123
}
144124

145125
@Override
@@ -165,7 +145,6 @@ protected void scanFile(PythonInputFile inputFile) throws IOException {
165145
searchForDataBricks(visitorContext);
166146
}
167147

168-
169148
private PythonVisitorContext createVisitorContext(PythonInputFile inputFile, PythonFile pythonFile, InputFile.Type fileType) throws IOException {
170149
PythonVisitorContext visitorContext;
171150
try {
@@ -530,7 +509,8 @@ public boolean getFoundDatabricks() {
530509
return foundDatabricks.get();
531510
}
532511

533-
private static Integer getNumberOfThreads(SensorContext context) {
512+
@Override
513+
protected int getNumberOfThreads(SensorContext context) {
534514
return context.config().getInt(THREADS_PROPERTY_NAME)
535515
.orElse(1);
536516
}

python-commons/src/main/java/org/sonar/plugins/python/Scanner.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.sonar.sslr.api.RecognitionException;
2020
import java.io.IOException;
2121
import java.util.List;
22+
import java.util.concurrent.ForkJoinPool;
2223
import java.util.concurrent.atomic.AtomicInteger;
2324
import java.util.stream.Stream;
2425
import org.slf4j.Logger;
@@ -50,11 +51,27 @@ public void execute(List<PythonInputFile> files, SensorContext context) {
5051
}
5152

5253
protected void processFiles(List<PythonInputFile> files, SensorContext context, MultiFileProgressReport progressReport, AtomicInteger numScannedWithoutParsing) {
53-
getFilesStream(files).forEach(file -> processFile(context, file, progressReport, numScannedWithoutParsing));
54+
var numberOfThreads = getNumberOfThreads(context);
55+
logStart(numberOfThreads);
56+
if (numberOfThreads == 1) {
57+
getFilesStream(files).forEach(file -> processFile(context, file, progressReport, numScannedWithoutParsing));
58+
return;
59+
}
60+
var pool = new ForkJoinPool(numberOfThreads);
61+
try {
62+
pool.submit(() -> getFilesStream(files).forEach(file -> processFile(context, file, progressReport, numScannedWithoutParsing)))
63+
.join();
64+
} finally {
65+
pool.shutdown();
66+
}
5467
}
5568

69+
protected abstract void logStart(int numThreads);
70+
5671
protected Stream<PythonInputFile> getFilesStream(List<PythonInputFile> files) {
57-
return files.stream();
72+
return getNumberOfThreads(context) == 1
73+
? files.stream()
74+
: files.parallelStream();
5875
}
5976

6077
private void processFile(SensorContext context, PythonInputFile file, MultiFileProgressReport progressReport, AtomicInteger numScannedWithoutParsing) {
@@ -110,4 +127,7 @@ private static boolean isParseErrorOnTestFile(PythonInputFile file, Exception e)
110127
// As test files may contain invalid syntax on purpose, we avoid failing the analysis when encountering parse errors on them
111128
return e instanceof RecognitionException && file.wrappedFile().type() == InputFile.Type.TEST;
112129
}
130+
131+
protected abstract int getNumberOfThreads(SensorContext context);
132+
113133
}

python-commons/src/main/java/org/sonar/plugins/python/indexer/PythonIndexer.java

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,13 @@
2222
import java.util.List;
2323
import java.util.Map;
2424
import java.util.concurrent.ConcurrentHashMap;
25-
import java.util.concurrent.ForkJoinPool;
26-
import java.util.concurrent.atomic.AtomicInteger;
2725
import java.util.function.Supplier;
28-
import java.util.stream.Stream;
2926
import javax.annotation.CheckForNull;
3027
import javax.annotation.Nullable;
3128
import org.slf4j.Logger;
3229
import org.slf4j.LoggerFactory;
3330
import org.sonar.api.batch.fs.InputFile;
3431
import org.sonar.api.batch.sensor.SensorContext;
35-
import org.sonar.plugins.python.MultiFileProgressReport;
3632
import org.sonar.plugins.python.PythonInputFile;
3733
import org.sonar.plugins.python.Scanner;
3834
import org.sonar.plugins.python.SonarQubePythonFile;
@@ -148,45 +144,22 @@ protected String name() {
148144
}
149145

150146
@Override
151-
protected void scanFile(PythonInputFile inputFile) throws IOException {
152-
// Global Symbol Table is deactivated for Notebooks see: SONARPY-2021
153-
if (inputFile.kind() == PythonInputFile.Kind.PYTHON) {
154-
addFile(inputFile);
147+
protected void logStart(int numThreads) {
148+
if (numThreads != 1) {
149+
LOG.debug("Scanning global symbols in {} threads", numThreads);
155150
}
156151
}
157152

158153
@Override
159-
protected Stream<PythonInputFile> getFilesStream(List<PythonInputFile> files) {
160-
var numberOfThreads = getNumberOfThreads(context);
161-
if (numberOfThreads == 1) {
162-
return files.stream();
154+
protected void scanFile(PythonInputFile inputFile) throws IOException {
155+
// Global Symbol Table is deactivated for Notebooks see: SONARPY-2021
156+
if (inputFile.kind() == PythonInputFile.Kind.PYTHON) {
157+
addFile(inputFile);
163158
}
164-
return files.stream().parallel();
165159
}
166160

167161
@Override
168-
protected void processFiles(List<PythonInputFile> files, SensorContext context, MultiFileProgressReport progressReport, AtomicInteger numScannedWithoutParsing) {
169-
var numberOfThreads = getNumberOfThreads(context);
170-
if (numberOfThreads != 1) {
171-
processFilesWithThreads(files, context, progressReport, numScannedWithoutParsing, numberOfThreads);
172-
} else {
173-
super.processFiles(files, context, progressReport, numScannedWithoutParsing);
174-
}
175-
}
176-
177-
private void processFilesWithThreads(List<PythonInputFile> files, SensorContext context, MultiFileProgressReport progressReport, AtomicInteger numScannedWithoutParsing,
178-
Integer numberOfThreads) {
179-
LOG.debug("Scanning global symbols in {} threads", numberOfThreads);
180-
ForkJoinPool pool = new ForkJoinPool(numberOfThreads);
181-
try {
182-
pool.submit(() -> super.processFiles(files, context, progressReport, numScannedWithoutParsing))
183-
.join();
184-
} finally {
185-
pool.shutdown();
186-
}
187-
}
188-
189-
private Integer getNumberOfThreads(SensorContext context) {
162+
protected int getNumberOfThreads(SensorContext context) {
190163
return context.config().getInt(THREADS_PROPERTY_NAME)
191164
.orElse(Math.max(2, Math.min((int) Math.round(Runtime.getRuntime().availableProcessors() * 0.9), 6)));
192165
}

0 commit comments

Comments
 (0)