AppEngine Memcache expiration policies

2019-03-02 14:03发布

问题:

I was expecting the following AppEngine code:

MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();
memcache.put("Foo", "Bar", Expiration.onDate(new Date(1)));
System.out.println(memcache.get("Foo"));
System.out.println(memcache.put("Foo", "Baz", null, SetPolicy.ADD_ONLY_IF_NOT_PRESENT));

to yield the following output:

null
true

I.e. by setting an Expiration date in 1970 when putting the entry into the cache, I was expecting it to get dropped immediately and be available for reuse.

Instead, I get:

Bar
false

I.e. the entry is still around.

Now, the strange thing is that if I change my code to Expiration.onDate(new Date()) (without 1), i.e. setting the expiration to right before doing the put operation, I do get the expected "null, true".

Does Memcache somehow interpret expiration dates that are too far in the past as relative to now rather than absolute??? But even that wouldn't fit the result, because 1ms from the put should still have expired by the time the get comes around?!?

What value can I set Expiration to, to guarantee an immediate expiration (and deletion!) of the put entry? Keep in mind that simply using the current time-stamp might not work reliably as AppEngine does not offer any clock-synchronization guarantees across servers!

I know that wanting to do this sounds nonsensical at first glance (why not just delete it?), but I would like to use it here: AppEngine Memcache atomic get-and-delete (sentence right above "Conclusion").

回答1:

Wow! This was obscure, but I figure it out:

Taking a look at the source for the doPut()-method in AsyncMemcacheServiceImpl.java, line 505 reads:

itemBuilder.setExpirationTime(expires == null ? 0 : expires.getSecondsValue());

And Expiration.getSecondsValue() contains the following line:

return (int) (getMillisecondsValue() / 1000);

In other words: An expiration value of "0" is equivalent to no expiration (same as null), and the expiration time is converted to seconds, by dividing by 1000.

So, if I set an expiration of 1ms, it gets turned into 0 seconds (rounded down when divided by 1000), which is equivalent to no expiration... Blah!!!

So, the answer is: Expiration.onDate(new Date(1000)) should expire immediately, unless the memcache server is still living in the 60's... :) Tried it. Works. Done...

(These tests were done on the DevServer. I'm hoping that the production server will behave the same.)