-
1. Re: Classloader leak via CacheImpl.invocationContextContaine
jason.greene Jun 7, 2007 5:01 PM (in response to brian.stansberry)So why don't we make it a weak ref, and recreate it if its null?
-
2. Re: Classloader leak via CacheImpl.invocationContextContaine
brian.stansberry Jun 7, 2007 5:09 PM (in response to brian.stansberry)Yeah, that should work. We pass the context as a param to Interceptor.invoke now, so there is no chance of it getting lost in the middle of a call.
Guess solving it's not such a pain. :) Thanks. -
3. Re: Classloader leak via CacheImpl.invocationContextContaine
brian.stansberry Jun 7, 2007 5:17 PM (in response to brian.stansberry)Hmm, yeah there is a chance of losing it...
cache.getInvocationContext().getOptionOverrides().setCacheModelLocal(true);
// gc runs
cache.put(fqn, key, value);
Call gets replicated. -
4. Re: Classloader leak via CacheImpl.invocationContextContaine
jason.greene Jun 7, 2007 5:41 PM (in response to brian.stansberry)Ah yes. Perhaps just clearing it is better. Although then it wouldn't survive calls.
cache.getInvocationContext().getOptionOverrides().setCacheModelLocal(true); cache.put(fqn, key, value); cache.put(fqn, key, value);
Another option would be to have CacheImpl store a strong reference to every known context, which would go away on cleanup, although this would probably be expensive (at least for creation of the context)
Last, we could require that calling code hold the reference (somewhat cryptic, but this is an advanced feature).InvocationContext ic = cache.getInvocationContext(); ic.getOptionOverrides().setCacheModelLocal(true); cache.put(fqn, key, value); cache.put(fqn, key, value);
-Jason -
5. Re: Classloader leak via CacheImpl.invocationContextContaine
manik Jun 8, 2007 7:42 AM (in response to brian.stansberry)I think the InvocationContextInterceptor should clean up the thread local entry as the invocation exits.
The only place this causes a problem is if there is a callback (like you said, with the notifier) and this triggers another cache operation which ends up resetting the thread local entry. This is less of a problem now since interceptors don't rely on the thread local once the call goes past the ICI (the IC is passed as a param). It is also less of a problem since (JBCACHE-1022) all notifications will now be emitted from the NotificationInterceptor, after which there is not much more than cleanup work remaining.
I think having the ICI clean up thread locals explicitly is more robust and maintainable than weak refs or calling code holding on to refs. -
6. Re: Classloader leak via CacheImpl.invocationContextContaine
jason.greene Jun 8, 2007 9:41 AM (in response to brian.stansberry)I know we are too late in the game for API changes but...
If the InvocationContext is only available for one call, then does it really make sense to expose this as a public API? Wouldn't it be more sensible to make this part of CacheSPI?
There are a lot of options here that would be pretty hazardous to mess with.
-Jason -
7. Re: Classloader leak via CacheImpl.invocationContextContaine
brian.stansberry Jun 8, 2007 9:49 AM (in response to brian.stansberry)There absolutely needs to be some mechanism for clients to set Option flags on calls via the Cache API. Pretty much all AS uses of JBC would fail w/o that.
Agreed though that InvocationContext exposes more than a client should be able to tweak. -
8. Re: Classloader leak via CacheImpl.invocationContextContaine
manik Jun 8, 2007 10:06 AM (in response to brian.stansberry)Needed by Hibernate providers to inject their own DataVersion implementations for optimistically locked nodes, where versioning is maintained elsewhere (e.g., in a DB).
Among other things. -
9. Re: Classloader leak via CacheImpl.invocationContextContaine
brian.stansberry Jun 8, 2007 10:16 AM (in response to brian.stansberry)That's via the Option too, right?
All the stuff in Option is appropriate for a client API, except I guess failSilently which AIUI is an implementation detail of putForExternalRead.
How about using interfaces for this -- InvocationContext and InvocationContextSPI, plus InvocationContextImpl? The InvocationContext interface just exposes the getters that make sense for a client, and via getOptionOverrides() makes the Option available.
If getOptionOverrides() is the only thing a client InvocationContext interface should expose, then maybe it makes more sense to change Cache so it exposes Cache.getOptionOverride() rather than getInvocationContext(). CacheSPI can expose getInvocationContext(). -
10. Re: Classloader leak via CacheImpl.invocationContextContaine
jason.greene Jun 8, 2007 10:51 AM (in response to brian.stansberry)If we do this, we could keep options around for ever (no CL leak) by having the Options object delegate to a hashmap on the threadlocal.
-
11. Re: Classloader leak via CacheImpl.invocationContextContaine
brian.stansberry Jun 8, 2007 11:28 AM (in response to brian.stansberry)Does keeping any of the options around beyond the life of a single invocation make sense? When I look at them they all seem like one-time-only settings.
-
12. Re: Classloader leak via CacheImpl.invocationContextContaine
jason.greene Jun 8, 2007 11:37 AM (in response to brian.stansberry)IMO, if they shouldn't survive multiple invocations, then they should just be a parameter, else its really alien to general java usage.
cache.put(fqn, key, object, options);
-Jason -
13. Re: Classloader leak via CacheImpl.invocationContextContaine
brian.stansberry Jun 8, 2007 11:44 AM (in response to brian.stansberry)No argument there. That's how it is in the 1.x API, but the overloaded methods got cut in a drive to trim the 2.0 API.
-
14. Re: Classloader leak via CacheImpl.invocationContextContaine
jason.greene Jun 8, 2007 12:24 PM (in response to brian.stansberry)A one shot option that is not associated with a method is error prone and verbose for calling code.
Consider this codecache.getOptions().setForceWriteLock(true); String atomicUserCounter = cache.get("/user/123", "counter");
Later someone assumes this is a persisting option and updates itcache.getOptions().setForceWriteLock(true); String atomicUserCounter = cache.get("/user/123", "counter"); String atomicGroupCounter = cache.get("/group/456", "counter");
The fix is overly verbose:cache.getOptions().setForceWriteLock(true); String atomicUserCounter = cache.get("/user/123", "counter"); cache.getOptions().setForceWriteLock(true); String atomicGroupCounter = cache.get("/group/456", "counter");
That said persistent options could lead to problems as well.
An overloaded parameter is neither error prone, nor overly verbose, and is intuitive:Options options = new Options(); options.setForceWriteLock(true); String atomicUserCounter = cache.get("/user/123", "counter", options); String atomicGroupCounter = cache.get("/group/456", "counter", options); String regularReadValue = cache.get("/foo", "foo");
You could even offer constant options (via an immutable extension):String atomicUserCounter = cache.get("/user/123", "counter", Options.FORCE_WRITE_LOCK); String atomicGroupCounter = cache.get("/group/456", "counter", Options.FORCE_WRITE_LOCK); String regularReadValue = cache.get("/foo", "foo");
-Jason