You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-dev@xmlgraphics.apache.org by George Armhold <ar...@cs.rutgers.edu> on 2001/09/12 18:12:07 UTC

synchronization bug in 1.0 sources

Hi,

I was running into frequent ArrayIndexOutOfBoundsException when using
Batik-1.0.  Here are two typical stack traces:

2001-09-10 04:55:37 - Ctx( /annotate ): Exception in: R( /annotate +
/servlet/Submit + null) - java.lang.ArrayIndexOutOfBoundsException: 7 >=
7
        at java.util.Vector.elementAt(Vector.java:417)
        at
org.apache.batik.svggen.DOMTreeManager.recycleTopLevelGroup(DOMTreeManager.java:181)
        at
org.apache.batik.svggen.DOMTreeManager.getTopLevelGroup(DOMTreeManager.java:363)
        at
org.apache.batik.svggen.SVGGraphics2D.getTopLevelGroup(SVGGraphics2D.java:387)
        at
org.apache.batik.svggen.SVGGraphics2D.getTopLevelGroup(SVGGraphics2D.java:373)


2001-09-10 05:01:31 - Ctx( /annotate ): Exception in: R( /annotate +
/servlet/Submit + null) - java.lang.ArrayIndexOutOfBoundsException: 8 >=
6
        at java.util.Vector.elementAt(Vector.java:417)
        at
org.apache.batik.svggen.DOMTreeManager.appendGroup(DOMTreeManager.java:160)
        at
org.apache.batik.svggen.DOMGroupManager.addElement(DOMGroupManager.java:151)
        at
org.apache.batik.svggen.SVGGraphics2D.fill(SVGGraphics2D.java:1019)



It seems to crash roughly half the time with one of the above stack
traces, so I'm guessing it's a threading problem in the Batik library;
my code is single-threaded.  I was able to fix it with the following
patch.  I'm not on the batik-dev mailing list, so please Cc me with any
replies to this message.  (I am on batik-users.)

Thanks.


