memory.go

 1package ratelimiter
 2
 3import (
 4	"errors"
 5	"time"
 6)
 7
 8const (
 9	GC_SIZE   int           = 100
10	GC_PERIOD time.Duration = 60 * time.Second
11)
12
13type Memory struct {
14	store           map[string]LeakyBucket
15	lastGCCollected time.Time
16}
17
18func NewMemory() *Memory {
19	m := new(Memory)
20	m.store = make(map[string]LeakyBucket)
21	m.lastGCCollected = time.Now()
22	return m
23}
24
25func (m *Memory) GetBucketFor(key string) (*LeakyBucket, error) {
26
27	bucket, ok := m.store[key]
28	if !ok {
29		return nil, errors.New("miss")
30	}
31
32	return &bucket, nil
33}
34
35func (m *Memory) SetBucketFor(key string, bucket LeakyBucket) error {
36
37	if len(m.store) > GC_SIZE {
38		m.GarbageCollect()
39	}
40
41	m.store[key] = bucket
42
43	return nil
44}
45
46func (m *Memory) GarbageCollect() {
47	now := time.Now()
48
49	// rate limit GC to once per minute
50	if now.Unix() >= m.lastGCCollected.Add(GC_PERIOD).Unix() {
51		for key, bucket := range m.store {
52			// if the bucket is drained, then GC
53			if bucket.DrainedAt().Unix() < now.Unix() {
54				delete(m.store, key)
55			}
56		}
57
58		m.lastGCCollected = now
59	}
60}