There are many interfaces for caching things. This one is ours. It reads and writes io.ReadSeekCloser
instances.
This package supersedes go-whosonfirst-cache which will be retired soon.
Caches are instantiated with the cache.NewCache
method which takes as its arguments a context.Context
instance and a URI string. The URI's scheme represents the type of cache it implements and the remaining (URI) properties are used by that cache type to instantiate itself.
For example to cache files to/from a directory on the local filesystem you would write:
import (
"context"
"flag"
"github.com/whosonfirst/go-cache"
"log"
)
func main() {
ctx := context.Background()
c, _ := cache.NewCache(ctx, "fs:///usr/local/cache")
str, err := cache.GetString(c, "some-key")
if err != nil && !cache.IsCacheMiss(err) {
log.Fatal(err)
}
str, _ := cache.SetString(ctx, c, "some-key", "some-value")
str2, _ := cache.GetString(ctx, c, "some-key")
log.Println(str2)
}
Two things to note:
-
The use of the
fs://
scheme rather than the more conventionalfile://
. This is deliberate so as not to overlap with the Go CloudBlob
package's file handler. -
The use of the
cache.GetString
andcache.SetString
methods. Thecache.Cache
interface expectsio.ReadSeekCloser
instances so these methods are shortcuts to hide the boilerplate code necessary to work withio.ReadSeekCloser
interfaces.
There is also a handy null://
cache which doesn't do anything at all (expect implement the cache.Cache
interface). For example:
ctx := context.Background()
c, _ := cache.NewCache(ctx, "null://")
type Cache interface {
Name() string
Close(context.Context) error
Get(context.Context, string) (io.ReadSeekCloser, error)
Set(context.Context, string, io.ReadSeekCloser) (io.ReadSeekCloser, error)
Unset(context.Context, string) error
Hits() int64
Misses() int64
Evictions() int64
Size() int64
SizeWithContext(context.Context) int64
}
Custom caches need to:
- Implement the interface above.
- Announce their availability using the
go-cache.Cache
method on initialization.
For example, here is an abbreviated example of how the go-cache-blob is implemented:
package cache
import (
"bufio"
"bytes"
"context"
wof_cache "github.com/whosonfirst/go-cache"
"gocloud.dev/blob"
"io"
"io/ioutil"
"sync/atomic"
)
type BlobCache struct {
wof_cache.Cache
TTL int64
bucket *blob.Bucket
hits int64
misses int64
sets int64
evictions int64
}
func init() {
ctx := context.Background()
for _, scheme := range blob.DefaultURLMux().BucketSchemes() {
wof_cache.RegisterCache(ctx, scheme, NewBlobCache)
}
}
Note: See the way we're registering available cache types based on the the list of available Go Cloud Bucket
schemes? By design the go-cache-blob
doesn't try to load any Go Cloud providers. That is left up to your code.
func NewBlobCache() wof_cache.Cache {
bucket, err := blob.OpenBucket(ctx, uri)
if err != nil {
return nil, err
}
c := &BlobCache{
TTL: 0,
misses: 0,
sets: 0,
evictions: 0,
bucket: bucket,
}
return c
}
And then to use it you would do this:
package main
import (
"context"
"github.com/whosonfirst/go-cache"
_ "github.com/whosonfirst/go-cache-blob"
_ "gocloud.dev/blob/memblob"
)
func main() {
ctx := context.Background()
c, _ := cache.NewCache(ctx, "mem://")
fh, _ := c.Get(ctx, "some-key")
}
Cache data using any registered Go Cloud Blob
source. For example:
import (
"context"
"github.com/whosonfirst/go-cache"
_ "github.com/whosonfirst/go-cache-blob"
_ "gocloud.dev/blob/s3blob"
)
func main() {
ctx := context.Background()
c, _ := cache.NewCache(ctx, "s3://cache-bucket?region=us-west-1")
}
Cache data using a local filesystem.
import (
"context"
"github.com/whosonfirst/go-cache"
)
func main() {
ctx := context.Background()
c, _ := cache.NewCache(ctx, "fs:///usr/local/cache")
}
Cache data using a go-cache backend.
import (
"context"
"github.com/whosonfirst/go-cache"
)
func main() {
ctx := context.Background()
c, _ := cache.NewCache(ctx, "gocache://")
}
To specify custom values for the DefaultExpiration
and CleanupInterval
properties pass use the default_expiration
and cleanup_interval
parameters, respectively. For example:
c, _ := cache.NewCache(ctx, "gocache://?default_expiration=300&cleanup_interval=200")
Pretend to cache data.
import (
"context"
"github.com/whosonfirst/go-cache"
)
func main() {
ctx := context.Background()
c, _ := cache.NewCache(ctx, "null://")
}