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

    Seam Manager Persistence

    Benjamin Graf Novice

      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 Master

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

          • 2. Re: Seam Manager Persistence
            Khaled Yousfi Newbie

            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 Master

              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
                James Kelly Newbie

                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
                  Guillaume Jeudy Master

                  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
                    James Kelly Newbie

                    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
                      Benjamin Graf Novice

                      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
                        Benjamin Graf Novice

                        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
                          Pete Muir Master

                          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
                            Benjamin Graf Novice

                            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
                              Benjamin Graf Novice

                              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
                                Pete Muir Master

                                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
                                  Pete Muir Master

                                  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
                                    Benjamin Graf Novice

                                    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