Clear persistent unit cache when relevant options change.
Change-Id: Id74918bc73a0c223ec4401fb5586d06bb5697718
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
index 5a3e769..dcf2b13 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
@@ -68,7 +68,9 @@
try {
File baseCacheDir =
DiskCachingUtil.computePreferredCacheDir(options.getModuleNames(), logger);
- UnitCache unitCache = UnitCacheSingleton.get(logger, null, baseCacheDir);
+ UnitCache unitCache = UnitCacheSingleton.get(logger, null, baseCacheDir,
+ new CompilerOptionsImpl(options));
+
MinimalRebuildCacheManager minimalRebuildCacheManager =
createMinimalRebuildCacheManager(logger, options, baseCacheDir);
@@ -141,7 +143,8 @@
TreeLogger startupLogger = topLogger.branch(Type.INFO, "Super Dev Mode starting up");
File baseCacheDir =
DiskCachingUtil.computePreferredCacheDir(options.getModuleNames(), startupLogger);
- UnitCache unitCache = UnitCacheSingleton.get(startupLogger, null, baseCacheDir);
+ UnitCache unitCache = UnitCacheSingleton.get(
+ startupLogger, null, baseCacheDir, new CompilerOptionsImpl(options));
MinimalRebuildCacheManager minimalRebuildCacheManager =
createMinimalRebuildCacheManager(topLogger, options, baseCacheDir);
OutboxTable outboxTable =
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/CompilerOptionsImpl.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/CompilerOptionsImpl.java
index 9e28b32..8921246 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/CompilerOptionsImpl.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/CompilerOptionsImpl.java
@@ -49,6 +49,10 @@
private final boolean closureFormattedOutput;
private final JsOutputOption output;
+ CompilerOptionsImpl(Options options) {
+ this(null, null, options);
+ }
+
CompilerOptionsImpl(CompileDir compileDir, String moduleName, Options options) {
this.compileDir = compileDir;
this.incremental = options.isIncrementalCompileEnabled();
diff --git a/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java
index c63e949..03abc05 100644
--- a/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java
+++ b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java
@@ -159,6 +159,7 @@
public void testIncrementalRecompile_compileErrorDoesntCorruptMinimalRebuildCache()
throws UnableToCompleteException, IOException, InterruptedException {
+ String moduleName = "com.foo.SimpleModule";
PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
logger.setMaxDetail(TreeLogger.ERROR);
@@ -166,7 +167,7 @@
// Setup options to perform a per-file compile and compile the given module.
Options options = new Options();
options.parseArgs(new String[] {
- "-incremental", "-src", sourcePath.getAbsolutePath(), "com.foo.SimpleModule"});
+ "-incremental", "-src", sourcePath.getAbsolutePath(), moduleName});
// Prepare the basic resources in the test application.
List<MockResource> originalResources = Lists.newArrayList(simpleModuleResource,
@@ -175,11 +176,12 @@
writeResourcesTo(originalResources, sourcePath);
File baseCacheDir = Files.createTempDir();
- UnitCache unitCache = UnitCacheSingleton.get(logger, null, baseCacheDir);
+ UnitCache unitCache = UnitCacheSingleton.get(
+ logger, null, baseCacheDir, new CompilerOptionsImpl(options));
MinimalRebuildCacheManager minimalRebuildCacheManager =
new MinimalRebuildCacheManager(logger, baseCacheDir, ImmutableMap.<String, String>of());
Recompiler recompiler = new Recompiler(OutboxDir.create(Files.createTempDir(), logger), null,
- "com.foo.SimpleModule", options, unitCache, minimalRebuildCacheManager);
+ moduleName, options, unitCache, minimalRebuildCacheManager);
Outbox outbox = new Outbox("Transactional Cache", recompiler, options, logger);
OutboxTable outboxTable = new OutboxTable();
outboxTable.addOutbox(outbox);
@@ -205,6 +207,7 @@
public void testIncrementalRecompile_modulePropertyEditsWork() throws UnableToCompleteException,
IOException, InterruptedException {
+ String moduleName = "com.foo.PropertyModule";
PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
logger.setMaxDetail(TreeLogger.ERROR);
@@ -212,7 +215,7 @@
// Setup options to perform a per-file compile and compile the given module.
Options options = new Options();
options.parseArgs(new String[] {
- "-incremental", "-src", sourcePath.getAbsolutePath(), "com.foo.PropertyModule"});
+ "-incremental", "-src", sourcePath.getAbsolutePath(), moduleName});
// Prepare the basic resources in the test application.
List<MockResource> originalResources = Lists.newArrayList(propertyIsFooModuleResource,
@@ -221,11 +224,12 @@
writeResourcesTo(originalResources, sourcePath);
File baseCacheDir = Files.createTempDir();
- UnitCache unitCache = UnitCacheSingleton.get(logger, null, baseCacheDir);
+ UnitCache unitCache = UnitCacheSingleton.get(
+ logger, null, baseCacheDir, new CompilerOptionsImpl(options));
MinimalRebuildCacheManager minimalRebuildCacheManager =
new MinimalRebuildCacheManager(logger, baseCacheDir, ImmutableMap.<String, String>of());
Recompiler recompiler = new Recompiler(OutboxDir.create(Files.createTempDir(), logger), null,
- "com.foo.PropertyModule", options, unitCache, minimalRebuildCacheManager);
+ moduleName, options, unitCache, minimalRebuildCacheManager);
Outbox outbox = new Outbox("Transactional Cache", recompiler, options, logger);
OutboxTable outboxTable = new OutboxTable();
outboxTable.addOutbox(outbox);
diff --git a/dev/core/src/com/google/gwt/dev/Compiler.java b/dev/core/src/com/google/gwt/dev/Compiler.java
index 9496222..3e4f0a7 100644
--- a/dev/core/src/com/google/gwt/dev/Compiler.java
+++ b/dev/core/src/com/google/gwt/dev/Compiler.java
@@ -87,7 +87,7 @@
}
// TODO: returns the same UnitCache even if the passed directory changes. Make this less
// surprising.
- return UnitCacheSingleton.get(logger, null, persistentUnitCacheDir);
+ return UnitCacheSingleton.get(logger, null, persistentUnitCacheDir, options);
}
public static void main(String[] args) {
diff --git a/dev/core/src/com/google/gwt/dev/DevModeBase.java b/dev/core/src/com/google/gwt/dev/DevModeBase.java
index 3618977..b7cc46d 100644
--- a/dev/core/src/com/google/gwt/dev/DevModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/DevModeBase.java
@@ -784,7 +784,7 @@
topLogger = ui.getTopLogger();
compilerContext = compilerContextBuilder.unitCache(
- UnitCacheSingleton.get(getTopLogger(), null, persistentCacheDir)).build();
+ UnitCacheSingleton.get(getTopLogger(), null, persistentCacheDir, options)).build();
// Set done callback
ui.setCallback(DoneEvent.getType(), this);
diff --git a/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java b/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java
index e18160e..8b6d378 100644
--- a/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java
+++ b/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java
@@ -99,8 +99,11 @@
private Semaphore cleanupInProgress = new Semaphore(1);
private AtomicInteger newUnitsSinceLastCleanup = new AtomicInteger();
+ private final String relevantOptionsHash;
- PersistentUnitCache(final TreeLogger logger, File parentDir) throws UnableToCompleteException {
+ PersistentUnitCache(final TreeLogger logger, File parentDir, String relevantOptionsHash)
+ throws UnableToCompleteException {
+ this.relevantOptionsHash = relevantOptionsHash;
this.backgroundService = new BackgroundService(logger, parentDir, this);
}
@@ -272,7 +275,8 @@
BackgroundService(TreeLogger logger, File parentDir, final PersistentUnitCache cacheToLoad)
throws UnableToCompleteException {
this.logger = logger;
- this.cacheDir = new PersistentUnitCacheDir(logger, parentDir);
+ this.cacheDir =
+ new PersistentUnitCacheDir(logger, parentDir, cacheToLoad.relevantOptionsHash);
this.cacheToLoad = cacheToLoad;
start();
diff --git a/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCacheDir.java b/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCacheDir.java
index 8b04f19..4c2e648 100644
--- a/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCacheDir.java
+++ b/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCacheDir.java
@@ -50,10 +50,11 @@
private static final String CACHE_FILE_PREFIX = "gwt-unitCache-";
static final String CURRENT_VERSION_CACHE_FILE_PREFIX =
- CACHE_FILE_PREFIX + CompilerVersion.getHash() + "-";
+ CACHE_FILE_PREFIX + CompilerVersion.getHash();
private final TreeLogger logger;
private final File dir;
+ private final String filePrefix;
// Non-null when a a cache file is open for writing. (Always true in normal operation.)
private OpenFile openFile;
@@ -62,8 +63,10 @@
* Finds the child directory where the cache files will be stored and opens a new cache
* file for appending.
*/
- PersistentUnitCacheDir(TreeLogger logger, File parentDir) throws UnableToCompleteException {
+ PersistentUnitCacheDir(TreeLogger logger, File parentDir, String cacheFilePrefix)
+ throws UnableToCompleteException {
this.logger = logger;
+ this.filePrefix = CURRENT_VERSION_CACHE_FILE_PREFIX + "-" + cacheFilePrefix + "-";
/*
* We must canonicalize the path here, otherwise we might set cacheDirectory
@@ -96,7 +99,7 @@
logger.log(TreeLogger.TRACE, "Persistent unit cache dir set to: " + dir.getAbsolutePath());
- openFile = new OpenFile(logger, createEmptyCacheFile(logger, dir));
+ openFile = new OpenFile(logger, createEmptyCacheFile(logger, dir, filePrefix));
}
/**
@@ -110,7 +113,7 @@
* Returns the number of files written to the cache directory and closed.
*/
synchronized int getClosedCacheFileCount() {
- return selectClosedFiles(listFiles(CURRENT_VERSION_CACHE_FILE_PREFIX)).size();
+ return selectClosedFiles(listFiles(filePrefix)).size();
}
/**
@@ -124,7 +127,7 @@
+ getPath());
}
try {
- List<File> files = selectClosedFiles(listFiles(CURRENT_VERSION_CACHE_FILE_PREFIX));
+ List<File> files = selectClosedFiles(listFiles(filePrefix));
for (File cacheFile : files) {
loadOrDeleteCacheFile(cacheFile, destination);
}
@@ -162,7 +165,7 @@
openFile.close(logger);
openFile = null;
}
- openFile = new OpenFile(logger, createEmptyCacheFile(logger, dir));
+ openFile = new OpenFile(logger, createEmptyCacheFile(logger, dir, filePrefix));
}
/**
@@ -311,14 +314,13 @@
/**
* Creates a new, empty file with a name based on the current system time.
*/
- private static File createEmptyCacheFile(TreeLogger logger, File dir)
+ private static File createEmptyCacheFile(TreeLogger logger, File dir, String filePrefix)
throws UnableToCompleteException {
File newFile = null;
long timestamp = System.currentTimeMillis();
try {
do {
- newFile = new File(dir, CURRENT_VERSION_CACHE_FILE_PREFIX +
- String.format("%016X", timestamp++));
+ newFile = new File(dir, filePrefix + String.format("%016X", timestamp++));
} while (!newFile.createNewFile());
} catch (IOException ex) {
logger.log(TreeLogger.WARN, "Can't create new cache log file "
diff --git a/dev/core/src/com/google/gwt/dev/javac/UnitCacheSingleton.java b/dev/core/src/com/google/gwt/dev/javac/UnitCacheSingleton.java
index bce16c7..4d01f3e 100644
--- a/dev/core/src/com/google/gwt/dev/javac/UnitCacheSingleton.java
+++ b/dev/core/src/com/google/gwt/dev/javac/UnitCacheSingleton.java
@@ -18,6 +18,11 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.jjs.JJSOptions;
+import com.google.gwt.thirdparty.guava.common.base.Joiner;
+import com.google.gwt.util.tools.shared.Md5Utils;
+import com.google.gwt.util.tools.shared.StringUtils;
+
import java.io.File;
/**
@@ -47,6 +52,15 @@
instance.clear();
}
+ public static String getRelevantOptionsHash(JJSOptions options) {
+ return StringUtils.toHexString(
+ Md5Utils.getMd5Digest(
+ Joiner.on('-').join(
+ options.getJsInteropExportFilter(),
+ options.shouldGenerateJsInteropExports()
+ ).getBytes()));
+ }
+
/**
* If the cache is enabled, instantiates the cache and begins loading units
* into memory in a background thread. If the cache is not enabled, it clears
@@ -57,8 +71,9 @@
* <p>
* The specified cache dir parameter is optional.
*/
- public static synchronized UnitCache get(TreeLogger logger, File specifiedCacheDir) {
- return get(logger, specifiedCacheDir, null);
+ public static synchronized UnitCache get(
+ TreeLogger logger, File specifiedCacheDir, JJSOptions options) {
+ return get(logger, specifiedCacheDir, null, options);
}
/**
@@ -72,7 +87,7 @@
* Both specified and fallback cache dir parameters are optional.
*/
public static synchronized UnitCache get(TreeLogger logger, File specifiedCacheDir,
- File fallbackCacheDir) {
+ File fallbackCacheDir, JJSOptions options) {
assert logger != null;
if (instance == null) {
String propertyCachePath = System.getProperty(GWT_PERSISTENTUNITCACHEDIR);
@@ -95,7 +110,8 @@
if (actualCacheDir != null) {
try {
- return instance = new PersistentUnitCache(logger, actualCacheDir);
+ return instance =
+ new PersistentUnitCache(logger, actualCacheDir, getRelevantOptionsHash(options));
} catch (UnableToCompleteException ignored) {
}
}
diff --git a/dev/core/test/com/google/gwt/dev/javac/PersistentUnitCacheTest.java b/dev/core/test/com/google/gwt/dev/javac/PersistentUnitCacheTest.java
index 59f3e81..f68460e 100644
--- a/dev/core/test/com/google/gwt/dev/javac/PersistentUnitCacheTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/PersistentUnitCacheTest.java
@@ -24,7 +24,6 @@
import junit.framework.TestCase;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -54,6 +53,8 @@
private TreeLogger logger;
private File lastParentDir = null;
+ private String hash1 = "HASH1";
+ private String hash2 = "HASH2";
@Override
protected void setUp() throws Exception {
@@ -90,7 +91,7 @@
assertTrue(fileInTheWay.exists());
fileInTheWay.deleteOnExit();
try {
- new PersistentUnitCache(logger, fileInTheWay);
+ new PersistentUnitCache(logger, fileInTheWay, hash1);
fail("Expected an exception to be thrown");
} catch (UnableToCompleteException expected) {
}
@@ -115,7 +116,7 @@
assertTrue(baseDir.exists());
assertTrue(baseDir.delete());
File parentDir = lastParentDir = new File(baseDir, "sHoUlDnOtExi57");
- new PersistentUnitCache(logger, parentDir);
+ new PersistentUnitCache(logger, parentDir, hash1);
assertTrue(parentDir.isDirectory());
}
@@ -125,7 +126,7 @@
File parentDir = lastParentDir = File.createTempFile("persistentCacheTest", "");
File unitCacheDir = mkCacheDir(parentDir);
- PersistentUnitCache cache = new PersistentUnitCache(logger, parentDir);
+ PersistentUnitCache cache = new PersistentUnitCache(logger, parentDir, hash1);
MockCompilationUnit foo1 = new MockCompilationUnit("com.example.Foo", "Foo: source1");
cache.add(foo1);
@@ -172,7 +173,7 @@
// Fire up the cache again. It should be pre-populated.
// Search by type name
- cache = new PersistentUnitCache(logger, parentDir);
+ cache = new PersistentUnitCache(logger, parentDir, hash1);
result = cache.find("com/example/Foo.java");
assertNotNull(result);
assertEquals("com.example.Foo", result.getTypeName());
@@ -204,7 +205,7 @@
assertNumCacheFiles(unitCacheDir, 1);
// Fire up the cache again. (Creates a second file in the background.)
- cache = new PersistentUnitCache(logger, parentDir);
+ cache = new PersistentUnitCache(logger, parentDir, hash1);
// keep making more files
MockCompilationUnit lastUnit = null;
@@ -221,7 +222,7 @@
}
// One last check, we should load the last unit added to the cache.
- cache = new PersistentUnitCache(logger, parentDir);
+ cache = new PersistentUnitCache(logger, parentDir, hash1);
result = cache.find(lastUnit.getContentId());
assertNotNull(result);
assertEquals("com.example.Foo", result.getTypeName());
@@ -262,13 +263,55 @@
assertNumCacheFiles(unitCacheDir, 1);
// Fire up the cache on this one coalesced file.
- cache = new PersistentUnitCache(logger, parentDir);
+ cache = new PersistentUnitCache(logger, parentDir, hash1);
// Verify that we can still find the content that was coalesced.
assertNotNull(cache.find("com/example/Foo.java"));
assertNotNull(cache.find("com/example/Bar.java"));
assertNotNull(cache.find("com/example/Baz.java"));
assertNotNull(cache.find("com/example/Qux.java"));
+
+ cache.shutdown();
+
+ // There should be a single file in the cache dir.
+ assertNumCacheFiles(unitCacheDir, 1);
+
+ cache = new PersistentUnitCache(logger, parentDir, hash2);
+ // A different hash implies a new cache.
+ assertNull(cache.find("com/example/Foo.java"));
+ assertNull(cache.find("com/example/Bar.java"));
+ assertNull(cache.find("com/example/Baz.java"));
+ assertNull(cache.find("com/example/Qux.java"));
+
+ cache.internalAdd(
+ new MockCompilationUnit("com.example.Hash2", "Foo Source")).get();
+
+ assertNotNull(cache.find("com/example/Hash2.java"));
+
+ cache.shutdown();
+
+ // There should be a single file in the cache dir.
+ assertNumCacheFiles(unitCacheDir, 2);
+
+ cache = new PersistentUnitCache(logger, parentDir, hash1);
+ // Verify that we can still find the content with the original hash.
+ assertNotNull(cache.find("com/example/Foo.java"));
+ assertNotNull(cache.find("com/example/Bar.java"));
+ assertNotNull(cache.find("com/example/Baz.java"));
+ assertNotNull(cache.find("com/example/Qux.java"));
+ assertNull(cache.find("com/example/Hash2.java"));
+
+ cache.shutdown();
+
+ cache = new PersistentUnitCache(logger, parentDir, hash2);
+ // A different hash implies a new cache.
+ assertNull(cache.find("com/example/Foo.java"));
+ assertNull(cache.find("com/example/Bar.java"));
+ assertNull(cache.find("com/example/Baz.java"));
+ assertNull(cache.find("com/example/Qux.java"));
+ assertNotNull(cache.find("com/example/Hash2.java"));
+
+ cache.shutdown();
}
private void assertNumCacheFiles(File unitCacheDir, int expected) {
@@ -290,7 +333,7 @@
}
private void checkInvalidObjectInCache(Object toSerialize) throws IOException,
- FileNotFoundException, UnableToCompleteException, InterruptedException, ExecutionException {
+ UnableToCompleteException, InterruptedException, ExecutionException {
File parentDir = lastParentDir = File.createTempFile("PersistentUnitTest-CNF", "");
File unitCacheDir = mkCacheDir(parentDir);
@@ -299,14 +342,14 @@
* object in it.
*/
File errorFile = new File(unitCacheDir,
- PersistentUnitCacheDir.CURRENT_VERSION_CACHE_FILE_PREFIX + "12345");
+ PersistentUnitCacheDir.CURRENT_VERSION_CACHE_FILE_PREFIX + "-" + hash1 + "-" + "12345");
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(errorFile));
os.writeObject(toSerialize);
os.close();
assertNumCacheFiles(unitCacheDir, 1);
- PersistentUnitCache cache = new PersistentUnitCache(logger, parentDir);
+ PersistentUnitCache cache = new PersistentUnitCache(logger, parentDir, hash1);
cache.cleanup(logger);
cache.shutdown();