Fixes workDir directory contention between multiple concurrent hosted mode sessions.
- each StandardLinkerContext gets a unique directory in the workDir
- each session gets its own linker stack
- outputing files into war directory is serialized
Review by: jat
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6919 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/DevMode.java b/dev/core/src/com/google/gwt/dev/DevMode.java
index 5dd351b..665f924 100644
--- a/dev/core/src/com/google/gwt/dev/DevMode.java
+++ b/dev/core/src/com/google/gwt/dev/DevMode.java
@@ -41,8 +41,6 @@
import java.io.File;
import java.io.IOException;
import java.net.BindException;
-import java.util.HashMap;
-import java.util.Map;
/**
* The main executable class for the hosted mode shell. NOTE: the public API for
@@ -204,10 +202,6 @@
return new File(new File(getWorkDir(), moduleDef.getName()), "shell");
}
- public File getShellPublicGenDir(ModuleDef moduleDef) {
- return new File(getShellBaseWorkDir(moduleDef), "public");
- }
-
public File getWarDir() {
return warDir;
}
@@ -259,17 +253,6 @@
protected final HostedModeOptionsImpl options = (HostedModeOptionsImpl) super.options;
/**
- * Maps each active linker stack by module.
- */
- private final Map<String, StandardLinkerContext> linkerStacks = new HashMap<String, StandardLinkerContext>();
-
- /**
- * The set of specified modules by name; the keys represent the renamed name
- * of each module rather than the canonical name.
- */
- private Map<String, ModuleDef> modulesByName = new HashMap<String, ModuleDef>();
-
- /**
* The server that was started.
*/
private ServletContainer server;
@@ -302,11 +285,13 @@
}
@Override
- protected ArtifactAcceptor doCreateArtifactAcceptor(final ModuleDef module) {
+ protected ArtifactAcceptor doCreateArtifactAcceptor(TreeLogger logger,
+ final ModuleDef module) throws UnableToCompleteException {
+ final StandardLinkerContext linkerContext = link(logger, module);
return new ArtifactAcceptor() {
- public void accept(TreeLogger logger, ArtifactSet newlyGeneratedArtifacts)
+ public void accept(TreeLogger relinkLogger, ArtifactSet newArtifacts)
throws UnableToCompleteException {
- relink(logger, module, newlyGeneratedArtifacts);
+ relink(relinkLogger, linkerContext, module, newArtifacts);
}
};
}
@@ -355,6 +340,7 @@
TreeLogger moduleBranch = branch.branch(TreeLogger.INFO, moduleName);
try {
ModuleDef module = loadModule(moduleBranch, moduleName, false);
+ Util.recursiveDelete(options.getShellBaseWorkDir(module), false);
validateServletTags(moduleBranch, servletValidator, module, webXml);
TreeLogger loadLogger = moduleBranch.branch(TreeLogger.DEBUG,
"Bootstrap link for command-line module '" + moduleName + "'");
@@ -404,22 +390,6 @@
return options.getServletContainerLauncher().getName();
}
- /*
- * Overridden to keep our map up to date.
- */
- @Override
- protected ModuleDef loadModule(TreeLogger logger, String moduleName,
- boolean refresh) throws UnableToCompleteException {
- ModuleDef module = super.loadModule(logger, moduleName, refresh);
- modulesByName.put(module.getName(), module);
- return module;
- }
-
- protected void restartServer(TreeLogger logger)
- throws UnableToCompleteException {
- server.refresh();
- }
-
/**
* Perform an initial hosted mode link, without overwriting newer or
* unmodified files in the output folder.
@@ -428,7 +398,7 @@
* @param module the module to link
* @throws UnableToCompleteException
*/
- private void link(TreeLogger logger, ModuleDef module)
+ private StandardLinkerContext link(TreeLogger logger, ModuleDef module)
throws UnableToCompleteException {
TreeLogger linkLogger = logger.branch(TreeLogger.DEBUG, "Linking module '"
+ module.getName() + "'");
@@ -436,13 +406,12 @@
// Create a new active linker stack for the fresh link.
StandardLinkerContext linkerStack = new StandardLinkerContext(linkLogger,
module, options);
- linkerStacks.put(module.getName(), linkerStack);
-
ArtifactSet artifacts = linkerStack.invokeLink(linkLogger);
produceOutput(linkLogger, linkerStack, artifacts, module);
+ return linkerStack;
}
- private void produceOutput(TreeLogger logger,
+ private synchronized void produceOutput(TreeLogger logger,
StandardLinkerContext linkerStack, ArtifactSet artifacts, ModuleDef module)
throws UnableToCompleteException {
TreeLogger linkLogger = logger.branch(TreeLogger.DEBUG, "Linking module '"
@@ -477,18 +446,15 @@
* @param newlyGeneratedArtifacts the set of new artifacts
* @throws UnableToCompleteException
*/
- private void relink(TreeLogger logger, ModuleDef module,
- ArtifactSet newlyGeneratedArtifacts) throws UnableToCompleteException {
+ private void relink(TreeLogger logger, StandardLinkerContext linkerContext,
+ ModuleDef module, ArtifactSet newlyGeneratedArtifacts)
+ throws UnableToCompleteException {
TreeLogger linkLogger = logger.branch(TreeLogger.DEBUG,
"Relinking module '" + module.getName() + "'");
- // Find the existing linker stack.
- StandardLinkerContext linkerStack = linkerStacks.get(module.getName());
- assert linkerStack != null;
-
- ArtifactSet artifacts = linkerStack.invokeRelink(linkLogger,
+ ArtifactSet artifacts = linkerContext.invokeRelink(linkLogger,
newlyGeneratedArtifacts);
- produceOutput(linkLogger, linkerStack, artifacts, module);
+ produceOutput(linkLogger, linkerContext, artifacts, module);
}
private void validateServletTags(TreeLogger logger,
diff --git a/dev/core/src/com/google/gwt/dev/DevModeBase.java b/dev/core/src/com/google/gwt/dev/DevModeBase.java
index efd998a..971ef98 100644
--- a/dev/core/src/com/google/gwt/dev/DevModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/DevModeBase.java
@@ -60,6 +60,7 @@
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicLong;
/**
* The main executable class for the hosted mode shell. This class must not have
@@ -400,10 +401,10 @@
private File logDir;
private int port;
private int portHosted;
- private final List<String> startupURLs = new ArrayList<String>();
private String remoteUIClientId;
private String remoteUIHost;
private int remoteUIHostPort;
+ private final List<String> startupURLs = new ArrayList<String>();
public void addStartupURL(String url) {
startupURLs.add(url);
@@ -575,6 +576,8 @@
private static final Random RNG = new Random();
+ private static final AtomicLong uniqueId = new AtomicLong();
+
public static String normalizeURL(String unknownUrlText, int port, String host) {
if (unknownUrlText.indexOf(":") != -1) {
// Assume it's a full url.
@@ -722,7 +725,7 @@
try {
// Eager AWT init for OS X to ensure safe coexistence with SWT.
BootStrapPlatform.initGui();
-
+
if (startUp()) {
// The web server is running now, so launch browsers for startup urls.
launchStartupUrls(getTopLogger());
@@ -753,7 +756,8 @@
protected abstract HostedModeBaseOptions createOptions();
- protected abstract ArtifactAcceptor doCreateArtifactAcceptor(ModuleDef module);
+ protected abstract ArtifactAcceptor doCreateArtifactAcceptor(
+ TreeLogger logger, ModuleDef module) throws UnableToCompleteException;
/**
* Creates an instance of ShellModuleSpaceHost (or a derived class) using the
@@ -766,12 +770,16 @@
* @return ShellModuleSpaceHost instance
*/
protected final ShellModuleSpaceHost doCreateShellModuleSpaceHost(
- TreeLogger logger, CompilationState compilationState, ModuleDef moduleDef) {
+ TreeLogger logger, CompilationState compilationState, ModuleDef moduleDef)
+ throws UnableToCompleteException {
// Clear out the shell temp directory.
- Util.recursiveDelete(options.getShellBaseWorkDir(moduleDef), true);
+ File shellBaseWorkDir = options.getShellBaseWorkDir(moduleDef);
+ File sessionWorkDir = new File(shellBaseWorkDir,
+ String.valueOf(uniqueId.getAndIncrement()));
+ Util.recursiveDelete(sessionWorkDir, true);
return new ShellModuleSpaceHost(logger, compilationState, moduleDef,
- options.getGenDir(), new File(options.getShellBaseWorkDir(moduleDef),
- "gen"), doCreateArtifactAcceptor(moduleDef));
+ options.getGenDir(), new File(sessionWorkDir, "gen"),
+ doCreateArtifactAcceptor(logger, moduleDef));
}
protected abstract void doShutDownServer();
@@ -847,8 +855,8 @@
protected void launchURL(String url) throws UnableToCompleteException {
/*
- * TODO(jat): properly support launching arbitrary browsers -- need some
- * UI API tweaks to support that.
+ * TODO(jat): properly support launching arbitrary browsers -- need some UI
+ * API tweaks to support that.
*/
URL parsedUrl = null;
try {
@@ -883,7 +891,7 @@
public String getAnchorText() {
return "Launch default browser";
}
-
+
@Override
public String getPrefix() {
return "";
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index 9df74f6..3bf1332 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -192,7 +192,8 @@
}
@Override
- protected ArtifactAcceptor doCreateArtifactAcceptor(final ModuleDef module) {
+ protected ArtifactAcceptor doCreateArtifactAcceptor(TreeLogger logger,
+ final ModuleDef module) {
return new ArtifactAcceptor() {
public void accept(TreeLogger logger, ArtifactSet artifacts)
throws UnableToCompleteException {