• Stars
    star
    1,249
  • Rank 36,247 (Top 0.8 %)
  • Language
    Go
  • License
    MIT License
  • Created over 10 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A golang LRU Cache for high concurrency

CCache

Generic version is on the way: https://github.com/karlseguin/ccache/tree/generic

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

Unless otherwise stated, all methods are thread-safe.

The non-generic version of this cache can be imported via github.com/karlseguin/ccache/.

Configuration

Import and create a Cache instance:

import (
  github.com/karlseguin/ccache/v3
)

// create a cache with string values
var cache = ccache.New(ccache.Configure[string]())

Configure exposes a chainable API:

// creates a cache with int values
var cache = ccache.New(ccache.Configure[int]().MaxSize(1000).ItemsToPrune(100))

The most likely configuration options to tweak are:

  • MaxSize(int) - the maximum number size 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 hit MaxSize. 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. Must be a power of 2 (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 *Item:

Get

item := cache.Get("user:4")
if item == nil {
  //handle
} else {
  user := item.Value()
}

The returned *Item exposes a number of methods:

  • Value() T - the value cached
  • Expired() bool - whether the item is expired or not
  • TTL() time.Duration - the duration before the item expires (will be a negative value for expired items)
  • Expires() time.Time - the time the item will expire

By returning expired items, CCache lets you decide if you want to serve stale content or not. For example, you might decide to serve up slightly stale content (< 30 seconds old) while re-fetching newer data in the background. You might also decide to serve up infinitely stale content if you're unable to get new data from your source.

GetWithoutPromote

Same as Get but does not "promote" the value, which is to say it circumvents the "lru" aspect of this cache. Should only be used in limited cases, such as peaking at the value.

Set

Set expects the key, value and ttl:

cache.Set("user:4", user, time.Minute * 10)

Fetch

There's also a Fetch which mixes a Get and a Set:

item, err := cache.Fetch("user:4", time.Minute * 10, func() (*User, error) {
  //code to fetch the data incase of a miss
  //should return the data to cache and the error, if any
})

Fetch doesn't do anything fancy: it merely uses the public Get and Set functions. If you want more advanced behavior, such as using a singleflight to protect against thundering herd, support a callback that accepts the key, or returning expired items, you should implement that in your application.

Delete

Delete expects the key to delete. It's ok to call Delete on a non-existent key:

cache.Delete("user:4")

DeletePrefix

DeletePrefix deletes all keys matching the provided prefix. Returns the number of keys removed.

DeleteFunc

DeleteFunc deletes all items that the provided matches func evaluates to true. Returns the number of keys removed.

ForEachFunc

ForEachFunc iterates through all keys and values in the map and passes them to the provided function. Iteration stops if the function returns false. Iteration order is random.

Clear

Clear clears the cache. If the cache's gc is running, Clear waits for it to finish.

Extend

The life of an item can be changed via the Extend method. This will change the expiry of the item by the specified duration relative to the current time.

Replace

The value of an item can be updated to a new value without renewing the item's TTL or it's position in the LRU:

cache.Replace("user:4", user)

Replace returns true if the item existed (and thus was replaced). In the case where the key was not in the cache, the value is not inserted and false is returned.

GetDropped

You can get the number of keys evicted due to memory pressure by calling GetDropped:

dropped := cache.GetDropped()

The counter is reset on every call. If the cache's gc is running, GetDropped waits for it to finish; it's meant to be called asynchronously for statistics /monitoring purposes.

Stop

The cache's background worker can be stopped by calling Stop. Once Stop is called the cache should not be used (calls are likely to panic). Stop must be called in order to allow the garbage collector to reap the cache.

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[int]().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 practice, Release wouldn't be called until later, at some other place in your code. TrackingSet can be used to set a value to be tracked.

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 your 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.

LayeredCache

CCache's LayeredCache stores and retrieves values by both a primary and secondary key. Deletion can happen against either the primary and secondary key, or the primary key only (removing all values that share the same primary key).

LayeredCache is useful for HTTP caching, when you want to purge all variations of a request.

LayeredCache takes the same configuration object as the main cache, exposes the same optional tracking capabilities, but exposes a slightly different API:

cache := ccache.Layered(ccache.Configure[string]())

cache.Set("/users/goku", "type:json", "{value_to_cache}", time.Minute * 5)
cache.Set("/users/goku", "type:xml", "<value_to_cache>", time.Minute * 5)

json := cache.Get("/users/goku", "type:json")
xml := cache.Get("/users/goku", "type:xml")

cache.Delete("/users/goku", "type:json")
cache.Delete("/users/goku", "type:xml")
// OR
cache.DeleteAll("/users/goku")

SecondaryCache

In some cases, when using a LayeredCache, it may be desirable to always be acting on the secondary portion of the cache entry. This could be the case where the primary key is used as a key elsewhere in your code. The SecondaryCache is retrieved with:

cache := ccache.Layered(ccache.Configure[string]())
sCache := cache.GetOrCreateSecondaryCache("/users/goku")
sCache.Set("type:json", "{value_to_cache}", time.Minute * 5)

The semantics for interacting with the SecondaryCache are exactly the same as for a regular Cache. However, one difference is that Get will not return nil, but will return an empty 'cache' for a non-existent primary key.

Size

By default, items added to a cache have a size of 1. This means that if you configure MaxSize(10000), you'll be able to store 10000 items in the cache.

However, if the values you set into the cache have a method Size() int64, this size will be used. Note that ccache has an overhead of ~350 bytes per entry, which isn't taken into account. In other words, given a filled up cache, with MaxSize(4096000) and items that return a Size() int64 of 2048, we can expect to find 2000 items (4096000/2048) taking a total space of 4796000 bytes.

Want Something Simpler?

For a simpler cache, checkout out rcache

More Repositories

1

the-little-go-book

TeX
2,119
star
2

the-little-mongodb-book

The Little MongoDB Book
TeX
1,491
star
3

the-little-redis-book

TeX
1,431
star
4

http.zig

An HTTP/1.1 server for zig
Zig
345
star
5

websocket.zig

A websocket implementation for zig
Zig
221
star
6

Algorithms

Algorithms
JavaScript
152
star
7

pg.zig

Native PostgreSQL driver / client for Zig
Zig
108
star
8

Foundations-of-Programming-2

103
star
9

typed

A wrapper around map[string]interface{} to provide some strong typing
Go
88
star
10

log.zig

A structured logger for Zig
Zig
68
star
11

zuckdb.zig

A DuckDB driver for Zig
Zig
59
star
12

zul

zig utility library
Zig
59
star
13

liquid

Liquid Template Engine for Go
Go
56
star
14

the-little-introduction-to-programming

The Little Introduction To Programming
CSS
43
star
15

Mongo-Web-Admin

A web-based shell for MongoDB
JavaScript
36
star
16

scaling-viki

Scaling Viki
35
star
17

parse-dotnet

A Windows Phone library for Parse.com
C#
35
star
18

Metsys.Bson

A BSON serializer/deserializer for .NET
C#
32
star
19

mongly

The MongoDB Collection is a group of essays for mastering MongoDB
JavaScript
31
star
20

rcache

A simple cache meant to hold a small number of values
Go
28
star
21

cache.zig

A thread-safe, expiration-aware, LRU cache for Zig
Zig
26
star
22

zqlite.zig

A thin SQLite wrapper for Zig
C
26
star
23

bytepool

Thread safe []byte pool for Go
Go
26
star
24

gerb

An erb inspired templating engine for Go
Go
23
star
25

dcache

A simple elixir cache
Elixir
23
star
26

metrics.zig

Prometheus metrics for library and application developers
Zig
22
star
27

expect

A testing framework for Go
Go
21
star
28

router

A fast standalone router for Go.
Go
19
star
29

jsonwriter

Manually write JSON to an io.Writer
Go
19
star
30

Metsys.WebOp

Web Optimization Framework for ASP.NET
C#
18
star
31

aolium-api

API server for aolium.com
C
17
star
32

jquery.simpleDatePicker

JavaScript
16
star
33

ratelimit

A rate limit library for go
Go
16
star
34

nabu

in-memory go-based set query engine
Go
15
star
35

validate.zig

A validation framework for Zig
Zig
15
star
36

sq

Go
15
star
37

Foundations-of-Programming-Ebook

14
star
38

blog

https://www.openmymind.net/
HTML
14
star
39

MyLittleBlog

My first Rails application - a very lightweight blog, powering www.openmymind.net
JavaScript
14
star
40

jobs.openmymind.net

I'm bored
Ruby
13
star
41

mongospy

Develop with the MongoDB Profiler shown in your browser's console
JavaScript
13
star
42

redisync

Redis Disk Persisting Slave
Go
12
star
43

MongoPlus

Making the Mongo Shell More Magical, One Hack At A Time
JavaScript
12
star
44

exws

Elixir Websocket - Kitchen Sink Not Included
Elixir
11
star
45

gofake

A stub helper for writing effective golang tests.
Go
11
star
46

scratch

Pool of []ints and []string
Go
11
star
47

mongowatch

[Very] Simple MongoDB monitor
JavaScript
11
star
48

jquery.dateRange

JavaScript
10
star
49

buffer.zig

A poolable string builder (aka string buffer) for Zig
Zig
10
star
50

pots-web

Points of Interest demo site
JavaScript
8
star
51

smtp_client.zig

SMTP client for Zig
Zig
8
star
52

intset

golang int set
Go
8
star
53

params

An efficient way to represents small map[string]string
Go
7
star
54

golang-set-fun

Playing with Go and testing Set implementation
Go
7
star
55

MongoLight

A lightweight ORM for Rails and MongoDB
Ruby
7
star
56

redispy-web

web-based redis montior
CoffeeScript
7
star
57

Metsys.Little

A fast and compact binary [de]serializer for .NET
C#
7
star
58

pbuf

An Elixir Library for Protocol Buffer 3. Focused on encoding and decoding speed.
Elixir
6
star
59

auditor

A sample project that uses Amazon's DynamoDB
CoffeeScript
6
star
60

benchmark.zig

Simple Benchmarking for Zig
Zig
6
star
61

aproxi

API proxy
CoffeeScript
6
star
62

lazycache

Lazy cache for Go
Go
5
star
63

Alternator

A locally-hosted DynamoDB emulator
CoffeeScript
5
star
64

hydrator

Sample hydrator code
Go
5
star
65

csv_parser

A simple CSV (.csv, .xlsx) parser for elixir
Elixir
4
star
66

pots-importer

C#
4
star
67

node-model

lightweight model facility for node.js
CoffeeScript
4
star
68

cmap

concurrent-safe map[string]interface for golang
Go
4
star
69

Metsys.Validate

An ASP.NET MVC validation framework
C#
4
star
70

jstub

a lightweight javascript stubbing framework
JavaScript
4
star
71

mongodb-tutorial

JavaScript
4
star
72

Metsys.Caching

A .NET Caching API
C#
4
star
73

autocomplete

Autocomplete engine for Go
Go
3
star
74

redispy

expose Redis' monitor output as a node.js package
CoffeeScript
3
star
75

vendor

Minimalist Go Dependencies Management
Go
3
star
76

Metsys.Redis

C#
3
star
77

trie

A trie written in go
Go
3
star
78

dnscache

A DNS Cache for Go
Go
2
star
79

mashape-dotnet-client-library

.NET client driver for mashape.com
C#
2
star
80

monet

A MonetDB driver for Elixir
Elixir
2
star
81

singleflight.zig

Duplicate function call suppression for Zig
Zig
2
star
82

geminex

[WIP] Gemini server in Elixir
Elixir
2
star
83

error_notifier

Ruby gem that posts errors to a specified url. Includes a rack middleware
Ruby
2
star
84

pg_exporter

A Prometheus PostgreSQL exporter for table-level metrics
Go
2
star
85

thirdlaw

do things and react
Go
2
star
86

signals

a thin wrapper around go's os/signals package
Go
2
star
87

jquery.purdyselect

makes select boxes nicer
JavaScript
2
star
88

idmap

a simple string -> int mapper for go
Go
1
star
89

MongoLight-node

A lightweight mongodb mapper for node.js
CoffeeScript
1
star
90

redislight

redis mapper for node.js
CoffeeScript
1
star
91

nd

Non-Deterministic Helper for Go
Go
1
star
92

bufferedwriter

A buffer-backed file writer for Go
Go
1
star
93

garnish

Go
1
star
94

garbage3

CoffeeScript
1
star
95

typed.zig

Tagged union that can represent many different types
Zig
1
star
96

statsreg

collector and writer for simple statistics
Go
1
star
97

garbage

garbage
CoffeeScript
1
star
98

garbage2

garbage2
CoffeeScript
1
star
99

redisha

garbage
CoffeeScript
1
star
100

scache

a simple cache for go
Go
1
star