ttlcache icon indicating copy to clipboard operation
ttlcache copied to clipboard

PurgeCallback to be called on Purge()

Open fxff opened this issue 2 years ago • 5 comments

I needed a callback to be called on Purge. If I just wrapped it in an internal package, I'd invent a possible race condition:

thread1 purges 
thread2 adds
add callback
purge callback

Thus this PR.

fxff avatar Mar 02 '22 15:03 fxff

Sorry for the delay. It was a bit busy here.

I notice in your PR that you try to avoid a race condition, but in any case you are also introducing one by not having a lock around the SetPurgeCallback call. If you can add that then i think we can add it.

ReneKroon avatar Mar 14 '22 08:03 ReneKroon

It is worth noting that v3 has a similar (if not the same) feature: it calls all registered callbacks when DeleteAll() (the successor of Purge() ) is called.

swithek avatar Mar 14 '22 12:03 swithek

So you can update this for v2, or wait a few weeks for v3 (with generics support)

ReneKroon avatar Mar 14 '22 15:03 ReneKroon

Now it's me, who was busy.

Yes, lack of mutex in SetPurgeCallback is definitely a miss (and inconsistency). I'll try to update it to v2 soon.

My point was to invent a dedicated callback for Purge() to let user know that absolutely everything is deleted. As far as I understand, v3 calls Evict callback for every deleted item: that leads to multiple calls instead of one. In my case I wanted to cleanup some linked data and clean it once.

fxff avatar Mar 30 '22 14:03 fxff

In v3, cache.Len() can be combined with cache.OnEviction() to achieve what you need:

var (
     mu sync.Mutex
     needsCleanup bool
)

cache.OnEviction(func(ctx context.Context, r EvictionReason, item *Item[K, V]) {
     if r != EvictionReasonDeleted || cache.Len() > 0 {
           return
     }
     
     mu.Lock()
     defer mu.Unlock()
             
     if needsCleanup {
             needsCleanup = false
             go func() {
                   // clean up
             }() 
     }
})

cache.OnInsertion(func(ctx context.Context, item *Item[K, V]) {
        if cache.Len() == 0 {
             return
        }

        mu.Lock()
        defer mu.Unlock()
             
        if !needsCleanup {
               needsCleanup = true
               go func() {
                      // set up
               }() 
        }
})

swithek avatar Apr 01 '22 10:04 swithek

I'm closing this PR since the same result can already be achieved in the latest version.

swithek avatar Oct 19 '22 14:10 swithek