Re: Understanding clojure.core.cache TTL cache
Just to push to the limit. Lets say we saved/serializer the cache to a secondary storage (file or ZooKeeper). What happen when the cache is restored? I mean TTL is still honored? expired data while been sleeping will be evicted upon an operation is performed after deserialization? Thanks a lot! On Tuesday, October 23, 2012 1:42:28 AM UTC+3, Sean Corfield wrote: > > On Mon, Oct 22, 2012 at 3:30 PM, Hussein B. > > wrote: > > So we need to call evict explicitly if we want to remove an entry? no > > automatic deletion after expiring? > > The cache is immutable. > > When you call hit / miss, you get a new instance of the cache with the > expired entries removed, and the hit entry updated (if appropriate) or > the miss entry added. > > That new instance needs to be stored somewhere (or passed to future > code execution). > > Entries will be automatically deleted after expiring in any new > instance of the cache - returned by hit / miss. > > You can see that here: > > user=> (swap! c3 hit-or-miss :a 1) > {:a 1} > user=> (swap! c3 hit-or-miss :b 2) > {:a 1, :b 2} > user=> (swap! c3 hit-or-miss :c 3) > {:c 3, :b 2} > user=> (swap! c3 hit-or-miss :d 4) > {:c 3, :d 4} > user=> (swap! c3 hit-or-miss :e 5) > {:c 3, :d 4, :e 5} > > We add :a, then :b. By the time we add :c, :a has expired (and been > removed). By the time we add :d, :b has expired (and been removed). > Then we add :e before any more expiries. If I wait awhile and add a > new value for :a... > > user=> (swap! c3 hit-or-miss :a 6) > {:a 6} > > ...you'll see :c, :d and :e have expired. > -- > Sean A Corfield -- (904) 302-SEAN > An Architect's View -- http://corfield.org/ > World Singles, LLC. -- http://worldsingles.com/ > > "Perfection is the enemy of the good." > -- Gustave Flaubert, French realist novelist (1821-1880) > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
> And thank you Mr. Fogus. Don't thank me, Sean did all the hard work. :-) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
Thank you, I understand it :) And thank you Mr. Fogus. What a great pleasure! On Tuesday, October 23, 2012 1:42:28 AM UTC+3, Sean Corfield wrote: > > On Mon, Oct 22, 2012 at 3:30 PM, Hussein B. > > wrote: > > So we need to call evict explicitly if we want to remove an entry? no > > automatic deletion after expiring? > > The cache is immutable. > > When you call hit / miss, you get a new instance of the cache with the > expired entries removed, and the hit entry updated (if appropriate) or > the miss entry added. > > That new instance needs to be stored somewhere (or passed to future > code execution). > > Entries will be automatically deleted after expiring in any new > instance of the cache - returned by hit / miss. > > You can see that here: > > user=> (swap! c3 hit-or-miss :a 1) > {:a 1} > user=> (swap! c3 hit-or-miss :b 2) > {:a 1, :b 2} > user=> (swap! c3 hit-or-miss :c 3) > {:c 3, :b 2} > user=> (swap! c3 hit-or-miss :d 4) > {:c 3, :d 4} > user=> (swap! c3 hit-or-miss :e 5) > {:c 3, :d 4, :e 5} > > We add :a, then :b. By the time we add :c, :a has expired (and been > removed). By the time we add :d, :b has expired (and been removed). > Then we add :e before any more expiries. If I wait awhile and add a > new value for :a... > > user=> (swap! c3 hit-or-miss :a 6) > {:a 6} > > ...you'll see :c, :d and :e have expired. > -- > Sean A Corfield -- (904) 302-SEAN > An Architect's View -- http://corfield.org/ > World Singles, LLC. -- http://worldsingles.com/ > > "Perfection is the enemy of the good." > -- Gustave Flaubert, French realist novelist (1821-1880) > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
On Mon, Oct 22, 2012 at 3:30 PM, Hussein B. wrote: > So we need to call evict explicitly if we want to remove an entry? no > automatic deletion after expiring? The cache is immutable. When you call hit / miss, you get a new instance of the cache with the expired entries removed, and the hit entry updated (if appropriate) or the miss entry added. That new instance needs to be stored somewhere (or passed to future code execution). Entries will be automatically deleted after expiring in any new instance of the cache - returned by hit / miss. You can see that here: user=> (swap! c3 hit-or-miss :a 1) {:a 1} user=> (swap! c3 hit-or-miss :b 2) {:a 1, :b 2} user=> (swap! c3 hit-or-miss :c 3) {:c 3, :b 2} user=> (swap! c3 hit-or-miss :d 4) {:c 3, :d 4} user=> (swap! c3 hit-or-miss :e 5) {:c 3, :d 4, :e 5} We add :a, then :b. By the time we add :c, :a has expired (and been removed). By the time we add :d, :b has expired (and been removed). Then we add :e before any more expiries. If I wait awhile and add a new value for :a... user=> (swap! c3 hit-or-miss :a 6) {:a 6} ...you'll see :c, :d and :e have expired. -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ "Perfection is the enemy of the good." -- Gustave Flaubert, French realist novelist (1821-1880) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
I see, it works now. So we need to call evict explicitly if we want to remove an entry? no automatic deletion after expiring? On Tuesday, October 23, 2012 1:21:54 AM UTC+3, Sean Corfield wrote: > > On Mon, Oct 22, 2012 at 3:08 PM, Hussein B. > > wrote: > > I tried this: > > > > (defn hit-or-miss > > [a k v] > > (if (c/has? @a k) > > (c/hit @a k) > > (c/miss @a k v))) > > My bad... got a bit carried away with the derefs based on code I was > playing around with in the REPL. Try this: > > (defn hit-or-miss > [c k v] > (if (c/has? c k) > (c/hit c k) > (c/miss c k v))) > > (swap! acu hit-or-miss :e 55) > > That will update the atom to hold the new cache with {:e 55}. > -- > Sean A Corfield -- (904) 302-SEAN > An Architect's View -- http://corfield.org/ > World Singles, LLC. -- http://worldsingles.com/ > > "Perfection is the enemy of the good." > -- Gustave Flaubert, French realist novelist (1821-1880) > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
On Mon, Oct 22, 2012 at 3:08 PM, Hussein B. wrote: > I tried this: > > (defn hit-or-miss > [a k v] > (if (c/has? @a k) > (c/hit @a k) > (c/miss @a k v))) My bad... got a bit carried away with the derefs based on code I was playing around with in the REPL. Try this: (defn hit-or-miss [c k v] (if (c/has? c k) (c/hit c k) (c/miss c k v))) (swap! acu hit-or-miss :e 55) That will update the atom to hold the new cache with {:e 55}. -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ "Perfection is the enemy of the good." -- Gustave Flaubert, French realist novelist (1821-1880) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
I tried this: (defn hit-or-miss [a k v] (if (c/has? @a k) (c/hit @a k) (c/miss @a k v))) (def acu (atom (c/ttl-cache-factory {} :ttl 2))) (swap! acu hit-or-miss :e 55) But I got: ClassCastException clojure.core.cache.TTLCache cannot be cast to clojure.lang.IDeref clojure.core/deref (core.clj:2080) Any ideas? On Tuesday, October 23, 2012 1:03:10 AM UTC+3, Sean Corfield wrote: > > Just to clarify, hit does nothing for TTL (since items timeout based > solely on when they were added, not when they were last touched), so > swap! on the hit really makes no difference here. It would, however, > be required for some of the other types of cache. > > Also, exactly how you use has? / hit / miss is going to depend on how > you're interacting with the cache and what behavior you want. > > For example, at World Singles, we use TTL caches and have three > operations: > * evict - this uses swap! and cache/evict to remove a cache entry > * fetch - this uses get to return an entry if present > * store - this uses swap! and cache/miss to add/update a cache entry > > Since hit doesn't do anything on a TTL cache, we don't bother calling > it. If we switch to other types of cache, our fetch operation would > need to be updated to use cache/has?, swap! and cache/hit (as well as > get), or we'd need to change our API somewhat... > > It's my understanding that you can use assoc / dissoc on a cache as > synonyms for miss / evict (that seemed to be true with the version of > core.cache that I initially used - I'm fairly confident it's still > true of assoc but not so confident that dissoc still works that way... > maybe Fogus can help me out there?). > > Sean > > On Mon, Oct 22, 2012 at 2:31 PM, Sean Corfield > > > wrote: > > On Mon, Oct 22, 2012 at 1:50 PM, Hussein B. > > > > wrote: > >> c3 holds a map containing {:a 1} that will lives for two minutes. > > > > In the code I provided, c3 is an atom that holds a cache (which is the > map). > > > >> After two minutes, requesting :a is generating false since it reached > its > >> TTL but it will still live in map until it is removed explicitly by > invoking > >> evict. > > > > Because the cache itself is immutable. That's why you need to store > > the cache in an atom (so the atom can be updated to contain the > > modified cache): > > > > (defn hit-or-miss > > "Given an atom containing a cache, a key, and a value, update the > > cache and return..." > > [a k v] > > (if (cache/has? @a k) > > (cache/hit @a k) > > (cache/miss @a k v))) > > > > ... (swap! c3 hit-or-miss :c 42) ... > > > >> On Monday, October 22, 2012 11:15:06 PM UTC+3, Sean Corfield wrote: > >>> In other words you need something like this: > >>> > >>> (def c3 (atom (cache/ttl-cache-factory {:a 1} :ttl 2))) > >>> user=> @c3 > >>> {:a 1} > >>> user=> (cache/has? @c3 :a) > >>> true > >>> user=> (cache/has? @c3 :a) > >>> false > >>> user=> @c3 > >>> {:a 1} > >>> user=> (swap! c3 cache/evict :a) > >>> {} > >>> user=> @c3 > >>> {} > > > > -- > Sean A Corfield -- (904) 302-SEAN > An Architect's View -- http://corfield.org/ > World Singles, LLC. -- http://worldsingles.com/ > > "Perfection is the enemy of the good." > -- Gustave Flaubert, French realist novelist (1821-1880) > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
Just to clarify, hit does nothing for TTL (since items timeout based solely on when they were added, not when they were last touched), so swap! on the hit really makes no difference here. It would, however, be required for some of the other types of cache. Also, exactly how you use has? / hit / miss is going to depend on how you're interacting with the cache and what behavior you want. For example, at World Singles, we use TTL caches and have three operations: * evict - this uses swap! and cache/evict to remove a cache entry * fetch - this uses get to return an entry if present * store - this uses swap! and cache/miss to add/update a cache entry Since hit doesn't do anything on a TTL cache, we don't bother calling it. If we switch to other types of cache, our fetch operation would need to be updated to use cache/has?, swap! and cache/hit (as well as get), or we'd need to change our API somewhat... It's my understanding that you can use assoc / dissoc on a cache as synonyms for miss / evict (that seemed to be true with the version of core.cache that I initially used - I'm fairly confident it's still true of assoc but not so confident that dissoc still works that way... maybe Fogus can help me out there?). Sean On Mon, Oct 22, 2012 at 2:31 PM, Sean Corfield wrote: > On Mon, Oct 22, 2012 at 1:50 PM, Hussein B. wrote: >> c3 holds a map containing {:a 1} that will lives for two minutes. > > In the code I provided, c3 is an atom that holds a cache (which is the map). > >> After two minutes, requesting :a is generating false since it reached its >> TTL but it will still live in map until it is removed explicitly by invoking >> evict. > > Because the cache itself is immutable. That's why you need to store > the cache in an atom (so the atom can be updated to contain the > modified cache): > > (defn hit-or-miss > "Given an atom containing a cache, a key, and a value, update the > cache and return..." > [a k v] > (if (cache/has? @a k) > (cache/hit @a k) > (cache/miss @a k v))) > > ... (swap! c3 hit-or-miss :c 42) ... > >> On Monday, October 22, 2012 11:15:06 PM UTC+3, Sean Corfield wrote: >>> In other words you need something like this: >>> >>> (def c3 (atom (cache/ttl-cache-factory {:a 1} :ttl 2))) >>> user=> @c3 >>> {:a 1} >>> user=> (cache/has? @c3 :a) >>> true >>> user=> (cache/has? @c3 :a) >>> false >>> user=> @c3 >>> {:a 1} >>> user=> (swap! c3 cache/evict :a) >>> {} >>> user=> @c3 >>> {} -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ "Perfection is the enemy of the good." -- Gustave Flaubert, French realist novelist (1821-1880) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
On Mon, Oct 22, 2012 at 1:50 PM, Hussein B. wrote: > c3 holds a map containing {:a 1} that will lives for two minutes. In the code I provided, c3 is an atom that holds a cache (which is the map). > After two minutes, requesting :a is generating false since it reached its > TTL but it will still live in map until it is removed explicitly by invoking > evict. Because the cache itself is immutable. That's why you need to store the cache in an atom (so the atom can be updated to contain the modified cache): (defn hit-or-miss "Given an atom containing a cache, a key, and a value, update the cache and return..." [a k v] (if (cache/has? @a k) (cache/hit @a k) (cache/miss @a k v))) ... (swap! c3 hit-or-miss :c 42) ... > On Monday, October 22, 2012 11:15:06 PM UTC+3, Sean Corfield wrote: >> In other words you need something like this: >> >> (def c3 (atom (cache/ttl-cache-factory {:a 1} :ttl 2))) >> user=> @c3 >> {:a 1} >> user=> (cache/has? @c3 :a) >> true >> user=> (cache/has? @c3 :a) >> false >> user=> @c3 >> {:a 1} >> user=> (swap! c3 cache/evict :a) >> {} >> user=> @c3 >> {} -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
I see. But I didn't really grasp the whole concept firmly . c3 holds a map containing {:a 1} that will lives for two minutes. After two minutes, requesting :a is generating false since it reached its TTL but it will still live in map until it is removed explicitly by invoking evict. Correct? Also, would you please explain the recommended pattern to use core.cache for me? (if (cache/has? C :c) ;; has? checks that the cache contains an item (cache/hit C :c);; hit returns a cache with any relevant internal information updated (cache/miss C :c 42)) ;; miss returns a new cache with the new item and without evicted entries What I'm thinking of is a map that will remove an entry automatically (without calling evict) after TTL. Thanks a lot! On Monday, October 22, 2012 11:15:06 PM UTC+3, Sean Corfield wrote: > > On Mon, Oct 22, 2012 at 12:05 PM, Michael Fogus > > > wrote: > > First, thanks for trying c.c.cache! The answer to your question is > > that the TTL cache implementation is non-destructive. The `evict` > > call returns the cache without the element, but does not remove it > > from the original cache. > > In other words you need something like this: > > (def c3 (atom (cache/ttl-cache-factory {:a 1} :ttl 2))) > user=> @c3 > {:a 1} > user=> (cache/has? @c3 :a) > true > user=> (cache/has? @c3 :a) > false > user=> @c3 > {:a 1} > user=> (swap! c3 cache/evict :a) > {} > user=> @c3 > {} > > -- > Sean A Corfield -- (904) 302-SEAN > An Architect's View -- http://corfield.org/ > World Singles, LLC. -- http://worldsingles.com/ > > "Perfection is the enemy of the good." > -- Gustave Flaubert, French realist novelist (1821-1880) > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
On Mon, Oct 22, 2012 at 12:05 PM, Michael Fogus wrote: > First, thanks for trying c.c.cache! The answer to your question is > that the TTL cache implementation is non-destructive. The `evict` > call returns the cache without the element, but does not remove it > from the original cache. In other words you need something like this: (def c3 (atom (cache/ttl-cache-factory {:a 1} :ttl 2))) user=> @c3 {:a 1} user=> (cache/has? @c3 :a) true user=> (cache/has? @c3 :a) false user=> @c3 {:a 1} user=> (swap! c3 cache/evict :a) {} user=> @c3 {} -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ "Perfection is the enemy of the good." -- Gustave Flaubert, French realist novelist (1821-1880) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
Wow, What an honor to get a reply from my idol and mentor !! Thanks a lot. I really appreciate to hear your opinion regarding this: http://stackoverflow.com/questions/13015906/is-it-safe-to-use-a-clojure-core-cache-guarded-by-ref-type Every thing started with this issue. Appreciate your precious time. On Monday, October 22, 2012 10:05:25 PM UTC+3, Fogus wrote: > > > What I'm missing? > > First, thanks for trying c.c.cache! The answer to your question is > that the TTL cache implementation is non-destructive. The `evict` > call returns the cache without the element, but does not remove it > from the original cache. > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Understanding clojure.core.cache TTL cache
> What I'm missing? First, thanks for trying c.c.cache! The answer to your question is that the TTL cache implementation is non-destructive. The `evict` call returns the cache without the element, but does not remove it from the original cache. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Understanding clojure.core.cache TTL cache
Hi, I created this: (def c3 (cache/ttl-cache-factory {:a 1} :ttl 2)) user=> c3 {:a 1} user=> (cache/has? c3 :a) true user=> (cache/has? c3 :a) false user=> c3 {:a 1} user=> (cache/evict c3 :a) {} user=> c3 {:a 1} After TTL, cache doesn't has :a entry but printing the var shows the map contains :a Then evicting :a shows {} but printing the c3 shows again the map contains :a What I'm missing? Thanks for help and time -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en