Skip to content

Commit db377ae

Browse files
maksim-grebeniuk-sonarsourcesonartech
authored andcommitted
SONARPY-2889 Make PythonCpdAnalyzer thread-safe (#239)
GitOrigin-RevId: 3e2ab0dac8f289fa09018f8047f4cfc1867411f1
1 parent b97c7e4 commit db377ae

3 files changed

Lines changed: 32 additions & 14 deletions

File tree

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,13 @@
2424
import java.util.Collection;
2525
import java.util.Collections;
2626
import java.util.HashSet;
27-
import java.util.List;
2827
import java.util.Map;
2928
import java.util.Set;
3029
import java.util.concurrent.ConcurrentHashMap;
3130
import java.util.concurrent.atomic.AtomicBoolean;
3231
import java.util.concurrent.atomic.AtomicInteger;
3332
import java.util.function.Supplier;
3433
import java.util.regex.Pattern;
35-
import javax.annotation.CheckForNull;
3634
import org.slf4j.Logger;
3735
import org.slf4j.LoggerFactory;
3836
import org.sonar.api.SonarProduct;
@@ -81,7 +79,7 @@ public PythonScanner(
8179
Supplier<PythonParser> parserSupplier, PythonIndexer indexer, PythonFileConsumer architectureCallback) {
8280
super(context);
8381
this.checks = checks;
84-
this.cpdAnalyzer = new PythonCpdAnalyzer(context);
82+
this.cpdAnalyzer = new PythonCpdAnalyzer(context, this);
8583
this.parserSupplier = parserSupplier;
8684
this.indexer = indexer;
8785
this.indexer.buildOnce(context);
@@ -165,7 +163,7 @@ private PythonVisitorContext createVisitorContext(PythonInputFile inputFile, Pyt
165163
return visitorContext;
166164
}
167165

168-
private synchronized void pushTokens(PythonInputFile inputFile, PythonVisitorContext visitorContext) {
166+
private void pushTokens(PythonInputFile inputFile, PythonVisitorContext visitorContext) {
169167
if (!isInSonarLint(context) && inputFile.kind() == PythonInputFile.Kind.PYTHON) {
170168
cpdAnalyzer.pushCpdTokens(inputFile.wrappedFile(), visitorContext);
171169
}
@@ -335,7 +333,7 @@ protected void reportStatistics(int numSkippedFiles, int numTotalFiles) {
335333
numSkippedFiles, numTotalFiles);
336334
}
337335

338-
private synchronized boolean restoreAndPushMeasuresIfApplicable(PythonInputFile inputFile) {
336+
private boolean restoreAndPushMeasuresIfApplicable(PythonInputFile inputFile) {
339337
if (inputFile.wrappedFile().type() == InputFile.Type.TEST) {
340338
return true;
341339
}

python-commons/src/main/java/org/sonar/plugins/python/cpd/PythonCpdAnalyzer.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ public class PythonCpdAnalyzer {
4343
private static final Logger LOG = LoggerFactory.getLogger(PythonCpdAnalyzer.class);
4444

4545
private final SensorContext context;
46+
private final Object monitor;
4647

47-
public PythonCpdAnalyzer(SensorContext context) {
48+
public PythonCpdAnalyzer(SensorContext context, Object monitor) {
4849
this.context = context;
50+
this.monitor = monitor;
4951
}
5052

5153
public void pushCpdTokens(InputFile inputFile, PythonVisitorContext visitorContext) {
@@ -68,7 +70,7 @@ public void pushCpdTokens(InputFile inputFile, PythonVisitorContext visitorConte
6870
}
6971
}
7072
saveTokensToCache(visitorContext, tokensToCache);
71-
cpdTokens.save();
73+
save(cpdTokens);
7274
}
7375
}
7476

@@ -87,9 +89,8 @@ public boolean pushCachedCpdTokens(InputFile inputFile, CacheContext cacheContex
8789
NewCpdTokens cpdTokens = context.newCpdTokens().onFile(inputFile);
8890
tokens.forEach(tokenInfo ->
8991
cpdTokens.addToken(tokenInfo.startLine, tokenInfo.startLineOffset, tokenInfo.endLine, tokenInfo.endLineOffset, tokenInfo.value));
90-
cpdTokens.save();
91-
cacheContext.getWriteCache().copyFromPrevious(dataKey);
92-
cacheContext.getWriteCache().copyFromPrevious(tableKey);
92+
save(cpdTokens);
93+
copyFromPrevious(cacheContext, dataKey, tableKey);
9394
return true;
9495
} catch (IOException e) {
9596
LOG.warn("Failed to deserialize CPD tokens ({}: {})", e.getClass().getSimpleName(), e.getMessage());
@@ -98,7 +99,7 @@ public boolean pushCachedCpdTokens(InputFile inputFile, CacheContext cacheContex
9899
return false;
99100
}
100101

101-
private static void saveTokensToCache(PythonVisitorContext visitorContext, List<Token> tokensToCache) {
102+
private void saveTokensToCache(PythonVisitorContext visitorContext, List<Token> tokensToCache) {
102103
CacheContext cacheContext = visitorContext.cacheContext();
103104
if (!cacheContext.isCacheEnabled()) {
104105
return;
@@ -108,13 +109,32 @@ private static void saveTokensToCache(PythonVisitorContext visitorContext, List<
108109
String fileKey = visitorContext.pythonFile().key();
109110

110111
CpdSerializer.SerializationResult result = CpdSerializer.serialize(tokensToCache);
111-
cacheContext.getWriteCache().write(stringTableCacheKey(fileKey), result.stringTable);
112-
cacheContext.getWriteCache().write(dataCacheKey(fileKey), result.data);
112+
writeToCache(cacheContext, fileKey, result);
113113
} catch (Exception e) {
114114
LOG.warn("Could not write CPD tokens to cache ({}: {})", e.getClass().getSimpleName(), e.getMessage());
115115
}
116116
}
117117

118+
private void save(NewCpdTokens cpdTokens) {
119+
synchronized (monitor) {
120+
cpdTokens.save();
121+
}
122+
}
123+
124+
private void copyFromPrevious(CacheContext cacheContext, String dataKey, String tableKey) {
125+
synchronized (monitor) {
126+
cacheContext.getWriteCache().copyFromPrevious(dataKey);
127+
cacheContext.getWriteCache().copyFromPrevious(tableKey);
128+
}
129+
}
130+
131+
private void writeToCache(CacheContext cacheContext, String fileKey, CpdSerializer.SerializationResult result) {
132+
synchronized (monitor) {
133+
cacheContext.getWriteCache().write(stringTableCacheKey(fileKey), result.stringTable);
134+
cacheContext.getWriteCache().write(dataCacheKey(fileKey), result.data);
135+
}
136+
}
137+
118138
private static boolean isNewLineWithIndentationChange(TokenType currentTokenType, TokenType nextTokenType) {
119139
return currentTokenType.equals(PythonTokenType.NEWLINE) && nextTokenType.equals(PythonTokenType.DEDENT);
120140
}

python-commons/src/test/java/org/sonar/plugins/python/cpd/PythonCpdAnalyzerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class PythonCpdAnalyzerTest {
3939

4040
private static final String BASE_DIR = "src/test/resources/org/sonar/plugins/python";
4141
private SensorContextTester context = SensorContextTester.create(new File(BASE_DIR));
42-
private PythonCpdAnalyzer cpdAnalyzer = new PythonCpdAnalyzer(context);
42+
private PythonCpdAnalyzer cpdAnalyzer = new PythonCpdAnalyzer(context, new Object());
4343

4444
@Test
4545
void code_chunks_2() {

0 commit comments

Comments
 (0)