***
/home/armhold/z/xml-batik/sources/org/apache/batik/svggen/DOMTreeManager.java
Thu Apr 26 07:17:02 2001
--- DOMTreeManager.java	Wed Sep 12 11:44:07 2001
***************
*** 155,166 ****
       */
      public void appendGroup(Element group, DOMGroupManager
groupManager){
          topLevelGroup.appendChild(group);
!         int nManagers = groupManagers.size();
!         for(int i=0; i<nManagers; i++){
              DOMGroupManager gm =
(DOMGroupManager)groupManagers.elementAt(i);
              if( gm != groupManager )
!                 gm.recycleCurrentGroup();
!         }
      }
  
      /**
--- 155,168 ----
       */
      public void appendGroup(Element group, DOMGroupManager
groupManager){
          topLevelGroup.appendChild(group);
! 	synchronized (groupManagers) {
! 	  int nManagers = groupManagers.size();
! 	  for(int i=0; i<nManagers; i++){
              DOMGroupManager gm =
(DOMGroupManager)groupManagers.elementAt(i);
              if( gm != groupManager )
! 	      gm.recycleCurrentGroup();
! 	  }
! 	}
      }
  
      /**
***************
*** 176,186 ****
       */
      private void recycleTopLevelGroup(boolean recycleConverters){
          // First, recycle group managers
!         int nManagers = groupManagers.size();
!         for(int i=0; i<nManagers; i++){
              DOMGroupManager gm =
(DOMGroupManager)groupManagers.elementAt(i);
              gm.recycleCurrentGroup();
!         }
  
          // Create top level group node
          topLevelGroup = generatorContext.domFactory.
--- 178,190 ----
       */
      private void recycleTopLevelGroup(boolean recycleConverters){
          // First, recycle group managers
! 	synchronized (groupManagers) {
! 	  int nManagers = groupManagers.size();
! 	  for(int i=0; i<nManagers; i++){
              DOMGroupManager gm =
(DOMGroupManager)groupManagers.elementAt(i);
              gm.recycleCurrentGroup();
! 	  }
! 	}
  
          // Create top level group node
          topLevelGroup = generatorContext.domFactory.






--
George Armhold
Rutgers University
Bioinformatics Initiative

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org


Re: synchronization bug in 1.0 sources

Posted by George Armhold <ar...@cs.rutgers.edu>.
I wrote:

> To be honest I'm not sure why the create() is needed; I'm just
> mimicking what's being done in SwingSVGPrettyPrint.  I'd love to hear
> an explanation from the author of what that's all about.  But as I
> said before, it's always the same thread calling the create().

Hi all,

I seem to have solved my problem simply by removing that call to
g.create().  I'm still confused by the example in SwingSVGPrettyPrint,
but this seems to have done the trick for me.

PS: Batik 1.1rc2 seems pretty stable to me... eagerly waiting for
dynamic SVG/Javascript support. :-)  

Thanks.

--
George Armhold
Rutgers University
Bioinformatics Initiative

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org


Re: synchronization bug in 1.0 sources

Posted by George Armhold <ar...@cs.rutgers.edu>.
Thomas E Deweese wrote:

>     Ok as I thought you are definitely beeing called from multiple
> threads (as you admit later :).

Yes there are multiple threads in my program, but my graphics code is
only being called by one thread.  I tried printing the SVGGraphics2D
and thread name as you suggested, and there's only one thread
(originated by the servlet's doGet()) manipulating the SVGGraphics2D.

> GA>       // my pre-existing SVGGraphics2D, that I wish to paint on
> GA> SVGGraphics2D g = ...;
> 
>     I assume by this you mean it is some sort of singleton or shared
> instance (from a static or some such)?

No not static or shared, but rather dynamically created for each
doGet().  

> GA>       // create a copy of this SVG SVGGraphics2D g2 =
> GA> (SVGGraphics2D) g.create();
> 
>     Be aware that this does not appear to do a deep copy , and this
> method is not thread safe (so if two threads call g.create() at the
> same time you will be in trouble).

To be honest I'm not sure why the create() is needed; I'm just
mimicking what's being done in SwingSVGPrettyPrint.  I'd love to hear
an explanation from the author of what that's all about.  But as I
said before, it's always the same thread calling the create().

>     Have you tried putting the above code in a synchronize block on g?

Yes, and I still get ArrayIndexOutOfBoundsException.

> GA> Actually it's being called from a Servlet so there are certainly
> GA> multiple threads in play, but a new SVGGraphics2D is created for
> GA> each doPost/doGet, and I do all my painting serially from that
> GA> thread.  I'm not doing any painting in response to GUI/Swing
> GA> events.
> 
>     When you say a new SVGGraphics2D is created for each one are you
> counting 'create' as creating a new one?  If so this is the problem.

No.  I'm doing the following for each doGet():

    DOMImplementation impl =
SVGDOMImplementation.getDOMImplementation();
    Document doc = impl.createDocument(svgNS, "svg", null);
    g = new SVGGraphics2D(doc);

(Perhaps the DOMImplementation should be cached...)

Thanks again for your help in debugging this.


--
George Armhold
Rutgers University
Bioinformatics Initiative

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org


Re: synchronization bug in 1.0 sources

Posted by Thomas E Deweese <th...@kodak.com>.
>>>>> "GA" == George Armhold <ar...@cs.rutgers.edu> writes:

>> First off Batik 1.0 is getting pretty old now. I strongly suggest
>> using one of 1.1 rc releases.

GA> Ok, perhaps that will help.  I was sticking with 1.0 thinking it
GA> would be less feature-rich but more stable.  Can anyone tell me
GA> about any known problems with Batik-1.1 RC2?

    Well I can name a few that have been discovered in the past day or
two, but in most cases they were also in 1.0.  Until we start serious
work on the Dynamic stuff, before which we will fork the code base,
with a stable and development branch, and do a formal 1.1 release. You
can probably assume that every 1.1 RC canidate is better than the
previous one (in fact this is essentially our criteria for doing an RC
release).

>>  Who is calling this???

GA> Sorry, here's a more complete stack trace.

GA> org.apache.tomcat.service.TcpWorkerThread.runIt(PoolTcpEndpoint.java:416)
GA> at
GA> org.apache.tomcat.util.ThreadPool$ControlRunnable.run(ThreadPool.java:498)
GA> at java.lang.Thread.run(Thread.java:484)

    Ok as I thought you are definitely beeing called from multiple
threads (as you admit later :).

GA> Some more context: I'm trying to get access to the DOM nodes that
GA> are created by SVGGraphics2D.  I'm doing this in the fashion of
GA> SwingSVGPrettyPrint, as was suggested on the batik-users list.
GA> Here's what I'm doing, boiled down to essentials:

GA>       // my pre-existing SVGGraphics2D, that I wish to paint on
GA> SVGGraphics2D g = ...;

    I assume by this you mean it is some sort of singleton or shared
instance (from a static or some such)?

GA>       // create a copy of this SVG SVGGraphics2D g2 =
GA> (SVGGraphics2D) g.create();

    Be aware that this does not appear to do a deep copy , and this
method is not thread safe (so if two threads call g.create() at the
same time you will be in trouble).
    
GA>       // prune existing top level group Element origTopLevelGroup
GA> = g2.getTopLevelGroup();

GA>       // do my drawing g2.fill(shape);

GA>       // prune this top level group with our drawing off Element
GA> drawGroup = g2.getTopLevelGroup();

GA>       // set an id, so we can refer back to it later if desired
GA> String id =
GA> g.getGeneratorContext().getIDGenerator().generateID(name);
GA> drawGroup.setAttributeNS(null, "id", id);

GA>       // splice our node back in
GA> origTopLevelGroup.appendChild(drawGroup);
GA> g.setTopLevelGroup(origTopLevelGroup);

    Have you tried putting the above code in a synchronize block on g?

GA> I don't entirely comprehend what's going on in
GA> SwingSVGPrettyPrint, but my understanding is that you essentially
GA> create a clean slate (a new <g> tag) with the first call to
GA> getTopLevelGroup.  Then you do your drawing.  Then you call
GA> getTopLevelGroup again, and you now have access to the <g> that
GA> contains your recent drawing.  Then you can set attributes on this
GA> <g>, and splice it back into the DOM tree.  Is this accurate?
GA> (Suggestions on cleaner ways to get access to the nodes are
GA> welcome...)

    I dunno, Vincent?

>> Is the code calling your code single-threaded?  Just because _you_
>> don't create threads doesn't mean you aren't be invoked from
>> multiple threads (such as the event thread, and the application
>> main thread for a swing application, as a servelet you may be
>> invoked

GA> Actually it's being called from a Servlet so there are certainly
GA> multiple threads in play, but a new SVGGraphics2D is created for
GA> each doPost/doGet, and I do all my painting serially from that
GA> thread.  I'm not doing any painting in response to GUI/Swing
GA> events.

    When you say a new SVGGraphics2D is created for each one are you
counting 'create' as creating a new one?  If so this is the problem.

GA> Ok, I agree that the patch is not the best solution.  But to the
GA> best of my knowledge my code is manipulating the DOM serially, so
GA> I'm not sure where to look for the real problem.  Perhaps someone
GA> can comment on whether my manipulations with getTopLevelGroup are
GA> really ok or not.

    Before I ever do anything with an SVGGraphics2D I would print my
current thread and the Graphics2D, if you ever see the same Graphics2D
used with two threads you know you have a problem.


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org


Re: synchronization bug in 1.0 sources

Posted by George Armhold <ar...@cs.rutgers.edu>.
>    First off Batik 1.0 is getting pretty old now. I strongly suggest
> using one of 1.1 rc releases.

Ok, perhaps that will help.  I was sticking with 1.0 thinking it would
be less feature-rich but more stable.  Can anyone tell me about any
known problems with
Batik-1.1 RC2?  

>    You appear to have trimmed the stack traces...
>
> GA> org.apache.batik.svggen.SVGGraphics2D.getTopLevelGroup(SVGGraphics2D.java:373)
>
>    Who is calling this???

Sorry, here's a more complete stack trace.

2001-09-13 01:04:51 - Ctx( /annotate ): Exception in: R( /annotate +
/servlet/Submit + null) - java.lang.ArrayIndexOutOfBoundsException: 7 >=
7
        at java.util.Vector.elementAt(Vector.java:417)
        at
org.apache.batik.svggen.DOMTreeManager.appendGroup(DOMTreeManager.java:160)
        at
org.apache.batik.svggen.DOMGroupManager.addElement(DOMGroupManager.java:151)
        at
org.apache.batik.svggen.SVGGraphics2D.fill(SVGGraphics2D.java:1019)
        at
edu.rutgers.bioinf.annotate.SequenceRenderer.drawObject(SequenceRenderer.java:140)
        at
edu.rutgers.bioinf.annotate.SequenceRenderer.render(SequenceRenderer.java:73)
        at
edu.rutgers.bioinf.annotate.Submit.processSequences(Submit.java:184)
        at edu.rutgers.bioinf.annotate.Submit.submitJob(Submit.java:143)
        at edu.rutgers.bioinf.annotate.Submit.doPost(Submit.java:48)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at
org.apache.tomcat.core.ServletWrapper.doService(ServletWrapper.java:404)
        at org.apache.tomcat.core.Handler.service(Handler.java:286)
        at
org.apache.tomcat.core.ServletWrapper.service(ServletWrapper.java:372)
        at
org.apache.tomcat.core.ContextManager.internalService(ContextManager.java:797)
        at
org.apache.tomcat.core.ContextManager.service(ContextManager.java:743)
        at
org.apache.tomcat.service.connector.Ajp12ConnectionHandler.processConnection(Ajp12ConnectionHandler.java:166)
        at
org.apache.tomcat.service.TcpWorkerThread.runIt(PoolTcpEndpoint.java:416)
        at
org.apache.tomcat.util.ThreadPool$ControlRunnable.run(ThreadPool.java:498)
        at java.lang.Thread.run(Thread.java:484)


Some more context:  I'm trying to get access to the DOM nodes that are
created by SVGGraphics2D.  I'm doing this in the fashion of
SwingSVGPrettyPrint, as was suggested on the batik-users list.  Here's
what I'm doing, boiled down to essentials:

      // my pre-existing SVGGraphics2D, that I wish to paint on 
      SVGGraphics2D g = ...;  

      // create a copy of this SVG
      SVGGraphics2D g2 = (SVGGraphics2D) g.create();    
    
      // prune existing top level group   
      Element origTopLevelGroup = g2.getTopLevelGroup();

      // do my drawing 
      g2.fill(shape);

      // prune this top level group with our drawing off
      Element drawGroup = g2.getTopLevelGroup();

      // set an id, so we can refer back to it later if desired
      String id =
g.getGeneratorContext().getIDGenerator().generateID(name);
      drawGroup.setAttributeNS(null, "id", id);

      // splice our node back in
      origTopLevelGroup.appendChild(drawGroup);
      g.setTopLevelGroup(origTopLevelGroup);


I don't entirely comprehend what's going on in SwingSVGPrettyPrint,
but my understanding is that you essentially create a clean slate (a
new <g> tag) with the first call to getTopLevelGroup.  Then you do
your drawing.  Then you call getTopLevelGroup again, and you now have
access to the <g> that contains your recent drawing.  Then you can
set attributes on this <g>, and splice it back into the DOM tree.  Is
this accurate? (Suggestions on cleaner ways to get access to the nodes
are welcome...)

>    Is the code calling your code single-threaded?  Just because
> _you_ don't create threads doesn't mean you aren't be invoked from
> multiple threads (such as the event thread, and the application main
> thread for a swing application, as a servelet you may be invoked

Actually it's being called from a Servlet so there are certainly
multiple threads in play, but a new SVGGraphics2D is created for each
doPost/doGet, and I do all my painting serially from that thread.  I'm
not doing any painting in response to GUI/Swing events. 

>    It appears that this patch is attempting to make the SVGGen
> classes at least partially thread safe.  This is essentially a
> hopeless cause (as the entire DOM tree implementation would have to
> be made thread safe to really solve the problem).

Ok, I agree that the patch is not the best solution.  But to the best
of my knowledge my code is manipulating the DOM serially, so I'm not
sure where to look for the real problem.  Perhaps someone can comment
on whether my manipulations with getTopLevelGroup are really ok or
not.

>     I don't think this is the answer you are looking for but I hope it
>  helps anyway.

Yes, any enlightenment is always helpful. :-)  Thank you.


--
George Armhold
Rutgers University
Bioinformatics Initiative

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org


synchronization bug in 1.0 sources

Posted by Thomas E Deweese <th...@kodak.com>.
>>>>> "GA" == George Armhold <ar...@cs.rutgers.edu> writes:

GA> Hi, I was running into frequent ArrayIndexOutOfBoundsException
GA> when using Batik-1.0.  

    First off Batik 1.0 is getting pretty old now. I strongly suggest
using one of 1.1 rc releases.

GA> Here are two typical stack traces:

    You appear to have trimmed the stack traces...

GA> org.apache.batik.svggen.SVGGraphics2D.getTopLevelGroup(SVGGraphics2D.java:373)

    Who is calling this???

GA> org.apache.batik.svggen.SVGGraphics2D.fill(SVGGraphics2D.java:1019)

    Who is calling this???

GA> It seems to crash roughly half the time with one of the above
GA> stack traces, so I'm guessing it's a threading problem in the
GA> Batik library; 

    There are no Batik threads shown in those stack traces.  Note that
the SVGGen class is _not_ thread safe and for performance and
complexity reasons probably never will be.

GA> my code is single-threaded.  

    Is the code calling your code single-threaded?  Just because _you_
don't create threads doesn't mean you aren't be invoked from multiple
threads (such as the event thread, and the application main thread for
a swing application, as a servelet you may be invoked from a
different thread for every server request).  If you are using a
non-thread safe object in such circumstances it is up to you to use
mutex blocks to protect all your accesses to the shared unthread safe
resource.

GA> I was able to fix it with the following patch.  

    It appears that this patch is attempting to make the SVGGen
classes at least partially thread safe.  This is essentially a
hopeless cause (as the entire DOM tree implementation would have to be
made thread safe to really solve the problem).

GA> I'm not on the batik-dev mailing list, so please Cc me with any
GA> replies to this message.  (I am on batik-users.)

    I strongly suspect that your code is being called from multiple
threads, and those multiple threads are then accessing a shared
instance of SVGGen, this will not work.

GA> Thanks.

    I don't think this is the answer you are looking for but I hope it
helps anyway.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org