bucket.go | ||
bucket_test.go | ||
cache.go | ||
cache_test.go | ||
configuration.go | ||
item.go | ||
item_test.go | ||
license.txt | ||
readme.md |
CCache
CCache is an LRU Cache, written in Go, focused on supporting high concurrency.
Lock contention on the list is reduced by:
- Introducing a window which limits the frequency that an item can get promoted
- Using a buffered channel to queue promotions for a single worker
- Garbage collecting within the same thread as the worker
Setup
First, download the project:
go get github.com/karlseguin/ccache
Configuration
Next, import and create a ccache
instance:
import (
"github.com/karlseguin/ccache"
)
var cache = ccache.New(ccache.Configure())
Configure
exposes a chainable API:
var cache = ccache.New(ccache.Configure().MaxItems(1000).itemsToPrune(100))
The most likely configuration options to tweak are:
MaxItems(int)
- the maximum number of items to store in the cache (default: 5000)GetsPerPromote(int)
- the number of times an item is fetched before we promote it. For large caches with long TTLs, it normally isn't necessary to promote an item after every fetch (default: 3)ItemsToPrune(int)
- the number of items to prune when we hitMaxItems
. Freeing up more than 1 slot at a time improved performance (default: 500)
Configurations that change the internals of the cache, which aren't as likely to need tweaking:
Buckets
- ccache shards its internal map to provide a greater amount of concurrency. The number of buckets is configurable (default: 16)PromoteBuffer(int)
- the size of the buffer to use to queue promotions (default: 1024)DeleteBuffer(int)
the size of the buffer to use to queue deletions (default: 1024)
Usage
Once the cache is setup, you can Get
, Set
and Delete
items from it. A Get
returns an interface{}
which you'll want to cast back to the type of object you stored:
item := cache.Get("user:4")
if item == nil {
//handle
} else {
user := item.(*User)
}
Set
expects the key, value and ttl:
cache.Set("user:4", user, time.Minute * 10)
There's also a Fetch
which mixes a Get
and a Set
:
item, err := cache.Fetch("user:4", time.Minute * 10, func() (interface{}, error) {
//code to fetch the data incase of a miss
//should return the data to cache and the error, if any
})
Tracking
ccache supports a special tracking mode which is meant to be used in conjunction with other pieces of your code that maintains a long-lived reference to data.
When you configure your cache with Track()
:
cache = ccache.New(ccache.Configure().Track())
The items retrieved via TrackingGet
will not be eligible for purge until Release
is called on them:
item := cache.TrackingGet("user:4")
user := item.Value() //will be nil if "user:4" didn't exist in the cache
item.Release() //can be called even if item.Value() returned nil
In practive, Release
wouldn't be called until later, at some other place in your code.
There's a couple reason to use the tracking mode if other parts of your code also hold references to objects. First, if you're already going to hold a reference to these objects, there's really no reason not to have them in the cache - the memory is used up anyways.
More important, it helps ensure that you're code returns consistent data. With tracking, "user:4" might be purged, and a subsequent Fetch
would reload the data. This can result in different versions of "user:4" being returned by different parts of your system.