Seppuku pattern

Discussions

J2EE patterns: Seppuku pattern

  1. Seppuku pattern (22 messages)

    This example illustrates how ReadOnly entity beans and JMS can be used to implement non-transactional distributed cache in 5.1 or 6.0 - WebLogic 6.1 has this feature. It is based on the fact that it is Container's responsibility to discard bean instance if a non-application exception is thrown by its business method - [17.3.1]. The second assumption made here is that there is only one bean instance per PK in the single instance of WebLogic Server if the bean concurrency strategy is ReadOnly.

    While the example works on WebLogic, this approach is fairly portable - the only assumption is that the container supports read-only entity beans.

    This example uses ReadOnly Entity Bean with read-timeout-seconds set to 0, meaning that WebLogic Server will call ejbLoad() only when bean is brought into the cache.

    The updates (invalidations) are published on the JMS topic (for an actual implementation multicast can be used, for example - JavaGroups, or 6.0 JMS using multicast) and the MDB in its onMessage method invokes invalidate() method on the ReadOnly bean instance, which commits suicide by throwing a SeppukuException.

    WebLogic 6.1 adds enchancements to read-only entity beans, which do this automatically: all RO entity home interfaces implement weblogic.ejb.CachingHome interface:


    public interface weblogic.ejb.CachingHome extends javax.ejb.EJBHome
    {
        public abstract void invalidate(java.lang.Object) throws java.rmi.RemoteException;
        public abstract void invalidate(java.util.Collection) throws java.rmi.RemoteException;
        public abstract void invalidateAll() throws java.rmi.RemoteException;
        public abstract void invalidateAllLocalServer() throws java.rmi.RemoteException;
        public abstract void invalidateLocalServer(java.lang.Object) throws java.rmi.RemoteException;
        public abstract void invalidateLocalServer(java.util.Collection) throws java.rmi.RemoteException;
    }


    which invalidate() methods to invalidate individual beans or collections locally and in the cluster. In the read-mostly pattern read-write entity bean can invalidate it's read-only counterpart automatically (<invalidation-target> tag in the weblogic-ejb-jar.xml). Here is modified readMostly example which uses this functionality:readMostlyImproved.
    The example is based on the readMostly example and consists of 4 EJBs:

    StockBean
            ReadOnly bean with an additional invalidate() business method
            which simply throws an exception forcing the container to remove
            bean's instance.

    StockWriterBean
            regular read-write Entity Bean.

    StockUpdateBean
            Message Driven Bean, which, in its onMessage() method
            invalidates the read-only bean instance by calling invalidate()
            method

    UpdateBean
            Stateless Session Bean, which has increaseStockValue(String symbol)
            uncreases stock value by 1 (using StockWriterBean) and publishes text
            JMS message containing the symbol name to invalidate.

    Client starts separate 'reader' thread which displays "BEAS" stock information and, on it's main thread updates "BEAS" periodically using UpdateBean.increaseStockValue() method.

    Building the example (Windows): similar to WebLogic examples

    1. run C:/bea/wlserver6.0/config/examples/setExamplesEnv.cmd script to set the examples
       environment.

    2. build.cmd is similar to the build scripts supplied with WebLogic examples with an
       additional step of generation of Home and Remote interfaces and deployment descriptors
       using EJBGen tool by Cedric Beust (http://www.beust.com/cedric/ejbgen)

    Configuration:

       This example uses examples server configuration. The only change required is:
       increase number of connections for the "demoPool".
       The JMS topic used is: weblogic.examples.jms.exampleTopic

    Running the example:

      same as standard Weblogic ejb examples. Client class name is
      examples.readonlycache.Client

    The Client produces the following output: (reader obtains "BEAS" quote every 500ms using ReadOnly StockBean and writer increases "BEAS" value every 1500ms)

    C:\cacheexample>java examples.cacheexample.Client

    Beginning cacheexample.Client...

    Creating a StockWriter for BEAS
    Starting reader thread
    Symbol:BEAS price:111.0 volume:1011
    writer increased stock price
    Symbol:BEAS price:101.0 volume:1001
    Symbol:BEAS price:101.0 volume:1001
    Symbol:BEAS price:101.0 volume:1001
    writer increased stock price
    Symbol:BEAS price:102.0 volume:1002
    Symbol:BEAS price:102.0 volume:1002
    Symbol:BEAS price:102.0 volume:1002
    writer increased stock price
    Symbol:BEAS price:103.0 volume:1003
    Symbol:BEAS price:103.0 volume:1003
    Symbol:BEAS price:103.0 volume:1003
    writer increased stock price
    Symbol:BEAS price:104.0 volume:1004
    Symbol:BEAS price:104.0 volume:1004
    Symbol:BEAS price:104.0 volume:1004
    Symbol:BEAS price:104.0 volume:1004
    writer increased stock price
    Symbol:BEAS price:105.0 volume:1005
    Symbol:BEAS price:105.0 volume:1005
    Symbol:BEAS price:105.0 volume:1005
    writer increased stock price
    Symbol:BEAS price:106.0 volume:1006
    Symbol:BEAS price:106.0 volume:1006
    Symbol:BEAS price:106.0 volume:1006
    writer increased stock price
    Symbol:BEAS price:107.0 volume:1007
    Symbol:BEAS price:107.0 volume:1007
    Symbol:BEAS price:107.0 volume:1007
    writer increased stock price
    Symbol:BEAS price:108.0 volume:1008
    Symbol:BEAS price:108.0 volume:1008
    Symbol:BEAS price:108.0 volume:1008
    writer increased stock price
    Symbol:BEAS price:109.0 volume:1009
    Symbol:BEAS price:109.0 volume:1009
    Symbol:BEAS price:109.0 volume:1009
    writer increased stock price
    Symbol:BEAS price:110.0 volume:1010
    Symbol:BEAS price:110.0 volume:1010
    Symbol:BEAS price:110.0 volume:1010
    Stopping reader
    Removing the BEAS

    End cacheexample.Client...

    Credits
    To Cedric Beust for naming the pattern

    Threaded Messages (22)

  2. Seppuku pattern[ Go to top ]

    Finally here!
    This a very good pattern!
    (and the humour side Seppuku is the best pattern name ever seen)
    I cross post a remark I made on ACE (a bit late):
    My concerns:
     - work in any container that supports read-only entity beans (and no more)
     - hard believer of Tyler's true power of entity bean : readMostly entities is a matter of fact and jdbc sucks.
     - (!!) synchronized invalidation of read-only beans when a read-write bean change the data

    In other words,
     - I want to talk to the read-only bean after the transaction of the update is finished so that I am sure the db has been touched and that my read-only bean will see the latest data when they will be hitted and refreshed.
     - I don't want the session bean facade being responsible of refreshing the read-only beans but the entity himself, it makes more sense as he is aware of when he updates the database.
     - I don't want to use JMS or any messaging/asynchronous feature but want to make a direct/synchronous call. I do not want the situation where a client will update the data (in one Tx) then read the data (with no Tx or in another Tx) and still see the old one because JMS was not quick enough.

    Proposal:
    In all setter method of the entity bean (just after the line "dirty = true;" ;-) ) I create(),init() a stateful session bean and give him the home of the read-only entity bean and the pk.
    This stateful session bean implements javax.ejb.SessionSynchronization.
    In its afterCompletion() method, it calls the read-only beans fbpk() and invalidate() method. It also throws a RuntimeException to seppuku himself.
    Because afterCompletion() is called after the Tx has complete, the database has been updated (and changes can be seen by others), so the first coming to the read only bean will refresh its data with the updated data.

    I know this is a bit cumbersome and would ideally be handled by the container himself but using a good template engine, namely xdoclet (free publicity) it is could be easy to implement.

    Thanks.
  3. Seppuku pattern[ Go to top ]

    This a very good pattern!


    Thanks ;-) It's more than a year old, and, according to emails I receive it works (because it is so simple).

    >Seppuku is the best pattern name ever seen

    Cedric Beust from BEA deserves all the credit for the name ;-)

    >work in any container that supports read-only entity beans (and no more)

    That is pretty much the only assumption made (plus, it assumes that there is only one bean instance per PK, which is logical when caching is involved)

    >(!!) synchronized invalidation of read-only beans when a read-write bean change the data

    That means transactional cache, which is VERY, VERY hard to implement, especially without affecting performance/scalability much. Rumours are that the next major WebLogic release will do this (WebLogic 6.1 implements invalidation mechanism similar to Seppuku).

    Perhaps Tangosol Coherence cache is the solution. Cameron, any comments?
  4. Seppuku pattern[ Go to top ]

    (!!) synchronized invalidation of read-only beans when a

    >> read-write bean change the data

    > That means transactional cache

    Not necesseraly, the problem (maybe you can correct a misunderstanding) I see in seppuku is that the invalidation can be done before the transaction commit and so before the database was updated. If in between these 2 moment a client come and get the entity, it will refresh from old data. And the invalidation did not serve anything.
    Am I missing a point here ?
  5. Seppuku pattern[ Go to top ]

    Right. I simply used RequiresNew on a read-write entity bean method which does update.
  6. Seppuku pattern[ Go to top ]

    OK, I didn't pay attention to transaction attribute, it makes more sense now.
    This SessionSynchronization trick I proposed in fact comes from Gal on tha ACE pattern but in the other sense.
    Not Statefull SB wrapping entity bean but entity bean telling a linked (through EntityContext) a SFSB when he updates data.
    I am wondering if Gal is around and could comment on that...
  7. Seppuku pattern[ Go to top ]

    I think Seppuku (and read-mostly caches in general) is a great pattern, and I had allready commented on that in the ACE thread. I'd like to address one specific transaction-related issue that we discussed in ACE and seems to have come up in this thread as well.
    The problem is, how do we make sure data is refreshed only after the transaction writing it has commited. A simple solution used in the implementation Dimitri had published is to simply update the data in a sperate transaction, which means the data will have to be commited before invalidation takes place. Please correct me if I'm wrong.
    I think that this is a good common-case solution (which is what makes Seppuku so attractive in general), but it is too restrictive for a general-purpose pattern. By enforcing every single update to go through a seperate transaction, you loose a great deal of EJB's power. Even a basic task like updating two seperate beans as a single unit becomes impossible. If you want to allow the bean update to go in the same transaction as other operations, you must use a more complex approach. I described one possible strategy in the ACE thread.
    I also think it's worth mentioning that (to my understanding), in ACE all the cache-realted code went in the entity bean (well, I mean the client could just use the entity bean). I think this is a better approach than the one used in this impl, since I conisder the details of how you manage your cache to be an entity bean implementation detail. This slightly complicates the code, but I do think it's worth it (especially if you're gonna take the more general transaction approach).
    BTW - if you're planning to use the SessionSynchronization trick I suggest you read the ACE thread as well. There are some pitfalls to look out for.

    Gal
  8. Seppuku pattern[ Go to top ]

    Gal, this is a very good point. Like you mentioned in ACE thread, it is possible to do this if Transaction (and not UserTransaction) is accessible, but that is definitely not portable.

    In general, Seppuku simply illustrates how to do invalidations - I was pretty happy with read-only beans and read-mostly pattern in general, but the invalidation part was missing (until WebLogic 6.1 which implements seppuku automagically). So, the idea was to let the container to do it's caching thing and to add invalidation machanism which is simple and trivial to implement.
  9. Seppuku pattern[ Go to top ]

    Gal : A lot of pitfalls to implement completely the invalidation of cache after Transaction complete...
    Dimitri : Let the container do the invalidation, it's is simple and trivial to implement

    I will remember these 2 things, it makes more sense now, thank you very much for the patterns and discussion.

    One final note, I find recently in EJB spec 2.0 that read-only entity beans is in the list of future enhancements to the spec. Surely Seppuku and ACE will then become (more) widely adopted.
  10. Seppuku pattern[ Go to top ]

    Dimitri,
    You are right about the invalidation thing. I implemented the read-mostly cache using JDO rather than EJB, and I didn't notice that the ACE pattern didn't describe how to do invalidation (cause I was thinking in JDO terms). Throwing a system exception is not only a neat trick, it's also the only portable way to do invalidation that I can think of. Thats not surprising, since invalidation makes sense for read-only beans - which are not supported by the current spec.
    I have one more note about your single-instance assumption. The container may not need more than one instance due to multiple transactions, but it may require it for performance reasons. Entity bean instances are allways single-threaded. EJB vendors won't violate that requirement (and if they did you would have problems when invalidating an instance while it's serving requests). So if you have an EJB in your system that is used by many requests, it will become a single-thread barrier. No matter how many CPUs you add, the App server will have to process all requests serially. Even if the entity bean code is real small, just the context switches on it can be very expensive. In such a case, it's not only possible that the App server would create more than one instance - it's necessary.
    This kinds of problems can easily slip through the testing procedures if they're not massive enogth - pattern users be warned :)

    Regards
    Gal
  11. Seppuku pattern[ Go to top ]

    Gal,
    Your warnings are really important. And as somebody pointed in ACE pattern, the difficulty inherent to understand and correctly implement this pattern because you must know how a container is playing internally with entity bean instances (single/multiple - thread - locking) makes this pattern more a pattern for ejb container vendor that for ejb developers.
    In JBoss list recently somebody proposed to have a JMX MBean responsible to invalidate the (possibly) multi instance cache of entity bean (I guess by giving the JNDIName of the entity and the parameter(s) composing its primary key). With that in the hand of the developer, the single instance hypothese of this pattern can be forgotten.
  12. Seppuku pattern[ Go to top ]

    Vincent,
    I agree that handling the invalidation of beans, and any type of cache in general, is better placed in the hands of the App server. A vendor specific invalidation interface is useful in practice, but massive use of such interfaces (in the form of a widely adopted pattern) will break the portabillity of the EJB codebase, and make it very hard to reuse components. I think the EJB specification should quickly address these issues to prevent that, but in the mean-while I prefer not to use vendor specific interfaces (such as WebLogic's cache interface).
    I'm not sure an invalidation interface will ever have it's place in the EJB spec. It is too strongly connected to the persistent management specific to the App server, IMHO. I hope the EJB spec will address read-only transactions/beans, along with their invalidation, in a way that is transparent to the developer (such as allowing both read-only and normal transactions on the same bean, and invalidating when a normal transaction commits).

    Gal
  13. J2EE and Caching[ Go to top ]

    Hi Gal (and Dimitri and all),

    I guess it is high time I chimed in on this thread.

    Gal, thanks for directing attention to our discussion of the perils of asynchronous invalidation that we had in the ACE thread. Saves a lot of re-typing!

    I think that this read-mostly access pattern is so important to J2EE that one might think that it needs to be in the spec. However, I think this really falls under "caching capability of the J2EE app server vendor". After all, "read-mostly" is vague, and basically implies "cache it if you can" so to speak.

    I totally agree that invalidation (or expiration in the ACE-speak) is under the hood. The only reason that people like Gal, Dimitri and me had to think of ways to deal with it is because app-servers caches were not yet that advanced. Now the vendors are catching up, and what was a design pattern can fade away into something that inspired better implementation, or a new product, like Tangosol's products.

    A word on Tangosol's caches, or a similar product: I have heard great things about Coherence, and it accomplishes exactly what I wanted to accomplish with ACE. However, one reason for ACE was dissatisfaction with existing Entity Bean performance (i.e. caching). The best of both worlds is a app-server EB implementation that has high-performance caching. And this too must be done "under the hood" since the container has no interface to control how it caches.

    In essence, since there is no interface in the spec to improve a vendor's caching of EBs, the problems are coupled. So while I am very excited about Tangosol, I'd be even more excited if, say, BEA bought or wrote such a product and tightly integrated it into their EB architecture. Of course, there would still be a big place for a pure caching product, but for value objects, not entity beans.

    Lawrence






  14. J2EE and Caching[ Go to top ]

    Hi Lawrence (et al),

    Lawrence: "one reason for ACE was dissatisfaction with existing Entity Bean performance (i.e. caching). The best of both worlds is a app-server EB implementation that has high-performance caching. And this too must be done "under the hood" since the container has no interface to control how it caches."

    We are currently looking for pilot customers for our transactional Entity EJB cache (Coherence 1.2). It _does_ work "under the hood" (via JCA/JTA and our EnGarde! pattern-based customization technology) with the application server's CMP engine to coherently and transactionally cache CMP Entity EJBs in a cluster, providing close to zero-latency access to CMP data -- even for read/write beans.

    We plan to introduce the product to pilot customers on 28 January 2002, so if you are interested, please drop me an email at cpurdy at tangosol dot com.

    Peace,

    Cameron Purdy
    Tangosol, Inc.
  15. Seppuku pattern[ Go to top ]

    Dimitri: "That means transactional cache, which is VERY, VERY hard to implement.... Perhaps Tangosol Coherence cache is the solution. Cameron, any comments?"

    Yes, our upcoming Constellation product (based on TCMP, just like Coherence) will provide a distributed and/or replicated transactional cache, with support for 2PC, configurable isolation levels, optimistic (like Oracle serializable) v. pessimistic (like Sybase locking) transaction control and of course will support automatic failover -- even <b>within</b> a transaction!

    We use an algorithm that allows the distributed database or cache to be dynamically load-balanced without any particular additional cost associated with cluster membership changes (i.e. machine dies, new server added, etc.). We also have the cost of transactional distribution down under 2ms per update, which is basically as low now as Coherence provides with coherent cluster updates!

    Peace,

    Cameron Purdy
    Tangosol, Inc.
  16. jar???[ Go to top ]

    Hi!

    Where could I find this jar file?

    This domain name does not exist:
    http://dima.dhs.org/misc/readMostlyImproved.jar

    Thanks in advance,
    Zoltán
  17. Seppuku pattern[ Go to top ]

    It's about time Dimitri! You should also post a couple of your other cool patterns here; quit hording them all for yourself and share the wealth! The beauty of putting stuff on TSS is you get traffic. Few people know of dima.dhs.org, aside from me, Cameron and Cedric! :-)

    Your DynamicProxy for InitialContext/EJBHome/EJBObject is another good candidate. And the asynchronous servlet/jsp engine that I proposed and you prototyped is also worthy of note!

    Gene
  18. EJB spec change needed ?[ Go to top ]


    Surely this highlights a major underlying deficiency in the ejb spec ?.

    If entity beans had explicit read-only non serialised methods then the container could effeciently do "read mostly" itself. It could even maintain r/w and r/o copies of the bean independently - just as this pattern does by hand. Prehaps this is turning out to be EJBs most significant deficiency compared with more mature OODB/RDBMS systems.

    The more you think about it, the more laughable it is that we have a persistence mechanism isnt optimised for "read mostly" - that cannot in effect distinguish between read-for-update and a non updating read on the same data.

    Do we really want to saddle ourselves with having to duplicate every object manually and do manual cache dirtying for every app we design just to get passable performance - the .NET folks are going to be laughing at us.

    Paul Campbell

  19. EJB spec change needed ?[ Go to top ]

    Paul,

    I totally agree with your comments on the need for this kind of smarter persistence and that the container needs to provide this kind of cache management for you. But I am not so sure if "read-mostly" needs to be in the spec or not. I just consider this a case of highly optimized (and cached) read-write beans. See my post above.

    What I further envision and hope for is a container that can, at runtime, tune caching parameters to optimize the caching of various EBs. For example, it might allow more cached instances of a certain kind of EB, reduce cluster network traffic by using timed expiry in certain cases, etc.

    - Lawrence
  20. Seppuku pattern[ Go to top ]

    Dmitry,

    I have a couple of questions.

    1. Seppuku pattern (or WLS 6.1 read-mostly pattern) works fine for simple CMP EJBs. Now, I need cluster-aware cache with multicast invalidation for more complex persistent structures. E.g. I want to cache a tree and invalidate it whenever a link is added or removed. Tree node and link could well be CMP entities, but the "tree" itself logically maps to BMP entity. Do WebLogic read-only or read-mostly EJB work with BMP? Could I use WebLogic multicast invalidation for this? (I did not find any references in WebLogic documentation. I know though that I could not use <invalidation-target> with BMP).

    2. In Seppuku pattern you use message-driven bean to receive invalidation notifications. My understanding was that if WebLogic cluster gets JMS topic notification, only one instance of MDB will be created on one of the nodes to process the message. Thus, only cache on that node will be invalidated. I've assumed that one needs to use raw JMS with listener on each node in the cluster to support multicast invalidation. What am I missing? Is MDB instance created on each node in cluster? The jar on your site does not have deployment descriptors.

    Thank you,

    Joseph Sheinis
  21. Seppuku pattern[ Go to top ]

    Hi Joseph,

    It doesn't matter at all if the bean is CMP or BMP (unless you use WebLogic 6.1 automatic invalidation, which, as far as I know works only with CMP beans - if you use BMP, you can invalidate manually, using weblogic.ejb.CachingHome interface). Just make sure that you call CachingHome.invalidate() after update transaction commits.

    And yes, since invalidation messages need to be processed on each cluster node, MDB beans need to be deployed on each cluster node. JMS over multicast can be used to broadcast invalidation messages - since 5.1 didn't have this option, I simply used JavaGroups. There are no deployment descriptors in the example, because they are automagically generated by EJBGen.

    --
    Dimitri
  22. Seppuku pattern[ Go to top ]

    The updates (invalidations) are published on the JMS topic (for an actual implementation multicast can be used, for example - JavaGroups, or 6.0 JMS using multicast) and the MDB in its onMessage method invokes invalidate() method on the ReadOnly bean instance, which commits suicide by throwing a SeppukuException.

    >

    Hi, I have a little question about this pattern. Is it posible to implement the updates not using a JMS topic but a JMS queue? We're using JBoss as our application service...

    Thanks a lot

    Johannes
  23. Seppuku pattern[ Go to top ]

    Why can't you use topics? Which version of JBoss?

    Peace,

    Cameron Purdy
    Tangosol, Inc.
    Coherence: Easily share live data across a cluster!