cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Leo Sutic" <leo.su...@inspireinfrastructure.com>
Subject Re: [Kernel2.2] Comments
Date Thu, 01 Apr 2004 11:27:08 GMT
I and Pier exchanged some emails off-list (since I didn't have
access to the list). Here goes:

> >From: Pier Fumagalli <pier@betaversion.org>
> >
> >On 31 Mar 2004, at 20:34, Leo Sutic wrote:
> >
> >>Pier,
> >>
> >>I'm out of [the] office, so I can't reply to the list. But it 
> >>seems like we 
> >>have different ideas about what will happen in some scenarios.
> >
> >No worries...
> >
> >>The scenario I'm thinking about is this:
> >>
> >>     MyInterface object = (MyInterface) wires.lookup (
> >>                              MyInterface.class,
> >>                              "wiringname");
> >>
> >>     ((Wire)object).ensureWired();
> >>     try {
> >>         // OK, object is wired....
> >>
> >>         object.doSomething ();
> >>         object.doSomethingElse ();
> >>
> >>         // At this point, the block we're using via
> >>         // object is reloaded...
> >>
> >>         object.doSomething() // What happens here?
> >>     } finally {
> >>         ((Wire)object).release() / dispose();
> >>     }
> >>
> >>Question: What happens at the line marked with "// What happens 
> >>here?"?
> >
> >My first though was that you would get an 
> "IllegalStateException" (and 
> >that's how it behaves right now). Once the wire is cut the 
> instance of 
> >the proxy is lost. Look here:
> >
> >http://cvs.apache.org/viewcvs.cgi/cocoon-2.2/src/kernel/org/apache/
> >cocoon/kernel/ProxyWire.java?annotate=1.4
> >
> >Lines from 259 to 275, especially 265, the instance is set to null 
> >during a call to "cut()", and if you look at lines 243 to 248, you'll

> >notice that once the wire is cut, any call apart from 
> release, dispose, 
> >finalize or wired is going to throw an IllegalStateException.
> >
> >>Do I get an exception thrown (wire is cut)? Or does the call go 
> >>through to the version of the block I had before it was 
> reloaded (wire 
> >>isn't cut)?
> >>
> >>What I *want* to happen is to have an Exception throws 
> (forcibly cut 
> >>the wire when the thing it is connected to is reloaded).
> >>
> >>What you have told me happens is that I will keep on using the old 
> >>version until I call ensureWired() again. The reason I 
> think that is 
> >>dangerous is because bad code may forget to call 
> ensureWired() and may 
> >>forget to release the wire. If Exceptions are thrown I'll know that 
> >>there's something wrong. If they aren't I'll just get corruption.
> >
> >Now, that's the evolution on my though, and what I asked to the 
> >community to think about because I'm still unsure of what's the best 
> >practice.
> >
> >We could consider a situation in which an undeployment of a block 
> >doesn't actually forcedly CUT the wire, so, if I'm using a 
> transformer, 
> >for example, that transformer will render the entire page 
> and will not 
> >fail with an IllegalStateException.
> >
> >The block could be marked as "undeployed" and therefore the new 
> >instance will always return the new wires for all new 
> lookups. We would 
> >have a block "undeployed" associated with some "stale" wires, and a 
> >"deployed" block where new wires will be loaded from...
> >
> >It's a bad situation in which we're in because the JVM garbage 
> >collector wouldn't be able to dispose of the old 
> (undeployed) block, as 
> >somehow we're still holding references to it, but on the 
> other hand, it 
> >would be a good situation for nicely developed blocks 
> because it would 
> >basically means that when I redeploy a transformer, all requests 
> >processed with it would not fail miserably.
> >
> >Clear case scenario, if I "update" (replace the running 
> instance) of my 
> >XSLT transformer block on a live website, I want all requests to go 
> >through anyway, and after 2 minutes, if someone is holding (still) a 
> >wire, and the block was not garbage collected, well, I'm going to 
> >forcedly cut all the wires, and exceptions will be thrown to anyone 
> >holding the stale wires.
> >
> >You have to remember that redeployment is a manual operation 
> (a human 
> >being is actually doing it) and that person is going to be 
> looking at 
> >what's going on through a cocoon management console, so, 
> anyhow, I'll 
> >always be checking on the status of my cocoon when I redeploy a 
> >block...
> >
> >Also, having the "undeployed" instance still available and perfectly 
> >configured will allow me to easily roll back to the 
> well-known working 
> >block instance in case of problems...
> >
> >Imagine that I redeploy (again) my XSLT transformer, but I 
> immediately 
> >find out that a patch made on XALAN breaks 1/2 of my stylesheets for 
> >god knows what reason: I'll be able to immediately revert 
> back to the 
> >old one, and destroy the new (but faulty) one...
> >
> >So, I see advantages (and disadvantages) in both ways, and 
> that's what 
> >I want people to think about: more responsibility to the admin to be 
> >the trigger of garbage colleciton (and force wires to be 
> cut), or less 
> >responsibility to the admin and having requests fail halfway through 
> >(we can also partially automate the GC process, by saying that if an 
> >instance has been undeployed for more than 10 minutes, for 
> example, and 
> >it has no wirings, well, then clear it out).
> >
> >Now, more on the ensureWired() method...
> >
> >I would think that if we adopt the second scenarion (manual GC) the 
> >"ensureWired()" method could simply check if the proxied component 
> >block has been undeployed. If it did, then it should automatically 
> >perform an internal disposition to the old composer, and 
> re-lookup in 
> >the new composer to get a "fresh" copy of the proxied instance.
> >
> >It complicates the code a little bit (from the framework 
> perspective) 
> >but I think it's doable.
> >
> >Something like:
> >
> >public void ensureWired()
> >throws WiringException {
> >   if (originalblock.isDeployed()) return;
> >   Composer newBlockComposer = ...; // fetch the new block's composer
> >   this.proxiedinstance = newBlockComposer.lookup(...); // 
> my old role 
> >and name }
> >
> >Which means that "ensureWired()" will never return true or false (on 
> >which the block developer has to decide whether to release 
> or keep the 
> >wire), but will rather automatically rewire itself, and throw an 
> >exception if it can not...
> >
> >I think that this is the best way to go and a good trade off between 
> >administration complexity and not having requests to crash in the 
> >middle...
> >
> >         Pier
> >
> >BTW, can I forward this to the list?

Sure! I take that as implicit permission to forward it myself...

More detailed answer tomorrow, but how about making the behavior
configurable on a per-block basis?

Basically you suggest two ways of going about it:

 1. Forcibly cut all wires and undeploy the block. Let's call this a
"Hard" undeploy.

 2. Don't cut any existing wires, but route any new lookups to the new
instance of the block. (Thus allowing your SAXTransformer to finish
rendering the page.) Let's call this a "Soft"/"Graceful" undeploy.

I'd like to use (1) for DB connection pools. I'll be in a world of hurt
if
more than one instance is loaded at any time.

I'd like to use (2) for Pipeline components.

Can we add an attribute or something to each block saying "yes, I can be
gracefully redeployed" or "when you undeploy me, you must cut all wires
immediately"?

/LS


Mime
View raw message