1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-01 21:35:40 +02:00

Bug 397652 - Exporting a PDOM fails due to wrong index-in-sync check

Fixes an incorrect workaround from bug 229989 comment 6:
It is perfectly valid for one location to map to multiple index files.
Also adds better error reporting for out-of-sync files, and adds API
to allow exporting a PDOM without any index-in-sync check.

Change-Id: I63a7d36a2de465f9994cc9b9698688e3ad6850ee
This commit is contained in:
Martin Oberhuber 2013-01-14 12:36:51 -08:00 committed by Sergey Prigogin
parent 9e6ee807a9
commit 111b6ba185
2 changed files with 124 additions and 73 deletions

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2005, 2012 QNX Software Systems and others. * Copyright (c) 2005, 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -13,6 +13,7 @@
* Tim Kelly (Nokia) * Tim Kelly (Nokia)
* Anna Dushistova (MontaVista) * Anna Dushistova (MontaVista)
* Marc-Andre Laperle * Marc-Andre Laperle
* Martin Oberhuber (Wind River) - [397652] fix up-to-date check for PDOM
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.pdom; package org.eclipse.cdt.internal.core.pdom;
@ -23,6 +24,7 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
@ -93,6 +95,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Path;
@ -109,6 +112,7 @@ import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.core.runtime.preferences.InstanceScope;
import com.ibm.icu.text.MessageFormat; import com.ibm.icu.text.MessageFormat;
import com.ibm.icu.text.SimpleDateFormat;
/** /**
* Manages PDOM updates and events associated with them. Provides methods for index access. * Manages PDOM updates and events associated with them. Provides methods for index access.
@ -1529,11 +1533,25 @@ public class PDOMManager implements IWritableIndexManager, IListener {
* @throws CoreException * @throws CoreException
*/ */
public boolean isProjectContentSynced(ICProject cproject) throws CoreException { public boolean isProjectContentSynced(ICProject cproject) throws CoreException {
IStatus s = getProjectContentSyncState(cproject);
return s == null;
}
/**
* Checks whether the index is in sync with the file system.
* @param cproject the project to check
* @return <code>null</code> when the content in the project fragment of the specified project's index
* is complete (contains all sources) and up to date; or an @link{IStatus} indicating the first
* occurrence of an index file found not up-to-date, along with its include trail.
* @throws CoreException in case of a file access or other internal error
*/
public IStatus getProjectContentSyncState(ICProject cproject) throws CoreException {
if (!"true".equals(IndexerPreferences.get(cproject.getProject(), IndexerPreferences.KEY_INDEX_ALL_FILES, null))) //$NON-NLS-1$ if (!"true".equals(IndexerPreferences.get(cproject.getProject(), IndexerPreferences.KEY_INDEX_ALL_FILES, null))) //$NON-NLS-1$
return true; // no check performed in this case return null; // No check is performed in this case
Set<ITranslationUnit> sources= new HashSet<ITranslationUnit>(); Set<ITranslationUnit> sources= new HashSet<ITranslationUnit>();
cproject.accept(new TranslationUnitCollector(sources, null, new NullProgressMonitor())); cproject.accept(new TranslationUnitCollector(sources, null, new NullProgressMonitor()));
IStatus syncStatus = null;
try { try {
IIndex index= getIndex(cproject); IIndex index= getIndex(cproject);
@ -1543,8 +1561,9 @@ public class PDOMManager implements IWritableIndexManager, IListener {
IResource resource= tu.getResource(); IResource resource= tu.getResource();
if (resource instanceof IFile && isSubjectToIndexing(tu.getLanguage())) { if (resource instanceof IFile && isSubjectToIndexing(tu.getLanguage())) {
IIndexFileLocation location= IndexLocationFactory.getWorkspaceIFL((IFile) resource); IIndexFileLocation location= IndexLocationFactory.getWorkspaceIFL((IFile) resource);
if (!areSynchronized(new HashSet<IIndexFileLocation>(), index, resource, location)) { syncStatus = areSynchronized(new HashSet<IIndexFileLocation>(), index, resource, location);
return false; if (syncStatus != null) {
return syncStatus;
} }
} }
} }
@ -1555,11 +1574,11 @@ public class PDOMManager implements IWritableIndexManager, IListener {
CCorePlugin.log(e); CCorePlugin.log(e);
} }
return true; return null;
} }
private boolean isSubjectToIndexing(ILanguage language) { private boolean isSubjectToIndexing(ILanguage language) {
final int linkageID=language.getLinkageID(); final int linkageID = language.getLinkageID();
for (int id : IDS_FOR_LINKAGES_TO_INDEX) { for (int id : IDS_FOR_LINKAGES_TO_INDEX) {
if (linkageID == id) if (linkageID == id)
return true; return true;
@ -1568,45 +1587,57 @@ public class PDOMManager implements IWritableIndexManager, IListener {
} }
/** /**
* Recursively checks that the specified file, and its include are up-to-date. * Recursively checks that the specified file, and its includes are up-to-date.
* @param trail a set of previously checked include file locations * @param trail a set of previously checked include file locations
* @param index the index to check against * @param index the index to check against
* @param resource the resource to check from the workspace * @param resource the resource to check from the workspace
* @param location the location to check from the index * @param location the location to check from the index
* @return whether the specified file, and its includes are up-to-date. * @return <code>null</code> when whether the specified file, and its includes are up-to-date,
* or a MultiStatus indicating the file found to be not in sync along with it include trail.
* @throws CoreException * @throws CoreException
*/ */
private static boolean areSynchronized(Set<IIndexFileLocation> trail, IIndex index, IResource resource, IIndexFileLocation location) throws CoreException { private static MultiStatus areSynchronized(Set<IIndexFileLocation> trail, IIndex index,
IResource resource, IIndexFileLocation location) throws CoreException {
if (!trail.contains(location)) { if (!trail.contains(location)) {
trail.add(location); trail.add(location);
IIndexFile[] file= index.getFiles(location); IIndexFile[] files= index.getFiles(location);
// pre-includes may be listed twice (191989) if (files.length <= 0)
if (file.length < 1 || file.length > 2) return new MultiStatus(CCorePlugin.PLUGIN_ID, IStatus.OK, "No index file found for: " + location, null); //$NON-NLS-1$
return false;
if (resource.getLocalTimeStamp() != file[0].getTimestamp()) for (IIndexFile file : files) {
return false; long diff = resource.getLocalTimeStamp() - file.getTimestamp();
if (diff != 0) {
return new MultiStatus(CCorePlugin.PLUGIN_ID, IStatus.OK,
"Index timestamp for '" //$NON-NLS-1$
+ file.getLocation().getFullPath()
+ "' is " + diff + " msec older than " //$NON-NLS-1$ //$NON-NLS-2$
+ location
+ "(" + SimpleDateFormat.getDateTimeInstance().format(new Date(resource.getLocalTimeStamp())) //$NON-NLS-1$
+ ")", null); //$NON-NLS-1$
}
// if it is up-to-date, the includes have not changed and may // If it is up-to-date, the includes have not changed and may be read from the index.
// be read from the index. IIndexInclude[] includes= index.findIncludes(file);
IIndexInclude[] includes= index.findIncludes(file[0]); for (IIndexInclude inc : includes) {
for (IIndexInclude inc : includes) { IIndexFileLocation newLocation= inc.getIncludesLocation();
IIndexFileLocation newLocation= inc.getIncludesLocation(); if (newLocation != null) {
if (newLocation != null) { String path= newLocation.getFullPath();
String path= newLocation.getFullPath(); if (path != null) {
if (path != null) { IResource newResource= ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(path));
IResource newResource= ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(path)); MultiStatus m = areSynchronized(trail, index, newResource, newLocation);
if (!areSynchronized(trail, index, newResource, newLocation)) { if (m != null) {
return false; m.add(new Status(IStatus.INFO, CCorePlugin.PLUGIN_ID,
"Included by " + file.getLocation().getFullPath())); //$NON-NLS-1$
return m;
}
} }
} }
} }
} }
} }
return null;
return true;
} }
public boolean isFileIndexedUnconditionally(IIndexFileLocation ifl) { public boolean isFileIndexedUnconditionally(IIndexFileLocation ifl) {

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2007, 2009 Symbian Software Systems and others. * Copyright (c) 2007, 2013 Symbian Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -8,11 +8,11 @@
* Contributors: * Contributors:
* Andrew Ferguson (Symbian) - Initial implementation * Andrew Ferguson (Symbian) - Initial implementation
* Markus Schorn (Wind River Systems) * Markus Schorn (Wind River Systems)
* Martin Oberhuber (Wind River) - [397652] fix up-to-date check for PDOM
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.export; package org.eclipse.cdt.internal.core.pdom.export;
import java.io.File; import java.io.File;
import com.ibm.icu.text.MessageFormat;
import java.util.Map; import java.util.Map;
import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CCorePlugin;
@ -26,9 +26,12 @@ import org.eclipse.cdt.internal.core.pdom.WritablePDOM;
import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences; import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.Status;
import com.ibm.icu.text.MessageFormat;
/** /**
* An ISafeRunnable which * An ISafeRunnable which
* <ul> * <ul>
@ -43,14 +46,28 @@ public class GeneratePDOM {
protected File targetLocation; protected File targetLocation;
protected String indexerID; protected String indexerID;
protected boolean deleteOnExit; protected boolean deleteOnExit;
protected boolean checkIndexStatus;
public GeneratePDOM(IExportProjectProvider pm, String[] applicationArguments, File targetLocation, String indexerID) {
/**
* Runnable to export a PDOM.
* @param checkIndexStatus <code>true</code> to check index completeness before exporting, or
* <code>false</code> to export the index without checking anything
* @since 5.5
*/
public GeneratePDOM(IExportProjectProvider pm, String[] applicationArguments, File targetLocation,
String indexerID, boolean checkIndexStatus) {
this.pm= pm; this.pm= pm;
this.applicationArguments= applicationArguments; this.applicationArguments= applicationArguments;
this.targetLocation= targetLocation; this.targetLocation= targetLocation;
this.indexerID= indexerID; this.indexerID= indexerID;
this.checkIndexStatus= checkIndexStatus;
} }
public GeneratePDOM(IExportProjectProvider pm, String[] applicationArguments, File targetLocation,
String indexerID) {
this(pm, applicationArguments, targetLocation, indexerID, true);
}
/** /**
* When set, the project created by the associated {@link IExportProjectProvider} will * When set, the project created by the associated {@link IExportProjectProvider} will
* be deleted after {@link #run()} completes. By default this is not set. * be deleted after {@link #run()} completes. By default this is not set.
@ -66,74 +83,77 @@ public class GeneratePDOM {
* @throws CoreException if an internal or invalid configuration error occurs * @throws CoreException if an internal or invalid configuration error occurs
*/ */
public final IStatus run() throws CoreException { public final IStatus run() throws CoreException {
boolean isContentSynced= false; // Create the project
// create the project
pm.setApplicationArguments(applicationArguments); pm.setApplicationArguments(applicationArguments);
final ICProject cproject = pm.createProject(); final ICProject cproject = pm.createProject();
if(cproject==null) { if (cproject == null) {
fail(MessageFormat.format(Messages.GeneratePDOM_ProjectProviderReturnedNullCProject, fail(MessageFormat.format(Messages.GeneratePDOM_ProjectProviderReturnedNullCProject,
new Object [] {pm.getClass().getName()})); new Object[] { pm.getClass().getName() }));
return null; // cannot be reached, inform the compiler return null; // Cannot be reached, inform the compiler
} }
IIndexLocationConverter converter= pm.getLocationConverter(cproject); IIndexLocationConverter converter= pm.getLocationConverter(cproject);
if(converter==null) { if (converter == null) {
fail(MessageFormat.format(Messages.GeneratePDOM_NullLocationConverter, fail(MessageFormat.format(Messages.GeneratePDOM_NullLocationConverter,
new Object [] {pm.getClass().getName()})); new Object[] { pm.getClass().getName() }));
} }
// index the project // Index the project
IndexerPreferences.set(cproject.getProject(), IndexerPreferences.KEY_INDEXER_ID, indexerID); IndexerPreferences.set(cproject.getProject(), IndexerPreferences.KEY_INDEXER_ID, indexerID);
try { try {
final IIndexManager im = CCorePlugin.getIndexManager(); final IIndexManager manager = CCorePlugin.getIndexManager();
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
if(CCoreInternals.getPDOMManager().isProjectRegistered(cproject)) { if (CCoreInternals.getPDOMManager().isProjectRegistered(cproject)) {
im.joinIndexer(Integer.MAX_VALUE, new NullProgressMonitor()); manager.joinIndexer(Integer.MAX_VALUE, new NullProgressMonitor());
if (!im.isIndexerSetupPostponed(cproject)) { if (!manager.isIndexerSetupPostponed(cproject)) {
break; break;
} }
} }
Thread.sleep(200); Thread.sleep(200);
} }
// check status if (checkIndexStatus) {
isContentSynced= CCoreInternals.getPDOMManager().isProjectContentSynced(cproject); // Check status
IStatus syncStatus = CCoreInternals.getPDOMManager().getProjectContentSyncState(cproject);
if(isContentSynced) { if (syncStatus != null) {
// export a .pdom file // Add message and error severity
CCoreInternals.getPDOMManager().exportProjectPDOM(cproject, targetLocation, converter); IStatus myStatus = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, Messages.GeneratePDOM_Incomplete);
MultiStatus m = new MultiStatus(CCorePlugin.PLUGIN_ID, 1, new IStatus[] {myStatus, syncStatus},
// write properties to exported PDOM Messages.GeneratePDOM_Incomplete, null);
WritablePDOM exportedPDOM= new WritablePDOM(targetLocation, converter, LanguageManager.getInstance().getPDOMLinkageFactoryMappings()); // Log the status right away since legacy clients did not return any status details
exportedPDOM.acquireWriteLock(0); CCorePlugin.log(m);
try { return m;
Map<String,String> exportProperties= pm.getExportProperties();
if(exportProperties!=null) {
for(Map.Entry<String,String> entry : exportProperties.entrySet()) {
exportedPDOM.setProperty(entry.getKey(), entry.getValue());
}
}
exportedPDOM.close();
}
finally {
exportedPDOM.releaseWriteLock();
} }
} }
// Export a .pdom file
} catch(InterruptedException ie) { CCoreInternals.getPDOMManager().exportProjectPDOM(cproject, targetLocation, converter);
// Write properties to exported PDOM
WritablePDOM exportedPDOM= new WritablePDOM(targetLocation, converter,
LanguageManager.getInstance().getPDOMLinkageFactoryMappings());
exportedPDOM.acquireWriteLock(0);
try {
Map<String, String> exportProperties= pm.getExportProperties();
if (exportProperties != null) {
for(Map.Entry<String, String> entry : exportProperties.entrySet()) {
exportedPDOM.setProperty(entry.getKey(), entry.getValue());
}
}
exportedPDOM.close();
} finally {
exportedPDOM.releaseWriteLock();
}
} catch (InterruptedException ie) {
String msg= MessageFormat.format(Messages.GeneratePDOM_GenericGenerationFailed, new Object[] {ie.getMessage()}); String msg= MessageFormat.format(Messages.GeneratePDOM_GenericGenerationFailed, new Object[] {ie.getMessage()});
throw new CoreException(CCorePlugin.createStatus(msg, ie)); throw new CoreException(CCorePlugin.createStatus(msg, ie));
} finally { } finally {
if(deleteOnExit) { if (deleteOnExit) {
cproject.getProject().delete(true, new NullProgressMonitor()); cproject.getProject().delete(true, new NullProgressMonitor());
} }
} }
return isContentSynced ? return new Status(IStatus.OK, CCorePlugin.PLUGIN_ID, Messages.GeneratePDOM_Success);
new Status(IStatus.OK, CCorePlugin.PLUGIN_ID, Messages.GeneratePDOM_Success)
: new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, Messages.GeneratePDOM_Incomplete);
} }
private void fail(String message) throws CoreException { private void fail(String message) throws CoreException {