7 Replies Latest reply on May 6, 2005 7:57 AM by andreaswalsh

    How do I avoid "Unable to Passivate due to context lock" wit

    andreaswalsh

      Hi all,

      I have a CMP application where I have to perfom thousands of inserts in a single transaction. As you would imagine after a while memory gets scarce and JBoss tries to passivate some objects. Unfortunately all the objects are involved in the transaction and so no passivation is possible and I get the "Unable to passivate due to context lock" warnings.

      The thing is I very rarely have any need for the entity objects to be returned to memory once I have created them and so I would like to find some way to remove these objects from memory while also not committing them till the end of the transaction. I am happy to take the performance hit of removing them (and if needs be returning them to memory)

      Any ideas as to how this could be done?
      Andreas

      PS
      I am using the default settings for the container configuration:
      <container-configuration>
      <container-name>Standard CMP 2.x EntityBean</container-name>
      <call-logging>false</call-logging>
      <invoker-proxy-binding-name>entity-rmi-invoker</invoker-proxy-binding-name>
      <sync-on-commit-only>false</sync-on-commit-only>
      <insert-after-ejb-post-create>false</insert-after-ejb-post-create>
      <container-interceptors>
      org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor
      org.jboss.ejb.plugins.LogInterceptor
      org.jboss.ejb.plugins.SecurityInterceptor
      org.jboss.ejb.plugins.TxInterceptorCMT
      org.jboss.ejb.plugins.MetricsInterceptor
      org.jboss.ejb.plugins.EntityCreationInterceptor
      org.jboss.ejb.plugins.EntityLockInterceptor
      org.jboss.ejb.plugins.EntityInstanceInterceptor
      org.jboss.ejb.plugins.EntityReentranceInterceptor
      org.jboss.resource.connectionmanager.CachedConnectionInterceptor
      org.jboss.ejb.plugins.EntitySynchronizationInterceptor
      org.jboss.ejb.plugins.cmp.jdbc.JDBCRelationInterceptor
      </container-interceptors>
      <instance-pool>org.jboss.ejb.plugins.EntityInstancePool</instance-pool>
      <instance-cache>org.jboss.ejb.plugins.InvalidableEntityInstanceCache</instance-cache>
      <persistence-manager>org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager</persistence-manager>
      <locking-policy>org.jboss.ejb.plugins.lock.QueuedPessimisticEJBLock</locking-policy>
      <container-cache-conf>
      <cache-policy>org.jboss.ejb.plugins.LRUEnterpriseContextCachePolicy</cache-policy>
      <cache-policy-conf>
      <min-capacity>50</min-capacity>
      <max-capacity>1000000</max-capacity>
      <overager-period>300</overager-period>
      <max-bean-age>600</max-bean-age>
      <resizer-period>400</resizer-period>
      <max-cache-miss-period>60</max-cache-miss-period>
      <min-cache-miss-period>1</min-cache-miss-period>
      <cache-load-factor>0.75</cache-load-factor>
      </cache-policy-conf>
      </container-cache-conf>
      <container-pool-conf>
      100
      </container-pool-conf>
      <commit-option>B</commit-option>
      </container-configuration>

        • 1. Re: How do I avoid
          aloubyansky

          This is not supported.

          • 2. Re: How do I avoid
            andreaswalsh

            Are you saying that handling large numbers of inserts in a single transaction using CMP is not supported?

            • 3. Re: How do I avoid

              No he is saying your choice of options is not supported/ doesn't make sense.

              i.e. Don't synchronize with the DB until commit time, but you still want it to free up memory
              which would potentially discard state that is not synchronized with the db yet.

              I guess it could work, if the check that warns:
              "Unable to passivate due to context lock"
              also checked whether the bean state was "dirty".

              Care to provide a patch, since you want this feature?

              • 4. Re: How do I avoid

                Actually, you are not using sync-on-commit,
                but the checking dirty to allow passivation is still missing from the cache policy:

                
                 protected boolean canPassivate(EnterpriseContext ctx)
                 {
                 if (ctx.isLocked())
                 {
                 // The context is in the interceptor chain
                 return false;
                 }
                
                 if (ctx.getTransaction() != null)
                 {
                 return false;
                 }
                
                 Object key = ((EntityEnterpriseContext)ctx).getCacheKey();
                 return m_container.getLockManager().canPassivate(key);
                 }
                


                • 5. Re: How do I avoid
                  andreaswalsh

                  I suppose that is what I do not understand: why is passivation not allowed just because I am in the midst of a transaction?

                  In this particular transaction once I invoke create to create the entity bean I retrieve its primary key and then no longer need access to that bean during the transaction. There is absolutely no need for me to have those objects hang around in memory.
                  If I were using JDBC I would not get this problem.

                  So from what you suggested I should be able to stick in a configurable option to allow this? Why should it only be allowed if the data is dirty and not if it is clean?

                  Thanks a million
                  Andreas

                  • 6. Re: How do I avoid
                    triathlon98

                    - the system tries to reduce the number of db accesses as much as possible. It does this by caching the state and only saving at certain events (somewhat depending on your configuration). IIRC it normally it saves before each finder/selector invocation or (when sync-on-commit-only is true) only at the end of the transaction.

                    - Maybe you know you don't need it again, but Jboss doesn't and there is no standard way to indicate this to the container.

                    - An entity is considered dirty when the state has changed and the data needs to be written to the db again. As long as the data is dirty the entity cannot be discarde, or you would loose you changes. Adrian suggested you enhance JBoss so that it throws away entities when it tries to passivate if the entity is not dirty (and hence some memory would be fred and you would not get the passivation warning).

                    Joachim

                    • 7. Re: How do I avoid
                      andreaswalsh

                       

                      "triathlon98" wrote:
                      - the system tries to reduce the number of db accesses as much as possible. It does this by caching the state and only saving at certain events (somewhat depending on your configuration). IIRC it normally it saves before each finder/selector invocation or (when sync-on-commit-only is true) only at the end of the transaction.

                      Fair enough

                      "triathlon98" wrote:

                      - Maybe you know you don't need it again, but Jboss doesn't and there is no standard way to indicate this to the container.

                      - An entity is considered dirty when the state has changed and the data needs to be written to the db again. As long as the data is dirty the entity cannot be discarde, or you would loose you changes. Adrian suggested you enhance JBoss so that it throws away entities when it tries to passivate if the entity is not dirty (and hence some memory would be fred and you would not get the passivation warning).


                      In my case this would not help as all the data is dirty as it has all just been created in the current transaction.

                      What I would really like to do is be able to indicate to JBoss that a particular entity bean will no longer be changed in the current transaction i.e. readonly-for-rest-of-transaction.

                      The logic for passivation could then be changed so that if an object is in a transaction but has been marked as 'readonly-for-rest-of-transaction' then the state of the object can be sent to the DB and the object can then be passivated. Obviously the writing to DB would happen on the set of passivatable, dirty, readonly-for-rest-of-transaction entities rather than individually.

                      Does this make sense?