Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 package util | 1 package util |
| 2 | 2 |
| 3 import ( | 3 import ( |
| 4 "encoding/json" | 4 "encoding/json" |
| 5 "reflect" | 5 "reflect" |
| 6 "sync" | 6 "sync" |
| 7 | 7 |
| 8 "github.com/golang/groupcache/lru" | 8 "github.com/golang/groupcache/lru" |
| 9 ) | 9 ) |
| 10 | 10 |
| 11 // Generic LRUCache interface. | 11 // Generic LRUCache interface. |
| 12 type LRUCache interface { | 12 type LRUCache interface { |
| 13 // Add adds a key-value pair to the cache. | 13 // Add adds a key-value pair to the cache. |
| 14 Add(key, value interface{}) bool | 14 Add(key, value interface{}) bool |
| 15 | 15 |
| 16 // Get returns a key value for the given cache. If ok is true | 16 // Get returns a key value for the given cache. If ok is true |
| 17 // the fetch was succesfull. | 17 // the fetch was succesfull. |
| 18 Get(key interface{}) (value interface{}, ok bool) | 18 Get(key interface{}) (value interface{}, ok bool) |
| 19 | 19 |
| 20 // Len returns the current size of the cache. | 20 // Len returns the current size of the cache. |
| 21 Len() int | 21 Len() int |
| 22 | 22 |
| 23 // Remove removes a key value pair from the cache. | 23 // Remove removes a key value pair from the cache. |
| 24 Remove(key interface{}) | 24 Remove(key interface{}) |
| 25 | |
| 26 // Keys returns all the keys in the LRUCache. | |
| 27 Keys() []interface{} | |
| 25 } | 28 } |
| 26 | 29 |
| 27 // LRUCodec converts serializes/deserializes an instance of a type to/from | 30 // LRUCodec converts serializes/deserializes an instance of a type to/from |
| 28 // byte arrays. Encode and Decode have to be the inverse of each other. | 31 // byte arrays. Encode and Decode have to be the inverse of each other. |
| 29 type LRUCodec interface { | 32 type LRUCodec interface { |
| 30 // Encode serializes the given value to a byte array (inverse of Decode) . | 33 // Encode serializes the given value to a byte array (inverse of Decode) . |
| 31 Encode(interface{}) ([]byte, error) | 34 Encode(interface{}) ([]byte, error) |
| 32 | 35 |
| 33 // Decode deserializes the byte array to an instance of the type that | 36 // Decode deserializes the byte array to an instance of the type that |
| 34 // was passed to Encode in a prior call. | 37 // was passed to Encode in a prior call. |
| 35 Decode([]byte) (interface{}, error) | 38 Decode([]byte) (interface{}, error) |
| 36 } | 39 } |
| 37 | 40 |
| 38 type MemLRUCache struct { | 41 type MemLRUCache struct { |
| 39 cache *lru.Cache | 42 cache *lru.Cache |
| 43 keys map[string]bool | |
| 40 mutex sync.RWMutex | 44 mutex sync.RWMutex |
| 41 } | 45 } |
| 42 | 46 |
| 43 func NewMemLRUCache(maxEntries int) *MemLRUCache { | 47 func NewMemLRUCache(maxEntries int) *MemLRUCache { |
| 44 » return &MemLRUCache{ | 48 » ret := &MemLRUCache{ |
| 45 cache: lru.New(maxEntries), | 49 cache: lru.New(maxEntries), |
| 50 keys: map[string]bool{}, | |
| 46 } | 51 } |
| 52 | |
| 53 ret.cache.OnEvicted = func(key lru.Key, value interface{}) { | |
| 54 delete(ret.keys, getStringKey(key)) | |
| 55 } | |
| 56 | |
| 57 return ret | |
| 58 } | |
| 59 | |
| 60 func getStringKey(key interface{}) string { | |
| 61 k := "" | |
| 62 switch key := key.(type) { | |
| 63 case string: | |
| 64 k = key | |
| 65 case []byte: | |
| 66 if key != nil { | |
| 67 k = string(key) | |
| 68 } | |
| 69 } | |
| 70 return k | |
| 47 } | 71 } |
| 48 | 72 |
| 49 func (m *MemLRUCache) Add(key, value interface{}) bool { | 73 func (m *MemLRUCache) Add(key, value interface{}) bool { |
| 50 m.mutex.Lock() | 74 m.mutex.Lock() |
| 51 defer m.mutex.Unlock() | 75 defer m.mutex.Unlock() |
| 52 m.cache.Add(key, value) | 76 m.cache.Add(key, value) |
| 77 m.keys[getStringKey(key)] = true | |
| 53 return true | 78 return true |
| 54 } | 79 } |
| 55 | 80 |
| 56 func (m *MemLRUCache) Get(key interface{}) (value interface{}, ok bool) { | 81 func (m *MemLRUCache) Get(key interface{}) (value interface{}, ok bool) { |
| 57 m.mutex.RLock() | 82 m.mutex.RLock() |
| 58 m.mutex.RUnlock() | 83 m.mutex.RUnlock() |
| 59 return m.cache.Get(key) | 84 return m.cache.Get(key) |
| 60 } | 85 } |
| 61 | 86 |
| 62 func (m *MemLRUCache) Len() int { | 87 func (m *MemLRUCache) Len() int { |
| 63 m.mutex.RLock() | 88 m.mutex.RLock() |
| 64 m.mutex.RUnlock() | 89 m.mutex.RUnlock() |
| 65 return m.cache.Len() | 90 return m.cache.Len() |
| 66 } | 91 } |
| 67 | 92 |
| 68 func (m *MemLRUCache) Remove(key interface{}) { | 93 func (m *MemLRUCache) Remove(key interface{}) { |
| 69 m.mutex.Lock() | 94 m.mutex.Lock() |
| 70 defer m.mutex.Unlock() | 95 defer m.mutex.Unlock() |
| 96 m.cache.Remove(key) | |
| 97 delete(m.keys, getStringKey(key)) | |
| 98 } | |
| 99 | |
| 100 func (m *MemLRUCache) Keys() []interface{} { | |
|
jcgregorio
2015/10/13 18:40:24
Needs unit tests.
stephana
2015/10/14 14:26:30
Done. I factored out tests from redisutils to be a
| |
| 101 m.mutex.RLock() | |
| 102 m.mutex.RUnlock() | |
|
jcgregorio
2015/10/13 18:40:24
defer m.mutex.RUnlock()
stephana
2015/10/14 14:26:30
Good catch. Fixed.
| |
| 103 ret := make([]interface{}, 0, len(m.keys)) | |
| 104 for k := range m.keys { | |
| 105 ret = append(ret, k) | |
| 106 } | |
| 107 return ret | |
| 71 } | 108 } |
| 72 | 109 |
| 73 type jsonCodec struct { | 110 type jsonCodec struct { |
| 74 targetType reflect.Type | 111 targetType reflect.Type |
| 75 isSlice bool | 112 isSlice bool |
| 76 } | 113 } |
| 77 | 114 |
| 78 // JSONCodec implements the LRUCodec interface by serializing and | 115 // JSONCodec implements the LRUCodec interface by serializing and |
| 79 // deserializing instances of the underlying type of 'instance'. | 116 // deserializing instances of the underlying type of 'instance'. |
| 80 // Generally it's assumed that 'instance' is a struct, a pointer to | 117 // Generally it's assumed that 'instance' is a struct, a pointer to |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 101 ret := reflect.New(j.targetType).Interface() | 138 ret := reflect.New(j.targetType).Interface() |
| 102 err := json.Unmarshal(byteData, ret) | 139 err := json.Unmarshal(byteData, ret) |
| 103 if err != nil { | 140 if err != nil { |
| 104 return nil, err | 141 return nil, err |
| 105 } else if j.isSlice { | 142 } else if j.isSlice { |
| 106 return reflect.ValueOf(ret).Elem().Interface(), nil | 143 return reflect.ValueOf(ret).Elem().Interface(), nil |
| 107 } | 144 } |
| 108 | 145 |
| 109 return ret, nil | 146 return ret, nil |
| 110 } | 147 } |
| OLD | NEW |