Revision: 6919 Author: sco...@google.com Date: Mon Nov 16 11:37:40 2009 Log: 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 http://code.google.com/p/google-web-toolkit/source/detail?r=6919 Modified: /trunk/dev/core/src/com/google/gwt/dev/DevMode.java /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java /trunk/dev/core/src/com/google/gwt/dev/GWTShell.java ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/DevMode.java Thu Nov 5 10:42:40 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/DevMode.java Mon Nov 16 11:37:40 2009 @@ -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 @@ -203,10 +201,6 @@ public File getShellBaseWorkDir(ModuleDef moduleDef) { 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; @@ -258,17 +252,6 @@ @SuppressWarnings("hiding") 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. */ @@ -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 + "'"); @@ -403,22 +389,6 @@ protected String getWebServerName() { 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 @@ -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, ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java Fri Nov 13 10:26:21 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java Mon Nov 16 11:37:40 2009 @@ -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 ""; ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/GWTShell.java Fri Nov 13 07:52:59 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/GWTShell.java Mon Nov 16 11:37:40 2009 @@ -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 { -- http://groups.google.com/group/Google-Web-Toolkit-Contributors