Skip to content

Commit 5aeff7e

Browse files
committed
Review comments #1.
1 parent ad8a340 commit 5aeff7e

File tree

2 files changed

+37
-56
lines changed

2 files changed

+37
-56
lines changed

balancer/rls/internal/cache/cache.go

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727

2828
"google.golang.org/grpc/grpclog"
2929
"google.golang.org/grpc/internal/backoff"
30-
"google.golang.org/grpc/status"
3130
)
3231

3332
// Key represents the cache key used to uniquely identify a cache entry.
@@ -44,9 +43,9 @@ type Key struct {
4443
// Entry wraps all the data to be stored in a cache entry.
4544
type Entry struct {
4645
// Mu synchronizes access to this particular cache entry. The LB policy
47-
// will also hold another mutex to synchornize access to the cache as a
46+
// will also hold another mutex to synchronize access to the cache as a
4847
// whole. To avoid holding the top-level mutex for the whole duration for
49-
// which one particular cache entry is acted up, we use this entry mutex.
48+
// which one particular cache entry is acted upon, we use this entry mutex.
5049
Mu sync.Mutex
5150
// ExpiryTime is the absolute time at which the data cached as part of this
5251
// entry stops being valid. When an RLS request succeeds, this is set to
@@ -74,9 +73,10 @@ type Entry struct {
7473
// new entry added to the cache is not evicted before the RLS response
7574
// arrives (usually when the cache is too small).
7675
EarliestEvictTime time.Time
77-
// CallStatus stores the RPC status of the previous RLS request. Picks for
78-
// entries with a non-OK status are failed with the error stored here.
79-
CallStatus *status.Status
76+
// CallStatus stores the RPC status of the previous RLS request for this
77+
// entry. Picks for entries with a non-nil value for this field are failed
78+
// with the error stored here.
79+
CallStatus error
8080
// Backoff contains all backoff related state. When an RLS request
8181
// succeeds, backoff state is reset.
8282
Backoff *BackoffState
@@ -85,6 +85,16 @@ type Entry struct {
8585
HeaderData string
8686
// TODO(easwars): Add support to store the ChildPolicy here. Need a
8787
// balancerWrapper type to be implemented for this.
88+
89+
// size stores the size of this cache entry. Uses only a subset of the
90+
// fields. See `entrySize` for this is computed.
91+
size int
92+
// key contains the cache key corresponding to this entry. This is required
93+
// from methods like `removeElement` which only have a pointer to the
94+
// list.Element which contains a reference to the cache.Entry. But these
95+
// methods need the cache.Key to be able to remove the entry from the
96+
// underlying map.
97+
key Key
8898
}
8999

90100
// BackoffState wraps all backoff related state associated with a cache entry.
@@ -104,15 +114,6 @@ type BackoffState struct {
104114
Callback func()
105115
}
106116

107-
// lruEntry is the actual entry which is stored in the LRU cache. It requires
108-
// the key (in addition to the actual entry) as well, since the onEvicted
109-
// callback and expiry timer would need the key to perform their job.
110-
type lruEntry struct {
111-
key Key
112-
val *Entry
113-
size int
114-
}
115-
116117
// LRU is a cache with a least recently used eviction policy.
117118
//
118119
// It is not safe for concurrent access. The RLS LB policy will provide a mutex
@@ -160,6 +161,7 @@ func entrySize(key Key, value *Entry) int {
160161
// removeToFit removes older entries from the cache to make room for a new
161162
// entry of size newSize.
162163
func (lru *LRU) removeToFit(newSize int) {
164+
now := time.Now()
163165
for lru.usedSize+newSize > lru.maxSize {
164166
elem := lru.ll.Back()
165167
if elem == nil {
@@ -169,15 +171,15 @@ func (lru *LRU) removeToFit(newSize int) {
169171
return
170172
}
171173

172-
entry := elem.Value.(*lruEntry).val
173-
if t := entry.EarliestEvictTime; !t.IsZero() && t.Before(time.Now()) {
174+
entry := elem.Value.(*Entry)
175+
if t := entry.EarliestEvictTime; !t.IsZero() && t.Before(now) {
174176
// When the oldest entry is too new (it hasn't even spent a default
175177
// minimum amount of time in the cache), we abort and allow the
176178
// cache to grow bigger than the configured maxSize.
177179
grpclog.Info("rls: LRU eviction finds oldest entry to be too new. Allowing cache to exceed maxSize momentarily")
178180
return
179181
}
180-
lru.removeOldest()
182+
lru.removeElement(elem)
181183
}
182184
}
183185

@@ -188,16 +190,18 @@ func (lru *LRU) Add(key Key, value *Entry) {
188190
if !ok {
189191
lru.removeToFit(size)
190192
lru.usedSize += size
191-
elem := lru.ll.PushFront(&lruEntry{key, value, size})
193+
value.size = size
194+
value.key = key
195+
elem := lru.ll.PushFront(value)
192196
lru.cache[key] = elem
193197
return
194198
}
195199

196-
lruE := elem.Value.(*lruEntry)
197-
sizeDiff := size - lruE.size
200+
existing := elem.Value.(*Entry)
201+
sizeDiff := size - existing.size
198202
lru.removeToFit(sizeDiff)
199-
lruE.val = value
200-
lruE.size = size
203+
value.size = size
204+
elem.Value = value
201205
lru.ll.MoveToFront(elem)
202206
lru.usedSize += sizeDiff
203207
}
@@ -209,20 +213,13 @@ func (lru *LRU) Remove(key Key) {
209213
}
210214
}
211215

212-
func (lru *LRU) removeOldest() {
213-
elem := lru.ll.Back()
214-
if elem != nil {
215-
lru.removeElement(elem)
216-
}
217-
}
218-
219216
func (lru *LRU) removeElement(e *list.Element) {
220-
lruE := e.Value.(*lruEntry)
217+
entry := e.Value.(*Entry)
221218
lru.ll.Remove(e)
222-
delete(lru.cache, lruE.key)
223-
lru.usedSize -= lruE.size
219+
delete(lru.cache, entry.key)
220+
lru.usedSize -= entry.size
224221
if lru.onEvicted != nil {
225-
lru.onEvicted(lruE.key, lruE.val)
222+
lru.onEvicted(entry.key, entry)
226223
}
227224
}
228225

@@ -233,5 +230,5 @@ func (lru *LRU) Get(key Key) *Entry {
233230
return nil
234231
}
235232
lru.ll.MoveToFront(elem)
236-
return elem.Value.(*lruEntry).val
233+
return elem.Value.(*Entry)
237234
}

balancer/rls/internal/cache/cache_test.go

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@ func TestGet(t *testing.T) {
8181
for i, key := range test.keysToAdd {
8282
lru.Add(key, test.valsToAdd[i])
8383
}
84-
if gotEntry := lru.Get(test.keyToGet); !cmp.Equal(gotEntry, test.wantEntry, cmpopts.IgnoreInterfaces(struct{ sync.Locker }{})) {
84+
opts := []cmp.Option{
85+
cmpopts.IgnoreInterfaces(struct{ sync.Locker }{}),
86+
cmpopts.IgnoreUnexported(Entry{}),
87+
}
88+
if gotEntry := lru.Get(test.keyToGet); !cmp.Equal(gotEntry, test.wantEntry, opts...) {
8589
t.Errorf("lru.Get(%+v) = %+v, want %+v", test.keyToGet, gotEntry, test.wantEntry)
8690
}
8791
})
@@ -108,26 +112,6 @@ func TestRemove(t *testing.T) {
108112
}
109113
}
110114

111-
// TestRemove verifies the removeOldest method.
112-
func TestGetWithRemoveOldest(t *testing.T) {
113-
keys := []Key{
114-
{Path: "/service1/method1", KeyMap: "k1=v1,k2=v2"},
115-
{Path: "/service2/method2", KeyMap: "k1=v1,k2=v2"},
116-
{Path: "/service3/method3", KeyMap: "k1=v1,k2=v2"},
117-
}
118-
119-
lru := NewLRU(testCacheMaxSize, nil)
120-
for _, key := range keys {
121-
lru.Add(key, &Entry{})
122-
}
123-
for _, key := range keys {
124-
lru.removeOldest()
125-
if entry := lru.Get(key); entry != nil {
126-
t.Fatalf("lru.Get(%+v) after a call to lru.removeOldest succeeds, should have failed", key)
127-
}
128-
}
129-
}
130-
131115
// TestExceedingSizeCausesEviction verifies the case where adding a new entry
132116
// to the cache leads to eviction of old entries to make space for the new one.
133117
func TestExceedingSizeCausesEviction(t *testing.T) {

0 commit comments

Comments
 (0)