aboutsummaryrefslogtreecommitdiff
path: root/nailgun_launcher/NailgunLauncher.java
diff options
context:
space:
mode:
authorChristopher Vogt <oss.nsp@cvogt.org>2017-02-09 21:20:11 -0500
committerChristopher Vogt <oss.nsp@cvogt.org>2017-02-09 22:43:00 -0500
commite8673866b79f7473391dcee26243eee80d5d3cb6 (patch)
tree16146affeebdb58cd302a1f8527220c906818c96 /nailgun_launcher/NailgunLauncher.java
parentbee13ba7a4458482ce00a5c6bae4cd64328c4e5e (diff)
downloadcbt-e8673866b79f7473391dcee26243eee80d5d3cb6.tar.gz
cbt-e8673866b79f7473391dcee26243eee80d5d3cb6.tar.bz2
cbt-e8673866b79f7473391dcee26243eee80d5d3cb6.zip
idempotent change propagation
using lastModified instead of a non-idempotent needsUpdate flag this fixes a bug where dependees would not be rebuilt if cbt exited or was killed after dependencies were already rebuilt.
Diffstat (limited to 'nailgun_launcher/NailgunLauncher.java')
-rw-r--r--nailgun_launcher/NailgunLauncher.java80
1 files changed, 51 insertions, 29 deletions
diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java
index c397810..8a330d8 100644
--- a/nailgun_launcher/NailgunLauncher.java
+++ b/nailgun_launcher/NailgunLauncher.java
@@ -26,12 +26,12 @@ public class NailgunLauncher{
@SuppressWarnings("unchecked")
public static Object getBuild( Object context ) throws Throwable{
BuildStage1Result res = buildStage1(
- (Boolean) get(context, "cbtHasChangedCompat"),
- (Long) get(context, "startCompat"),
+ (long) get(context, "cbtLastModified"),
+ (long) get(context, "start"),
((File) get(context, "cache")).toString() + "/",
((File) get(context, "cbtHome")).toString(),
((File) get(context, "compatibilityTarget")).toString() + "/",
- new JavaCache<ClassLoader>(
+ new ClassLoaderCache(
(HashMap) get(context, "persistentCache")
)
);
@@ -43,6 +43,8 @@ public class NailgunLauncher{
.invoke(null, context, res);
}
+ public static long nailgunLauncherLastModified = -1; // this initial value should be overwritten, never read
+
public static void main( String[] args ) throws Throwable {
Long _start = System.currentTimeMillis();
if(args[0].equals("check-alive")){
@@ -76,13 +78,18 @@ public class NailgunLauncher{
String CBT_HOME = System.getenv("CBT_HOME");
String cache = CBT_HOME + "/cache/";
String compatibilityTarget = CBT_HOME + "/compatibility/" + TARGET;
- // copy cache, so that this thread has a consistent view
- // replace before returning, see below
- JavaCache<ClassLoader> classLoaderCache = new JavaCache<ClassLoader>(
+ // copy cache, so that this thread has a consistent view despite other threads
+ // changing their copies
+ // replace again before returning, see below
+ ClassLoaderCache classLoaderCache = new ClassLoaderCache(
new HashMap<Object,Object>(classLoaderCacheHashMap)
);
+
+ String nailgunTarget = CBT_HOME + "/" + NAILGUN + TARGET;
+ long nailgunLauncherLastModified = new File( nailgunTarget + "../classes.last-success" ).lastModified();
+
BuildStage1Result res = buildStage1(
- false, start, cache, CBT_HOME, compatibilityTarget, classLoaderCache
+ nailgunLauncherLastModified, start, cache, CBT_HOME, compatibilityTarget, classLoaderCache
);
try{
@@ -90,9 +97,9 @@ public class NailgunLauncher{
.classLoader
.loadClass("cbt.Stage1")
.getMethod(
- "run", String[].class, File.class, File.class, BuildStage1Result.class, Long.class, Map.class
+ "run", String[].class, File.class, File.class, BuildStage1Result.class, Map.class
).invoke(
- null, (Object) args, new File(cache), new File(CBT_HOME), res, start, classLoaderCache.hashMap
+ null, (Object) args, new File(cache), new File(CBT_HOME), res, classLoaderCache.hashMap
);
System.exit( exitCode );
@@ -115,7 +122,8 @@ public class NailgunLauncher{
}
public static BuildStage1Result buildStage1(
- Boolean changed, long start, String cache, String cbtHome, String compatibilityTarget, JavaCache<ClassLoader> classLoaderCache
+ final long lastModified, final long start, final String cache, final String cbtHome,
+ final String compatibilityTarget, final ClassLoaderCache classLoaderCache
) throws Throwable {
_assert(TARGET != null, "environment variable TARGET not defined");
String nailgunTarget = cbtHome + "/" + NAILGUN + TARGET;
@@ -128,9 +136,11 @@ public class NailgunLauncher{
ClassLoader rootClassLoader = new CbtURLClassLoader( new URL[]{}, ClassLoader.getSystemClassLoader().getParent() ); // wrap for caching
EarlyDependencies earlyDeps = new EarlyDependencies(mavenCache, mavenUrl, classLoaderCache, rootClassLoader);
- ClassLoader compatibilityClassLoader;
+ long nailgunLauncherLastModified = new File( nailgunTarget + "../classes.last-success" ).lastModified();
+
+ long compatibilityLastModified;
if(!compatibilityTarget.startsWith(cbtHome)){
- compatibilityClassLoader = classLoaderCache.get( compatibilityTarget );
+ compatibilityLastModified = new File( compatibilityTarget + "../classes.last-success" ).lastModified();
} else {
List<File> compatibilitySourceFiles = new ArrayList<File>();
for( File f: compatibilitySources.listFiles() ){
@@ -138,20 +148,20 @@ public class NailgunLauncher{
compatibilitySourceFiles.add(f);
}
}
- changed = compile(changed, start, "", compatibilityTarget, earlyDeps, compatibilitySourceFiles);
-
- if( classLoaderCache.contains( compatibilityTarget ) ){
- compatibilityClassLoader = classLoaderCache.get( compatibilityTarget );
- } else {
- compatibilityClassLoader = classLoaderCache.put( classLoader(compatibilityTarget, rootClassLoader), compatibilityTarget );
+
+ compatibilityLastModified = compile( 0L, "", compatibilityTarget, earlyDeps, compatibilitySourceFiles);
+
+ if( !classLoaderCache.containsKey( compatibilityTarget, compatibilityLastModified ) ){
+ classLoaderCache.put( compatibilityTarget, classLoader(compatibilityTarget, rootClassLoader), compatibilityLastModified );
}
}
+ final ClassLoader compatibilityClassLoader = classLoaderCache.get( compatibilityTarget, compatibilityLastModified );
String[] nailgunClasspathArray = append( earlyDeps.classpathArray, nailgunTarget );
String nailgunClasspath = classpath( nailgunClasspathArray );
- ClassLoader nailgunClassLoader = new CbtURLClassLoader( new URL[]{}, NailgunLauncher.class.getClassLoader() ); // wrap for caching
- if( !classLoaderCache.contains( nailgunClasspath ) ){
- nailgunClassLoader = classLoaderCache.put( nailgunClassLoader, nailgunClasspath );
+ final ClassLoader nailgunClassLoader = new CbtURLClassLoader( new URL[]{}, NailgunLauncher.class.getClassLoader() ); // wrap for caching
+ if( !classLoaderCache.containsKey( nailgunClasspath, nailgunLauncherLastModified ) ){
+ classLoaderCache.put( nailgunClasspath, nailgunClassLoader, nailgunLauncherLastModified );
}
String[] stage1ClasspathArray =
@@ -164,14 +174,24 @@ public class NailgunLauncher{
stage1SourceFiles.add(f);
}
}
- changed = compile(changed, start, stage1Classpath, stage1Target, earlyDeps, stage1SourceFiles);
- ClassLoader stage1classLoader;
- if( !changed && classLoaderCache.contains( stage1Classpath ) ){
- stage1classLoader = classLoaderCache.get( stage1Classpath );
- } else {
- stage1classLoader =
+ final long stage1BeforeCompiled = System.currentTimeMillis();
+ final long stage0LastModified = Math.max(
+ lastModified,
+ Math.max( lastModified, compatibilityLastModified )
+ );
+ final long stage1LastModified = compile(
+ stage0LastModified, stage1Classpath, stage1Target, earlyDeps, stage1SourceFiles
+ );
+
+ if( stage1LastModified < compatibilityLastModified )
+ throw new AssertionError(
+ "Cache invalidation bug: cbt compatibility layer recompiled, but cbt stage1 did not."
+ );
+
+ if( !classLoaderCache.containsKey( stage1Classpath, stage1LastModified ) ){
classLoaderCache.put(
+ stage1Classpath,
classLoader(
stage1Target,
new MultiClassLoader2(
@@ -180,12 +200,14 @@ public class NailgunLauncher{
earlyDeps.classLoader
)
),
- stage1Classpath
+ stage1LastModified
);
}
+ final ClassLoader stage1classLoader = classLoaderCache.get( stage1Classpath, stage1LastModified );
return new BuildStage1Result(
- changed,
+ start,
+ stage1LastModified,
stage1classLoader,
stage1Classpath,
nailgunClasspath,