memory.go 1.0 KB

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