diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java index bfbd506d5f7a..3ed28295bad8 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java @@ -31,6 +31,7 @@ import org.jetbrains.jps.server.ProjectDescriptor; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; import java.io.PrintStream; import java.util.*; @@ -149,11 +150,11 @@ final class BuildSession implements Runnable, CanceledStatus { ProjectDescriptor pd; final Project project = loadProject(projectPath); final BuildFSState fsState = new BuildFSState(false); - ProjectTimestamps timestamps = null; + ProjectTimestamps projectTimestamps = null; BuildDataManager dataManager = null; final File dataStorageRoot = Utils.getDataStorageRoot(project); try { - timestamps = new ProjectTimestamps(dataStorageRoot); + projectTimestamps = new ProjectTimestamps(dataStorageRoot); dataManager = new BuildDataManager(dataStorageRoot, true); if (dataManager.versionDiffers()) { forceCleanCaches = true; @@ -163,21 +164,21 @@ final class BuildSession implements Runnable, CanceledStatus { catch (Exception e) { // second try LOG.info(e); - if (timestamps != null) { - timestamps.close(); + if (projectTimestamps != null) { + projectTimestamps.close(); } if (dataManager != null) { dataManager.close(); } forceCleanCaches = true; FileUtil.delete(dataStorageRoot); - timestamps = new ProjectTimestamps(dataStorageRoot); + projectTimestamps = new ProjectTimestamps(dataStorageRoot); dataManager = new BuildDataManager(dataStorageRoot, true); // second attempt succeded msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.INFO, "Project rebuild forced: " + e.getMessage())); } - pd = new ProjectDescriptor(project, fsState, timestamps, dataManager, BuildLoggingManager.DEFAULT); + pd = new ProjectDescriptor(project, fsState, projectTimestamps, dataManager, BuildLoggingManager.DEFAULT); try { for (int attempt = 0; attempt < 2; attempt++) { @@ -185,8 +186,19 @@ final class BuildSession implements Runnable, CanceledStatus { // if compilation scope is the whole project and cache rebuild is forced, use PROJECT_REBUILD for faster compilation buildType = BuildType.PROJECT_REBUILD; } - final CompileScope compileScope = createCompilationScope(buildType, pd, modules, artifacts, paths); - final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), builderParams, cs); + + if (buildType == BuildType.PROJECT_REBUILD || forceCleanCaches) { + try { + pd.timestamps.clean(); + } + catch (IOException e) { + throw new ProjectBuildException("Error cleaning timestamps storage", e); + } + } + + final Timestamps timestamps = pd.timestamps.getStorage(); + final CompileScope compileScope = createCompilationScope(buildType, pd, timestamps, modules, artifacts, paths); + final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), timestamps, builderParams, cs); builder.addMessageHandler(msgHandler); try { switch (buildType) { @@ -352,7 +364,11 @@ final class BuildSession implements Runnable, CanceledStatus { return !(projectFile.isFile() && projectFile.getName().endsWith(".ipr")); } - private static CompileScope createCompilationScope(BuildType buildType, ProjectDescriptor pd, Set modules, Collection artifactNames, Collection paths) throws Exception { + private static CompileScope createCompilationScope(BuildType buildType, + ProjectDescriptor pd, + final Timestamps timestamps, Set modules, + Collection artifactNames, + Collection paths) throws Exception { Set artifacts = new HashSet(); if (artifactNames.isEmpty() && buildType == BuildType.PROJECT_REBUILD) { artifacts.addAll(pd.project.getArtifacts().values()); @@ -385,8 +401,6 @@ final class BuildSession implements Runnable, CanceledStatus { forcedModules = Collections.emptySet(); } - final Timestamps tsStorage = pd.timestamps.getStorage(); - final Map> filesToCompile; if (!paths.isEmpty()) { filesToCompile = new HashMap>(); @@ -401,7 +415,7 @@ final class BuildSession implements Runnable, CanceledStatus { } files.add(file); if (buildType == BuildType.FORCED_COMPILATION) { - pd.fsState.markDirty(file, rd, tsStorage); + pd.fsState.markDirty(file, rd, timestamps); } } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java index c22dcb204dba..5be5335c9a02 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java @@ -51,9 +51,9 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler ProjectChunks testChunks, MessageHandler delegateMessageHandler, Map builderParams, - CanceledStatus cancelStatus) throws ProjectBuildException { + final Timestamps timestamps, CanceledStatus cancelStatus) throws ProjectBuildException { myProjectDescriptor = pd; - myTimestamps = myProjectDescriptor.timestamps.getStorage(); + myTimestamps = timestamps; myBuilderParams = Collections.unmodifiableMap(builderParams); myCancelStatus = cancelStatus; myCompilationStartStamp = System.currentTimeMillis(); @@ -272,7 +272,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler return myProjectDescriptor.dataManager; } - public Timestamps getTimestampStorage() { + public Timestamps getTimestamps() { return myTimestamps; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 713c0f1ad472..83bbfcef0963 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -1,8 +1,6 @@ package org.jetbrains.jps.incremental; -import com.intellij.openapi.Forceable; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.LowMemoryWatcher; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.io.MappingFailedException; @@ -22,6 +20,7 @@ import org.jetbrains.jps.incremental.messages.ProgressMessage; import org.jetbrains.jps.incremental.storage.BuildDataManager; import org.jetbrains.jps.incremental.storage.SourceToFormMapping; import org.jetbrains.jps.incremental.storage.SourceToOutputMapping; +import org.jetbrains.jps.incremental.storage.Timestamps; import org.jetbrains.jps.server.ProjectDescriptor; import java.io.BufferedWriter; @@ -63,8 +62,9 @@ public class IncProjectBuilder { private final float myTotalModulesWork; private final int myTotalModuleLevelBuilderCount; private final List myAsyncTasks = new ArrayList(); + private final Timestamps myTimestamps; - public IncProjectBuilder(ProjectDescriptor pd, BuilderRegistry builderRegistry, Map builderParams, CanceledStatus cs) { + public IncProjectBuilder(ProjectDescriptor pd, BuilderRegistry builderRegistry, final Timestamps timestamps, Map builderParams, CanceledStatus cs) { myProjectDescriptor = pd; myBuilderRegistry = builderRegistry; myBuilderParams = builderParams; @@ -73,6 +73,7 @@ public class IncProjectBuilder { myTestChunks = new ProjectChunks(pd.project, ClasspathKind.TEST_COMPILE); myTotalModulesWork = (float)pd.rootsIndex.getTotalModuleCount() * 2; /* multiply by 2 to reflect production and test sources */ myTotalModuleLevelBuilderCount = builderRegistry.getModuleLevelBuilderCount(); + myTimestamps = timestamps; } public void addMessageHandler(MessageHandler handler) { @@ -80,18 +81,6 @@ public class IncProjectBuilder { } public void build(CompileScope scope, final boolean isMake, final boolean isProjectRebuild, boolean forceCleanCaches) throws RebuildRequestedException{ - final LowMemoryWatcher memWatcher = LowMemoryWatcher.register(new Forceable() { - @Override - public boolean isDirty() { - return true; // always perform flush when not enough memory - } - - @Override - public void force() { - myProjectDescriptor.dataManager.flush(false); - myProjectDescriptor.timestamps.getStorage().force(); - } - }); CompileContext context = null; try { context = createContext(scope, isMake, isProjectRebuild); @@ -121,7 +110,6 @@ public class IncProjectBuilder { } } finally { - memWatcher.stop(); flushContext(context); // wait for the async tasks for (Future task : myAsyncTasks) { @@ -137,7 +125,7 @@ public class IncProjectBuilder { private static void flushContext(CompileContext context) { if (context != null) { - context.getProjectDescriptor().timestamps.getStorage().force(); + context.getTimestamps().force(); context.getDataManager().flush(false); } final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context); @@ -208,18 +196,12 @@ public class IncProjectBuilder { private CompileContext createContext(CompileScope scope, boolean isMake, final boolean isProjectRebuild) throws ProjectBuildException { return new CompileContext( scope, myProjectDescriptor, isMake, isProjectRebuild, myProductionChunks, myTestChunks, myMessageDispatcher, - myBuilderParams, myCancelStatus + myBuilderParams, myTimestamps, myCancelStatus ); } private void cleanOutputRoots(CompileContext context) throws ProjectBuildException { // whole project is affected - try { - myProjectDescriptor.timestamps.clean(); - } - catch (IOException e) { - throw new ProjectBuildException("Error cleaning timestamps storage", e); - } try { context.getDataManager().clean(); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/Timestamps.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/Timestamps.java index c9b569010430..3a3cacc374c1 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/Timestamps.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/Timestamps.java @@ -8,6 +8,7 @@ import java.io.IOException; * Date: 4/24/12 */ public interface Timestamps { + void force(); void saveStamp(File file, long timestamp) throws IOException; diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java b/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java index 22ab7f10cd6a..81d2716e18ad 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java @@ -1,6 +1,8 @@ package org.jetbrains.jps.server; +import com.intellij.openapi.Forceable; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.LowMemoryWatcher; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import groovy.util.Node; @@ -28,6 +30,7 @@ import org.jetbrains.jps.incremental.storage.ProjectTimestamps; import org.jetbrains.jps.incremental.storage.Timestamps; import java.io.File; +import java.io.IOException; import java.lang.reflect.Method; import java.util.*; @@ -171,14 +174,39 @@ class ServerState { pd.incUsageCounter(); } + final ProjectDescriptor finalPd = pd; + final LowMemoryWatcher memWatcher = LowMemoryWatcher.register(new Forceable() { + @Override + public boolean isDirty() { + return true; // always perform flush when not enough memory + } + + @Override + public void force() { + finalPd.dataManager.flush(false); + finalPd.timestamps.getStorage().force(); + } + }); + try { for (int attempt = 0; attempt < 2; attempt++) { if (forceCleanCaches && modules.isEmpty() && paths.isEmpty()) { // if compilation scope is the whole project and cache rebuild is forced, use PROJECT_REBUILD for faster compilation buildType = BuildType.PROJECT_REBUILD; } - final CompileScope compileScope = createCompilationScope(buildType, pd, modules, artifacts, paths); - final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), builderParams, cs); + + if (buildType == BuildType.PROJECT_REBUILD || forceCleanCaches) { + try { + pd.timestamps.clean(); + } + catch (IOException e) { + throw new ProjectBuildException("Error cleaning timestamps storage", e); + } + } + + final Timestamps timestamps = pd.timestamps.getStorage(); + final CompileScope compileScope = createCompilationScope(buildType, pd, timestamps, modules, artifacts, paths); + final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), timestamps, builderParams, cs); builder.addMessageHandler(msgHandler); try { switch (buildType) { @@ -213,13 +241,18 @@ class ServerState { } } finally { + memWatcher.stop(); pd.release(); clearZipIndexCache(); } } - private static CompileScope createCompilationScope(BuildType buildType, ProjectDescriptor pd, Set modules, - Collection artifactNames, Collection paths) throws Exception { + private static CompileScope createCompilationScope(BuildType buildType, + ProjectDescriptor pd, + final Timestamps timestamps, + Set modules, + Collection artifactNames, + Collection paths) throws Exception { Set artifacts = new HashSet(); if (artifactNames.isEmpty() && buildType == BuildType.PROJECT_REBUILD) { artifacts.addAll(pd.project.getArtifacts().values()); @@ -252,8 +285,6 @@ class ServerState { forcedModules = Collections.emptySet(); } - final Timestamps marker = pd.timestamps.getStorage(); - final Map> filesToCompile; if (!paths.isEmpty()) { filesToCompile = new HashMap>(); @@ -268,7 +299,7 @@ class ServerState { } files.add(file); if (buildType == BuildType.FORCED_COMPILATION) { - pd.fsState.markDirty(file, rd, marker); + pd.fsState.markDirty(file, rd, timestamps); } } } diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java index 914eb06882f8..c51683c00f27 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java @@ -208,7 +208,7 @@ public abstract class IncrementalTestCase extends TestCase { new BuildDataManager(dataStorageRoot, true), new BuildLoggingManager(new ArtifactBuilderLoggerImpl(), javaBuilderLogger)); try { new IncProjectBuilder( - projectDescriptor, BuilderRegistry.getInstance(), Collections.emptyMap(), CanceledStatus.NULL + projectDescriptor, BuilderRegistry.getInstance(), projectDescriptor.timestamps.getStorage(), Collections.emptyMap(), CanceledStatus.NULL ).build( new AllProjectScope(project, Collections.emptySet(), true), false, true, false ); @@ -220,7 +220,7 @@ public abstract class IncrementalTestCase extends TestCase { } new IncProjectBuilder( - projectDescriptor, BuilderRegistry.getInstance(), Collections.emptyMap(), CanceledStatus.NULL + projectDescriptor, BuilderRegistry.getInstance(), projectDescriptor.timestamps.getStorage(), Collections.emptyMap(), CanceledStatus.NULL ).build( new AllProjectScope(project, Collections.emptySet(), false), true, false, false ); diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java index 7bf374ff77d5..4c0bd5dd6479 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java @@ -31,6 +31,7 @@ import org.jetbrains.jps.incremental.java.JavaBuilderLoggerImpl; import org.jetbrains.jps.incremental.messages.BuildMessage; import org.jetbrains.jps.incremental.storage.BuildDataManager; import org.jetbrains.jps.incremental.storage.ProjectTimestamps; +import org.jetbrains.jps.incremental.storage.Timestamps; import org.jetbrains.jps.server.ClasspathBootstrap; import org.jetbrains.jps.server.ProjectDescriptor; @@ -181,7 +182,8 @@ public abstract class ArtifactBuilderTestCase extends UsefulTestCase { myDescriptor.incUsageCounter(); } myArtifactBuilderLogger.clear(); - IncProjectBuilder builder = new IncProjectBuilder(myDescriptor, BuilderRegistry.getInstance(), Collections.emptyMap(), CanceledStatus.NULL); + final Timestamps timestamps = myDescriptor.timestamps.getStorage(); + IncProjectBuilder builder = new IncProjectBuilder(myDescriptor, BuilderRegistry.getInstance(), timestamps, Collections.emptyMap(), CanceledStatus.NULL); final List errorMessages = new ArrayList(); final List infoMessages = new ArrayList(); builder.addMessageHandler(new MessageHandler() { diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java index 9a1511f1bba6..9f778b7cf9ed 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java @@ -318,7 +318,7 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { final AndroidFileSetState newState = new AndroidFileSetState(allFiles, AndroidJpsUtil.CLASSES_AND_JARS_FILTER, true); final AndroidFileSetState oldState = proguardStateStorage.getState(module.getName()); - if (context.getTimestampStorage().getStamp(proguardCfgFile) == proguardCfgFile.lastModified() && + if (context.getTimestamps().getStamp(proguardCfgFile) == proguardCfgFile.lastModified() && newState.equalsTo(oldState)) { return true; } @@ -349,7 +349,7 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { proguardStateStorage.update(module.getName(), success ? newState : null); if (success) { - context.getTimestampStorage().saveStamp(proguardCfgFile, proguardCfgFile.lastModified()); + context.getTimestamps().saveStamp(proguardCfgFile, proguardCfgFile.lastModified()); } return success; }