Discussions

EJB programming & troubleshooting: Setting cache-size to 100 limits DB to 100 records!!

  1. Hello,
    I'm using Weblogic 5.1 under Win NT. I found out that if max-bean-in-cache is set to 100 I get the following error message if the records in the table are over 100:

    Thu Jan 11 12:01:43 GMT+01:00 2001:<I> <EJB JAR deployment, url: http://mypc/ejb_deploy/accounting.jar> Transaction: '979210575999_1' rolled back due to EJB exception:
    javax.ejb.EJBException: REMOTEEDPCache for home: 'Subaccount' is at its limit of: '100' *active* beans.
            at com.lmt.accounting.ejb.AccountingManagerBean.getAccountsplan(AccountingManagerBean.java, Compiled Code)
            at com.lmt.accounting.ejb.AccountingManagerBeanEOImpl.getAccountsplan(AccountingManagerBeanEOImpl.java:509)
            at com.lmt.accounting.ejb.AccountingManagerBeanEOImpl_WLSkel.invoke(AccountingManagerBeanEOImpl_WLSkel.java:779)
            at weblogic.rmi.extensions.BasicServerObjectAdapter.invoke(BasicServerObjectAdapter.java, Compiled Code)
            at weblogic.rmi.extensions.BasicRequestHandler.handleRequest(BasicRequestHandler.java, Compiled Code)
            at weblogic.rmi.internal.BasicExecuteRequest.execute(BasicExecuteRequest.java, Compiled Code)
            at weblogic.kernel.ExecuteThread.run(ExecuteThread.java, Compiled Code)

    Thu Jan 11 12:01:43 GMT+01:00 2001:<E> <Adapter> Exception thrown by rmi server: [-1578076148871584661S192.168.0.120:[7001,7001,7002,7002,7001,-1]/321]
    javax.ejb.EJBException: REMOTEEDPCache for home: 'Subaccount' is at its limit of: '100' *active* beans.
            at com.lmt.accounting.ejb.AccountingManagerBean.getAccountsplan(AccountingManagerBean.java, Compiled Code)
            at com.lmt.accounting.ejb.AccountingManagerBeanEOImpl.getAccountsplan(AccountingManagerBeanEOImpl.java:509)
            at com.lmt.accounting.ejb.AccountingManagerBeanEOImpl_WLSkel.invoke(AccountingManagerBeanEOImpl_WLSkel.java:779)
            at weblogic.rmi.extensions.BasicServerObjectAdapter.invoke(BasicServerObjectAdapter.java, Compiled Code)
            at weblogic.rmi.extensions.BasicRequestHandler.handleRequest(BasicRequestHandler.java, Compiled Code)
            at weblogic.rmi.internal.BasicExecuteRequest.execute(BasicExecuteRequest.java, Compiled Code)
            at weblogic.kernel.ExecuteThread.run(ExecuteThread.java, Compiled Code)

    Is it possible that I have to set the cache to a value
    that's higher then the records in DB...? it would be
    terribly ugly since I don't know how many records I'll have.
    Hope Not!
    Thanks for your feedback
    Francesco
  2. Francesco-

    This is a very odd error that you are getting. The cache-size tag for entity beans in WLS 5.1 is used to specify the number of beans that are in the "Ready" state -- not the number of records in the database. If you are getting this error, this tells me that your applicaiton has done something to cause 100 bean instances to have setEntityContext(...) called and to have an identity given to them (not necessarily have ejbLoad() called, but at least given a PK). Is this happening and you might not be realizing it?

    Tyler
  3. Hi Tyler!
    Thanks for your reply. Maybe we're discovering what's happening: we created an application that creates a big cache of data at startup and encode it in a Vector.
    The data is queried in this way: session bean----->entity bean findMethods. Maybe creating a cache with lots of recursive ejbFind is a mistake. Can it be that the EJB instance is cached somehow when I put ejbFind in a loop ?
    I think this must be the problem.....Maybe I have to issue single SELECT statements instead...
    what do you say to it?
    Francesco
  4. That cache is definitely your problem. All of those find methods are causing beans to be loaded into memory. Now, I think that 100 is too small for your cache-size, it should be much larger depending upon how much RAM that you have, but I have general concerns about making the cache during startup.

    A cache is only advantageous if your cache size is large enough to hold all of the objects AND you still have a cache size that is big enough to hold the leftovers. If you have the RAM and processing power to meet these criteria, then you can use a cache successfully. Otherwise, you will run into problems like the one you are seeing.

    Tyler
  5. Thank you again for your feedback.
    So that's it,find loads beans into memory! as a matter of fact I put some loggin info into ejbLoad() and it's true,
    even if there are some options in Weblogic5.1 to avoid unnecessary trips to ejbLoad.Anyway if I can beg for more feedback, when the bean instance is removed from memory...and maybe definetely removed from disk?
    Thanks a lot
    Francesco
  6. The entity beans are passivated to disk when <idle-timeout-seconds> are reached or ejbRemove() is called. I am not sure when they get removed from disk.
  7. Ummmm.... I don't think the behavior that Eric is describing is quite right.

    Entity EJBs are pooled and put into a Pooled state by an application server. Entity EJBs that are in the "pooled" state are similar to bare-naked EJBs (I'm calling them this because I have a particular interest in the band Bare Naked Ladies).

    These "naked" objects do not have an identity associated with them. They don't have a PK to call their own, but they DO have an EntityContext object. These "naked" objects can have a couple of activities that do not require an identity to be performed:

    ejbFind methods
    ejbSelect methods
    ejbHome methods

    These are all methods that are either part of the home interface or operate on all entity objects generically. In essence, they are all methods that are part of the generic factory, so a "naked" entity EJB object can perform this operation. Application servers can pool these objects together and allow any object to handle any request (just like stateless session beans).

    It is important to know that when a client calls ejbFindByPrimaryKey (or another finder method), the EJB does not transition from the "pooled" state to the "ready" state. This is confirmed in the EJB specification in section 9.6:
    "The instance does not move to the ready state during the execution of a finder or a home
    method."

    The container decides to given an object an identity when it needs to service a client invocation. This may take place immediately after an ejbFind method, but it doesn't have to. As part of this transition, the ejbActivate() method will be called. Even though the instance wasn't stored to the hard drive, this is STILL a form of activation. When EJBs are in the "naked" state, they are effectively passiviated -- they likely don't have any open connections to resources and their attributes aren't available to be accessed. So when a naked object becomes an object with identity, it goes through the activation process.

    Only then, after a naked object has been given its identity and gone through the activation process will ejbLoad() be called. The container can call ejbLoad() whenever it wants to, ensuring that the data in the bean and the data in the persistent store are synchronized. Different application server implement this differently depending upon the locking model selected, the type of behavior of the bean, etc.

    Now, if a client calls Home.remove(pk) or EJBObject.remove() then the instance will be destroyed in the database and moved back to the "naked" ready state. If the client never calls remove() (which it only does when it actually needs something destroyed), then the container can passivate the bean whenever it feels like it. Passivating an entity bean does not have its state written to the hard drive like session beans. Rather, passivation is the transition from the Ready state where an object has an identity to the pooled state where it is naked again. Also, ejbPassivate will be called.

    A container may decide to passivate an entity bean for a variety of reasons -- in WLS, the <idle-timeout-seconds> and <max-beans-in-cache> tags are used to determine when WLS should passivate beans. WLS will start to passivate entity beans when <max-beans-in-cache> is 85% full. WLS will only passivate entity beans that have exceeded their <idle-timeout-seconds> tag. If the <max-beans-in-cache> has been reached and there are no beans that qualify for the <idle-timeout-seconds> then you will see the exception that was generated in the post above.

    BEWARE: Stateful session beans in WLS use the same <max-beans-in-cache> and <idle-timeout-seconds> tag that is used in entity beans, but they have a very different behavior! <max-beans-in-cache> is used to determine how many stateful session instances can remain in memory concurrently (it, too, will start passivating at 85%), but the<idle-timeout-seconds> is used to indicate when a stateful session bean should be destroyed by the server, not passivation!!!

    Tyler
  8. Thanks so much for putting actual words to the somewhat cryptic Entity Bean state diagrams one sees in Monson-Haefel's EJB 1.1 book and the Professional WebLogic book from Wrox. Your description is the clearest by far I have read and I hope it gets incorporated into the book you are working on with Ed Roman (how soon will Wiley publish it? I can't wait). I made a mistake by saying entity EJB's are passivated to disk while in reality they are returned to the pool upon passivation which is still in memory, not persistent storage.

    Can you comment on my question about the <max-beans-in-cache> and the use of finder methods? Thanks.
  9. What question is that? I don't see any questions referring to those two topics here.

    Tyler
  10. Tyler:

    My question is essentially this: since you are practically limited by the number of <max-beans-in-cache>, if your findByXXX() method returns a Collection of bean instances greater than that number, you are in trouble. Is this understanding correct?

    Thanks again for your reply.
  11. Actually, you aren't in any trouble at all.

    When you invoke a find method that returns a large Collection, an application server vendor only returns a collection of Remote references that contain the primary key. The actual objects aren't activated and loaded until the client performs a request on a remote reference that requires the particular values of the bean to be loaded.

    So, if you call a find method and then immediately call a remote method on each of the references in the Collection, then you have something to consider. But, there are a variety of design patterns that can accommodate your concerns here. First, you are going to want your cache size for an entity EJB to be at least 1,000 for each entity EJB type that you have. Second, you are going to be hard pressed to identify a situation where a find method will return more than a 1,000 instances that you are going to work on immediately. If you are in a situation where you need to perform business logic on over 1000 instances of an EJB, I would want to analyze the situation that you are describing and see if there wasn't a better alternative.

    In my opinions, find methods are excellent implementations for requests that typically return less than 50 records, such as all of the requests here on TSS. Anything that goes over the 50 record mark can be paginated, optimized in the database, or architect differently.

    Tyler
  12. Let me know whether I am hearing you correctly --- if you anticipate to retrieve database records in excess of the EJB container's cache size, you really shouldn't do it in a finder method. Use JDBC to return a Vector of detail objects instead. Is this true?