1 2 3 4 Previous Next 50 Replies Latest reply on Aug 29, 2006 7:54 AM by Manik Surtani

    Designing Habanero - Cache and Node interfaces and JSR-107

    Manik Surtani Master

      This discussion is linked to http://jira.jboss.com/jira/browse/JBCACHE-57.

      The plan for JBoss Cache 2.0.0 (Habanero) is

      1) to access cche instances using a CacheFactory
      2) CacheFactory would return an instance of a new interface - org.jboss.cache.Cache - which TreeCache will implement.
      3) An additional CacheSPI interface (which extends Cache) will be provided if client access requires further non-public API functionality for writing custom interceptors, etc.

      In addition, all references to nodes passed back by Cache will be Node interfaces (implemented by TreeNode) and similarly, there will be a NodeSPI sub-interface.

      The purpose of this thread is to discuss what should and should not be in these interfaces.

        • 1. Re: Designing Habanero - Cache and Node interfaces and JSR-1
          Ben Wang Master

          Manik, do you have a draft list of public CACHE API and SPI already? Maybe you can throw it out and then we can see if there are other things that are desirable.

          • 2. Re: Designing Habanero - Cache and Node interfaces and JSR-1
            Manik Surtani Master

            I don't have one yet - let me put one together and post it here so we can refine it.

            • 3. Re: Designing Habanero - Cache and Node interfaces and JSR-1
              Galder Zamarreño Master

              Btw, I just came accross with JSR 107, :-$ and from what I can see, there has not been any acitivity since 2001. Does anyone know what is happening with it?

              • 4. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                Manik Surtani Master

                Yeah, JSR-107 is pretty dormant at the moment. Just trying to get as close to a standard as possible.

                • 5. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                  Elias Ross Master

                  This seems to have been updated as recently as 2005. It doesn't seem to be complete.

                  https://jsr-107-interest.dev.java.net/

                  How many other companies have built to the JSR-107 standard?

                  It seems like a fine standard, but I wonder if users could be served better by simply keeping a slimmed down TreeCache API and creating the necessary adaptors if a user wants to use the standard.

                  The reason I suggest not necessarily adapting the JSR-107 standard is that TreeCache is a Tree and Cache is a Map, although what you could possibly do is have a Fqn + Key be your key.

                  • 6. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                    Manik Surtani Master

                    I've got a preliminary set of interfaces available. Pls have a look at http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheHabanero, which is the landing page for this new design. There are links to sample javadocs of the interfaces I have put together.

                    I'll put up UML diagrams there very shortly too.

                    Feedback appreciated, especially around the SPI interfaces which are a bit sparse at the moment.

                    • 7. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                      Ben Wang Master

                      I have some comments here. Maybe I will split them up into api and spis so it is easier to discuss.

                      Cache API:

                      1. From the Cache interface, it looks like getRootNode() is the starting place. So does that mean, a user need to do something like this often?

                      cache.getRootNode().getChild(fqn).get(key)?

                      Of course, I can potentially get a Node first. But if my operation is random or jumping around, keeping the Node references can be tedious.

                      So would it be better to a have wrapper in the Cache interface to do just:

                      cache.get(fqn, key)

                      as in the old way? We will just need put, get, and remove, IMO.

                      2. What exactly is the factory lifecycle method now? Create, start, stop, and destroy as well?

                      3. How do we instantiate the cache in a MBeanSerice under JBoss? Can you give an example?


                      Node API:

                      1. createIfNoteExist. It looks like we need to do addChild first to create a new node, is it correct?

                      2. What about put, get, and remove() with Option? Are we still providing them?

                      3. Do we still need evict api exposed?

                      4. exists() for Node api?

                      5. remoeData for Node api or this is clearData?

                      6. Will node.getData() go through any interceptor? Triggering any event? Is it modifiable?

                      7. What about node.move()? Will it have any event notification?

                      8. Finally, what about managemenet attribute? What are we going to provide? The same as before as a MBeanService?

                      • 8. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                        Ben Wang Master

                        This is the part for SPI comments and questions.

                        Cache SPI:

                        1. Do you have a use case for getTransactionTable? Just curious.

                        2. Is getInterceptorChain returning a List that is modifiable such that we can customize it?

                        3. What about setInterceptorChain api?

                        4. Return config element for different interceptors? Say, I need to provide extra behavior for eviction interceptor? How do I do that?

                        5. What about marshalling and activateRegion? I think they need to be in SPI so user can customize them. Also state transfer, I think.

                        6. Can we have a getCurrentTransaction() api?


                        Node SPI:
                        1. What about the lock type? Optimistic or pessimistic? Can we have a method to expose it?

                        2. Can we have an option to do "get" without going thru the Loader? I just want to retrieve the in-memory value. If it is null, I don't care.

                        • 9. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                          Manik Surtani Master

                          Note from Bela:

                          Did the putIfAbsent() method fall through the cracks ? :-)

                          Will look into adding this soon.

                          • 10. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                            Manik Surtani Master

                             

                            "ben.wang@jboss.com" wrote:

                            Cache API:

                            1. From the Cache interface, it looks like getRootNode() is the starting place. So does that mean, a user need to do something like this often?

                            cache.getRootNode().getChild(fqn).get(key)?

                            Of course, I can potentially get a Node first. But if my operation is random or jumping around, keeping the Node references can be tedious.

                            So would it be better to a have wrapper in the Cache interface to do just:

                            cache.get(fqn, key)

                            as in the old way? We will just need put, get, and remove, IMO.


                            This is just a convenience method. Cache will be the root Node anyway, only accessed via the Cache interface. This method will allow you to get a reference to the root node as a Node. May be unnecessary, if we feel it is, I'll remove this meth.

                            You would simply do cache.getChild(fqn).get(key).

                            Do we feel we want to provide the older, flatter API of cache.get(fqn, key) as well?


                            "ben.wang@jboss.com" wrote:

                            2. What about put, get, and remove() with Option? Are we still providing them?


                            Yes, except that you register the Option with the InvocationContext before making your invocation.

                            E.g., InvocationContext.getCurrentContext().setOption( myOption );

                            "ben.wang@jboss.com" wrote:

                            4. exists() for Node api?


                            I presume this is will apply to the data map? Ok.

                            "ben.wang@jboss.com" wrote:

                            5. remoeData for Node api or this is clearData?


                            Yes


                            Sorry, these are only a few quick answers. More from me on this later.


                            • 11. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                              Elias Ross Master

                              CacheListener ... lots of methods for an interface.

                              I suggest creating an Event, and/or CacheEvent + NodeEvent, so you have

                              interface CacheListener {
                               void event(NodeEvent e);
                               void event(CacheEvent e);
                              }
                              


                              CacheFactory ... the stop and start methods seem like they should belong on the Cache itself, sort of OOP standard practice. createCache() -- why the two methods, one with the "start" boolean? Why only String for the configuration? I would probably make CacheFactory an abstract base class and a static method with the signature "CacheFactory getFactory()". This will allow you to add more methods later on to do with configuration details. I would create a Configuration class, e.g. you could do this:

                              Cache c = CacheFactory.getFactory().create(new Configuration(new URL("...")));
                              c.start();
                              


                              You could also put the Configuration in the Cache itself. (I don't like SPI as a TLA myself, ugly name...) I would also have the Configuration as an abstract base class for flexibility in expansion for additional features.

                              Here's my suggestion:
                              interface Cache {
                               Node getNode(Fqn n);
                               Node getRoot();
                               List<CacheListener> getCacheListeners();
                               void start();
                               void stop();
                               Configuration getConfiguration();
                              }
                              


                              Node... One thing I hate are methods, one with Object the other with some other type, in thi s case Fqn. And there's the problem again with too many interface methods that do about the same thing. The java.util.Map interface provides all the various mutators you need, so why implement them again?

                              interface Node {
                               Map<Object key, Object value> getData();
                               Fqn getFqn();
                               Map<Object name, Node n> getChildren();
                               Node createChild(Fqn name); // factory method
                               // SPI etc.
                              }
                              


                              I'm not sure about the relative operation frequency. Methods such as "getParent()" seem a little too infrequent to be part of an interface, but this admittedly is a bit verbose:
                               cache.getNode(n.getFqn().getParent());
                              


                              Still, it isn't bad to do these sorts of common operations.
                               node.getData().remove("key1");
                               node.getChildren().get("child1").getData().clear();
                              

                              .

                              As a suggestion, you might want to go with java.util.concurrent.ConcurrentMap for your Map interfaces as well, to pick up some of those extra transaction methods.


                              • 12. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                                Brian Stansberry Master

                                 

                                "manik.surtani@jboss.com" wrote:

                                Do we feel we want to provide the older, flatter API of cache.get(fqn, key) as well?


                                I'd say yes, or something like it. Compare the code required for a simple get:

                                Now:

                                Object value = cache.get(fqn, key);


                                Proposed:

                                Object value = null;
                                Node node = cache.getChild(fqn);
                                if (node != null) {
                                 value = node.get(key);
                                }


                                • 13. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                                  Bela Ban Master

                                  -1 on Event: I don't like this 'de-typing'. And if we have a CacheListenerAdapter, which is a class implementing all methods as no-ops, you could simply derive your listener from it, and don't have a lot of work

                                  • 14. Re: Designing Habanero - Cache and Node interfaces and JSR-1
                                    Brian Stansberry Master

                                    Ben asked earlier about exposing the evict() method. We need that for HttpSession repl, where we call evict(Fqn) to passivate a session. The session passivation semantics work better if we control the eviction rather than using an eviction policy.

                                    Actually, an evictSubtree(Fqn) would be even better, as we need to evict all nodes that comprise the session.

                                    The session repl layer also needs access to the marshalling-related API. I don't see that as being part of the SPI; it's meant for use by normal application code. So, for that, in the Node interface:

                                    void registerClassLoader(Object name, ClassLoader cl) throws RegionNameConflictException;
                                    void unregisterClassLoader(Object name) throws RegionNotFoundException;
                                    void activateRegion(Object name) throws RegionNotEmptyException, RegionNameConflictException, CacheException;
                                    void inactivateRegion(Object name) throws RegionNameConflictException, CacheException;


                                    We also need an equivalent to getUseRegionBasedMarshalling(), as that tells us whether we need to marshall objects to a byte[] before putting them in the cache. I'll try and run some speed tests today to see if not using marshalling results in any performance gains; if not for 5.0.x we can just require useRegionBasedMarshalling=true and the session repl layer will not need to check.

                                    1 2 3 4 Previous Next