Thanks much for this, Bill. Sorry for the slow reply. I'm going to
wait and let Manik Surtani comment on this, as I know he's thought a lot
more than I have about how he wants the factories and the CacheImpl
constructor to work.
Bill Middleton wrote:
Thanks for the encouraging reply, Brian. My followup is inline, and
there's a proposed patch at the end.
Bill
On 4/6/07, *Brian Stansberry* < brian.stansberry(a)redhat.com
<mailto:brian.stansberry@redhat.com>> wrote:
Bill Middleton wrote:
> A cursory (and likely naive) inspection of DefaultCacheFactory and
> CacheImpl seems to indicate that providing my own channel should be
> fairly easy to implement, even if an extension won't quite get
the job
> done, since channel is private. The intimidating part is the binding
> between the "official" multiplexed channel (mbean) and other
> functionality which implies a full app-server, such as the
> TransactionManager.
Not sure what you mean here by "binding". Passing a JChannelFactoryMBean
to the RuntimeConfig doesn't carry with it a requirement to pass in a
TransactionManager. Think of RuntimeConfig as basically being a
placeholder through which the external environment can pass in complex
objects the cache may need and through which callers can get access to a
few of the cache internals.
Every test I run does insist upon looking for a TransactionManager, if
one isn't found then a DummyTransactionManager is the "fall back"
solution. Granted though, it's not bound to an app server.
> If I were to pass in a channel to CacheImpl,
> whether multiplexed or not, I don't think I'll mess with
> setUsingMultiplexer() and friends in the Configuration. Since I'm
going
> to manage the muliplexer functionality myself I guess it makes
sense to
> let Cache think that it's just a simple channel. This seems safe
> enough, I hope.
>
Sure, as long as in reality it's a multiplexed channel, so the cache
doesn't get messages it won't understand. If you're writing your own
extensions, then presumably you know how the code will be used and can
guard against misuse. So, the barrier for what's considered "safe" can
be a lot lower. :)
My proposed patch doesn't require a multiplexed channel be passed in.
The implementation can pass in either an ordinary JChannel (via new
JChannel()) or one that's created via createMultiplexerChannel(). All
of the state transfer tests pass in either case. In neither case is the
Configuration set using setUsingMultiplexer(true). isUsingMultiplexer is
always false. Seems to work ok - all tests pass using an adapted
StateTransferCompatibilityTest.java, anyhow.
Generally, my patch adds a new constructor, CacheImpl(Channel c). This
is called by a new createChannel() method in the DefaultChannelFactory
which accepts a channel, configuration, and boolean. If the new
constructor is used to construct a ChannelImpl, then a global boolean is
set which makes the create() method do the right thing at init-time.
Is this approach way too simple minded? It's not providing any
additional access to the internals of the cache per se, but yes, one
must be careful in configuring the channel. Whats still missing here is
the ability to fetch the entire Element <protocol_stacks> from the
Configuration and pass it directly to the JChannelFactory(Element)
constructor, so that the external JGroups stack would be guaranteed to
match the one which is specified in the config.
Bill
PS - sorry about the indentation in the patch, Eclipse cant quite
figure out the scheme that jbosscache is using.
------------------------------------------------------------------------
? patch
Index: CacheFactory.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/CacheFactory.java,v
retrieving revision 1.7
diff -r1.7 CacheFactory.java
11a12
> import org.jgroups.Channel;
111a113,131
> /**
> * Creates {@link Cache} instance, by passing in a pre-configured {@link
org.jgroups.JChannel}
> * and optionally starts it based on the boolean start value. The new cache's
configuration
> * will be based on a {@link org.jboss.cache.config.Configuration} passed in.
> * <p/>
> * Ensure that the Configuration you pass in is not used by another cache instance
in the same JVM,
> * as it may be concurrently modified. Clone the configuration, if shared, using
> * {@link org.jboss.cache.config.Configuration#clone()}.
> *
> * @param configuration the {@link org.jgroups.JChannel} to use (cast to simple
channel).
> * @param configuration the {@link Configuration} object that is passed in to
setCache the {@link Cache}.
> * @param start if true, the cache is started before returning.
> * @return an optionally running {@link Cache} instance
> * @throws org.jboss.cache.config.ConfigurationException
> * if there are problems with the configuration
> */
> Cache<K, V> createCache(Channel ch, Configuration configuration, boolean
start) throws ConfigurationException;
>
Index: CacheImpl.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/CacheImpl.java,v
retrieving revision 1.57
diff -r1.57 CacheImpl.java
238c238,245
<
---
>
> /**
> * Have we gotten a channel passed in from the
> * implementation? We set this to false in the
> * constructor if so. Ordinarily isMyChannel is always true.
> */
> private boolean isMyChannel = true;
>
260a268,282
> /**
> * Constructs an uninitialized CacheImpl with a provided channel
> */
> protected CacheImpl(Channel ch) throws Exception
> {
> isMyChannel = false;
> if(ch instanceof JChannel){
> channel = (JChannel)ch;
> }
> else{
> throw new Exception("Not a JChannel!");
> }
> notifier = new Notifier(this);
> regionManager = new RegionManager(this);
> }
643c665,669
< if (channel != null)
---
> // We have to test both the channel and disp here, in
> // case we've passed in our own channel. The dispatcher
> // must be created in either case.
> if ((channel != null) && (disp != null))
649,653c675,686
< // Try to create a multiplexer channel
< channel = getMultiplexerChannel();
<
< if (channel != null)
< {
---
> // Try to create a multiplexer channel if we didnt get a channel passed
in
> if(isMyChannel){
> channel = getMultiplexerChannel();
> }
>
> if ((channel != null) && isMyChannel)
> {
>
> // Success creating the multiplexer channel.
> // Now we have to let the config know about our joy.
> // Note that we never do this if we've passed in a channel,
> // even if that channel is multiplexed.
676,680c709,712
< try
< {
< channel = new JChannel(configuration.getClusterConfig());
< }
< catch (Exception e)
---
>
> // If we've not passed in a channel
> // we need to create a non-multiplexed one now
> if (isMyChannel)
682,683c714,720
< throw new CacheException("Unable to create JGroups
channel", e);
< }
---
> try {
> channel = new JChannel(configuration.getClusterConfig());
> } catch (Exception e) {
> throw new CacheException(
> "Unable to create JGroups channel", e);
> }
> }
Index: DefaultCacheFactory.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/DefaultCacheFactory.java,v
retrieving revision 1.6
diff -r1.6 DefaultCacheFactory.java
11a12
> import org.jgroups.Channel;
102a104,135
> /**
> * This implementation clones the configuration passed in before using it.
> * It also allows the client to pass in its own channel.
> *
> * @param ch the pre-configured JChannel to use
> * @param configuration to use. We assume that the channel has been setup using
this
> * @param start whether to start the cache
> * @return a cache
> * @throws ConfigurationException if there are problems with the cfg
> */
> public Cache<K, V> createCache(Channel ch, Configuration configuration,
boolean start) throws ConfigurationException
> {
> try
> {
> CacheImpl<K, V> cache = new CacheImpl<K, V>(ch);
> cache.setConfiguration(configuration);
> if (start) cache.start();
> return cache;
> }
> catch (ConfigurationException ce)
> {
> throw ce;
> }
> catch (RuntimeException re)
> {
> throw re;
> }
> catch (Exception e)
> {
> throw new RuntimeException(e);
> }
> }
--
Brian Stansberry
Lead, AS Clustering
JBoss, a division of Red Hat
brian.stansberry(a)redhat.com