So to be clear... @stickfigure 's answer is the definitive answer for standard Objectify. I'm hoping that he can look over this code and comment. And I'm hoping that Objectify might have more caching options in the future... even perhaps at the entity level! Until then, below is a hack that I"m using that perhaps someone else will find useful.
Those if you who have been using Objectify for a while might remember this service model idea. You use this OfyService
by including
import static com.industryopenings.seeker.shared.OfyService.ofyw;
at the top of your class. Then you just call ofyw()
where you would normally call ofy()
. Please note... mixing of ofyr()
and ofyw()
not my intent with this code. Mixing could have potentially strange results. Particularly in transactions.
This OfyService
does two things...
- Ensures instances of
Objectify
created with ofyw()
have cache(false)
specification instead of the default cache(true)
- Periodically calls the
clear()
method for you after OFYW_USE_COUNT_THRESHOLD
calls to ofyw()
Bear in mind we don't really have much ability to inspect the objectify session... there is no object size or object count logic here. It assumes you periodically call ofyw()
(without holding onto the Objectify instance) and just clears session periodically for you.
import com.googlecode.objectify.*;
import com.googlecode.objectify.impl.ObjectifyImpl;
public final class OfyService {
public final static int OFYW_USE_COUNT_THRESHOLD = 10;
public static int currentReferenceCount = 0;
private static ObjectifyFactory defaultFactory = new ObjectifyFactory();
private static ObjectifyFactory noCacheFactory = new NoCacheFactory();
// This factory always returns a no-cache instance.
// BUT: end users can be foolish and turn it back on if they want... having potentially ripple effects downstream
// Best practice if you're going to use this OfyService is to never call the cache(boolean) method
private static class NoCacheFactory extends ObjectifyFactory {
@Override
public Objectify begin() {
return new ObjectifyImpl<>(this).cache(false);
}
}
// Note! We probably need to register our classes in both factories
static {
defaultFactory.register(Doc.class);
defaultFactory.register(SiteLogEntry.class);
defaultFactory.register(SiteLogRunSummary.class);
noCacheFactory.register(Doc.class);
noCacheFactory.register(SiteLogEntry.class);
noCacheFactory.register(SiteLogRunSummary.class);
}
// ofyr to get an Objectify... with the "r" to denote read / caching enabled.
public static Objectify ofyr() {
ObjectifyService.setFactory(defaultFactory);
return ObjectifyService.ofy();
}
// ofyr to get an Objectify... with the "w" to denote writing / no caching enabled.
public static Objectify ofyw(){
// This will ensure we're not using second level cache (memecache)
ObjectifyService.setFactory(noCacheFactory);
// In lieu of a true solution we're simply going to clean house every X times ofyw() is called
currentReferenceCount++;
Objectify o = ObjectifyService.ofy();
if(currentReferenceCount > OFYW_USE_COUNT_THRESHOLD){
o.clear();
currentReferenceCount = 0;
}
return o;
}
}
Hope this helps someone else.