@@ -2,6 +2,7 @@ package stores
22
33import (
44 "fmt"
5+ "sort"
56 "strings"
67 "sync"
78 "time"
@@ -10,6 +11,8 @@ import (
1011const (
1112 // Maximum entries to keep in session storage
1213 maxCacheSize = 1000
14+ // Cache clear interval
15+ clearInterval = 10 * time .Minute
1316)
1417
1518// SessionEntry is the struct for entry stored in store
@@ -20,30 +23,64 @@ type SessionEntry struct {
2023
2124// SessionStore struct to store the env variables
2225type SessionStore struct {
23- mutex sync.Mutex
24- store map [string ]* SessionEntry
25- itemsToEvict []string
26+ wg sync.WaitGroup
27+ mutex sync.RWMutex
28+ store map [string ]* SessionEntry
29+ // stores expireTime: key to remove data when cache is full
30+ // map is sorted by key so older most entry can be deleted first
31+ keyIndex map [int64 ]string
32+ stop chan struct {}
2633}
2734
2835// NewSessionStore create a new session store
2936func NewSessionStore () * SessionStore {
30- return & SessionStore {
31- mutex : sync.Mutex {},
32- store : make (map [string ]* SessionEntry ),
37+ store := & SessionStore {
38+ mutex : sync.RWMutex {},
39+ store : make (map [string ]* SessionEntry ),
40+ keyIndex : make (map [int64 ]string ),
41+ stop : make (chan struct {}),
42+ }
43+ store .wg .Add (1 )
44+ go func () {
45+ defer store .wg .Done ()
46+ store .clean ()
47+ }()
48+ return store
49+ }
50+
51+ func (s * SessionStore ) clean () {
52+ t := time .NewTicker (clearInterval )
53+ defer t .Stop ()
54+ for {
55+ select {
56+ case <- s .stop :
57+ return
58+ case <- t .C :
59+ s .mutex .Lock ()
60+ currentTime := time .Now ().Unix ()
61+ for k , v := range s .store {
62+ if v .ExpiresAt < currentTime {
63+ delete (s .store , k )
64+ delete (s .keyIndex , v .ExpiresAt )
65+ }
66+ }
67+ s .mutex .Unlock ()
68+ }
3369 }
3470}
3571
3672// Get returns the value of the key in state store
3773func (s * SessionStore ) Get (key , subKey string ) string {
38- s .mutex .Lock ()
39- defer s .mutex .Unlock ()
74+ s .mutex .RLock ()
75+ defer s .mutex .RUnlock ()
4076 currentTime := time .Now ().Unix ()
4177 k := fmt .Sprintf ("%s:%s" , key , subKey )
4278 if v , ok := s .store [k ]; ok {
4379 if v .ExpiresAt > currentTime {
4480 return v .Value
4581 }
46- s .itemsToEvict = append (s .itemsToEvict , k )
82+ // Delete expired items
83+ delete (s .store , k )
4784 }
4885 return ""
4986}
@@ -54,17 +91,25 @@ func (s *SessionStore) Set(key string, subKey, value string, expiration int64) {
5491 defer s .mutex .Unlock ()
5592 k := fmt .Sprintf ("%s:%s" , key , subKey )
5693 if _ , ok := s .store [k ]; ! ok {
57- s .store [k ] = & SessionEntry {
58- Value : value ,
59- ExpiresAt : expiration ,
60- // TODO add expire time
94+ // check if there is enough space in cache
95+ // else delete entries based on FIFO
96+ if len (s .store ) == maxCacheSize {
97+ // remove older most entry
98+ sortedKeys := []int64 {}
99+ for ik := range s .keyIndex {
100+ sortedKeys = append (sortedKeys , ik )
101+ }
102+ sort .Slice (sortedKeys , func (i , j int ) bool { return sortedKeys [i ] < sortedKeys [j ] })
103+ itemToRemove := sortedKeys [0 ]
104+ delete (s .store , s .keyIndex [itemToRemove ])
105+ delete (s .keyIndex , itemToRemove )
61106 }
62107 }
63108 s .store [k ] = & SessionEntry {
64109 Value : value ,
65110 ExpiresAt : expiration ,
66- // TODO add expire time
67111 }
112+ s .keyIndex [expiration ] = k
68113}
69114
70115// RemoveAll all values for given key
0 commit comments