1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-31 21:05:37 +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
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -13,6 +13,7 @@
* Tim Kelly (Nokia)
* Anna Dushistova (MontaVista)
* Marc-Andre Laperle
* Martin Oberhuber (Wind River) - [397652] fix up-to-date check for PDOM
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom;
@ -23,6 +24,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
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.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
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 com.ibm.icu.text.MessageFormat;
import com.ibm.icu.text.SimpleDateFormat;
/**
* 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
*/
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$
return true; // no check performed in this case
return null; // No check is performed in this case
Set<ITranslationUnit> sources= new HashSet<ITranslationUnit>();
cproject.accept(new TranslationUnitCollector(sources, null, new NullProgressMonitor()));
IStatus syncStatus = null;
try {
IIndex index= getIndex(cproject);
@ -1543,8 +1561,9 @@ public class PDOMManager implements IWritableIndexManager, IListener {
IResource resource= tu.getResource();
if (resource instanceof IFile && isSubjectToIndexing(tu.getLanguage())) {
IIndexFileLocation location= IndexLocationFactory.getWorkspaceIFL((IFile) resource);
if (!areSynchronized(new HashSet<IIndexFileLocation>(), index, resource, location)) {
return false;
syncStatus = areSynchronized(new HashSet<IIndexFileLocation>(), index, resource, location);
if (syncStatus != null) {
return syncStatus;
}
}
}
@ -1555,11 +1574,11 @@ public class PDOMManager implements IWritableIndexManager, IListener {
CCorePlugin.log(e);
}
return true;
return null;
}
private boolean isSubjectToIndexing(ILanguage language) {
final int linkageID=language.getLinkageID();
final int linkageID = language.getLinkageID();
for (int id : IDS_FOR_LINKAGES_TO_INDEX) {
if (linkageID == id)
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 index the index to check against
* @param resource the resource to check from the workspace
* @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
*/
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)) {
trail.add(location);
IIndexFile[] file= index.getFiles(location);
IIndexFile[] files= index.getFiles(location);
// pre-includes may be listed twice (191989)
if (file.length < 1 || file.length > 2)
return false;
if (files.length <= 0)
return new MultiStatus(CCorePlugin.PLUGIN_ID, IStatus.OK, "No index file found for: " + location, null); //$NON-NLS-1$
if (resource.getLocalTimeStamp() != file[0].getTimestamp())
return false;
for (IIndexFile file : files) {
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
// be read from the index.
IIndexInclude[] includes= index.findIncludes(file[0]);
for (IIndexInclude inc : includes) {
IIndexFileLocation newLocation= inc.getIncludesLocation();
if (newLocation != null) {
String path= newLocation.getFullPath();
if (path != null) {
IResource newResource= ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(path));
if (!areSynchronized(trail, index, newResource, newLocation)) {
return false;
// If it is up-to-date, the includes have not changed and may be read from the index.
IIndexInclude[] includes= index.findIncludes(file);
for (IIndexInclude inc : includes) {
IIndexFileLocation newLocation= inc.getIncludesLocation();
if (newLocation != null) {
String path= newLocation.getFullPath();
if (path != null) {
IResource newResource= ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(path));
MultiStatus m = areSynchronized(trail, index, newResource, newLocation);
if (m != null) {
m.add(new Status(IStatus.INFO, CCorePlugin.PLUGIN_ID,
"Included by " + file.getLocation().getFullPath())); //$NON-NLS-1$
return m;
}
}
}
}
}
}
return true;
return null;
}
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
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -8,11 +8,11 @@
* Contributors:
* Andrew Ferguson (Symbian) - Initial implementation
* 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;
import java.io.File;
import com.ibm.icu.text.MessageFormat;
import java.util.Map;
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.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import com.ibm.icu.text.MessageFormat;
/**
* An ISafeRunnable which
* <ul>
@ -43,14 +46,28 @@ public class GeneratePDOM {
protected File targetLocation;
protected String indexerID;
protected boolean deleteOnExit;
public GeneratePDOM(IExportProjectProvider pm, String[] applicationArguments, File targetLocation, String indexerID) {
protected boolean checkIndexStatus;
/**
* 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.applicationArguments= applicationArguments;
this.targetLocation= targetLocation;
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
* 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
*/
public final IStatus run() throws CoreException {
boolean isContentSynced= false;
// create the project
// Create the project
pm.setApplicationArguments(applicationArguments);
final ICProject cproject = pm.createProject();
if(cproject==null) {
if (cproject == null) {
fail(MessageFormat.format(Messages.GeneratePDOM_ProjectProviderReturnedNullCProject,
new Object [] {pm.getClass().getName()}));
return null; // cannot be reached, inform the compiler
new Object[] { pm.getClass().getName() }));
return null; // Cannot be reached, inform the compiler
}
IIndexLocationConverter converter= pm.getLocationConverter(cproject);
if(converter==null) {
if (converter == null) {
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);
try {
final IIndexManager im = CCorePlugin.getIndexManager();
final IIndexManager manager = CCorePlugin.getIndexManager();
for (int i = 0; i < 20; i++) {
if(CCoreInternals.getPDOMManager().isProjectRegistered(cproject)) {
im.joinIndexer(Integer.MAX_VALUE, new NullProgressMonitor());
if (!im.isIndexerSetupPostponed(cproject)) {
if (CCoreInternals.getPDOMManager().isProjectRegistered(cproject)) {
manager.joinIndexer(Integer.MAX_VALUE, new NullProgressMonitor());
if (!manager.isIndexerSetupPostponed(cproject)) {
break;
}
}
Thread.sleep(200);
}
// check status
isContentSynced= CCoreInternals.getPDOMManager().isProjectContentSynced(cproject);
if(isContentSynced) {
// export a .pdom file
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();
if (checkIndexStatus) {
// Check status
IStatus syncStatus = CCoreInternals.getPDOMManager().getProjectContentSyncState(cproject);
if (syncStatus != null) {
// Add message and error severity
IStatus myStatus = new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, Messages.GeneratePDOM_Incomplete);
MultiStatus m = new MultiStatus(CCorePlugin.PLUGIN_ID, 1, new IStatus[] {myStatus, syncStatus},
Messages.GeneratePDOM_Incomplete, null);
// Log the status right away since legacy clients did not return any status details
CCorePlugin.log(m);
return m;
}
}
} catch(InterruptedException ie) {
// Export a .pdom file
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()});
throw new CoreException(CCorePlugin.createStatus(msg, ie));
} finally {
if(deleteOnExit) {
if (deleteOnExit) {
cproject.getProject().delete(true, new NullProgressMonitor());
}
}
return isContentSynced ?
new Status(IStatus.OK, CCorePlugin.PLUGIN_ID, Messages.GeneratePDOM_Success)
: new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, Messages.GeneratePDOM_Incomplete);
return new Status(IStatus.OK, CCorePlugin.PLUGIN_ID, Messages.GeneratePDOM_Success);
}
private void fail(String message) throws CoreException {