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

Reply via email to