1 2 Previous Next 21 Replies Latest reply on May 28, 2008 4:06 PM by graben

    Seam Manager Persistence

    graben

      I have a strange problem. In my application I need to work with many instances of enties (~100000) If I use the seam managed persisitence injected with @In there is usuage of over 100000 jndi calls to java:/comp/userTransaction and a duration of several minutes before page is rendered in the browser. This does not happen if using extended persistence context insteed. Problem even recognized in seam-booking example after changing.


      THX for help!

        • 1. Re: Seam Manager Persistence
          christian.bauer

          I think it might be that you have the wrong polarity in your neutron flow.

          • 2. Re: Seam Manager Persistence
            yk

            See Caching Chapter of the Seam Documentation:



            In particular, the Seam-managed persistence context (or an extended EJB container-managed persistence context associated with a conversation-scoped stateful session bean) acts as a cache of data that has been read in the current conversation. This cache tends to have a pretty high hitrate! Seam optimizes the replication of Seam-managed persistence contexts in a clustered environment, and there is no requirement for transactional consistency with the database (optimistic locking is sufficient) so you don't need to worry too much about the performance implications of this cache, unless you read thousands of objects into a single persistence context.

            ....
            • 3. Re: Seam Manager Persistence
              christian.bauer

              This paragraph has nothing to do with the problem of the original posters. In fact, unless magic crystal balls start working, nobody knows what their problem is.

              • 4. Re: Seam Manager Persistence
                jimk1723

                I think I need to third this; I noticed it after profiling my app in YourKit. My note to self dates back to November though, so I'll need to refresh my memory on what was going on...


                • 5. Re: Seam Manager Persistence
                  gjeudy

                  Are you using the Seam entityConverter ? If so, that thread might be related to the performance hit you are witnessing.


                  PerformanceOfEntityConverter


                  I think a proposed fix is posted at the end of this thread. Anyways you should use query-driven paging mechanism if you are dealing with thousands of entities...

                  • 6. Re: Seam Manager Persistence
                    jimk1723

                    Huh, yeah actually. In a bunch of places...with entity backed selectOneMenus. I'll take a look at that thread.

                    • 7. Re: Seam Manager Persistence
                      graben

                      Thank you for any helpful comment so far! After a very long and sometimes frustrating time of profiling and debugging I think I got closer to the underlying problem. I recognized that Seam tries to passivate every entity after jsf request has been finished that has been loaded during that request and conversation.

                      ServerConversationContext.flush() --> ServerConversationContext.isAttributeDirty() -->
                      EntityBeanList.passivate() --> EntityBeanList.passivateAll() -->
                      PassivatedEntity.passivateEntity()


                      This seems to try to get every single instance from the database. Maybe the reason for so many transactions. I don't know whether that is necessary and why there is so many time lost. I will do further investigation but those sourcecode files a hardly commented. I would suggest to close this gap between claim and reality!


                      I hope that we got this solved!


                      Greets Benjamin

                      • 8. Re: Seam Manager Persistence
                        graben

                        Another performance killer found!


                        class EntityBeanList
                        
                        protected void passivateAll()
                        
                           {       
                        
                               List<PassivatedEntity> newPassivatedList = new ArrayList<PassivatedEntity>(list.size());               
                        
                        
                               boolean found = false;
                        
                               for (int i=0; i<list.size(); i++) {
                        
                                   PassivatedEntity passivatedEntity = null;
                        
                                   Object value = list.get(i);
                        
                                   if (value != null) {
                        
                                       passivatedEntity = PassivatedEntity.passivateEntity(value);
                        
                                       
                        
                                       if (passivatedEntity!=null) {
                        
                                           if (!found) {
                        
                                               list = new ArrayList(list);
                        
                                               found=true;
                        
                                           }
                        
                        
                                           //this would be dangerous, except that we 
                        
                                           //are doing it to a copy of the original 
                        
                                           //list:
                        
                                           list.set(i, null); 
                        
                                       }                               
                        
                                   }          
                        
                                   newPassivatedList.add(passivatedEntity);
                        
                               }
                        
                               
                        
                               // if the original list was nulled out, we don't want to overwrite the passivatedEntity list
                        
                               if (found) {
                        
                                   passivatedEntityList = newPassivatedList;
                        
                               }
                        
                           } 



                        Well, bad performance with LinkedList cause of list.get(). Why not using iterator?

                        • 9. Re: Seam Manager Persistence
                          pmuir

                          Benjamin Graf wrote on Apr 08, 2008 08:18 PM:


                          This seems to try to get every single instance from the database. Maybe the reason for so many transactions.



                          Shouldn't do any loads, but just retrieve entities that are already loaded and have been outjected.



                          I don't know whether that is necessary and why there is so many time lost. I will do further investigation but those sourcecode files a hardly commented.

                          The purpose of the code is pretty much self-evident.



                          Well, bad performance with LinkedList cause of list.get(). Why not using iterator?

                          If the performance of doing a search of linked list is better using an iterator why does the implementation of get() in the SDK not use it?

                          • 10. Re: Seam Manager Persistence
                            graben

                            If the performance of doing a search of linked list is better using an iterator why does the implementation of get() in the SDK not use it?


                            Well, the SDK is doing the right job with get() if you want to get a specific index item. But in Seam this method is used in a for loop that will touch every single item of the list. For this purpose the iterator should be used instead of the loop because this cause a nested loop in java stack! (for loop in EntityBeanList and for loop in LinkedList -> 1000 items => 10002 = 1000000 actions)


                            Greets Benjamin

                            • 11. Re: Seam Manager Persistence
                              graben

                              Shouldn't do any loads, but just retrieve entities that are already loaded and have been outjected.


                              But what about entities that just have been created and not yet been persisted? As far as I understand the seam code it will try to find even those entity instances in entitymanager 2nd level pool without success --> transactions to the database to find them?

                              • 12. Re: Seam Manager Persistence
                                pmuir

                                Benjamin Graf wrote on Apr 10, 2008 02:03 PM:



                                If the performance of doing a search of linked list is better using an iterator why does the implementation of get() in the SDK not use it?


                                Well, the SDK is doing the right job with get() if you want to get a specific index item. But in Seam this method is used in a for loop that will touch every single item of the list. For this purpose the iterator should be used instead of the loop because this cause a nested loop in java stack! (for loop in EntityBeanList and for loop in LinkedList -> 1000 items => 10002 = 1000000 actions)



                                I see your point, please raise an issue in JIRA.

                                • 13. Re: Seam Manager Persistence
                                  pmuir

                                  I don't think so, from PassivatedEntity.createUsingEntityManager() the passivated entity metadata is only build if the entity is managed (i.e. the current SMPC contains the entity).

                                  • 14. Re: Seam Manager Persistence
                                    graben

                                    Quiet a long time ago, I know! Well, I recognized that the problem is a bit earlier while retrieving persistence context. For every entity instance seam tries to get a persistenceContext (PassivatedEntity.passivateEntity).


                                    public static PassivatedEntity passivateEntity(Object value)
                                    
                                       {
                                    
                                          Class entityClass = Seam.getEntityClass( value.getClass() );
                                    
                                          if (entityClass!=null)
                                    
                                          {
                                    
                                             for ( String persistenceContextName: PersistenceContexts.instance().getTouchedContexts() )
                                    
                                             {
                                    
                                                Object persistenceContext = Component.getInstance(persistenceContextName);
                                    
                                                return createPassivatedEntity(value, entityClass, persistenceContextName, persistenceContext);
                                    
                                             }
                                    
                                          }
                                    
                                          return null;
                                    
                                       }



                                    If you go further in the java stack you'll get to ManagedPersistenceContext.getEntityManager(). In my case this method wants to join a transaction.


                                    @Unwrap
                                    
                                       public EntityManager getEntityManager() throws NamingException, SystemException
                                    
                                       {
                                    
                                          if (entityManager==null) initEntityManager();
                                    
                                          
                                    
                                          if ( !synchronizationRegistered && !Lifecycle.isDestroying() )
                                    
                                          {
                                    
                                             joinTransaction();
                                    
                                          }
                                    
                                          
                                    
                                          return entityManager;
                                    
                                       }
                                    
                                    
                                       private void joinTransaction() throws SystemException
                                    
                                       {
                                    
                                          UserTransaction transaction = Transaction.instance();
                                    
                                          if ( transaction.isActive() )
                                    
                                          {
                                    
                                             transaction.enlist(entityManager);
                                    
                                             try
                                    
                                             {
                                    
                                                transaction.registerSynchronization(this);
                                    
                                                synchronizationRegistered = true;
                                    
                                             }
                                    
                                             catch (Exception e)
                                    
                                             {
                                    
                                                synchronizationRegistered = PersistenceProvider.instance().registerSynchronization(this, entityManager);
                                    
                                             }
                                    
                                          }
                                    
                                       }



                                    That causes a initialization of a new UserTransaction which leeds to a lookup of context.lookup("java:comp/UserTransaction").


                                    protected javax.transaction.UserTransaction getUserTransaction() throws NamingException
                                    
                                       {
                                    
                                          InitialContext context = Naming.getInitialContext();
                                    
                                          try
                                    
                                          {
                                    
                                             return (javax.transaction.UserTransaction) context.lookup("java:comp/UserTransaction");
                                    
                                          }
                                    
                                          catch (NameNotFoundException nnfe)
                                    
                                          {
                                    
                                             try
                                    
                                             {
                                    
                                                //Embedded JBoss has no java:comp/UserTransaction
                                    
                                                javax.transaction.UserTransaction ut = (javax.transaction.UserTransaction) context.lookup("UserTransaction");
                                    
                                                ut.getStatus(); //for glassfish, which can return an unusable UT
                                    
                                                return ut;
                                    
                                             }
                                    
                                             catch (Exception e)
                                    
                                             {
                                    
                                                throw nnfe;
                                    
                                             }
                                    
                                          }
                                    
                                       }



                                    I don't think that this behaviour is really helpful!

                                    1 2 Previous Next