[CCACHE-28] SoftCache NullPointerException in has? with many threads Created: 24/Oct/12 Updated: 09/Feb/13 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Defect | Priority: | Major |
| Reporter: | James Aley | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | None | ||
| Environment: |
Linux, Oracle JRE 1.6 |
||
| Attachments: |
|
| Patch: | Code |
| Description |
|
"cell" can be null on this call to SoftReference.get(): If the cache did not contain "item" in the call to (get cache item) in the let binding, but another thread pre-empts and adds it before the subsequent call to contains?, we'll attempt to call .get() on nil. Would it perhaps be sufficient to just check whether cell is nil instead of calling contains? in the check on the previous line? |
| Comments |
| Comment by Paul Stadig [ 09/Feb/13 6:13 AM ] |
|
Good catch! This is rather simple to reproduce: (use 'clojure.core.cache)
(def cache (soft-reference-cache {}))
(def mutator (Thread. #(loop [] (assoc cache :foo :bar) (dissoc cache :foo) (recur))))
(.start mutator)
(loop [] (has? cache :foo) (recur))
The attached patch fixes the issue, by not referring back to the cache after attempting to pull out a SoftReference. |
[CCACHE-30] make-reference need not be dynamic Created: 09/Feb/13 Updated: 09/Feb/13 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Enhancement | Priority: | Major |
| Reporter: | Paul Stadig | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | None | ||
| Description |
|
It looks like make-reference was made dynamic to support multiple clojure versions. Rebinding make-reference is really only needed for tests, and it would be a shame if making it dynamic causes performance issues. Perhaps it is not enough of a performance issue to worry about. Otherwise, it might be possible to work around it. Perhaps directly pasting in and using the with-redefs macro, or something similar? |
[CCACHE-29] Is IPersistentCollection definition of cons correct? Created: 18/Nov/12 Updated: 18/Nov/12 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Defect | Priority: | Major |
| Reporter: | Brian Marick | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | None | ||
| Description |
|
Here's the definition of `cons` for caches: clojure.lang.IPersistentCollection This seems wrong to me. Note first that the arguments to `clojure.core/cons` are in the wrong order. As a result, the result of (for example) conj is incorrect. Consider this: user=> (def starts-with-a (cache/fifo-cache-factory {:a 1} :threshold 3)) #'user/starts-with-a Even if the argument order was correct, the result would still be a sequence rather than the type of the base field. I think you want something more like clojure.lang.IPersistentCollection After all, this particular collection is an IPersistentMap, so its `conj` and `into` behavior should be the same as other objects for which `map?` is true. |
[CCACHE-27] Missing LU and LRU is linear complexity - performance Created: 04/Sep/12 Updated: 12/Sep/12 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Defect | Priority: | Major |
| Reporter: | Ghadi Shayban | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | enhancement, performance | ||
| Environment: |
Mac Oracle JDK, Linux OpenJDK |
||
| Attachments: |
|
| Patch: | Code |
| Description |
|
Profiling some code with YourKit showed a hotspot in cache statistics on (miss) for LU and LRU caches. Basically two issues: (count (keys {....})) is a count of a seq, not efficient. Replaced with a count of the map. Secondly, (apply f anything) is slow. Profiler showed that the (apply min-key) was really slow. This is mitigated by using a c.d.priority-map instead. On a priority-map, (ffirst {}) or (first (peek {}). Also inverted the logic for threshold comparison. Since there is a (build-leastness-queue) that populates statistics, should caches should favor codepaths for the state of being full all the time? |
| Comments |
| Comment by Ghadi Shayban [ 06/Sep/12 10:49 PM ] |
|
I take back the part about (apply) being slow. I think it's more the fact that it's doing a linear scan on keys every single time. (apply) does show up a lot in a profiler, but I haven't figured out why. (apply + (range big)) seems to even be slightly faster than (reduce +) on the same range. |
| Comment by Ghadi Shayban [ 12/Sep/12 9:27 AM ] |
|
Patch in proper format |
[CCACHE-26] hit function in LRU cache can give funny results Created: 22/Aug/12 Updated: 22/Aug/12 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Defect | Priority: | Major |
| Reporter: | Arthur Edelstein | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | None | ||
| Description |
|
A common-sense usage in caches is hit/get. But if I naively do this to an LRUCache, without checking first for the presence of the key, I can break the limit. (-> (cache/lru-cache-factory {} :threshold 2) ; {:e 5, :d 4, :c 3, :b 2, :a 1} |
[CCACHE-20] Add some examples to github page Created: 08/Feb/12 Updated: 19/Feb/12 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Task | Priority: | Major |
| Reporter: | Juha Syrjälä | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | None | ||
| Description |
|
Could you add some examples on how to use core.cache to github readme? |
| Comments |
| Comment by Fogus [ 19/Feb/12 6:24 PM ] |
|
Can do. In the meantime checkout how core.memoize uses it at https://github.com/clojure/core.memoize/blob/master/src/main/clojure/clojure/core/memoize.clj#L50 I think I might bring this through fn into core.cache in a more generic way. |
[CCACHE-17] Create function backed cache Created: 16/Dec/11 Updated: 19/Dec/11 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Enhancement | Priority: | Major |
| Reporter: | Fogus | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | cache, fn-cache, new-feature | ||
| Description |
|
A cache implementation that is backed by a function that performs some action on a cache miss could serve as a front for any of the existing cache impls. |
| Comments |
| Comment by Rich Hickey [ 16/Dec/11 9:45 AM ] |
|
It doesn't perform an action per se, it gets a passed key and returns a value, which the cache then caches (associates with the key) and returns. The tricky bit is when the function can't get a value. There needs to be some protocol for communicating that (could be like 3 arg get), and, should the cache be asked again later for the same key, calling the fn again. |
| Comment by Fogus [ 19/Dec/11 7:29 AM ] |
|
Thanks for the feedback Rich. I believe I understand the subtleties now. |
[CCACHE-18] Explore JSR 107- Java Temporary Caching API Created: 19/Dec/11 Updated: 19/Dec/11 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Task | Priority: | Trivial |
| Reporter: | Fogus | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | jsr-107, research | ||
| Description |
|
Is this relevant to core.cache? And many other questions answered. <http://jcp.org/en/jsr/detail?id=107> |
[CCACHE-16] Benchmark v0.5.x against Google Guava Created: 16/Dec/11 Updated: 16/Dec/11 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Task | Priority: | Major |
| Reporter: | Fogus | Assignee: | Unassigned |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | benchmark, cache, guava | ||
| Description |
|
Perform some tests and benchmarks of core.cache and Google Guava's com.google.common.cache library. |
[CCACHE-15] It appears that TTL cache exhibits quadratic performance (+ its evict is buggy) Created: 14/Dec/11 Updated: 15/Dec/11 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Defect | Priority: | Major |
| Reporter: | Jason Wolfe | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | None | ||
| Description |
|
The library looks useful, thanks! I looked at the code, and unless I'm mistaken, every cache miss seems to result in a full pass over the entire cache to evict old entries. The performance implications of this would be unacceptable for my target application. Replacing the TTL data structure with a persistent analog of a LinkedHashMap and using a take-while instead could fix this problem. Also, evict seems to pass the cache in twice, rather than the cache and the TTL... |
| Comments |
| Comment by Fogus [ 15/Dec/11 12:21 PM ] |
|
TTLCache eviction fixed. Patches welcomed for the other change, but we might be able to get away with a sorted map ttl map. |
[CCACHE-14] Asynchronous Cache Support Created: 13/Dec/11 Updated: 13/Dec/11 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Enhancement | Priority: | Minor |
| Reporter: | Pierre-Yves Ritschard | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | None | ||
| Description |
|
If people start implementing the cache protocol on top of external caches: Memcache, Redis, or others, an async version could make sense. I started toying with an AsyncCacheProtocol which for all functions returning values would take two arities, a standard one which would return an instance of IRef, a second one which would take an extra callback argument to be called with the results. This doesn't solve everything though and async versions of LRU and friends would have to be implemented. The alternative would be to have additional calls in CacheProtocol, such as async-has? async-lookup which would implement the 2 arity semantics and then rely on the fact that the underlying cache respects some sort of async semantics, since we cannot do that with Associative, maybe another middleman protocol CacheStorage could be used, this way, all external cache providers would have to do is implement a CacheProvider with optional asynchronous support. I hope at least part of this makes sense. |
[CCACHE-11] Add eviction implementation to LIRSCache Created: 08/Dec/11 Updated: 08/Dec/11 |
|
| Status: | Open |
| Project: | core.cache |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Task | Priority: | Major |
| Reporter: | Fogus | Assignee: | Fogus |
| Resolution: | Unresolved | Votes: | 0 |
| Labels: | associative, cache, evict, lirs | ||
| Description |
|
The evict method in the ProtocolCache needs implementation for LIRSCache. I will start initially with a single key eviction method to start. The evict method would form the basis for the associative dissoc which in turn forms the basis for proper limited seeding. LIRS poses an additional complication due to its dual limit lists. Currently only the BasicCache impl has evict. |