0

有没有办法根据时间戳条件删除咖啡因条目?例如,在T1我有以下条目

K1 -> V1
K2 -> V2
K3 -> V3

有时T2我只更新K2K3. (我不知道这两个条目是否都有确切的时间戳。K2可能有T2K3可能是T2 + some nanos。但为了这个问题,让我们假设他们有)

现在我希望咖啡因使条目无效K1 -> V1,因为T1 < T2.

一种方法是遍历条目并检查它们的写入时间戳是否为 < T2。收集此类密钥并最终调用invalidateKeys(keys)

也许有一种非迭代的方式?

4

1 回答 1

1

如果您使用的是expireAfterWrite,那么您可以按时间戳顺序获取条目的快照。由于这个调用需要获取驱逐锁,它提供了一个不可变的快照而不是一个迭代器。这很混乱,例如,您必须提供一个可能不正确的限制,并且取决于到期时间。

Duration maxAge = Duration.ofMinutes(1);
cache.policy().expireAfterWrite().ifPresent(policy -> {
  Map<K, V> oldest = policy.oldest(1_000);
  for (K key : oldest.keySet()) {
    // Remove everything written more than 1 minute ago
    policy.ageOf(key)
      .filter(duration -> duration.compareTo(maxAge) > 0)
      .ifPresent(duration -> cache.invalidate(key));
  }
});

如果您自己维护时间戳,则可以使用cache.asMap()视图进行无序迭代。这可能是最简单和快速的。

long cutoff = ...
var keys = cache.asMap().entrySet().stream()
  .filter(entry -> entry.getValue().timestamp() < cutoff)
  .collect(toList());
cache.invalidateAll(keys);

一种行不通但值得一提来解释原因的方法是变量过期,expireAfter(expiry). 您可以根据之前的设置为每次读取设置新的持续时间。这在条目返回给调用者后生效,因此虽然您可以立即过期,但它会K1(至少)服务一次。

否则,您可以在缓存之外的检索时间进行验证,并依靠大小驱逐。这种方法的缺陷是它确实会污染缓存将死条目。

V value = cache.get(key);
if (value.timestamp() < cutoff) {
  cache.asMap().remove(key, value);
  return cache.get(key); // load a new value
}
return value;

或者你可以维护你自己的写顺序队列等。所有这些都会让你得到更多的混乱。对于您的情况,完整的迭代可能是最简单且最不容易出错的方法。

于 2021-07-21T17:13:04.237 回答