1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 06:02:11 +02:00

Bug 509898 - IndexFileSet.containsDeclaration is slow and is causing UI

freezes

Added cycle detection to IndexFileSet.containsDeclaration.

Change-Id: I48a596bd680bd4f764739b9170a98c907c41ae8c
This commit is contained in:
Sergey Prigogin 2017-02-08 18:24:29 -08:00
parent 5e793c9b43
commit 5462bac381

View file

@ -13,7 +13,9 @@ package org.eclipse.cdt.internal.core.index;
import java.util.BitSet; import java.util.BitSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
@ -25,7 +27,9 @@ import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.PDOMFileSet; import org.eclipse.cdt.internal.core.pdom.PDOMFileSet;
import org.eclipse.cdt.internal.core.pdom.db.Database; import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.cdt.internal.core.pdom.dom.IRecordIterator; import org.eclipse.cdt.internal.core.pdom.dom.IRecordIterator;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName; import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode;
import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
@ -90,8 +94,14 @@ public class IndexFileSet implements IIndexFileSet {
PDOMFileSet pdomFileSet = (PDOMFileSet) fragmentFileSet; PDOMFileSet pdomFileSet = (PDOMFileSet) fragmentFileSet;
Database db = pdom.getDB(); Database db = pdom.getDB();
IRecordIterator nameIterator = pdom.getDeclarationsDefintitionsRecordIterator(binding); IRecordIterator nameIterator = pdom.getDeclarationsDefintitionsRecordIterator(binding);
Set<Long> visited = null;
long nameRecord; long nameRecord;
while ((nameRecord = nameIterator.next()) != 0) { while ((nameRecord = nameIterator.next()) != 0) {
if (visited != null && !visited.add(nameRecord)) {
// Cycle detected!
logInvalidNameChain(pdom, binding);
return false;
}
long fileRecord = PDOMName.getFileRecord(db, nameRecord); long fileRecord = PDOMName.getFileRecord(db, nameRecord);
if (pdomFileSet.containsFile(fileRecord)) { if (pdomFileSet.containsFile(fileRecord)) {
if (sDEBUG_INDEX_FILE_SET && iterationCount >= 200) { if (sDEBUG_INDEX_FILE_SET && iterationCount >= 200) {
@ -103,12 +113,11 @@ public class IndexFileSet implements IIndexFileSet {
} }
return true; return true;
} }
if (sDEBUG_INDEX_FILE_SET && ++iterationCount % 1000 == 0) { if (iterationCount >= 1000 && visited == null) {
System.out.println( // Iteration count is suspiciously high. Start keeping track of visited names
String.format("IndexFileSet: %s (%s) not yet found after %d iterations", //$NON-NLS-1$ // to be able to detect a cycle.
String.join("::", binding.getQualifiedName()), //$NON-NLS-1$ visited = new HashSet<>();
binding.getClass().getSimpleName(), visited.add(nameRecord);
iterationCount));
} }
} }
} }
@ -126,6 +135,40 @@ public class IndexFileSet implements IIndexFileSet {
return false; return false;
} }
private void logInvalidNameChain(PDOM pdom, IIndexBinding binding) {
try {
PDOMBinding pdomBinding = (PDOMBinding) binding;
for (String listType : new String[] {"declarations", "definitions"}) { //$NON-NLS-1$//$NON-NLS-2$
StringBuilder nameChain = new StringBuilder();
Set<PDOMName> visited = new HashSet<>();
PDOMName first = listType.equals("declarations") ? pdomBinding.getFirstDeclaration() : pdomBinding.getFirstDefinition(); //$NON-NLS-1$
for (PDOMName name = first; name != null; name= name.getNextInBinding()) {
if (nameChain.length() != 0)
nameChain.append(", "); //$NON-NLS-1$
nameChain.append(name.getRecord());
PDOMBinding nameBinding = name.getBinding();
if (!nameBinding.equals(binding)) {
nameChain.append(String.format(" belongs to %s (%s) @%d", //$NON-NLS-1$
String.join("::", nameBinding.getQualifiedName()), //$NON-NLS-1$
nameBinding.getClass().getSimpleName(),
((PDOMNode) nameBinding).getRecord()));
}
if (!visited.add(name)) {
CCorePlugin.log(String.format("IndexFileSet: %s (%s) @%d - list of %s contains a cycle: ", //$NON-NLS-1$
String.join("::", binding.getQualifiedName()), //$NON-NLS-1$
binding.getClass().getSimpleName(),
pdomBinding.getRecord(),
listType,
nameChain.toString()));
return;
}
}
}
} catch (CoreException e) {
CCorePlugin.log(e);
}
}
public long getTimingContainsDeclarationNanos() { public long getTimingContainsDeclarationNanos() {
return timingContainsDeclarationNanos; return timingContainsDeclarationNanos;
} }