Here is a re-working of the cache based on the feedback. I've removed caching inside CompilationStateBuilder, and made all cache lookups by the ContentId.
Still TODO on this patch is a unit test, which I will work on tomorrow. http://gwt-code-reviews.appspot.com/1375802/diff/1/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java File dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java (right): http://gwt-code-reviews.appspot.com/1375802/diff/1/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java#newcode232 dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java:232: logger.log(TreeLogger.TRACE, "Invalid units found: " + invalidatedUnits.size()); On 2011/03/07 20:14:13, scottb wrote:
I would dig on this more. It's perfectly fine and expected that some
units will
have null dependencies. That should not force those units to
recompile...
*provided that the dependencies remain null*.
I think we need to go deeper... When you say the dependencies remain null, remain from when until when? Are you saying the Dependencies.validate() method needs revamping? or that we add a special case for checking null dependencies? http://gwt-code-reviews.appspot.com/1375802/diff/1/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java#newcode450 dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java:450: On 2011/03/07 20:14:13, scottb wrote:
It does seem kind of strange, though, like the two need to be unified.
Maybe
PersistentUnitCache should be one of two UnitCache subclasses, or
maybe
internally it should either use the disk or not.
UnitCache is now an interface MemoryUnitCache implements an in-memory cache PersistentUnitCache extends MemoryUnitCache to back up and reload the cache from disk. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/Compiler.java File dev/core/src/com/google/gwt/dev/Compiler.java (right): http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/Compiler.java#newcode204 dev/core/src/com/google/gwt/dev/Compiler.java:204: // that persists between compilation runs and call PersistentCache.setCacheDir() On 2011/03/08 16:29:31, jbrosenberg wrote:
s/call/calls to/
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/DevMode.java File dev/core/src/com/google/gwt/dev/DevMode.java (right): http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/DevMode.java#newcode417 dev/core/src/com/google/gwt/dev/DevMode.java:417: File persistentCacheDir = new File(options.getWarDir(), "/WEB-INF/gwt-unitCache"); On 2011/03/08 02:31:25, tobyr wrote:
Make "gwt-unitCache" a constant somewhere (and replace all uses)?
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/DevModeBase.java File dev/core/src/com/google/gwt/dev/DevModeBase.java (right): http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/DevModeBase.java#newcode889 dev/core/src/com/google/gwt/dev/DevModeBase.java:889: PersistentUnitCache.init(getTopLogger().branch(TreeLogger.INFO, On 2011/03/08 02:31:25, tobyr wrote:
Why not just branch the TreeLogger inside of init?
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/DevModeBase.java#newcode1061 dev/core/src/com/google/gwt/dev/DevModeBase.java:1061: } On 2011/03/08 16:29:31, jbrosenberg wrote:
white space
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/GWTCompiler.java File dev/core/src/com/google/gwt/dev/GWTCompiler.java (right): http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/GWTCompiler.java#newcode180 dev/core/src/com/google/gwt/dev/GWTCompiler.java:180: } else { On 2011/03/08 02:31:25, tobyr wrote:
This logic was a bit confusing to follow. Mind setting
persistentCacheDir to
null in the if block instead of initializing it to null? A comment
might help
too.
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java File dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java (left): http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java#oldcode422 dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java:422: CompilationUnit existingUnit = unitCache.get(contentId); On 2011/03/08 02:31:25, tobyr wrote:
Put the check of the unitCache and PUC together (for example, in a
method) so
you don't duplicate the the cachedUnits.put/compileMoreLater logic.
Or...
replace unitCache with PUC altogether.
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java File dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java (right): http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java#newcode252 dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java:252: PersistentUnitCache.cleanup(logger); On 2011/03/08 02:31:25, tobyr wrote:
Is there some reason this can't just happen on a thread on a periodic
timer in
PUC?
There is an opportune time to cleanup the cache, and that is right after a compile finishes. There is no good timer value we could set, seeing as we have compiles that finish in just a few seconds, to more than a minute. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java#newcode393 dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java:393: // run in this process. On 2011/03/08 02:31:25, tobyr wrote:
Is it possible to just replace unitCache with PUC at this point? Under
what
circumstances would we want something in the unitCache, but not in the PersistentUnitCache?
done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/Dependencies.java File dev/core/src/com/google/gwt/dev/javac/Dependencies.java (right): http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/Dependencies.java#newcode47 dev/core/src/com/google/gwt/dev/javac/Dependencies.java:47: public CompiledClass getCompiledClass() { On 2011/03/07 20:14:13, scottb wrote:
Not used anymore.
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java File dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java (right): http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode49 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:49: * Each run of the compiler should call {@link cleanup()} when finished adding On 2011/03/08 02:31:25, tobyr wrote:
s/cleanup/#cleanup.
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode55 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:55: * single file. On 2011/03/08 02:31:25, tobyr wrote:
This reads really strange. I think more explanation is needed.
I revamped, let me know if you think it still needs work. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode61 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:61: * uses lots of heap and takes 5-10 seconds ({@link #init(TreeLogger)} starts On 2011/03/08 02:31:25, tobyr wrote:
Missing a period?
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode62 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:62: * eagerly loading the cache a background thread). On 2011/03/08 02:31:25, tobyr wrote:
s/cache a background/cache in a background
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode64 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:64: * - Although duplicate units with the same type name are eventually cleaned up, On 2011/03/08 02:31:25, tobyr wrote:
It'd be nice for this doc to show up correctly in quick view for
javadoc. I.E.
use list, paragraph, etc... tags.
Done. I'm bad about that. I'll look around for more. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode77 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:77: * On 2011/03/08 02:31:25, tobyr wrote:
What happens if you run 2 devmodes or a devmode + web compile
concurrently with
the same cachdir set? Boom?
No, it won't go boom. It might cause a corrupt cache file if you start them at exactly the same second, but then the cache file will just be corrupt on the next startup, and therefore ignored.
I think that's a case where we need to make sure we don't explode,
even if it's
something along disabling cache writes or the cache entirely.
http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode85 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:85: private static class UnitCacheEntry { On 2011/03/07 21:03:15, scottb wrote:
Is this class an artifact of a previous design? I don't think it does
anything
anymore.
I had a weak hash map at one point that this was helping with. Now I am stuffing a another bit of information in there. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode109 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:109: unitCacheLoaderThread.setName("UnitCacheLoader"); On 2011/03/07 21:03:15, scottb wrote:
Also, setPriority()?
Set to normal priority - this needs to happen before the compile can start. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode110 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:110: unitCacheLoaderThread.start(); On 2011/03/07 21:03:15, scottb wrote:
I think this is Discouraged. It might make more sense to make simply
make this
class UnitCacheLoaderThread extends Thread, and have the caller call
'start' on
it, instead of decoupling the thread from the runnable. In this case,
the two
are so strongly bound that there's no simplicity in decoupling them.
Sounds arbitrary, but I am not going to get into a subclass verses compositing war. Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode117 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:117: logger.log(logger.ERROR, "Interrupted waiting for PersistentUnitCache to load.", ex); On 2011/03/08 02:31:25, tobyr wrote:
s/logger.ERROR/TreeLogger.ERROR
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode174 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:174: shutDownLatch.await(); On 2011/03/07 21:03:15, scottb wrote:
Use the await(long, TimeUnit) overload instead of the TimerTask stuff,
and check
the return value to decide if you should interrupt() the writer
thread. Much nicer. Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode205 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:205: // ignore On 2011/03/07 21:03:15, scottb wrote:
You'd want to bail here if you allow the Shutdown thread to interrupt
this one. Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode233 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:233: ex.printStackTrace(); On 2011/03/07 21:03:15, scottb wrote:
Logger?
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode246 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:246: private static boolean enabled = false; On 2011/03/07 21:03:15, scottb wrote:
It seems like the state of this variable has such radical implications
as to
warrant splitting a dummy vs. real cache class.
gone. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode250 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:250: private static File cacheDirectory = new File(System.getProperty("java.io.tmpdir", On 2011/03/08 16:29:31, jbrosenberg wrote:
cacheDirectory should be declared volatile, if it is assigned under a synchronized block, and referenced outside of one.
now encapsulated in MemoryUnitCache and not static. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode253 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:253: private static final String CACHE_PREFIX = "gwt-unitCache-"; On 2011/03/08 02:31:25, tobyr wrote:
I think this constant wants to be public and referenced from the other
places
it's already being used.
Moved to UnitCache interface http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode282 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:282: public static synchronized void cleanup(TreeLogger logger) { On 2011/03/07 21:03:15, scottb wrote:
I don't really understand why CSB needs to care, or why this needs to
be
explicitly called. Won't on-disk caches be cleaned up eventually in
subsequent
runs?
This call is to facilitate the auto cleanup. You don't want to run cleanup until after you run the build, otherwise your cleanup will include all of the stale units plus anything new. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode293 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:293: public static synchronized void clearPersistentCache(TreeLogger logger) { On 2011/03/08 02:31:25, tobyr wrote:
Nobody seems to call this, except for init() on cases of enabled ==
false which
should happen... never?
I moved this into PersistentUnitCache but still call from MemoryUnitCache.cleanup(). The behavior I wanted was that if you are ru nning from just memory, then clear the persistent cache because its probably no longer valid. Its not all that pretty and you could convice me that's a harebrained idea. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode295 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:295: // delete the current PersistentUnitCache instance On 2011/03/07 21:03:15, scottb wrote:
I don't think this code path is currently possible.
I removed it. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode324 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:324: * out any old cached files. On 2011/03/07 21:03:15, scottb wrote:
Why would running without a cache cause a clear?
Here's my logic. If you are compiling new units, then it is likely you'd be invalidating old units. Plus, I am just frightened of a cache that never gets purged. This is currently the only mechanism to purge the cache. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode346 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:346: logger.log(TreeLogger.TRACE, "Persistent unit cache dir set to: " On 2011/03/08 02:31:25, tobyr wrote:
Shouldn't this be cacheDirectory instead of cacheDir?
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode348 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:348: On 2011/03/08 02:31:25, tobyr wrote:
Should there be some test around here that ensures the cacheDirectory
is
actually available and accessible?
The thread UnitWriterThread handles that. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode352 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:352: PersistentUnitCache.clearPersistentCache(logger); On 2011/03/08 02:31:25, tobyr wrote:
Under what conditions would you call init() and enabled not be true?
For the auto cache cleanup, both memory and persistent unit cache need the directory. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode360 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:360: */ On 2011/03/08 16:29:31, jbrosenberg wrote:
This technically needs to be synchronized
Removed. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode374 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:374: * {@link #add(CompilationUnit)} and {@link #findUnit(String)} methods will be On 2011/03/08 02:31:25, tobyr wrote:
Bad link for add, but agree with scottb that it seems this method
should just
disappear.
Gone. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode397 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:397: if (current != null) { On 2011/03/08 02:31:25, tobyr wrote:
I don't understand the treatment of a null current. In the case that
current is
null, won't all of the equal tests in the for loop below fail? In
other words,
isn't this entire method a no-op with a null current?
This function gets referenced in 2 places. 1 is where you want to delete all but the currently accessed file. The other places is where you want to purge out all files in the cache (the null parameter case) http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode423 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:423: files = cacheFiles.toArray(new String[0]); On 2011/03/08 02:31:25, tobyr wrote:
s/new String[0]/new String[cacheFiles.size()]
Done. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode442 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:442: * forever in {@link ComplationStateBuilder} anyway. On 2011/03/08 02:31:25, tobyr wrote:
Bad link to CompilationStateBuilder. I think scottb's comment
resonates with
mine about dropping CSB.unitCache in favor of PUC.
I did this. I dropped a lot of weak hash map references from CSB. I think they are taken care of by the remove of the entry of the ContentId map when a unit is re-compiled. Please let me know if I'm being naive about something. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java#newcode471 dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java:471: private void cleanupCacheFiles(TreeLogger logger) { On 2011/03/07 21:03:15, scottb wrote:
I'm not sure I understand what this is doing, really. Shouldn't
everything have
already been written out to the current cache file? Why do we have to
do it
again?
This is to migrate the valid contents 10 log files into a single file. Normally, the cache only writes out newly compiled units to the current log. But when it is time to clean up, some of the currently valid units may be only stored in old files, not the currently open file. The currently open file becomes the new single cache file. I updated the comment a bit, and each cache entry now contains a source tag, so that we only re-write things we know are from old cache log files. http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerPersistentUnitCache.java File dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerPersistentUnitCache.java (right): http://gwt-code-reviews.appspot.com/1375802/diff/5002/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerPersistentUnitCache.java#newcode33 dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerPersistentUnitCache.java:33: return "Enable persistent CompliationUnit caching. If this argument " On 2011/03/08 02:31:25, tobyr wrote:
This seems like strange behavior to me.
I don't like the idea of a cache that never gets purged. At least this gives someone a foolproof method to purge it. "Are you having problems? Try running without the unit cache flag once and see if the problem goes away." http://gwt-code-reviews.appspot.com/1375802/ -- http://groups.google.com/group/Google-Web-Toolkit-Contributors