Hi All,

        Hope all is well.

        During our recent load tests I've come across a thread-related bug in
        the ProgramGenerator implementation. The symptoms are similar to the
        sitemap recompilation issue we faced last week.

        If 2 simultaneous requests ask for the same xsp resource, which is not
        compiled, or has changed, etc, then the that resource is created and
        loaded twice. If the loading of the class occurs while the second
        request is (re)compiling it, then very strange things happen.. :-)

        I've been able to reproduce this easily in our test environment, and
        have attached a patch (using the Carsten method (TM) :-) ) which fixes
        the problem. Hope it's all ok.

        Cheers,

        Marcus

-- 
        .....
     ,,$$$$$$$$$,      Marcus Crafter
    ;$'      '$$$$:    Computer Systems Engineer
    $:         $$$$:   Open Software Associates GmbH
     $       o_)$$$:   82-84 Mainzer Landstrasse
     ;$,    _/\ &&:'   60327 Frankfurt Germany
       '     /( &&&
           \_&&&&'     Email : [EMAIL PROTECTED]
          &&&&.        Business Hours : +49 69 9757 200
    &&&&&&&:

Index: src/org/apache/cocoon/components/language/generator/ProgramGeneratorImpl.java
===================================================================
RCS file: 
/home/cvspublic/xml-cocoon2/src/org/apache/cocoon/components/language/generator/ProgramGeneratorImpl.java,v

retrieving revision 1.5.2.14
diff -u -r1.5.2.14 ProgramGeneratorImpl.java
--- src/org/apache/cocoon/components/language/generator/ProgramGeneratorImpl.java      
 2001/08/22 03:57:58     1.5.2.14
