--- a/builder/com.nokia.carbide.cdt.builder/src/com/nokia/carbide/cdt/builder/DefaultIncludeFileLocator.java Tue Jan 05 11:22:47 2010 -0600
+++ b/builder/com.nokia.carbide.cdt.builder/src/com/nokia/carbide/cdt/builder/DefaultIncludeFileLocator.java Tue Jan 05 11:23:50 2010 -0600
@@ -23,12 +23,12 @@
import java.util.*;
import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.IPath;
import com.nokia.carbide.cdt.builder.project.ICarbideProjectInfo;
-import com.nokia.carbide.cpp.epoc.engine.model.sbv.ISBVView;
+import com.nokia.carbide.cpp.internal.api.sdk.SymbianBuildContext;
import com.nokia.carbide.cpp.sdk.core.*;
import com.nokia.carbide.internal.api.cpp.epoc.engine.preprocessor.BasicIncludeFileLocator;
+import com.nokia.cpp.internal.api.utils.core.Check;
public class DefaultIncludeFileLocator extends BasicIncludeFileLocator {
/**
@@ -40,7 +40,6 @@
*/
public DefaultIncludeFileLocator(IProject project, ISymbianBuildContext buildContext) {
super(null, null);
-
List<File> systemPaths = new ArrayList<File>();
if (buildContext != null && buildContext.getSDK() != null) {
// search implicit bld.inf directory if known
@@ -51,84 +50,11 @@
systemPaths.add(cpi.getAbsoluteBldInfPath().removeLastSegments(1).toFile());
}
}
+
+ // get info from context
+ Check.checkState(buildContext instanceof SymbianBuildContext);
- IBSFPlatform bsfplatform = buildContext.getSDK().getBSFCatalog().findPlatform(buildContext.getPlatformString());
- ISBVPlatform sbvPlatform = buildContext.getSDK().getSBVCatalog().findPlatform(buildContext.getPlatformString());
-
- // look in the epoc32 directory of the SDK
- IPath includePath = buildContext.getSDK().getIncludePath();
- if (includePath != null) {
- File includeDir = includePath.toFile().getAbsoluteFile();
- File dir;
-
- // get additional include directories from BSF platform, if defined
- if (bsfplatform != null) {
- IPath[] systemIncludePaths = bsfplatform.getSystemIncludePaths();
- for (IPath path : systemIncludePaths) {
- dir = path.toFile();
- if (dir.exists() && dir.isDirectory()) {
- systemPaths.add(dir);
- }
- }
- } else if (sbvPlatform != null){
-
- LinkedHashMap<IPath, String> platPaths = sbvPlatform.getBuildIncludePaths();
- Set<IPath> set = platPaths.keySet();
- for (IPath path : set) {
- String pathType = platPaths.get(path);
- if (pathType.equalsIgnoreCase(ISBVView.INCLUDE_FLAG_PREPEND) || pathType.equalsIgnoreCase(ISBVView.INCLUDE_FLAG_SET)){
- dir = path.toFile();
- systemPaths.add(dir);
- }
- }
- }
- else {
- // legacy behavior
- if (buildContext.getPlatformString().equals(ISymbianBuildContext.EMULATOR_PLATFORM)) {
- dir = new File(includeDir, "wins"); //$NON-NLS-1$
- if (dir.exists() && dir.isDirectory()) {
- systemPaths.add(dir);
- }
- }
- }
-
- // add OEM dir
- dir = new File(includeDir, "oem"); //$NON-NLS-1$
- if (dir.exists() && dir.isDirectory()) {
- systemPaths.add(dir);
- }
-
- // and finally the normal include dir
- systemPaths.add(includeDir);
-
- // and finally, finally, if this is an SBV add any paths with the append flag
- if (sbvPlatform != null){
-
- Map<IPath, String> platPaths = sbvPlatform.getBuildIncludePaths();
- Set<IPath> set = platPaths.keySet();
- for (IPath path : set) {
- String pathType = platPaths.get(path);
- if (pathType.equalsIgnoreCase(ISBVView.INCLUDE_FLAG_APPEND)){
- dir = path.toFile();
- systemPaths.add(dir);
- }
- }
- }
- }
-
- // also search files in same folder as variant.hrh
- File prefix = buildContext.getSDK().getPrefixFile();
- if (sbvPlatform != null){
- // might be an alternate HRH file to use
- IPath varVarHRH = sbvPlatform.getBuildVariantHRHFile();
- if (!varVarHRH.toFile().equals(prefix) && varVarHRH.toFile().exists()){
- prefix = varVarHRH.toFile();
- }
- }
- if (prefix != null) {
- systemPaths.add(prefix.getParentFile());
- }
-
+ systemPaths.addAll(((SymbianBuildContext) buildContext).getCachedSystemIncludePaths());
}
setPaths(null, (File[]) systemPaths.toArray(new File[systemPaths.size()]));
}
--- a/builder/com.nokia.carbide.cdt.builder/src/com/nokia/carbide/cdt/builder/EpocEngineHelper.java Tue Jan 05 11:22:47 2010 -0600
+++ b/builder/com.nokia.carbide.cdt.builder/src/com/nokia/carbide/cdt/builder/EpocEngineHelper.java Tue Jan 05 11:23:50 2010 -0600
@@ -27,6 +27,7 @@
import com.nokia.carbide.cpp.epoc.engine.preprocessor.AcceptedNodesViewFilter;
import com.nokia.carbide.cpp.epoc.engine.preprocessor.AllNodesViewFilter;
import com.nokia.carbide.cpp.internal.api.sdk.SymbianBuildContext;
+import com.nokia.carbide.cpp.internal.api.sdk.SymbianBuildContextDataCache;
import com.nokia.carbide.cpp.sdk.core.ISymbianBuildContext;
import com.nokia.carbide.cpp.sdk.core.ISymbianSDK;
import com.nokia.carbide.internal.api.cpp.epoc.engine.model.pkg.*;
@@ -88,35 +89,41 @@
monitor.beginTask("Scanning bld.inf for mmp and make files", buildConfigs.size());
- for (final ISymbianBuildContext context : buildConfigs) {
- EpocEnginePlugin.runWithBldInfData(bldInfFilePath,
- new DefaultViewConfiguration(context, bldInfFilePath, new AcceptedNodesViewFilter()),
- new BldInfDataRunnableAdapter() {
- public Object run(IBldInfData data) {
- for (IMakMakeReference ref : data.getMakMakeReferences()) {
- normalFiles.add(getFullPath(data, ref.getPath()));
- }
- for (IMakMakeReference ref : data.getTestMakMakeReferences()) {
- boolean ignore = false;
- for (String att : ref.getAttributes()) {
- if (att.equalsIgnoreCase("ignore")) { //$NON-NLS-1$
- ignore = true;
- break;
+ try {
+ // let cache know we're iterating a lot
+ SymbianBuildContextDataCache.startProjectOperation();
+
+ for (final ISymbianBuildContext context : buildConfigs) {
+ EpocEnginePlugin.runWithBldInfData(bldInfFilePath,
+ new DefaultViewConfiguration(context, bldInfFilePath, new AcceptedNodesViewFilter()),
+ new BldInfDataRunnableAdapter() {
+ public Object run(IBldInfData data) {
+ for (IMakMakeReference ref : data.getMakMakeReferences()) {
+ normalFiles.add(getFullPath(data, ref.getPath()));
+ }
+ for (IMakMakeReference ref : data.getTestMakMakeReferences()) {
+ boolean ignore = false;
+ for (String att : ref.getAttributes()) {
+ if (att.equalsIgnoreCase("ignore")) { //$NON-NLS-1$
+ ignore = true;
+ break;
+ }
+ }
+ if (!ignore) {
+ testFiles.add(getFullPath(data, ref.getPath()));
}
}
- if (!ignore) {
- testFiles.add(getFullPath(data, ref.getPath()));
- }
+ return null;
}
- return null;
- }
- });
-
- monitor.worked(1);
+ });
+
+ monitor.worked(1);
+ }
+
+ monitor.done();
+ } finally {
+ SymbianBuildContextDataCache.endProjectOperation();
}
-
- monitor.done();
-
for (IPath normalPath : normalFiles){
normalMakMakePaths.add(normalPath);
}
@@ -145,29 +152,35 @@
monitor.beginTask("Scanning bld.inf project extensions", buildConfigs.size());
- for (final ISymbianBuildContext context : buildConfigs) {
- EpocEnginePlugin.runWithBldInfData(bldInfFilePath,
- new DefaultViewConfiguration(context, bldInfFilePath, new AcceptedNodesViewFilter()),
- new BldInfDataRunnableAdapter() {
- public Object run(IBldInfData data) {
- BldInfViewPathHelper helper = new BldInfViewPathHelper(data, context);
- for (IExtension extension : data.getExtensions()) {
- IPath extensionMakefileBase = helper.convertExtensionTemplateToFilesystem(extension.getTemplatePath());
- normalFiles.add(extensionMakefileBase.addFileExtension("mk")); //$NON-NLS-1$
+ try {
+ // let cache know we're iterating a lot
+ SymbianBuildContextDataCache.startProjectOperation();
+
+ for (final ISymbianBuildContext context : buildConfigs) {
+ EpocEnginePlugin.runWithBldInfData(bldInfFilePath,
+ new DefaultViewConfiguration(context, bldInfFilePath, new AcceptedNodesViewFilter()),
+ new BldInfDataRunnableAdapter() {
+ public Object run(IBldInfData data) {
+ BldInfViewPathHelper helper = new BldInfViewPathHelper(data, context);
+ for (IExtension extension : data.getExtensions()) {
+ IPath extensionMakefileBase = helper.convertExtensionTemplateToFilesystem(extension.getTemplatePath());
+ normalFiles.add(extensionMakefileBase.addFileExtension("mk")); //$NON-NLS-1$
+ }
+ for (IExtension extension : data.getTestExtensions()) {
+ IPath extensionMakefileBase = helper.convertExtensionTemplateToFilesystem(extension.getTemplatePath());
+ testFiles.add(extensionMakefileBase.addFileExtension("mk")); //$NON-NLS-1$
+ }
+ return null;
}
- for (IExtension extension : data.getTestExtensions()) {
- IPath extensionMakefileBase = helper.convertExtensionTemplateToFilesystem(extension.getTemplatePath());
- testFiles.add(extensionMakefileBase.addFileExtension("mk")); //$NON-NLS-1$
- }
- return null;
- }
- });
-
- monitor.worked(1);
+ });
+
+ monitor.worked(1);
+ }
+ } finally {
+ SymbianBuildContextDataCache.endProjectOperation();
+ monitor.done();
}
- monitor.done();
-
for (IPath normalPath : normalFiles){
normalExtensionPaths.add(normalPath);
}
@@ -195,30 +208,37 @@
monitor.beginTask("Scanning bld.inf project extensions", buildConfigs.size());
- for (final ISymbianBuildContext context : buildConfigs) {
- EpocEnginePlugin.runWithBldInfData(bldInfFilePath,
- new DefaultViewConfiguration(context, bldInfFilePath, new AcceptedNodesViewFilter()),
- new BldInfDataRunnableAdapter() {
- public Object run(IBldInfData data) {
- for (IExtension extension : data.getExtensions()) {
- if (extension.getName() != null) {
- normalFiles.add(extension);
+ try {
+ // let cache know we're iterating a lot
+ SymbianBuildContextDataCache.startProjectOperation();
+
+ for (final ISymbianBuildContext context : buildConfigs) {
+ EpocEnginePlugin.runWithBldInfData(bldInfFilePath,
+ new DefaultViewConfiguration(context, bldInfFilePath, new AcceptedNodesViewFilter()),
+ new BldInfDataRunnableAdapter() {
+ public Object run(IBldInfData data) {
+ for (IExtension extension : data.getExtensions()) {
+ if (extension.getName() != null) {
+ normalFiles.add(extension);
+ }
}
+ for (IExtension extension : data.getTestExtensions()) {
+ if (extension.getName() != null) {
+ testFiles.add(extension);
+ }
+ }
+ return null;
}
- for (IExtension extension : data.getTestExtensions()) {
- if (extension.getName() != null) {
- testFiles.add(extension);
- }
- }
- return null;
- }
- });
-
- monitor.worked(1);
+ });
+
+ monitor.worked(1);
+ }
+ } finally {
+ monitor.done();
+
+ SymbianBuildContextDataCache.endProjectOperation();
}
- monitor.done();
-
for (IExtension normal : normalFiles){
normalExtensions.add(normal);
}
@@ -240,29 +260,36 @@
monitor.beginTask("Scanning bld.inf project extensions", buildConfigs.size());
- for (final ISymbianBuildContext context : buildConfigs) {
- EpocEnginePlugin.runWithBldInfData(bldInfFilePath,
- new DefaultViewConfiguration(context, bldInfFilePath, new AcceptedNodesViewFilter()),
- new BldInfDataRunnableAdapter() {
- public Object run(IBldInfData data) {
- for (IExtension extension : data.getExtensions()) {
- if (extension.getName() == null) {
- extensions.add(extension);
+ try {
+ // let cache know we're iterating a lot
+ SymbianBuildContextDataCache.startProjectOperation();
+
+ for (final ISymbianBuildContext context : buildConfigs) {
+ EpocEnginePlugin.runWithBldInfData(bldInfFilePath,
+ new DefaultViewConfiguration(context, bldInfFilePath, new AcceptedNodesViewFilter()),
+ new BldInfDataRunnableAdapter() {
+ public Object run(IBldInfData data) {
+ for (IExtension extension : data.getExtensions()) {
+ if (extension.getName() == null) {
+ extensions.add(extension);
+ }
}
+ for (IExtension extension : data.getTestExtensions()) {
+ if (extension.getName() == null) {
+ extensions.add(extension);
+ }
+ }
+ return null;
}
- for (IExtension extension : data.getTestExtensions()) {
- if (extension.getName() == null) {
- extensions.add(extension);
- }
- }
- return null;
- }
- });
+ });
+
+ monitor.worked(1);
+ }
+ } finally {
+ monitor.done();
- monitor.worked(1);
+ SymbianBuildContextDataCache.endProjectOperation();
}
-
- monitor.done();
return extensions.size() > 0;
}
--- a/builder/com.nokia.carbide.cdt.builder/src/com/nokia/carbide/cdt/internal/builder/CarbideBuildManager.java Tue Jan 05 11:22:47 2010 -0600
+++ b/builder/com.nokia.carbide.cdt.builder/src/com/nokia/carbide/cdt/internal/builder/CarbideBuildManager.java Tue Jan 05 11:23:50 2010 -0600
@@ -309,6 +309,7 @@
for (ICarbideBuildConfiguration config : cpi.getBuildConfigurations()) {
// force a rebuild of the CarbideLanguageData cache
+ // TODO PERFORMANCE EJS: why??? We end up forcing a cache rebuild even when you just switch configurations...
CLanguageData languageData = null;
ICProjectDescription projDes = CoreModel.getDefault().getProjectDescription(config.getCarbideProject().getProject());
if (projDes != null) {
--- a/builder/com.nokia.carbide.cdt.builder/src/com/nokia/carbide/cdt/internal/builder/CarbideProjectModifier.java Tue Jan 05 11:22:47 2010 -0600
+++ b/builder/com.nokia.carbide.cdt.builder/src/com/nokia/carbide/cdt/internal/builder/CarbideProjectModifier.java Tue Jan 05 11:23:50 2010 -0600
@@ -20,6 +20,7 @@
import com.nokia.carbide.cdt.builder.project.ICarbideBuildConfiguration;
import com.nokia.carbide.cdt.builder.project.ICarbideProjectModifier;
import com.nokia.carbide.cdt.internal.api.builder.CarbideConfigurationDataProvider;
+import com.nokia.carbide.cpp.internal.api.sdk.SymbianBuildContextDataCache;
import com.nokia.carbide.cpp.sdk.core.ISymbianBuildContext;
import com.nokia.cpp.internal.api.utils.core.Logging;
@@ -255,8 +256,17 @@
CarbideBuilderPlugin.getBuildManager().setProjectInfo(this);
// save the CDT project description
- CCorePlugin.getDefault().setProjectDescription(projectTracker.getProject(), projDes, true, new NullProgressMonitor());
+ try {
+ // let the build context caches know we may be iterating them all
+ SymbianBuildContextDataCache.startProjectOperation();
+
+ // TODO PERFORMANCE: this can lead to CarbideLanguageData#buildCache(), which is an enormously expensive operation.
+ // So use a real progress monitor, say from a Job, so UI will be updated
+ CCorePlugin.getDefault().setProjectDescription(projectTracker.getProject(), projDes, true, new NullProgressMonitor());
+ } finally {
+ SymbianBuildContextDataCache.endProjectOperation();
+ }
if (rebuildCacheAndReindex) {
ICProject cproject = CoreModel.getDefault().create(projectTracker.getProject());
if (cproject != null)
--- a/core/com.nokia.carbide.cpp.sdk.core/src/com/nokia/carbide/cpp/internal/api/sdk/SymbianBuildContext.java Tue Jan 05 11:22:47 2010 -0600
+++ b/core/com.nokia.carbide.cpp.sdk.core/src/com/nokia/carbide/cpp/internal/api/sdk/SymbianBuildContext.java Tue Jan 05 11:23:50 2010 -0600
@@ -18,13 +18,9 @@
import org.eclipse.core.runtime.IPath;
import org.osgi.framework.Version;
-import com.nokia.carbide.cpp.epoc.engine.model.sbv.ISBVView;
import com.nokia.carbide.cpp.epoc.engine.preprocessor.*;
import com.nokia.carbide.cpp.internal.sdk.core.model.SymbianMissingSDKFactory;
-import com.nokia.carbide.cpp.internal.sdk.core.model.SymbianSDK;
import com.nokia.carbide.cpp.sdk.core.*;
-import com.nokia.carbide.internal.api.cpp.epoc.engine.preprocessor.BasicIncludeFileLocator;
-import com.nokia.carbide.internal.api.cpp.epoc.engine.preprocessor.MacroScanner;
public class SymbianBuildContext implements ISymbianBuildContext {
@@ -43,22 +39,11 @@
// a copy of bad SDK default to fall back
private static ISymbianSDK fallbackForBadSdk = SymbianMissingSDKFactory.createInstance("dummy_ID"); //$NON-NLS-1$
- // last time we checked the hrh file mod dates - only check if changed in last second
- private static final long HRH_TIMESTAMP_CHECK_QUANTUM = 1000; // 1 sec
- private static long lastHrhTimestampCheck;
-
- private File prefixFileParsed;
- private List<File> hrhFilesParsed = new ArrayList<File>();
- private List<IDefine> variantHRHMacros = new ArrayList<IDefine>();
- private long hrhCacheTimestamp;
- private List<IDefine> compilerPrefixMacros = new ArrayList<IDefine>();
- private long compilerCacheTimestamp;
-
-
public SymbianBuildContext(ISymbianSDK theSDK, String thePlatform, String theTarget) {
sdkId = theSDK.getUniqueId();
platform = thePlatform;
target = theTarget;
+
getDisplayString();
}
@@ -329,150 +314,11 @@
public List<IDefine> getVariantHRHDefines() {
- // we parse the variant hrh file to gather macros. this can be time consuming so do it
- // once and cache the values. only reset the cache when the hrh or any of its includes
- // has changed.
-
- boolean buildCache = false;
-
- if (hrhCacheTimestamp == 0) {
- // hasn't been built yet
- buildCache = true;
- } else {
- // cache exists. see if any of the files have changed
- ISymbianSDK sdk = getSDK();
- if (sdk != null) {
- // the prefix may have been added, removed, or changed. in any case,
- // we would need to reset the cache
- File currentPrefixFile = sdk.getPrefixFile();
- if (currentPrefixFile == null) {
- if (prefixFileParsed != null) {
- // prefix file was removed from the SDK
- buildCache = true;
- }
- } else {
- if (prefixFileParsed == null) {
- // prefix file was added to the SDK
- buildCache = true;
- } else {
- // there was a prefix file before and now. see if it's the same file
- // and if so, has it been modified?
- if (!currentPrefixFile.equals(prefixFileParsed) || currentPrefixFile.lastModified() > hrhCacheTimestamp) {
- buildCache = true;
- }
- }
- }
- }
-
- // now check to see if any of the included hrh files have changed
- // we will do this at most once per quantum, because it is expensive and during import it was done 100 times per second
- if (!buildCache && (System.currentTimeMillis() - lastHrhTimestampCheck) > HRH_TIMESTAMP_CHECK_QUANTUM) {
- for (File file : hrhFilesParsed) {
- if (file.lastModified() > hrhCacheTimestamp) {
- buildCache = true;
- break;
- }
- }
- lastHrhTimestampCheck = System.currentTimeMillis();
- }
- }
-
- if (buildCache) {
-
- variantHRHMacros.clear();
-
- synchronized (this) {
-
- List<IDefine> macros = new ArrayList<IDefine>();
- Map<String, IDefine> namedMacros = new HashMap<String, IDefine>();
- File prefixFile = getSDK().getPrefixFile();
-
- if (prefixFile == null){
- // Check that the prefix file may have become available since the SDK was scanned last.
- // This can happen, for e.g., if the user opens the IDE _then_ does a subst on a drive that already has an SDK entry.
- IPath prefixCheck = ((SymbianSDK)getSDK()).getPrefixFromVariantCfg();
- if (prefixCheck != null){
- prefixFile = prefixCheck.toFile();
- getSDK().setPrefixFile(prefixCheck);
- }
- }
-
- if (prefixFile != null) {
-
- // add any BSF/SBV includes so the headers are picked up from the correct location
- List<File> systemPaths = new ArrayList<File>();
- IBSFPlatform bsfPlat = getSDK().getBSFCatalog().findPlatform(platform);
- ISBVPlatform sbvPlat = getSDK().getSBVCatalog().findPlatform(platform);
- if (bsfPlat != null) {
- for (IPath path : bsfPlat.getSystemIncludePaths()) {
- systemPaths.add(path.toFile());
- }
- } else if (sbvPlat != null) {
- LinkedHashMap<IPath, String> platPaths = sbvPlat.getBuildIncludePaths();
- Set<IPath> set = platPaths.keySet();
- for (IPath path : set) {
- String pathType = platPaths.get(path);
- if (pathType.equalsIgnoreCase(ISBVView.INCLUDE_FLAG_PREPEND) || pathType.equalsIgnoreCase(ISBVView.INCLUDE_FLAG_SET)){
- systemPaths.add(path.toFile());
- }
- }
- }
-
- MacroScanner scanner = new MacroScanner(
- new BasicIncludeFileLocator(null, systemPaths.toArray(new File[systemPaths.size()])),
- DefaultModelDocumentProvider.getInstance(),
- DefaultTranslationUnitProvider.getInstance());
- scanner.scanFile(prefixFile);
-
- List<IDefine> scannedMacros = (List<IDefine>)scanner.getMacroDefinitions();
- for (IDefine scannedMacro : scannedMacros){
- // we don't want duplicate macros, so check to see if it's already there.
- // if it is, remove it and then add the newer one. this is consistent with
- // how it would be from a compiler standpoint.
- IDefine macro = namedMacros.get(scannedMacro.getName());
- if (macro != null) {
- macros.remove(macro);
- }
-
- macros.add(scannedMacro);
- namedMacros.put(scannedMacro.getName(), scannedMacro);
- }
-
- hrhFilesParsed.clear();
- for (File inc : scanner.getIncludedFiles()) {
- hrhFilesParsed.add(inc);
- }
-
- List<String> variantCFGMacros = new ArrayList<String>();
- variantCFGMacros = getSDK().getVariantCFGMacros();
- for (String cfgMacros : variantCFGMacros){
- // we don't want duplicate macros, so check to see if it's already there.
- IDefine existingMacro = namedMacros.get(cfgMacros);
- if (existingMacro != null) {
- macros.remove(existingMacro);
- }
-
- IDefine macro = DefineFactory.createSimpleFreeformDefine(cfgMacros);
- macros.add(macro);
- namedMacros.put(macro.getName(), macro);
- }
-
- // store off the time when we created the cache
- hrhCacheTimestamp = System.currentTimeMillis();
- }
-
- // save the prefix file (which may be null)
- prefixFileParsed = prefixFile;
-
- variantHRHMacros = macros;
- }
- }
-
- return variantHRHMacros;
+ return getCachedData().getVariantHRHDefines();
}
public List<File> getPrefixFileIncludes() {
- return hrhFilesParsed;
+ return getCachedData().getPrefixFileIncludes();
}
@@ -481,54 +327,11 @@
// once and cache the values. only reset the cache when the compiler prefix has changed.
IPath prefixFile = getCompilerPrefixFile();
- if (prefixFile == null || !prefixFile.toFile().exists()) {
- compilerPrefixMacros.clear();
- return compilerPrefixMacros;
+ if (prefixFile == null) {
+ return Collections.emptyList();
}
-
- if ((compilerCacheTimestamp == 0) ||
- (prefixFile.toFile().lastModified() > compilerCacheTimestamp)) {
-
- compilerPrefixMacros.clear();
-
- synchronized (this) {
-
- List<IDefine> macros = new ArrayList<IDefine>();
- if (prefixFile != null) {
-
- List<File> userPaths = new ArrayList<File>();
- List<File> systemPaths = new ArrayList<File>();
-
- userPaths.add(prefixFile.removeLastSegments(1).toFile());
- systemPaths.add(prefixFile.removeLastSegments(1).toFile());
- IPath includePath = getSDK().getIncludePath();
- if (includePath != null) {
- File includeDir = includePath.toFile().getAbsoluteFile();
- userPaths.add(includeDir);
- systemPaths.add(includeDir);
- }
-
-
- // get macros from the compiler prefix file: note, this is a stupid
- // scan that will get the last version #defined, even if inside an #if.
- MacroScanner scanner = new MacroScanner(
- new BasicIncludeFileLocator(userPaths.toArray(new File[userPaths.size()]), systemPaths.toArray(new File[systemPaths.size()])),
- DefaultModelDocumentProvider.getInstance(),
- DefaultTranslationUnitProvider.getInstance());
- scanner.scanFile(prefixFile.toFile());
- for (IDefine define : scanner.getMacroDefinitions()) {
- macros.add(define);
- }
-
- // store off the time when we created the cache
- compilerCacheTimestamp = System.currentTimeMillis();
- }
-
- compilerPrefixMacros = macros;
- }
- }
-
- return compilerPrefixMacros;
+
+ return getCachedData().getCompilerMacros(prefixFile);
}
@@ -552,6 +355,16 @@
}
}
+ /**
+ * Get the cache holding the data that applies to this build context globally.
+ * A build context is subclassed by CarbideBuildConfiguration, which has multiple
+ * instances at runtime, thus, a SymbianBuildContext instance should not hold a cache itself.
+ * @return cache, never <code>null</code>
+ */
+ private SymbianBuildContextDataCache getCachedData() {
+ return SymbianBuildContextDataCache.getCache(this);
+ }
+
public String getBasePlatformForVariation() {
String plat = "";
@@ -565,6 +378,14 @@
return plat;
}
-
-
+
+
+ /**
+ * Get the list of #include paths detected for this context.
+ * @return List or <code>null</code>
+ */
+ public List<File> getCachedSystemIncludePaths() {
+ return getCachedData().getSystemIncludePaths();
+ }
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.carbide.cpp.sdk.core/src/com/nokia/carbide/cpp/internal/api/sdk/SymbianBuildContextDataCache.java Tue Jan 05 11:23:50 2010 -0600
@@ -0,0 +1,702 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+*/
+package com.nokia.carbide.cpp.internal.api.sdk;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.ObjectStreamException;
+import java.util.*;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+
+import com.nokia.carbide.cpp.epoc.engine.EpocEnginePlugin;
+import com.nokia.carbide.cpp.epoc.engine.model.sbv.ISBVView;
+import com.nokia.carbide.cpp.epoc.engine.preprocessor.*;
+import com.nokia.carbide.cpp.internal.sdk.core.model.SymbianSDK;
+import com.nokia.carbide.cpp.sdk.core.*;
+import com.nokia.carbide.internal.api.cpp.epoc.engine.preprocessor.BasicIncludeFileLocator;
+import com.nokia.carbide.internal.api.cpp.epoc.engine.preprocessor.MacroScanner;
+import com.nokia.cpp.internal.api.utils.core.ExternalFileInfoCollection;
+import com.nokia.cpp.internal.api.utils.core.FileUtils;
+import com.nokia.cpp.internal.api.utils.core.Logging;
+import com.nokia.cpp.internal.api.utils.core.ObjectUtils;
+
+/**
+ * This class holds the externally gathered data for a build context,
+ * such as the #include paths and macros defined in the SDK.
+ * <p>
+ * Unlike CarbideBuildConfiguration (which, unfortunately extends
+ * SymbianBuildContext), this will not be created multiple times for
+ * multiple projects, but only once for a different build context
+ * in an SDK or devkit.
+ */
+public class SymbianBuildContextDataCache {
+
+ public static boolean DEBUG = false;
+
+ // by default, only check HRH-included files if changed in last second (for ordinary operations)
+ // or the last minute (when doing a long project operation). see #startThrottle() and #stopThrottle()
+ private static final long DEFAULT_HRH_INFO_CHECK_QUANTUM = 1000; // 1 sec
+ private static final long THROTTLED_HRH_INFO_CHECK_QUANTUM = 60000; // 60 sec
+
+ // compiler prefixes are very unlikely to change, but we need to check
+ // occasionally in case a user installs a new one...
+ private static final long DEFAULT_COMPILER_PREFIX_INFO_CHECK_QUANTUM = 15 * 60 * 1000; // 15 minutes
+
+ // This is a count of times #startProjectOperation() was called without
+ // balancing #endProjectOperation().
+ private static int inProjectOperationCount;
+
+ private static Map<String, SymbianBuildContextDataCache> cacheMap = new HashMap<String, SymbianBuildContextDataCache>();
+
+ public static synchronized SymbianBuildContextDataCache getCache(ISymbianBuildContext context) {
+ // don't hash on ISymbianBuildContext itself since it is sometimes a ICarbideBuildConfiguration
+ String key = getBuildContextKey(context);
+
+ SymbianBuildContextDataCache cache = cacheMap.get(key);
+ if (cache == null) {
+ cache = new SymbianBuildContextDataCache(context);
+ cache.loadCacheFile();
+ cacheMap.put(key, cache);
+ }
+ return cache;
+ }
+
+ /**
+ * @param context
+ * @return
+ */
+ private static String getBuildContextKey(ISymbianBuildContext context) {
+ String key = context.getPlatformString() + "/" + context.getTargetString() + "/";
+ ISymbianSDK sdk = context.getSDK();
+ if (sdk != null)
+ key += sdk.getEPOCROOT();
+ return key;
+ }
+
+ //private File prefixFileParsed;
+ private List<File> hrhFilesParsed = new ArrayList<File>();
+ private ExternalFileInfoCollection hrhFileInfo = null;
+ private List<IDefine> variantHRHMacros = new ArrayList<IDefine>();
+ private List<IDefine> compilerPrefixMacros = new ArrayList<IDefine>();
+ private ExternalFileInfoCollection compilerPrefixFileInfo = null;
+ private List<File> systemIncludes;
+ private ISymbianSDK sdk;
+ private IPath compilerPrefixFile;
+
+ private String platformString;
+
+ private String displayString;
+
+ private String contextKey;
+
+ private boolean changed;
+
+ private File cacheFile;
+
+ private SymbianBuildContextDataCache(ISymbianBuildContext context) {
+ if (DEBUG) System.out.println("Creating cache for " + context.getDisplayString());
+ this.platformString = context.getPlatformString();
+ this.displayString = context.getDisplayString();
+ this.sdk = context.getSDK();
+ this.contextKey = getBuildContextKey(context);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "Cache for " + displayString;
+ }
+
+ public List<IDefine> getVariantHRHDefines() {
+
+ // we parse the variant hrh file to gather macros. this can be time consuming so do it
+ // once and cache the values. only reset the cache when the hrh or any of its includes
+ // has changed.
+
+ boolean buildCache = false;
+
+ if (hrhFileInfo == null) {
+ // hasn't been built yet, or was flushed
+ buildCache = true;
+ } else {
+ // Cache exists. See if any of the files have changed
+ if (sdk != null && hrhFileInfo.anyChanged()) {
+ buildCache = true;
+ }
+ }
+
+ if (buildCache) {
+ gatherVariantHRHDefines();
+ }
+
+ return variantHRHMacros;
+ }
+
+ /**
+ * Re-gather the #defines from the variant HRH file
+ */
+ private void gatherVariantHRHDefines() {
+ changed = true;
+ variantHRHMacros.clear();
+
+ synchronized (this) {
+
+ List<IDefine> macros = new ArrayList<IDefine>();
+ Map<String, IDefine> namedMacros = new HashMap<String, IDefine>();
+ File prefixFile = sdk.getPrefixFile();
+
+ if (prefixFile == null){
+ // Check that the prefix file may have become available since the SDK was scanned last.
+ // This can happen, for e.g., if the user opens the IDE _then_ does a subst on a drive that already has an SDK entry.
+ IPath prefixCheck = ((SymbianSDK)sdk).getPrefixFromVariantCfg();
+ if (prefixCheck != null){
+ prefixFile = prefixCheck.toFile();
+ sdk.setPrefixFile(prefixCheck);
+ }
+ }
+
+ File[] includedFiles = null;
+
+ if (prefixFile != null) {
+
+ // add any BSF/SBV includes so the headers are picked up from the correct location
+ List<File> systemPaths = new ArrayList<File>();
+ IBSFPlatform bsfPlat = sdk.getBSFCatalog().findPlatform(platformString);
+ ISBVPlatform sbvPlat = sdk.getSBVCatalog().findPlatform(platformString);
+ if (bsfPlat != null) {
+ for (IPath path : bsfPlat.getSystemIncludePaths()) {
+ systemPaths.add(path.toFile());
+ }
+ } else if (sbvPlat != null) {
+ LinkedHashMap<IPath, String> platPaths = sbvPlat.getBuildIncludePaths();
+ Set<IPath> set = platPaths.keySet();
+ for (IPath path : set) {
+ String pathType = platPaths.get(path);
+ if (pathType.equalsIgnoreCase(ISBVView.INCLUDE_FLAG_PREPEND) || pathType.equalsIgnoreCase(ISBVView.INCLUDE_FLAG_SET)){
+ systemPaths.add(path.toFile());
+ }
+ }
+ }
+
+ MacroScanner scanner = new MacroScanner(
+ new BasicIncludeFileLocator(null, systemPaths.toArray(new File[systemPaths.size()])),
+ DefaultModelDocumentProvider.getInstance(),
+ DefaultTranslationUnitProvider.getInstance());
+ scanner.scanFile(prefixFile);
+
+ List<IDefine> scannedMacros = (List<IDefine>)scanner.getMacroDefinitions();
+ for (IDefine scannedMacro : scannedMacros){
+ // we don't want duplicate macros, so check to see if it's already there.
+ // if it is, remove it and then add the newer one. this is consistent with
+ // how it would be from a compiler standpoint.
+ IDefine macro = namedMacros.get(scannedMacro.getName());
+ if (macro != null) {
+ macros.remove(macro);
+ }
+
+ macros.add(scannedMacro);
+ namedMacros.put(scannedMacro.getName(), scannedMacro);
+ }
+
+ hrhFilesParsed.clear();
+ includedFiles = scanner.getIncludedFiles();
+ for (File inc : includedFiles) {
+ hrhFilesParsed.add(inc);
+ }
+
+ List<String> variantCFGMacros = new ArrayList<String>();
+ variantCFGMacros = sdk.getVariantCFGMacros();
+ for (String cfgMacros : variantCFGMacros){
+ // we don't want duplicate macros, so check to see if it's already there.
+ IDefine existingMacro = namedMacros.get(cfgMacros);
+ if (existingMacro != null) {
+ macros.remove(existingMacro);
+ }
+
+ IDefine macro = DefineFactory.createSimpleFreeformDefine(cfgMacros);
+ macros.add(macro);
+ namedMacros.put(macro.getName(), macro);
+ }
+ }
+
+ // cache the info about when we created the cache
+ if (hrhFileInfo == null) {
+ hrhFileInfo = new ExternalFileInfoCollection(
+ EpocEnginePlugin.getExternalFileInfoCache(),
+ includedFiles,
+ DEFAULT_HRH_INFO_CHECK_QUANTUM);
+ } else {
+ hrhFileInfo.setFiles(includedFiles);
+ }
+
+ variantHRHMacros = macros;
+ saveCacheFile();
+ }
+ }
+
+ public List<File> getPrefixFileIncludes() {
+ return hrhFilesParsed;
+ }
+
+
+ public synchronized List<IDefine> getCompilerMacros(IPath prefixFile) {
+
+ // we assume that the prefix file will not change often,
+ // (if at all) for a build context, so dump the cache if the prefix file changes.
+
+ if (compilerPrefixFile != null && !compilerPrefixFile.equals(prefixFile)) {
+ compilerPrefixFileInfo = null;
+ }
+
+ compilerPrefixFile = prefixFile;
+
+ if (compilerPrefixFileInfo == null ||
+ compilerPrefixFileInfo.anyChanged()) {
+
+ changed = true;
+
+ compilerPrefixMacros.clear();
+
+ synchronized (this) {
+
+ List<IDefine> macros = new ArrayList<IDefine>();
+ if (prefixFile != null) {
+
+ List<File> userPaths = new ArrayList<File>();
+ List<File> systemPaths = new ArrayList<File>();
+
+ userPaths.add(prefixFile.removeLastSegments(1).toFile());
+ systemPaths.add(prefixFile.removeLastSegments(1).toFile());
+ IPath includePath = sdk.getIncludePath();
+ if (includePath != null) {
+ File includeDir = includePath.toFile().getAbsoluteFile();
+ userPaths.add(includeDir);
+ systemPaths.add(includeDir);
+ }
+
+
+ // get macros from the compiler prefix file: note, this is a stupid
+ // scan that will get the last version #defined, even if inside an #if.
+ MacroScanner scanner = new MacroScanner(
+ new BasicIncludeFileLocator(userPaths.toArray(new File[userPaths.size()]), systemPaths.toArray(new File[systemPaths.size()])),
+ DefaultModelDocumentProvider.getInstance(),
+ DefaultTranslationUnitProvider.getInstance());
+ scanner.scanFile(prefixFile.toFile());
+ for (IDefine define : scanner.getMacroDefinitions()) {
+ macros.add(define);
+ }
+
+ // store off the info about what we read for this cache
+ File[] files = scanner.getIncludedFiles();
+
+ if (compilerPrefixFileInfo == null)
+ compilerPrefixFileInfo = new ExternalFileInfoCollection(
+ EpocEnginePlugin.getExternalFileInfoCache(),
+ files,
+ DEFAULT_COMPILER_PREFIX_INFO_CHECK_QUANTUM);
+ else
+ compilerPrefixFileInfo.setFiles(files);
+ }
+
+ compilerPrefixMacros = macros;
+
+ saveCacheFile();
+ }
+ }
+
+ return compilerPrefixMacros;
+ }
+
+ /**
+ * Get the list of #include paths detected for this context.
+ * @return List or <code>null</code>
+ */
+ public synchronized List<File> getSystemIncludePaths() {
+ if (systemIncludes == null) {
+ gatherBuildContextSystemIncludePaths();
+ }
+ return systemIncludes;
+ }
+
+ /**
+ * Fetch the list of include paths for the build context
+ */
+ private void gatherBuildContextSystemIncludePaths() {
+ changed = true;
+
+ systemIncludes = new ArrayList<File>();
+
+ if (DEBUG) System.out.println("Scanning include paths for " + displayString);
+
+ IBSFPlatform bsfplatform = sdk.getBSFCatalog().findPlatform(platformString);
+ ISBVPlatform sbvPlatform = sdk.getSBVCatalog().findPlatform(platformString);
+
+ // look in the epoc32 directory of the SDK
+ IPath includePath = sdk.getIncludePath();
+ if (includePath != null) {
+ File includeDir = includePath.toFile().getAbsoluteFile();
+ File dir;
+
+ // get additional include directories from BSF platform, if defined
+ if (bsfplatform != null) {
+ IPath[] systemIncludePaths = bsfplatform.getSystemIncludePaths();
+ for (IPath path : systemIncludePaths) {
+ dir = path.toFile();
+ if (dir.exists() && dir.isDirectory()) {
+ systemIncludes.add(dir);
+ }
+ }
+ } else if (sbvPlatform != null){
+
+ LinkedHashMap<IPath, String> platPaths = sbvPlatform.getBuildIncludePaths();
+ Set<IPath> set = platPaths.keySet();
+ for (IPath path : set) {
+ String pathType = platPaths.get(path);
+ if (pathType.equalsIgnoreCase(ISBVView.INCLUDE_FLAG_PREPEND) || pathType.equalsIgnoreCase(ISBVView.INCLUDE_FLAG_SET)){
+ dir = path.toFile();
+ systemIncludes.add(dir);
+ }
+ }
+ }
+ else {
+ // legacy behavior
+ if (platformString.equals(ISymbianBuildContext.EMULATOR_PLATFORM)) {
+ dir = new File(includeDir, "wins"); //$NON-NLS-1$
+ if (dir.exists() && dir.isDirectory()) {
+ systemIncludes.add(dir);
+ }
+ }
+ }
+
+ // add OEM dir
+ dir = new File(includeDir, "oem"); //$NON-NLS-1$
+ if (dir.exists() && dir.isDirectory()) {
+ systemIncludes.add(dir);
+ }
+
+ // and finally the normal include dir
+ systemIncludes.add(includeDir);
+
+ // and finally, finally, if this is an SBV add any paths with the append flag
+ if (sbvPlatform != null){
+
+ Map<IPath, String> platPaths = sbvPlatform.getBuildIncludePaths();
+ Set<IPath> set = platPaths.keySet();
+ for (IPath path : set) {
+ String pathType = platPaths.get(path);
+ if (pathType.equalsIgnoreCase(ISBVView.INCLUDE_FLAG_APPEND)){
+ dir = path.toFile();
+ systemIncludes.add(dir);
+ }
+ }
+ }
+ }
+
+ // also search files in same folder as variant.hrh
+ File prefix = sdk.getPrefixFile();
+ if (sbvPlatform != null){
+ // might be an alternate HRH file to use
+ IPath varVarHRH = sbvPlatform.getBuildVariantHRHFile();
+ if (!varVarHRH.toFile().equals(prefix) && varVarHRH.toFile().exists()){
+ prefix = varVarHRH.toFile();
+ }
+ }
+ if (prefix != null) {
+ systemIncludes.add(prefix.getParentFile());
+ }
+
+ saveCacheFile();
+ }
+
+ /**
+ * Let cache know that the client is beginning an operation that
+ * will iterate all the build contexts. We use this information
+ * to optimize file info checks.
+ * <p>
+ * Each call must be balanced by an {@link #endProjectOperation()} call.
+ * Use a try ... finally block to make sure.
+ */
+ public static synchronized void startProjectOperation() {
+ inProjectOperationCount++;
+ if (inProjectOperationCount == 1) {
+ for (SymbianBuildContextDataCache cache : cacheMap.values()) {
+ cache.startThrottle();
+ }
+ }
+ }
+
+ /**
+ * Let cache know that a project-wide operation is done, so
+ * we can resume normal info checking behavior.
+ */
+ public static synchronized void endProjectOperation() {
+ inProjectOperationCount--;
+ if (inProjectOperationCount < 0) {
+ Logging.log(SDKCorePlugin.getDefault(),
+ Logging.newStatus(SDKCorePlugin.getDefault(),
+ new IllegalStateException("project operation count not balanced")));
+ inProjectOperationCount = 0;
+ }
+ if (inProjectOperationCount == 0) {
+ for (SymbianBuildContextDataCache cache : cacheMap.values()) {
+ cache.stopThrottle();
+ cache.saveCacheFile();
+ }
+ }
+ }
+
+ /**
+ * Throttle file info checks on this cache if we suspect the same
+ * files will be checked over and over again in a short time (e.g. through
+ * multiple contexts on the same SDK).
+ */
+ private void startThrottle() {
+ if (hrhFileInfo != null) {
+ hrhFileInfo.setRecheckQuantum(THROTTLED_HRH_INFO_CHECK_QUANTUM);
+ }
+ // note: compiler prefix infos already have a long delay, but
+ // this is a good place to refresh
+ if (compilerPrefixFileInfo != null) {
+ compilerPrefixFileInfo.refresh();
+ }
+ }
+
+ /**
+ * End file info throttling.
+ */
+ private void stopThrottle() {
+ if (hrhFileInfo != null)
+ hrhFileInfo.setRecheckQuantum(DEFAULT_HRH_INFO_CHECK_QUANTUM);
+ // note: compiler prefix infos already have a long delay
+ }
+
+ /**
+ * Refresh the cached data when there are substantial changes in the given SDKs.
+ *
+ * @param sdks SDKs for whose contexts the caches should be removed, or <code>null</code> for all of them
+ */
+ public static synchronized void refreshForSDKs(ISymbianSDK[] sdks) {
+ // refresh each context cache, meaning, delete its memory and disk values
+ Collection<String> values = cacheMap.keySet();
+ String[] keyArray = (String[]) values.toArray(new String[values.size()]);
+ for (String key : keyArray) {
+ SymbianBuildContextDataCache cache = cacheMap.get(key);
+ boolean forSDK = sdkInArray(sdks, cache.sdk);
+ if (forSDK) {
+ cache.reset();
+ cacheMap.remove(key);
+ }
+ }
+ }
+
+ private static boolean sdkInArray(ISymbianSDK[] sdks, ISymbianSDK anSDK) {
+ if (sdks == null)
+ return true;
+ if (anSDK == null)
+ return false;
+ // object identity is not appropriate; user may have renamed or moved an SDK
+ for (ISymbianSDK sdk : sdks) {
+ if (ObjectUtils.equals(sdk.getEPOCROOT(), anSDK.getEPOCROOT())
+ || ObjectUtils.equals(sdk.getUniqueId(), anSDK.getUniqueId()))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Reset the cached data for this context, ensuring it will be
+ * freshly gathered. This deletes anything stored on disk.
+ */
+ public synchronized void reset() {
+ hrhFileInfo = null;
+ compilerPrefixFileInfo = null;
+ systemIncludes = null;
+ getCacheFile().delete();
+ }
+
+ /**
+ * Get the file where we store cached data
+ * @return File in workspace plugin state storage
+ */
+ protected File getCacheFile() {
+ if (cacheFile == null) {
+ IPath statePath;
+ if (Platform.isRunning())
+ statePath = Platform.getStateLocation(SDKCorePlugin.getDefault().getBundle());
+ else
+ statePath = new Path(FileUtils.getTemporaryDirectory().getAbsolutePath());
+ cacheFile = statePath.append(contextKey.replaceAll("[^A-Za-z0-9_]", "_") + ".dat").toFile(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ return cacheFile;
+ }
+
+ /**
+ * Save cache to disk if changed.
+ */
+ protected void saveCacheFile() {
+ if (!changed)
+ return;
+
+ ObjectOutputStream os = null;
+ try {
+ File cacheFile = getCacheFile();
+ if (DEBUG) System.out.println("Saving to " + cacheFile); //$NON-NLS-1$
+ os = new ObjectOutputStream(new FileOutputStream(cacheFile));
+ doSaveCache(os);
+ changed = false;
+ } catch (ObjectStreamException e) {
+ Logging.log(SDKCorePlugin.getDefault(),
+ Logging.newStatus(SDKCorePlugin.getDefault(),
+ IStatus.WARNING,
+ "Tried to save uncacheable data for " + displayString, //$NON-NLS-1$
+ e));
+ } catch (IOException e) {
+ // oh well
+ Logging.log(SDKCorePlugin.getDefault(),
+ Logging.newStatus(SDKCorePlugin.getDefault(),
+ IStatus.WARNING,
+ "Failed to save cache state for " + displayString, //$NON-NLS-1$
+ e));
+ } finally {
+ if (os != null) {
+ try {
+ os.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ protected void loadCacheFile() {
+ ObjectInputStream is = null;
+ // Use the class loader that knows how to span plugins
+ final ClassLoader classLoader = SDKCorePlugin.getDefault().getClass().getClassLoader();
+ File cacheFile = getCacheFile();
+ try {
+ is = new ObjectInputStream(new FileInputStream(cacheFile)) {
+ /* (non-Javadoc)
+ * @see java.io.ObjectInputStream#resolveClass(java.io.ObjectStreamClass)
+ */
+ @Override
+ protected Class<?> resolveClass(ObjectStreamClass desc)
+ throws IOException, ClassNotFoundException {
+ String name = desc.getName();
+ try {
+ return classLoader.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ return super.resolveClass(desc);
+ }
+ }
+ };
+ doLoadCache(is);
+ if (DEBUG) System.out.println("Loaded cache from " + cacheFile); //$NON-NLS-1$
+ } catch (ClassNotFoundException e) {
+ // this is probably a bug
+ e.printStackTrace();
+ } catch (ObjectStreamException e) {
+ // assume it's just out of sync (e.g. object signatures changed), so nothing in Error Log
+ e.printStackTrace();
+ cacheFile.delete();
+ } catch (IOException e) {
+ // oh well, not made yet
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ }
+ changed = false;
+ }
+ }
+
+ /**
+ * @param os
+ */
+ private void doSaveCache(ObjectOutputStream os) throws IOException {
+ os.writeObject(systemIncludes);
+ savePath(os, compilerPrefixFile);
+ os.writeObject(compilerPrefixFileInfo);
+ os.writeObject(compilerPrefixMacros);
+ os.writeObject(hrhFileInfo);
+ os.writeObject(hrhFilesParsed);
+ os.writeObject(variantHRHMacros);
+ }
+
+
+ /**
+ * Load entries from the cache. This must match the ordering in
+ * {@link #doSaveCache(ObjectOutputStream)}.
+ * @param is
+ */
+ private void doLoadCache(ObjectInputStream is) throws IOException, ClassCastException, ClassNotFoundException {
+ systemIncludes = loadList(is, File.class);
+ compilerPrefixFile = loadPath(is);
+ compilerPrefixFileInfo = (ExternalFileInfoCollection) is.readObject();
+ compilerPrefixMacros = loadList(is, IDefine.class);
+ hrhFileInfo = (ExternalFileInfoCollection) is.readObject();
+ hrhFilesParsed = loadList(is, File.class);
+ variantHRHMacros = loadList(is, IDefine.class);
+ }
+
+ /**
+ * Read an IPath from a portable string
+ * @param is
+ * @return an IPath constructed from a String
+ */
+ private IPath loadPath(ObjectInputStream is) throws IOException, ClassCastException, ClassNotFoundException {
+ String path;
+ path = (String) is.readObject();
+ if (path != null)
+ return Path.fromPortableString(path);
+ return null;
+ }
+
+ /**
+ * Save an IPath as a portable string
+ * @param os
+ * @param path
+ * @throws IOException
+ */
+ private void savePath(ObjectOutputStream os, IPath path) throws IOException {
+ os.writeObject(path != null ? path.toPortableString() : null);
+ }
+
+ /**
+ * Load a list from the object stream, throwing if it appears to contain
+ * the wrong kind of data.
+ * @param is
+ * @param klass
+ * @return a List or <code>null</code>
+ */
+ @SuppressWarnings("unchecked")
+ private <T> List<T> loadList(ObjectInputStream is, Class<T> klass) throws IOException, ClassCastException, ClassNotFoundException {
+ List<T> list = (List) is.readObject();
+ if (list == null || klass == null || list.size() == 0)
+ return list;
+ if (!klass.isInstance(list.get(0)))
+ throw new IOException("Class contains " + list.get(0).getClass() + ", not " + klass); //$NON-NLS-1$ //$NON-NLS-2$
+ return list;
+ }
+}
--- a/core/com.nokia.carbide.cpp.sdk.core/src/com/nokia/carbide/cpp/internal/sdk/core/model/AbstractSDKManager.java Tue Jan 05 11:22:47 2010 -0600
+++ b/core/com.nokia.carbide.cpp.sdk.core/src/com/nokia/carbide/cpp/internal/sdk/core/model/AbstractSDKManager.java Tue Jan 05 11:23:50 2010 -0600
@@ -52,6 +52,7 @@
import com.nokia.carbide.cpp.internal.api.sdk.ISDKManagerInternal;
import com.nokia.carbide.cpp.internal.api.sdk.SBSv2Utils;
import com.nokia.carbide.cpp.internal.api.sdk.SDKManagerInternalAPI;
+import com.nokia.carbide.cpp.internal.api.sdk.SymbianBuildContextDataCache;
import com.nokia.carbide.cpp.internal.api.sdk.SymbianMacroStore;
import com.nokia.carbide.cpp.sdk.core.ICarbideInstalledSDKChangeListener;
import com.nokia.carbide.cpp.sdk.core.IRVCTToolChainInfo;
@@ -122,7 +123,7 @@
public void scanSDKs() {
synchronized (sdkList)
{
- ArrayList<ISymbianSDK> oldSDkList = new ArrayList<ISymbianSDK>(sdkList);
+ ArrayList<ISymbianSDK> oldSDKList = new ArrayList<ISymbianSDK>(sdkList);
getSBSv2Version(true);
@@ -143,7 +144,7 @@
// now these SDK's are removed from the old list, add to
// internal list
- for (ISymbianSDK oldSdk : oldSDkList) {
+ for (ISymbianSDK oldSdk : oldSDKList) {
boolean found = false;
for (ISymbianSDK sdk : sdkList) {
if (sdk.getUniqueId().equals(oldSdk.getUniqueId())) {
@@ -154,6 +155,8 @@
if (found == false) {
SDKManagerInternalAPI.addMissingSdk(oldSdk
.getUniqueId());
+ // flush cache
+ SymbianBuildContextDataCache.refreshForSDKs(new ISymbianSDK[] { oldSdk });
}
}
@@ -172,7 +175,7 @@
* Actually scan the SDKs available and populate sdkList.
* @param oldSDkList old list of SDKs available for reference, e.g., detecting
* when SDKs are newly missing
- * @return
+ * @return true if scan succeeded
*/
abstract protected boolean doScanSDKs();
--- a/core/com.nokia.carbide.cpp.sdk.ui/src/com/nokia/carbide/cpp/internal/sdk/ui/SDKPreferencePage.java Tue Jan 05 11:22:47 2010 -0600
+++ b/core/com.nokia.carbide.cpp.sdk.ui/src/com/nokia/carbide/cpp/internal/sdk/ui/SDKPreferencePage.java Tue Jan 05 11:23:50 2010 -0600
@@ -33,6 +33,7 @@
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.*;
+import com.nokia.carbide.cpp.internal.api.sdk.SymbianBuildContextDataCache;
import com.nokia.carbide.cpp.internal.sdk.core.model.SDKManager;
import com.nokia.carbide.cpp.sdk.core.*;
import com.nokia.carbide.cpp.sdk.ui.SDKUIPlugin;
@@ -370,6 +371,8 @@
if (sdkPropDlg.open() == SDKPropertiesDialog.OK){
sdkListTableViewer.refresh();
setSelectedSDKInfoText(sdk);
+ // forcible rescan; dump cache
+ SymbianBuildContextDataCache.refreshForSDKs(new ISymbianSDK[] { sdk });
rescanSDKs(false);
}
} else {
@@ -405,6 +408,8 @@
}
private void rescanNowButtonAction(){
+ // forcible rescan; dump cache
+ SymbianBuildContextDataCache.refreshForSDKs(null);
rescanSDKs(true);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/ExternalFileInfoCache.java Tue Jan 05 11:23:50 2010 -0600
@@ -0,0 +1,183 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+package com.nokia.cpp.internal.api.utils.core;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Use this object to cache the timestamps and sizes for files which
+ * are often queried. On some OSes or types of filesystems, attribute checking
+ * is very slow, and on others, the resolution of a timestamp is so low that
+ * checking too often is likely to be a waste of effort.
+ * <p>
+ * We only recommend using this tracker for files outside the Eclipse
+ * workspace. For workspace resources, use resource listeners to avoid
+ * polling for file changes.
+ */
+public class ExternalFileInfoCache implements Serializable {
+
+ private static final long serialVersionUID = -2810901674805567105L;
+
+ public static boolean DEBUG = false;
+ public static boolean DEBUG_VERBOSE = false;
+
+ // time in ms between checks of any given file
+ private int quantum;
+
+ static class FileInfo extends Tuple implements Serializable {
+
+ private static final long serialVersionUID = -1226913205921924292L;
+
+ protected FileInfo() {
+ // empty for serialization
+ }
+ public FileInfo(long lastModified, long lastQueried, long size) {
+ super(lastModified, lastQueried, size);
+ }
+ public long getLastModified() {
+ return (Long) get(0);
+ }
+ public long getLastQueried() {
+ return (Long) get(1);
+ }
+ public long getLength() {
+ return (Long) get(2);
+ }
+
+ public boolean isChangedFrom(FileInfo other) {
+ long origTime = getLastModified();
+ long origSize = getLength();
+
+ long newTime = other.getLastModified();
+ long newSize = other.getLength();
+
+ if (newTime == 0) { // 0 if deleted
+ return true;
+ }
+ if (origTime != newTime
+ || origSize != newSize)
+ return true;
+
+ return false;
+ }
+ }
+
+ /** map of file to file size + last queried timestamp + time of last query
+ * (use File, not IPath, so we canonicalize for the OS) */
+ private Map<File, FileInfo> info = new HashMap<File, FileInfo>();
+
+
+ /**
+ * Create a cache to track the states of file timestamps and sizes.
+ * @param quantumMs time in ms between updating the status of any given file
+ */
+ public ExternalFileInfoCache(int quantumMs) {
+ this.quantum = quantumMs;
+ }
+
+ /**
+ * Create a cache to track the states of file timestamps and sizes,
+ * using an OS-dependent default quantum.
+ */
+ public ExternalFileInfoCache() {
+ // this is based on the expensiveness of the attribute lookup, not the
+ // resolution of the timestamps
+ this.quantum = HostOS.IS_WIN32 ? 50 : 10;
+ }
+
+ /**
+ * Tell if the file's timestamp or size changed since the basis time,
+ * or otherwise changed in the past quantum,
+ * and update the record.
+ * <p>
+ * If a file does not exist, we always consider it to have changed
+ * (since otherwise, we cannot tell if a client saw the transition
+ * from existing to not existing).
+ * @param basis the system time in ms from which to judge the change
+ * @return true if file size or timestamp changed since basis, or
+ * the file does not exist
+ */
+ public FileInfo getFileInfo(File file, long basis) {
+ FileInfo finfo = info.get(file);
+ if (finfo == null) {
+ finfo = new FileInfo(file.lastModified(), basis, file.length());
+ synchronized(info) {
+ info.put(file, finfo);
+ }
+ if (DEBUG) System.out.println("First info for " + file + ": " + finfo);
+ return finfo;
+ } else if (finfo.getLastQueried() + quantum < basis) {
+ // note: if a file no longer exists, these return distinct values
+ // that also appear as changes
+ finfo = new FileInfo(file.lastModified(), basis, file.length());
+ synchronized(info) {
+ info.put(file, finfo);
+ }
+ return finfo;
+ } else {
+ return finfo;
+ }
+ }
+
+ /**
+ * Tell if the file's timestamp or size changed in the past quantum
+ * and update the record
+ * @return true if file size or timestamp changed.
+ */
+ public boolean isChanged(File file) {
+ return isChanged(file, System.currentTimeMillis());
+ }
+
+ /**
+ * Tell if the file's timestamp or size changed since the basis time,
+ * or otherwise changed in the past quantum,
+ * and update the record.
+ * <p>
+ * If a file does not exist, we always consider it to have changed
+ * (since otherwise, we cannot tell if a client saw the transition
+ * from existing to not existing).
+ * @param basis the system time in ms from which to judge the change
+ * @return true if file size or timestamp changed since basis, or
+ * the file does not exist
+ */
+ public boolean isChanged(File file, long basis) {
+ FileInfo finfo = info.get(file);
+ FileInfo newInfo = getFileInfo(file, basis);
+ if (finfo == newInfo)
+ return false;
+
+ // update info
+ info.put(file, newInfo);
+
+ return finfo.isChangedFrom(newInfo);
+ }
+
+ /**
+ * Force a refresh of the given file's status on the next #isChanged() call.
+ * @param file
+ */
+ public void refresh(File file) {
+ synchronized(info) {
+ info.remove(file);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/ExternalFileInfoCollection.java Tue Jan 05 11:23:50 2010 -0600
@@ -0,0 +1,153 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+package com.nokia.cpp.internal.api.utils.core;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import com.nokia.cpp.internal.api.utils.core.ExternalFileInfoCache.FileInfo;
+
+/**
+ * This object corrals a set of timestamp checks against a collection
+ * of related files (using an {@link ExternalFileInfoCache} for
+ * storage).
+ * <p>
+ * Multiple instances of this object can (and should) share a cache.
+ * <p>
+ * As with {@link ExternalFileInfoCache}, we recommend using this
+ * tracker only for files outside the Eclipse workspace. For workspace
+ * resources, use resource listeners to avoid polling for file changes.
+ */
+public class ExternalFileInfoCollection implements Serializable {
+
+ private static final long serialVersionUID = 3685308336593621639L;
+
+ // the files to check and the last info we found
+ private Map<File, ExternalFileInfoCache.FileInfo> fileMap = new HashMap<File, FileInfo>();
+
+ // time in ms between checks of all the files
+ private long quantum;
+
+ // last time we checked
+ private long lastCheckTime;
+
+ private ExternalFileInfoCache cache;
+
+ protected ExternalFileInfoCollection() {
+ // for serialization
+ }
+
+ /**
+ * Create an object to check the states of related file timestamps and sizes.
+ * @param quantumMs time in ms between checking all the files
+ */
+ public ExternalFileInfoCollection(ExternalFileInfoCache cache,
+ File[] files, long quantumMs) {
+ Check.checkArg(cache);
+ this.cache = cache;
+ this.quantum = quantumMs;
+ setFiles(files);
+ this.lastCheckTime = System.currentTimeMillis();
+ }
+
+ /**
+ * If the collection's time quantum has passed, check all the files
+ * to see if any have changed.
+ * <p>
+ * Note that by {@link ExternalFileInfoCache#isChanged(File, long)},
+ * a deleted file always appears to have changed, so it is assumed that if a
+ * change is detected, a client will invoke {@link #setFiles(File[])} to
+ * ensure deleted files are removed from the collection.
+ * @return true if any file in the collection has appeared to change
+ * since the last quantum
+ */
+ public synchronized boolean anyChanged() {
+ boolean changed = false;
+ if (System.currentTimeMillis() > lastCheckTime + quantum) {
+ for (File file : fileMap.keySet()) {
+ if (checkForChange(file)) {
+ changed = true;
+ // continue to check all the files, so we update the info uniformly
+ }
+ }
+ lastCheckTime = System.currentTimeMillis();
+ }
+ return changed;
+ }
+
+ /**
+ * Recheck one file in the collection and update data.
+ * @param file
+ * @return
+ */
+ protected boolean checkForChange(File file) {
+ FileInfo currentInfo = fileMap.get(file);
+ FileInfo newInfo = cache.getFileInfo(file, lastCheckTime);
+
+ fileMap.put(file, newInfo);
+
+ return currentInfo == null || currentInfo.isChangedFrom(newInfo);
+ }
+
+ /**
+ * Update the files incorporated in the timestamp/size check.
+ * @param files the files to set
+ */
+ public synchronized void setFiles(File[] files) {
+ this.fileMap.clear();
+
+ // prime the cache so every file's current timestamp and size is known
+ if (files != null) {
+ for (File file : files) {
+ checkForChange(file);
+ }
+ }
+ }
+
+ /**
+ * Get the files this collection checks.
+ * @return the files
+ */
+ public File[] getFiles() {
+ Set<File> files = fileMap.keySet();
+ return (File[]) files.toArray(new File[files.size()]);
+ }
+
+ /**
+ * Refresh the timestamps for the affected files, ensuring that
+ * changes on disk are immediately detected for the next {@link #anyChanged()}
+ * call.
+ */
+ public synchronized void refresh() {
+ for (File file : fileMap.keySet()) {
+ cache.refresh(file);
+ }
+ this.lastCheckTime = 0;
+ }
+
+ /**
+ * Set the quantum for the timestamp collection.
+ * @param quantumMs time is ms between checks of files
+ */
+ public void setRecheckQuantum(long quantum) {
+ this.quantum = quantum;
+ }
+}
--- a/core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/Tuple.java Tue Jan 05 11:22:47 2010 -0600
+++ b/core/com.nokia.cpp.utils.core/src/com/nokia/cpp/internal/api/utils/core/Tuple.java Tue Jan 05 11:23:50 2010 -0600
@@ -16,13 +16,20 @@
*/
package com.nokia.cpp.internal.api.utils.core;
+import java.io.Serializable;
+
/**
* A tuple of zero or more items.
*
*/
-public class Tuple {
+public class Tuple implements Serializable {
+ private static final long serialVersionUID = -3117335085610864101L;
+
private Object[] args;
+ protected Tuple() {
+ // for serialization
+ }
public Tuple(Object... args) {
this.args = args;
}
--- a/project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/cpp/epoc/engine/EpocEnginePlugin.java Tue Jan 05 11:22:47 2010 -0600
+++ b/project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/cpp/epoc/engine/EpocEnginePlugin.java Tue Jan 05 11:23:50 2010 -0600
@@ -29,6 +29,8 @@
import com.nokia.carbide.cpp.epoc.engine.model.sbv.*;
import com.nokia.carbide.internal.cpp.epoc.engine.model.SBVModelFactory;
import com.nokia.carbide.internal.cpp.epoc.engine.model.ViewDataCache;
+import com.nokia.cpp.internal.api.utils.core.ExternalFileInfoCache;
+import com.nokia.cpp.internal.api.utils.core.ExternalFileInfoCollection;
import com.nokia.cpp.internal.api.utils.core.Logging;
import com.nokia.cpp.internal.api.utils.core.MultiResourceChangeListenerDispatcher;
@@ -61,6 +63,10 @@
private static ViewDataCache<IBldInfOwnedModel, IBldInfModel, IBldInfView, IBldInfData> bldInfViewDataCache;
private static ViewDataCache<IImageMakefileOwnedModel, IImageMakefileModel, IImageMakefileView, IImageMakefileData> imageMakefileViewDataCache;
+
+ private static ExternalFileInfoCache externalFileTimestampSizeCache =
+ new ExternalFileInfoCache();
+
/**
* The constructor.
*/
@@ -506,6 +512,16 @@
return runnable.run(data);
}
+
+ /**
+ * Get the global cache of file timestamps and sizes associated with the EPOC engine.
+ * This is used to track the status of files in SDKs which are unlikely to change
+ * often and for which we don't want to waste OS time checking over and over.
+ * @return {@link ExternalFileInfoCache}
+ */
+ public static ExternalFileInfoCache getExternalFileInfoCache() {
+ return externalFileTimestampSizeCache;
+ }
}
--- a/project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/cpp/epoc/engine/preprocessor/DefaultTranslationUnitProvider.java Tue Jan 05 11:22:47 2010 -0600
+++ b/project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/cpp/epoc/engine/preprocessor/DefaultTranslationUnitProvider.java Tue Jan 05 11:23:50 2010 -0600
@@ -42,7 +42,7 @@
private boolean DUMP = false;
/** count of entries allowed */
- private static final int DEFAULT_MAX_CACHE_SIZE = 32;
+ private static final int DEFAULT_MAX_CACHE_SIZE = 256;
/** the minimum number of hits (accesses) to the TU to keep it when flushing cache. */
private static final int DEFAULT_MINIMUM_HITS_TO_KEEP = 8;
@@ -156,7 +156,8 @@
if (DUMP)
System.out.println("Releasing TU for " + file); //$NON-NLS-1$
tuCache.remove(file);
- cacheHits.remove(file);
+ // do not lose info about file importance
+ //cacheHits.remove(file);
cacheTimes.remove(file);
cacheOrder.remove(file);
}
--- a/project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/cpp/epoc/engine/preprocessor/IDefine.java Tue Jan 05 11:22:47 2010 -0600
+++ b/project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/cpp/epoc/engine/preprocessor/IDefine.java Tue Jan 05 11:23:50 2010 -0600
@@ -17,11 +17,13 @@
package com.nokia.carbide.cpp.epoc.engine.preprocessor;
+import java.io.Serializable;
+
/**
* High-level information about a macro definition.
*
*/
-public interface IDefine {
+public interface IDefine extends Serializable {
/**
* Get the macro name (never null)
*/
--- a/project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/internal/api/cpp/epoc/engine/preprocessor/MacroScanner.java Tue Jan 05 11:22:47 2010 -0600
+++ b/project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/internal/api/cpp/epoc/engine/preprocessor/MacroScanner.java Tue Jan 05 11:23:50 2010 -0600
@@ -96,13 +96,16 @@
if (DUMP)
System.out.println("Scanning #defines for " + file); //$NON-NLS-1$
- includes.add(file);
-
ITranslationUnit tu_ = tuProvider.getTranslationUnit(file, documentProvider);
if (!(tu_ instanceof IASTTranslationUnit)) {
EpocEnginePlugin.log(new FileNotFoundException("Failed to scan #defines for " + file)); //$NON-NLS-1$
return;
}
+
+ // only add file if it exists, otherwise, its absence makes clients
+ // think something has changed
+ includes.add(file);
+
IASTTranslationUnit tu = (IASTTranslationUnit) tu_;
for (IASTTopLevelNode node : tu.getNodes()) {
if (node instanceof IASTPreprocessorDefineStatement) {
@@ -163,8 +166,9 @@
}
/**
- * Get the list of all header files that were scanned
- * @return
+ * Get the list of all header files that were scanned (includes the
+ * top level file)
+ * @return non-<code>null</code> array of files
*/
public File[] getIncludedFiles() {
return includes.toArray(new File[includes.size()]);
--- a/project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/internal/cpp/epoc/engine/model/ViewDataCache.java Tue Jan 05 11:22:47 2010 -0600
+++ b/project/com.nokia.carbide.cpp.epoc.engine/src/com/nokia/carbide/internal/cpp/epoc/engine/model/ViewDataCache.java Tue Jan 05 11:23:50 2010 -0600
@@ -17,6 +17,7 @@
package com.nokia.carbide.internal.cpp.epoc.engine.model;
+import com.nokia.carbide.cpp.epoc.engine.EpocEnginePlugin;
import com.nokia.carbide.cpp.epoc.engine.model.*;
import com.nokia.carbide.cpp.epoc.engine.preprocessor.*;
import com.nokia.cpp.internal.api.utils.core.*;
@@ -38,6 +39,7 @@
public class ViewDataCache<OwnedModel extends IOwnedModel, Model extends IModel, View extends IView, Data extends IData<View>> {
public static boolean DEBUG = false;
+ public static boolean DEBUG_VERBOSE = false;
/** A key which can retrieve the current state of a model for a given filter. */
static class ViewConfigKey extends Pair<IPath, IViewFilter> {
@@ -60,7 +62,7 @@
*/
/*private*/ Object getMD5(String uniqueKey) {
try {
- MessageDigest md = MessageDigest.getInstance("MD5");
+ MessageDigest md = MessageDigest.getInstance("MD5"); //$NON-NLS-1$
return md.digest(uniqueKey.getBytes());
} catch (NoSuchAlgorithmException e) {
return uniqueKey;
@@ -114,7 +116,7 @@
IViewParserConfiguration parserConfig = viewConfiguration.getViewParserConfiguration();
String includeState = getIncludeState(parserConfig.getIncludeFileLocator());
String projectState = parserConfig.getProjectLocation().toOSString();
- return filterState + "/" + projectState + "/" + includeState + "/" + macroState;
+ return filterState + "/" + projectState + "/" + includeState + "/" + macroState; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
/**
@@ -164,110 +166,12 @@
}
- static class FileTimestampSizeCollection {
- static FileTimestampSizeCollection INSTANCE = new FileTimestampSizeCollection();
- /** Check timestamps only once in this number of milliseconds */
- final int QUANTUM = 0;
-
- static class FileInfo extends Tuple {
- public FileInfo(long lastModified, long lastQueried, long size) {
- super(lastModified, lastQueried, size);
- }
- public long getLastModified() {
- return (Long) get(0);
- }
- public long getLastQueried() {
- return (Long) get(0);
- }
- public long getLength() {
- return (Long) get(2);
- }
- }
- /** map of file to file size + last queried timestamp + time of last query
- * (use File, not IPath, so we canonicalize for the OS) */
- private Map<File, FileInfo> info = new HashMap<File, FileInfo>();
-
-
- /** Tell if the file's timestamp changed in the past quantum
- * and update the record */
- public boolean changed(File file) {
- long now = System.currentTimeMillis();
- FileInfo finfo = info.get(file);
- if (finfo == null) {
- finfo = new FileInfo(file.lastModified(), now, file.length());
- info.put(file, finfo);
- if (DEBUG) System.out.println("First info for " + file + ": " + finfo);
- return true;
- } else if (finfo.getLastQueried() + QUANTUM < now) {
- // don't check times more than QUANTUM
- long origTime = finfo.getLastModified();
- long origSize = finfo.getLength();
- finfo = new FileInfo(file.lastModified(), now, file.length());
- info.put(file, finfo);
- if (DEBUG) System.out.println("Updated info for " + file + ": " + origTime + "/" + origSize + " <=> "
- + finfo.getLastModified() + "/" + finfo.getLength());
- return origTime != finfo.getLastModified() || finfo.getLastModified() == 0 // 0 if deleted
- || origSize != finfo.getLength();
- } else {
- // not changed, as far as we assume
- if (DEBUG) System.out.println("Assuming no change for " + file);
- return false;
- }
- }
- }
-
- public static class ModelFileTimestampCollection {
- /**
- * Delay in ms between successive checks of the filesystem, to avoid wasting time
- * when such checks are slow, and in cases where it's unlikely the human will edit files
- * fast enough to care.
- */
- public static final long QUANTUM = HostOS.IS_WIN32 ? 50 : 10;
- private File[] files;
- private long lastQuery;
-
- public ModelFileTimestampCollection(IView view) {
- IPath[] paths = view.getReferencedFiles();
- this.files = new File[paths.length];
- int idx = 0;
- for (IPath path : paths) {
- files[idx] = path.toFile();
- // prime the cache
- FileTimestampSizeCollection.INSTANCE.changed(files[idx]);
- idx++;
- }
- this.lastQuery = System.currentTimeMillis();
- }
-
- /**
- * Tell if any of the files have changed
- * @return
- */
- public boolean changed() {
- long prevQuery = lastQuery;
- lastQuery = System.currentTimeMillis();
-
- // don't check more often than the resolution of the file allows
- if (prevQuery + QUANTUM > lastQuery) {
- if (DEBUG) System.out.println("Skipping fileinfo check");
- return false;
- }
-
- for (File file : files) {
- if (FileTimestampSizeCollection.INSTANCE.changed(file)) {
- return true;
- }
- }
- return false;
- }
- }
-
/** the minimum number of hits (accesses) to the entry to keep it when flushing cache. */
private static final int DEFAULT_MINIMUM_HITS_TO_KEEP = 8;
private IModelProvider<OwnedModel, Model> modelProvider;
private Map<ViewConfigKey, Pair<ViewConfigState, Data>> cachedData;
- private Map<ViewConfigKey, ModelFileTimestampCollection> cachedTimestamps;
+ private Map<ViewConfigKey, ExternalFileInfoCollection> cachedFileInfo;
private Map<ViewConfigKey, Integer> cacheHits;
private List<ViewConfigKey> cacheOrder;
@@ -281,7 +185,7 @@
this.modelProvider = provider;
this.cachedData = new HashMap<ViewConfigKey, Pair<ViewConfigState,Data>>();
- this.cachedTimestamps = new HashMap<ViewConfigKey, ModelFileTimestampCollection>();
+ this.cachedFileInfo = new HashMap<ViewConfigKey, ExternalFileInfoCollection>();
this.cacheHits = new HashMap<ViewConfigKey, Integer>();
this.cacheOrder = new LinkedList<ViewConfigKey>();
}
@@ -366,11 +270,11 @@
}
statefulData = cachedData.get(key);
if (statefulData != null) {
- // now check that the file timestamps are valid.
- ModelFileTimestampCollection timestamps = cachedTimestamps.get(key);
- if (timestamps.changed()) {
+ // now check that the file info is valid.
+ ExternalFileInfoCollection fileinfo = cachedFileInfo.get(key);
+ if (fileinfo.anyChanged()) {
if (DEBUG) {
- System.out.println("One or more relevant files changed for " + modelPath);
+ System.out.println("One or more relevant files changed for " + modelPath); //$NON-NLS-1$
}
removeAllEntriesForModel(modelPath);
statefulData = null;
@@ -380,9 +284,9 @@
if (DEBUG) {
String orig = statefulData.first.toString();
String curr = state.toString();
- System.out.println("State changed (from:\n"
- + orig.substring(0, Math.min(100, orig.length())) + "\nto:\n" +
- curr.substring(0, Math.min(100, curr.length())) + ")\n");
+ System.out.println("State changed (from:\n" //$NON-NLS-1$
+ + orig.substring(0, Math.min(100, orig.length())) + "\nto:\n" + //$NON-NLS-1$
+ curr.substring(0, Math.min(100, curr.length())) + ")\n"); //$NON-NLS-1$
}
removeEntry(key);
cachedData.remove(key);
@@ -392,8 +296,8 @@
}
if (statefulData != null) {
- if (DEBUG) {
- System.out.println("Found entry for " + key);
+ if (DEBUG_VERBOSE) {
+ System.out.println("Found entry for " + key); //$NON-NLS-1$
}
cacheHits.put(key, cacheHits.get(key) + 1);
data = statefulData.second;
@@ -422,7 +326,7 @@
ViewConfigState state, ViewConfigKey key) throws CoreException {
Data data;
if (DEBUG) {
- System.out.println("Fetching view data for " + key);
+ System.out.println("Fetching view data for " + key); //$NON-NLS-1$
}
Model model = modelProvider.getSharedModel(modelPath);
if (model == null)
@@ -437,11 +341,21 @@
if (data == null)
return null;
- ModelFileTimestampCollection timestamps = new ModelFileTimestampCollection(view);
+ IPath[] referencedFiles = view.getReferencedFiles();
+ File[] files = new File[referencedFiles.length];
+ for (int idx = 0; idx < referencedFiles.length; idx++) {
+ files[idx] = referencedFiles[idx].toFile();
+ }
+
+ ExternalFileInfoCollection fileinfo =
+ new ExternalFileInfoCollection(
+ EpocEnginePlugin.getExternalFileInfoCache(),
+ files,
+ FileUtils.getMinimumFileTimestampResolution(modelPath));
synchronized (cachedData) {
// the data may have already been registered... oh well
cachedData.put(key, new Pair<ViewConfigState, Data>(state, data));
- cachedTimestamps.put(key, timestamps);
+ cachedFileInfo.put(key, fileinfo);
cacheOrder.add(0, key);
cacheHits.put(key, 0);
}
@@ -470,8 +384,10 @@
* @param key
*/
private void removeEntry(ViewConfigKey key) {
- cachedTimestamps.remove(key);
- cacheHits.remove(key);
+ cachedFileInfo.remove(key);
+
+ // do not lose info about file importance
+ //cacheHits.remove(key);
cacheOrder.remove(key);
cachedData.remove(key);
}
@@ -497,7 +413,7 @@
Integer hits = cacheHits.get(key);
if (hits == null || hits < minimumHitsToKeep) {
if (DEBUG) {
- System.out.println("*** Flushing " + key);
+ System.out.println("*** Flushing " + key); //$NON-NLS-1$
}
removeEntry(key);
toRemove--;
@@ -512,12 +428,11 @@
if (key.equals(retainKey))
continue;
if (DEBUG) {
- System.out.println("*** Flushing " + key);
+ System.out.println("*** Flushing " + key); //$NON-NLS-1$
}
removeEntry(key);
toRemove--;
}
}
-
}