https://github.com/arp242/zcache
In-memory key:value store/cache (similar to Memcached) library for Go, suitable for single-machine applications
https://github.com/arp242/zcache
cache go
Last synced: about 1 year ago
JSON representation
In-memory key:value store/cache (similar to Memcached) library for Go, suitable for single-machine applications
- Host: GitHub
- URL: https://github.com/arp242/zcache
- Owner: arp242
- License: mit
- Created: 2020-07-30T20:34:21.000Z (almost 6 years ago)
- Default Branch: v2
- Last Pushed: 2024-01-03T15:53:53.000Z (over 2 years ago)
- Last Synced: 2025-04-01T16:05:11.729Z (about 1 year ago)
- Topics: cache, go
- Language: Go
- Homepage:
- Size: 217 KB
- Stars: 68
- Watchers: 4
- Forks: 8
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
zcache is an in-memory key:value store/cache with time-based evictions.
It is suitable for applications running on a single machine. It's essentially a
thread-safe map with expiration times. Any object can be stored, for a given
duration or forever, and the cache can be safely used by multiple goroutines.
Although zcache isn't meant to be used as a persistent datastore, the contents
can be saved to and loaded from a file (using `c.Items()` to retrieve the items
map to serialize, and `NewFrom()` to create a cache from a deserialized one) to
recover from downtime quickly.
The canonical import path is `zgo.at/zcache/v2`, or `zgo.at/zcache` for the v1.
Reference docs are at https://godocs.io/zgo.at/zcache/v2 and
https://godocs.io/zgo.at/zcache
This is a fork of https://github.com/patrickmn/go-cache – which no longer seems
actively maintained. There are two versions of zcache, both of which are
maintained:
- v1 is 100% compatible with go-cache and a drop-in replacement with various
enhancements.
- v2 makes various incompatible changes to the API; some functions calls are
improved and it uses generics, which requires Go 1.18.
**This README documents v2; see [README.v1.md](/README.v1.md) for the v1
README.** See the "changes" section below for a list of changes.
Usage
-----
Some examples from `example_test.go`:
```go
func ExampleSimple() {
// Create a cache with a default expiration time of 5 minutes, and which
// purges expired items every 10 minutes.
//
// This creates a cache with string keys and values, with Go 1.18 type
// parameters.
c := zcache.New[string, string](5*time.Minute, 10*time.Minute)
// Set the value of the key "foo" to "bar", with the default expiration.
c.Set("foo", "bar")
// Set the value of the key "baz" to "never", with no expiration time. The
// item won't be removed until it's removed with c.Delete("baz").
c.SetWithExpire("baz", "never", zcache.NoExpiration)
// Get the value associated with the key "foo" from the cache; due to the
// use of type parameters this is a string, and no type assertions are
// needed.
foo, ok := c.Get("foo")
if ok {
fmt.Println(foo)
}
// Output: bar
}
func ExampleStruct() {
type MyStruct struct{ Value string }
// Create a new cache that stores a specific struct.
c := zcache.New[string, *MyStruct](zcache.NoExpiration, zcache.NoExpiration)
c.Set("cache", &MyStruct{Value: "value"})
v, _ := c.Get("cache")
fmt.Printf("%#v\n", v)
// Output: &zcache_test.MyStruct{Value:"value"}
}
func ExampleAny() {
// Create a new cache that stores any value, behaving similar to zcache v1
// or go-cache.
c := zcache.New[string, any](zcache.NoExpiration, zcache.NoExpiration)
c.Set("a", "value 1")
c.Set("b", 42)
a, _ := c.Get("a")
b, _ := c.Get("b")
// This needs type assertions.
p := func(a string, b int) { fmt.Println(a, b) }
p(a.(string), b.(int))
// Output: value 1 42
}
func ExampleProxy() {
type Site struct {
ID int
Hostname string
}
site := &Site{
ID: 42,
Hostname: "example.com",
}
// Create a new site which caches by site ID (int), and a "proxy" which
// caches by the hostname (string).
c := zcache.New[int, *Site](zcache.NoExpiration, zcache.NoExpiration)
p := zcache.NewProxy[string, int, *Site](c)
p.Set(42, "example.com", site)
siteByID, ok := c.Get(42)
fmt.Printf("%v %v\n", ok, siteByID)
siteByHost, ok := p.Get("example.com")
fmt.Printf("%v %v\n", ok, siteByHost)
// They're both the same object/pointer.
fmt.Printf("%v\n", siteByID == siteByHost)
// Output:
// true &{42 example.com}
// true &{42 example.com}
// true
}
```
Changes
-------
### Incompatible changes in v2
- Use type parameters instead of `map[string]interface{}`; you can get the same
as before with `zcache.New[string, any](..)`, but if you know you will only
store `MyStruct` you can use `zcache.New[string, *MyStruct](..)` for
additional type safety.
- Remove `Save()`, `SaveFile()`, `Load()`, `LoadFile()`; you can still persist
stuff to disk by using `Items()` and `NewFrom()`. These methods were already
deprecated.
- Rename `Set()` to `SetWithExpire()`, and rename `SetDefault()` to `Set()`.
Most of the time you want to use the default expiry time, so make that the
easier path.
- The `Increment*` and `Decrement*` functions have been removed; you can replace
them with `Modify()`:
cache := New[string, int](DefaultExpiration, 0)
cache.Set("one", 1)
cache.Modify("one", func(v int) int { return v + 1 })
The performance of this is roughly the same as the old Increment, and this is
a more generic method that can also be used for other things like appending to
a slice.
- Rename `Flush()` to `Reset()`; I think that more clearly conveys what it's
intended for as `Flush()` is typically used to flush a buffer or the like.
### Compatible changes from go-cache
All these changes are in both v1 and v2:
- Add `Keys()` to list all keys.
- Add `Touch()` to update the expiry on an item.
- Add `GetStale()` to get items even after they've expired.
- Add `Pop()` to get an item and delete it.
- Add `Modify()` to atomically modify existing cache entries (e.g. lists, maps).
- Add `DeleteAll()` to remove all items from the cache with onEvicted call.
- Add `DeleteFunc()` to remove specific items from the cache atomically.
- Add `Rename()` to rename keys, retaining the value and expiry.
- Add `Proxy` type, to access cache items under a different key.
- Various small internal and documentation improvements.
See [issue-list.markdown](/issue-list.markdown) for a complete run-down of the
PRs/issues for go-cache and what was and wasn't included.
FAQ
---
### How can I limit the size of the cache? Is there an option for this?
Not really; zcache is intended as a thread-safe map with time-based eviction.
This keeps it nice and simple. Adding something like a LRU eviction mechanism
not only makes the code more complex, it also makes the library worse for cases
where you just want a map since it requires additional memory and makes some
operations more expensive (unless a new API is added which make the API worse
for those use cases).
So unless I or someone else comes up with a way to do this which doesn't detract
anything from the simple map use case, I'd rather not add it. Perhaps wrapping
`zcache.Cache` and overriding some methods could work, but I haven't looked at
it.
tl;dr: this isn't designed to solve every caching use case. That's a feature.