+++ src/org/apache/cocoon/components/language/generator/ProgramGeneratorImpl.java      
+ 2001/08/29 15:47:06
@@ -101,8 +101,9 @@
     }
 
     /**
-     * Set the global component manager. This metod also sets the
-     * <code>ComponentSelector</code> used as language factory for both markup and 
programming languages.
+     * Set the global component manager. This method also sets the
+     * <code>ComponentSelector</code> used as language factory for both markup
+     * and programming languages.
      * @param manager The global component manager
      */
     public void compose(ComponentManager manager) throws ComponentException {
@@ -171,7 +172,7 @@
             try {
                 programInstance = (CompiledComponent) select(normalizedName);
             } catch (Exception e) {
-                getLogger().debug("The instance was not accessible, creating it 
now.");
+                getLogger().debug("The instance was not accessible from the internal 
+cache. Proceeding.");
             }
     
             if ((programInstance == null) && this.preload) {
@@ -187,32 +188,11 @@
             }
     
             if (programInstance == null) {
-                MarkupLanguage markupLanguage = null;
-                ProgrammingLanguage programmingLanguage = null;
-                try {
-                    // Get markup and programming languages
-                    markupLanguage = 
(MarkupLanguage)this.markupSelector.select(markupLanguageName);
-                    programmingLanguage = 
(ProgrammingLanguage)this.languageSelector.select(programmingLanguageName);
-                    programmingLanguage.setLanguageName(programmingLanguageName);
-                    program = this.generateResource(newManager, fileName, 
normalizedName, markupLanguage, programmingLanguage, resolver);
-                } catch (LanguageException le) {
-                    getLogger().debug("Language Exception", le);
-                    throw new ProcessingException("Language Exception", le);
-                } finally {
-                    if (this.markupSelector != null) {
-                        this.markupSelector.release(markupLanguage);
-                    }
-    
-                    if (this.languageSelector != null) {
-                        this.languageSelector.release(programmingLanguage);
-                    }
-                }
-    
-                try {
-                    programInstance = (CompiledComponent) select(normalizedName);
-                } catch (Exception cme) {
-                    getLogger().debug("Can't load ServerPage", cme);
-                }
+               programInstance =
+                    this.createResource(
+                        newManager, fileName, normalizedName,
+                        markupLanguageName, programmingLanguageName, resolver
+                    );
             }
     
             if (this.autoReload == false) {
@@ -241,30 +221,80 @@
     
             if (programInstance == null) {
                 if (program == null) {
-                    MarkupLanguage markupLanguage = null;
-                    ProgrammingLanguage programmingLanguage = null;
-                    try {
-                        // Get markup and programming languages
-                        markupLanguage = 
(MarkupLanguage)this.markupSelector.select(markupLanguageName);
-                        programmingLanguage = 
(ProgrammingLanguage)this.languageSelector.select(programmingLanguageName);
-                        programmingLanguage.setLanguageName(programmingLanguageName);
-                        program = this.generateResource(newManager, fileName, 
normalizedName, markupLanguage, programmingLanguage, resolver);
-                    } catch (LanguageException le) {
-                        getLogger().debug("Language Exception", le);
-                        throw new ProcessingException("Language Exception", le);
-                    } finally {
-                        this.markupSelector.release(markupLanguage);
-                        this.languageSelector.release(programmingLanguage);
-                    }
-                }
-                // Instantiate
-                programInstance = (CompiledComponent) select(normalizedName);
+                    programInstance =
+                        this.createResource(
+                            newManager, fileName, normalizedName, 
+                            markupLanguageName, programmingLanguageName,
+                            resolver
+                        );
+                } else
+                    programInstance = (CompiledComponent) select(normalizedName);
             }
 
             return programInstance;
         } finally {
             source.recycle();
         }
+    }
+
+    /**
+     * Helper method to create resources in a threadsafe manner.
+     */
+    private CompiledComponent createResource(
+        ComponentManager newManager,
+        String fileName,
+        String normalizedName,
+        String markupLanguageName,
+        String programmingLanguageName,
+        SourceResolver resolver
+    )
+    throws Exception {
+
+        CompiledComponent programInstance = null;
+        MarkupLanguage markupLanguage = null;
+        ProgrammingLanguage programmingLanguage = null;
+        Class program = null;
+
+        // prevent 2 requests from generating this resource simultaneously
+        synchronized (this) {
+            try {
+                programInstance = (CompiledComponent) select(normalizedName);
+            } catch (Exception e) {
+
+                getLogger().debug(
+                     "Creating resource " +
+                     normalizedName.replace(File.separatorChar, '.') +
+                     ", using generator " + this
+                );
+
+                try {
+                    // Get markup and programming languages
+                    markupLanguage = 
+(MarkupLanguage)this.markupSelector.select(markupLanguageName);
+                    programmingLanguage = 
+(ProgrammingLanguage)this.languageSelector.select(programmingLanguageName);
+                    programmingLanguage.setLanguageName(programmingLanguageName);
+                    program = this.generateResource(newManager, fileName, 
+normalizedName, markupLanguage, programmingLanguage, resolver);
+                } catch (LanguageException le) {
+                    getLogger().debug("Language Exception", le);
+                    throw new ProcessingException("Language Exception", le);
+                } finally {
+                    if (this.markupSelector != null) {
+                        this.markupSelector.release(markupLanguage);
+                    }
+
+                    if (this.languageSelector != null) {
+                        this.languageSelector.release(programmingLanguage);
+                    }
+                }
+
+                try {
+                    programInstance = (CompiledComponent) select(normalizedName);
+                } catch (Exception cme) {
+                    getLogger().debug("Can't load ServerPage", cme);
+                }
+            }
+        }
+
+       return programInstance;
     }
 
     private Class generateResource(ComponentManager newManager,
Index: src/org/apache/cocoon/components/language/programming/java/JavaLanguage.java
===================================================================
RCS file: 
/home/cvspublic/xml-cocoon2/src/org/apache/cocoon/components/language/programming/java/JavaLanguage.java,v

retrieving revision 1.2.2.4
diff -u -r1.2.2.4 JavaLanguage.java
--- src/org/apache/cocoon/components/language/programming/java/JavaLanguage.java       
 2001/08/21 18:00:01     1.2.2.4
+++ src/org/apache/cocoon/components/language/programming/java/JavaLanguage.java       
+ 2001/08/29 15:47:06
@@ -149,11 +149,10 @@
       String pathname =
         baseDirectory.getCanonicalPath() + File.separator +
         name.substring(0, pos).replace(File.separatorChar, '/');
+      String filename_abs =
+        pathname + File.separator + filename + "." + this.getSourceExtension();
 
-      compiler.setFile(
-        pathname + File.separator +
-        filename + "." + this.getSourceExtension()
-      );
+      compiler.setFile(filename_abs);
 
       compiler.setSource(pathname);
 
@@ -179,6 +178,8 @@
       if (encoding != null) {
         compiler.setEncoding(encoding);
       }
+
+      getLogger().debug("Compiling " + filename_abs);
 
       if (!compiler.compile()) {
         StringBuffer message = new StringBuffer("Error compiling ");
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to