Closed GoogleCodeExporter closed 9 years ago
I'm...in favor of this, and tentatively endorse a beefed-up Supplier.
Original comment by wasserman.louis
on 18 Jan 2012 at 6:43
A proposed interface:
interface BeefySupplier<T> extends Supplier<T> {
void invalidate(); // or, perhaps, clear()
void refresh();
void put(T object);
}
It would also be nice if the "memoizeWithExpiration" static factory could
become a builder, so I could do something like:
BeefySupplier<Steer> steerSupplier = Suppliers.builder()
.memoize()
.expireAfterAccess(100)
.refreshAfterWrite(200)
.build(
new Supplier<Steer>() {
public Steer get() {
return raiseASteer(); // it takes a long time to raise one, hence why I want to cache it
}
}
);
Original comment by raymond....@gmail.com
on 18 Jan 2012 at 8:42
Hmm, so I just noticed that there is a CacheLoader.from(Supplier<V> supplier).
Is this intended to be the way to go about making a single-element cache? If
so, this issue can be closed.
Original comment by raymond....@gmail.com
on 19 Jan 2012 at 1:27
I'm not satisfied with that, exactly? I'd like to eliminate the key from the
picture, for the single-element cache.
Original comment by wasserman.louis
on 19 Jan 2012 at 1:30
Raymond, that's actually completely unrelated. It's just like any other cache,
just that the CacheLoader doesn't actually depend on the key.
Original comment by kevinb@google.com
on 19 Jan 2012 at 3:30
In general, I think it's probably a good idea to explore the idea of a
singleton-cache type that's the no-key,one-value analogue of
CacheBuilder/LoadingCache, then whittle the set of methods suggested by that
analogy down to the ones we know we have use cases for Out There, and see what
we arrive at.
To me, the fact it'll implement Supplier is just incidental, as with the case
of LoadingCache implementing Function, and so I don't think Supplier would
feature in the name.
Original comment by kevinb@google.com
on 19 Jan 2012 at 3:32
I have an implementation of this that I called ReferenceMaker, with options
similar to MapMaker/CacheLoader for expiry etc, but only storing the single
reference. There are plenty of things this could support that aren't applicable
to or done in CacheLoader, in particular timed async refresh as opposed to
expiry with on-demand reinitialisation.
I considered this to be more like a Reference with some extra options (e.g.
self-refreshable) than like a cache, though maybe these are close to the same
thing.
Original comment by joe.j.kearney
on 19 Jan 2012 at 9:54
Original comment by fry@google.com
on 16 Feb 2012 at 7:18
Not sure if OP had a similar scenario in mind, but I needed a memoizing
supplier which is calculated from non-static context (pseudo code):
if ((t = not_calculated_yet) != null) {
block_all_other_threads();
t = calculate(f);
memoize(t);
}
return t;
My initial response to this was to use Guava's cache (like OP) but I think
having an abstract class with double check idiom (to hide the inglorious bits)
is a better solution.
There are numerous implementations on the web, and this is one of them:
http://weblogs.java.net/blog/mason/archive/2006/09/rechecking_doub.html
Original comment by min...@gmail.com
on 26 Apr 2012 at 3:21
mindas, have you seen Suppliers.memoize?
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Su
ppliers.html#memoize%28com.google.common.base.Supplier%29
Original comment by cpov...@google.com
on 26 Apr 2012 at 3:34
Don't think Suppliers.memoize would be applicable for cases where supplier is
static and the data to build the supplier from ("f" in pseudo code) is coming,
say, from a method parameter. Consider something like
class Foo {
private static final Supplier<Bar> BAR_SUPPLIER = Suppliers.memoize(...);
private Foo() {}
public static Bar get(Baz baz) {
BAR_SUPPLIER.get(baz); // there's no .get(key, Callable) like in Cache
}
}
Original comment by min...@gmail.com
on 26 Apr 2012 at 3:50
Ah, so you know that get(Baz) will be called with the same Baz every time, but
you don't know the value ahead of time?
Original comment by cpov...@google.com
on 26 Apr 2012 at 9:01
Yes, exactly.
Original comment by min...@gmail.com
on 27 Apr 2012 at 8:29
+1
I had the exact same experience as the OP.
I like the pattern that Raymond proposed (the Supplier builder). However we
could start smaller by offering a supplier that behaves exactly like
memoizeWithExpiration, except that it loads the value asynchronously (using an
Executor passed at construction, for instance) automatically upon expiration or
upon the first request that follows expiration, and continues to supply the old
value until the new value is returned.
Original comment by shi...@gmail.com
on 25 May 2012 at 5:08
I must admit that my recent abuse of the glorious CacheLoader is even dirtier:
not only do I need just one value, so I use a dummy key,
but I also want my data to be set under a lock, so I also use a dummy value,
and just implement the get() method as:
public Object get(Object ignoredKey) {
mutex.lock();
try {
outerClass.this.value = calculateValue();
} finally {
mutex.unlock();
}
return DUMMY; // Cannot return null
}
So Ugly, I know. I cynically use its "should get() be run now?" logic without
anything else that has to do with a cache.
If memoizeWithExpiration is adapted to allow all the above, can it also please
accept an optional lock to make writes under?
Original comment by yoa...@google.com
on 28 May 2012 at 5:49
[deleted comment]
(sorry, OuterClass should be capitalized... and this is the load() method...)
Original comment by yoa...@google.com
on 28 May 2012 at 5:51
Original comment by kevinb@google.com
on 30 May 2012 at 7:43
I feel like this would be solved by just adding a reset method to the memoizing
suppliers available today. At least thats what I've done in my code.
I found a need to memoize values for a long period of time, but every once in a
while, usually triggered by users, I had to flush the value stored in the
supplier.
Original comment by emily@soldal.org
on 1 Jun 2012 at 2:16
Original comment by kevinb@google.com
on 22 Jun 2012 at 6:16
Another useful feature (that I have an immediate use for) that this singleton
cache could provide is memoise-with-soft-reference. Just to add to kevinb's
list for Comment 6.
Original comment by cky944
on 1 Jul 2012 at 6:13
Not sure if this should be its own issue...but... I just recalled that one of
my earliest "guava-like" classes was resettable variants of MemoizingSupplier
and ExpiringMemoizingSupplier.
The reason was simpy because we had a config object which rarely changed, so
holding it in a Memoizing supplier once it had been loaded was a good idea....
until it changed... then you had to reboot the server to get the changed to
propogate.
Perhaps cache is the wrong idea here, just adding an interface like Resettable
or Clearable akin to (Auto)Closable and attaching that to a tertiary interface
which joins both Supplier and Resettable and returning that so that we can
expose the reset method and supplier method but not the implementations.
Arguably these should be added to the current memoizing suppliers.
just my 2 cents
Original comment by emily@soldal.org
on 3 Jul 2012 at 1:22
I had a similar need. My solution was to ask an extended Predicate if the
memoized value should get updated. The memoizing Supplier calls a done() method
on the 'UpdateRequest' after the value is updated, so that it can change it's
state.
public interface UpdateRequest<T> extends Predicate<T> {
void done();
}
public static <T> Supplier<T> memoize(Supplier<T> delegate, UpdateRequest<?
super T> updateRequest) {...}
Original comment by christop...@gmail.com
on 30 Jul 2012 at 2:57
Louis, if you're looking for work, this would be good to look into, at least as
far as converging on an API/feature set we can all feel good about.
Original comment by kevinb@google.com
on 24 Aug 2012 at 3:57
I can do that; I'll do some experimentation over the next week or two.
Original comment by wasserman.louis
on 24 Aug 2012 at 7:21
There's another functionality aspect which can possibly be considered for this
feature.
Let's say there's some expensiveFunction() which takes a long time to
calculate. Data that makes the input of this function may change and might be a
need for an idiom which would invalidate the current process of expensive
calculation and start anew, making all waiting threads to wait for longer until
the calculation is complete and no more invalidations are done in the due
course.
Current LoadingCache does not support this feature (this is not too obvious
from the javadoc). In other words, call to cache.refresh(key) or
cache.invalidate(key) or cache.invalidateAll() is ignored if the calculation is
in process and only makes any difference if invalidation happens *after* the
calculation.
I needed this feature and wrote a quick hack myself. The source code is
available at
http://codereview.stackexchange.com/questions/18056/ability-to-forget-the-memoiz
ed-supplier-value -- I'd be more than happy to hear any
suggestions/improvements.
Original comment by min...@gmail.com
on 31 Oct 2012 at 10:56
Mindas, what you describe *seems* like something that should be filed
separately.
Original comment by kevinb@google.com
on 9 Nov 2012 at 11:07
Original comment by kevinb@google.com
on 12 Mar 2013 at 6:43
I'm also using a LoadingCache the same way as the OP; my own reasons are:
- expireAfterWrite
- thread-safe loading.
In general I can see most of the other features of CacheBuilder being useful
for a singleton holder (various expiration policies, etc).
Original comment by pern...@google.com
on 18 Jun 2013 at 12:55
Issue 1466 has been merged into this issue.
Original comment by cgdecker@google.com
on 3 Jul 2013 at 7:24
Issue 1466 has been merged into this issue.
Original comment by cgdecker@google.com
on 3 Jul 2013 at 7:30
Issue 1773 has been merged into this issue.
Original comment by lowas...@google.com
on 2 Jun 2014 at 7:24
Issue 1834 has been merged into this issue.
Original comment by cpov...@google.com
on 19 Aug 2014 at 1:41
This issue has been migrated to GitHub.
It can be found at https://github.com/google/guava/issues/<id>
Original comment by cgdecker@google.com
on 1 Nov 2014 at 4:14
Original comment by cgdecker@google.com
on 1 Nov 2014 at 4:18
Original comment by cgdecker@google.com
on 3 Nov 2014 at 9:09
Original issue reported on code.google.com by
raymond....@gmail.com
on 18 Jan 2012 at 2:55