From f7b80bf3068b7f97a9374df9e1c7384f9daeec5b Mon Sep 17 00:00:00 2001 From: Anton Leherbauer Date: Wed, 4 Apr 2007 13:38:20 +0000 Subject: [PATCH] Fix ASTCacheTests --- .../cdt/core/model/tests/ASTCacheTests.java | 87 +++++++++------ .../cdt/internal/core/model/ASTCache.java | 105 +++++++++--------- 2 files changed, 106 insertions(+), 86 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java index f40a20e7ad3..874fbb9719f 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/ASTCacheTests.java @@ -17,6 +17,7 @@ import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.index.IIndex; +import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.testplugin.CProjectHelper; @@ -37,26 +38,30 @@ public class ASTCacheTests extends BaseTestCase { private static int fgReconcilerCount; public class MockReconciler extends Thread { - private ITranslationUnit fTU; - private ASTCache fCache; + private final ITranslationUnit fTU; + private final ASTCache fCache; public volatile boolean fStopped; - private IASTTranslationUnit fAST; + public IASTTranslationUnit fAST; public MockReconciler(ITranslationUnit tu, ASTCache cache) { super("MockReconciler-"+fgReconcilerCount++); fTU= tu; fCache= cache; + setDaemon(true); } public void run() { while (!fStopped) { try { - Thread.sleep(200); - fCache.aboutToBeReconciled(fTU); synchronized (this) { - notifyAll(); + fCache.aboutToBeReconciled(fTU); + fAST= null; + notify(); + } + Thread.sleep(100); + synchronized (this) { + fAST= fCache.createAST(fTU, fIndex, null); + fCache.reconciled(fAST, fTU); } - fAST= fCache.createAST(fTU, fIndex, null); - fCache.reconciled(fAST, fTU); } catch (InterruptedException exc) { fStopped= true; break; @@ -84,17 +89,18 @@ public class ASTCacheTests extends BaseTestCase { public void setUp() throws Exception { super.setUp(); + IProgressMonitor npm= new NullProgressMonitor(); fProject= createProject("ASTCacheTest"); assertNotNull(fProject); IFile file1= createFile(fProject.getProject(), "source1.cpp", SOURCE1); assertNotNull(file1); - fTU1= CProjectHelper.findTranslationUnit(fProject, file1.getName()); - assertNotNull(fTU1); IFile file2= createFile(fProject.getProject(), "source2.cpp", SOURCE2); assertNotNull(file2); - fTU2= CProjectHelper.findTranslationUnit(fProject, file2.getName()); + fTU1= (ITranslationUnit) CoreModel.getDefault().create(file1); + assertNotNull(fTU1); + fTU2= (ITranslationUnit) CoreModel.getDefault().create(file2); assertNotNull(fTU2); - CCorePlugin.getIndexManager().joinIndexer(5000, new NullProgressMonitor()); + CCorePlugin.getIndexManager().joinIndexer(5000, npm); fIndex= CCorePlugin.getIndexManager().getIndex(fProject); fIndex.acquireReadLock(); } @@ -153,37 +159,47 @@ public class ASTCacheTests extends BaseTestCase { private void checkAccessWithSequentialReconciler() throws Exception { ASTCache cache= new ASTCache(); - cache.setActiveElement(fTU1); MockReconciler reconciler1= new MockReconciler(fTU1, cache); - MockReconciler reconciler2= null; + MockReconciler reconciler2= new MockReconciler(fTU2, cache); try { + cache.setActiveElement(fTU1); assertFalse(cache.isReconciling(fTU1)); synchronized (reconciler1) { reconciler1.start(); reconciler1.wait(); + assertNull(reconciler1.fAST); + assertTrue(cache.isActiveElement(fTU1)); + assertTrue(cache.isReconciling(fTU1)); } + reconciler1.fStopped= true; IASTTranslationUnit ast; ast= cache.getAST(fTU1, fIndex, true, null); assertNotNull(ast); + assertTrue(cache.isActiveElement(fTU1)); + assertFalse(cache.isReconciling(fTU1)); assertSame(ast, reconciler1.fAST); // change active element cache.setActiveElement(fTU2); - reconciler2= new MockReconciler(fTU2, cache); + assertFalse(cache.isReconciling(fTU2)); synchronized (reconciler2) { reconciler2.start(); reconciler2.wait(); + assertNull(reconciler2.fAST); + assertTrue(cache.isActiveElement(fTU2)); + assertTrue(cache.isReconciling(fTU2)); } + reconciler2.fStopped= true; ast= cache.getAST(fTU2, fIndex, true, null); assertNotNull(ast); + assertTrue(cache.isActiveElement(fTU2)); + assertFalse(cache.isReconciling(fTU2)); assertSame(ast, reconciler2.fAST); } finally { reconciler1.fStopped= true; reconciler1.join(1000); - if (reconciler2 != null) { - reconciler2.fStopped= true; - reconciler2.join(1000); - } + reconciler2.fStopped= true; + reconciler2.join(1000); } } @@ -192,37 +208,44 @@ public class ASTCacheTests extends BaseTestCase { MockReconciler reconciler1= new MockReconciler(fTU1, cache); MockReconciler reconciler2= new MockReconciler(fTU2, cache); reconciler1.start(); - Thread.sleep(100); + Thread.sleep(50); reconciler2.start(); try { - for (int i= 0; i < 10; i++) { + int cacheHits= 0; + int iterations= 0; + while (cacheHits < 4 && iterations < 10) { + ++iterations; IASTTranslationUnit ast; cache.setActiveElement(fTU1); + Thread.sleep(100); ast= cache.getAST(fTU1, fIndex, false, null); if (ast != null) { assertSame(ast, reconciler1.fAST); + ++cacheHits; + } else { + ast= cache.getAST(fTU1, fIndex, true, null); + assertNotNull(ast); + assertEquals("void foo1() {}", ast.getDeclarations()[0].getRawSignature()); } - ast= cache.getAST(fTU1, fIndex, true, null); - assertNotNull(ast); - assertEquals("void foo1() {}", ast.getDeclarations()[0].getRawSignature()); - + // change active element cache.setActiveElement(fTU2); + Thread.sleep(100); ast= cache.getAST(fTU1, fIndex, false, null); if (ast != null) { assertSame(ast, reconciler2.fAST); + ++cacheHits; + } else { + ast= cache.getAST(fTU2, fIndex, true, null); + assertNotNull(ast); + assertEquals("void foo2() {}", ast.getDeclarations()[0].getRawSignature()); } - ast= cache.getAST(fTU2, fIndex, true, null); - assertNotNull(ast); - assertEquals("void foo2() {}", ast.getDeclarations()[0].getRawSignature()); } } finally { reconciler1.fStopped= true; reconciler1.join(1000); - if (reconciler2 != null) { - reconciler2.fStopped= true; - reconciler2.join(1000); - } + reconciler2.fStopped= true; + reconciler2.join(1000); } } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java index b66d0214bf0..f50e9b9b7b1 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTCache.java @@ -13,7 +13,6 @@ import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.index.IIndex; -import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; @@ -70,7 +69,7 @@ public class ASTCache { */ private long fLastWriteOnIndex; /** Inidicates whether the AST is currenty being computed */ - private volatile boolean fIsReconciling; + private boolean fIsReconciling; /** * Create a new AST cache. @@ -133,7 +132,7 @@ public class ASTCache { if (DEBUG) System.out.println(DEBUG_PREFIX + getThreadName() + "waiting for AST for: " + tUnit.getElementName()); //$NON-NLS-1$ fCacheMutex.wait(); - // Check whether active element is still valid ( + // Check whether active element is still valid if (fAST != null) { if (DEBUG) System.out.println(DEBUG_PREFIX + getThreadName() + "...got AST for: " + tUnit.getElementName()); //$NON-NLS-1$ @@ -219,25 +218,24 @@ public class ASTCache { * @param tUnit the translation unit */ private void cache(IASTTranslationUnit ast, ITranslationUnit tUnit) { - synchronized (fCacheMutex) { - if (fActiveTU != null && !fActiveTU.equals(tUnit)) { - if (DEBUG && tUnit != null) // don't report call from disposeAST() - System.out.println(DEBUG_PREFIX + getThreadName() + "don't cache AST for inactive: " + toString(tUnit)); //$NON-NLS-1$ - return; - } - - if (DEBUG && (tUnit != null || ast != null)) // don't report call from disposeAST() - System.out.println(DEBUG_PREFIX + getThreadName() + "caching AST: " + toString(ast) + " for: " + toString(tUnit)); //$NON-NLS-1$ //$NON-NLS-2$ - - if (fAST != null) - disposeAST(); - - fAST= ast; - fLastWriteOnIndex= fAST == null ? 0 : fAST.getIndex().getLastWriteAccess(); - - // Signal AST change - fCacheMutex.notifyAll(); + assert Thread.holdsLock(fCacheMutex); + if (fActiveTU != null && !fActiveTU.equals(tUnit)) { + if (DEBUG && tUnit != null) // don't report call from disposeAST() + System.out.println(DEBUG_PREFIX + getThreadName() + "don't cache AST for inactive: " + toString(tUnit)); //$NON-NLS-1$ + return; } + + if (DEBUG && (tUnit != null || ast != null)) // don't report call from disposeAST() + System.out.println(DEBUG_PREFIX + getThreadName() + "caching AST: " + toString(ast) + " for: " + toString(tUnit)); //$NON-NLS-1$ //$NON-NLS-2$ + + if (fAST != null) + disposeAST(); + + fAST= ast; + fLastWriteOnIndex= fAST == null ? 0 : fAST.getIndex().getLastWriteAccess(); + + // Signal AST change + fCacheMutex.notifyAll(); } /** @@ -259,10 +257,10 @@ public class ASTCache { /** * Creates a new translation unit AST. * - * @param tUnit the C element for which to create the AST - * @param index for AST generation, needs to be read-locked. - * @param progressMonitor the progress monitor - * @return AST + * @param tUnit the translation unit for which to create the AST + * @param index the index for AST generation, needs to be read-locked. + * @param progressMonitor a progress monitor, may be null + * @return an AST for the translation unit, or null if the operation was cancelled */ public IASTTranslationUnit createAST(final ITranslationUnit tUnit, final IIndex index, final IProgressMonitor progressMonitor) { if (progressMonitor != null && progressMonitor.isCanceled()) @@ -294,14 +292,14 @@ public class ASTCache { /** * Set the given translation unit as active element to cache an AST for. * - * @param tUnit + * @param tUnit the translation unit */ public void setActiveElement(ITranslationUnit tUnit) { if (tUnit == fActiveTU) { return; } - fIsReconciling= false; synchronized (fCacheMutex) { + fIsReconciling= false; fActiveTU= tUnit; cache(null, tUnit); } @@ -312,7 +310,7 @@ public class ASTCache { /** * Check whether the given translation unit is the active element of this cache. * - * @param tUnit + * @param tUnit the translation unit * @return true, if this cache manages the given translation unit */ public boolean isActiveElement(ITranslationUnit tUnit) { @@ -325,43 +323,42 @@ public class ASTCache { * Informs that reconciling (computation of the AST) for the given element * is about to be started. * - * @param tUnit the C element - * @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#aboutToBeReconciled() + * @param tUnit the translation unit */ public void aboutToBeReconciled(ITranslationUnit tUnit) { if (tUnit == null) return; - if (fActiveTU == null || !fActiveTU.equals(tUnit)) { - return; + + synchronized (fCacheMutex) { + if (fActiveTU == null || !fActiveTU.equals(tUnit)) { + return; + } + + if (DEBUG) + System.out.println(DEBUG_PREFIX + getThreadName() + "about to reconcile: " + toString(tUnit)); //$NON-NLS-1$ + + fIsReconciling= true; + cache(null, tUnit); } - - if (DEBUG) - System.out.println(DEBUG_PREFIX + getThreadName() + "about to reconcile: " + toString(tUnit)); //$NON-NLS-1$ - - fIsReconciling= true; - cache(null, tUnit); } /** * Informs that reconciling of the AST of the given translation unit has finished. * - * @param ast - * @param tUnit + * @param ast the translation unit AST + * @param tUnit the translation unit */ public void reconciled(IASTTranslationUnit ast, ITranslationUnit tUnit) { synchronized (fCacheMutex) { + if (tUnit == null || !tUnit.equals(fActiveTU)) { + if (DEBUG) + System.out.println(DEBUG_PREFIX + getThreadName() + "ignoring AST of out-dated element"); //$NON-NLS-1$ + return; + } if (DEBUG) System.out.println(DEBUG_PREFIX + getThreadName() + "reconciled: " + toString(tUnit) + ", AST: " + toString(ast)); //$NON-NLS-1$ //$NON-NLS-2$ fIsReconciling= false; - if (tUnit == null || !tUnit.equals(fActiveTU)) { - if (DEBUG) - System.out.println(DEBUG_PREFIX + getThreadName() + " ignoring AST of out-dated element"); //$NON-NLS-1$ - - // Signal - threads might wait for wrong element - fCacheMutex.notifyAll(); - return; - } cache(ast, tUnit); } } @@ -370,7 +367,7 @@ public class ASTCache { * Tells whether the given C element is the one * reported as currently being reconciled. * - * @param tUnit the C element + * @param tUnit the translation unit * @return true if reported as currently being reconciled */ public boolean isReconciling(ITranslationUnit tUnit) { @@ -393,21 +390,21 @@ public class ASTCache { /** * Returns a string for the given C element used for debugging. * - * @param cElement the translation unit AST + * @param tUnit the translation unit * @return a string used for debugging */ - private static String toString(ICElement cElement) { - if (cElement == null) + private static String toString(ITranslationUnit tUnit) { + if (tUnit == null) return "null"; //$NON-NLS-1$ else - return cElement.getElementName(); + return tUnit.getElementName(); } /** * Returns a string for the given AST used for debugging. * - * @param ast the translation unit AST + * @param ast the translation unit AST * @return a string used for debugging */ private static String toString(IASTTranslationUnit ast) {