ben-manes / caffeine

A high performance caching library for Java
Apache License 2.0
15.85k stars 1.59k forks source link

[fr]can support the nested key #1689

Closed sunshio closed 5 months ago

sunshio commented 5 months ago

NestedCache<String, String, Object> cache = ...

cache.put("x", "y", 0)

sunshio commented 5 months ago

https://babyfish-ct.github.io/jimmer-doc/docs/cache/multiview-cache/concept

ben-manes commented 5 months ago

In Jimmer, SubKey must be the JSON-serialized string of java.util.SortedMap<String, Object>. This SortedMap must use the default sorting rule without custom Comparator. ... When invalidating cache, Jimmer will automatically delete invalid cached by key. Cached items of multi-view cache are always deleted as a whole based on Key rather than partially based on Key + SubKey, to maximize the relative simplicity of multi-view cache.

This means it is a Cache<Key, SortedMap<SubKey, Value>>, so that eviction / invalidation removes the key and sub-map. Likely one would want to bound the maximum size by the number of sub-map entries, so a weigher could be used in these cases. Those APIs don't specify if the sub-map can be modified, but for simpler concurrency I would treat it as a copy-on-write map.

Cache<Key, SortedMap<SubKey, Value>> multiViewCache = Caffeine.newBuilder()
    .expireAfterWrite(Duration.ofMinutes(10))
    .weigher((key, submap) -> submap.size())
    .maximumWeight(10_000)
    .build();

// get a subKey entry
var value = multiViewCache.asMap().getOrDefault(key, Collections.emptySortedMap()).get(subKey);

// add an subKey entry
multiViewCache.asMap().compute((key, submap) -> {
    var map = (submap == null) ? new TreeMap<> : new TreeMap<>(submap);
    map.put(subKey, value);
    return Collections.unmodifiableSortedMap(submap);
});

// remove a subKey entry
multiViewCache.asMap().computeIfPresent((key, submap) -> {
    if (!submap.containsKey(subKey)) {
      return submap;
    } else if (submap.size() == 1) {
      return null;
    }
    var map = new TreeMap<>(submap);
    map.remove(subKey);
    return Collections.unmodifiableSortedMap(map);
});
sunshio commented 5 months ago

This would lead to locks with exceedingly coarse granularity, and there is no eviction mechanism for the keys of the submap.

ben-manes commented 5 months ago

The eviction follows what the Jimmer documentation states for eviction, so that's following their expectations.

For locking, while it would be coarse as by Key, the operations are very fast since they are in-memory operations without I/O. That allows for a very high throughput of writes so I don't think that should cause a problem.