perf: tighten thumbnail cache memory usage
This commit is contained in:
@@ -37,7 +37,7 @@ func newThumbnailCache() *thumbnailCache {
|
|||||||
items: make(map[thumbnailCacheKey]*list.Element),
|
items: make(map[thumbnailCacheKey]*list.Element),
|
||||||
order: list.New(),
|
order: list.New(),
|
||||||
flights: make(map[thumbnailCacheKey]*thumbnailFlight),
|
flights: make(map[thumbnailCacheKey]*thumbnailFlight),
|
||||||
maxBytes: 32 << 20,
|
maxBytes: 8 << 20,
|
||||||
maxItems: 64,
|
maxItems: 64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ func (c *thumbnailCache) Do(key thumbnailCacheKey, fn func() ([]byte, error)) ([
|
|||||||
if f, ok := c.flights[key]; ok {
|
if f, ok := c.flights[key]; ok {
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
<-f.done
|
<-f.done
|
||||||
return append([]byte(nil), f.data...), f.err
|
return f.data, f.err
|
||||||
}
|
}
|
||||||
f := &thumbnailFlight{done: make(chan struct{})}
|
f := &thumbnailFlight{done: make(chan struct{})}
|
||||||
c.flights[key] = f
|
c.flights[key] = f
|
||||||
@@ -63,7 +63,7 @@ func (c *thumbnailCache) Do(key thumbnailCacheKey, fn func() ([]byte, error)) ([
|
|||||||
if err == nil && len(data) > 0 && int64(len(data)) <= c.maxBytes {
|
if err == nil && len(data) > 0 && int64(len(data)) <= c.maxBytes {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.putLocked(key, data)
|
c.putLocked(key, data)
|
||||||
f.data = append([]byte(nil), data...)
|
f.data = data
|
||||||
f.err = err
|
f.err = err
|
||||||
delete(c.flights, key)
|
delete(c.flights, key)
|
||||||
close(f.done)
|
close(f.done)
|
||||||
@@ -82,11 +82,11 @@ func (c *thumbnailCache) putLocked(key thumbnailCacheKey, data []byte) {
|
|||||||
if e, ok := c.items[key]; ok {
|
if e, ok := c.items[key]; ok {
|
||||||
old := e.Value.(thumbnailCacheEntry)
|
old := e.Value.(thumbnailCacheEntry)
|
||||||
c.bytes -= int64(len(old.data))
|
c.bytes -= int64(len(old.data))
|
||||||
e.Value = thumbnailCacheEntry{key: key, data: append([]byte(nil), data...)}
|
e.Value = thumbnailCacheEntry{key: key, data: data}
|
||||||
c.bytes += int64(len(data))
|
c.bytes += int64(len(data))
|
||||||
c.order.MoveToFront(e)
|
c.order.MoveToFront(e)
|
||||||
} else {
|
} else {
|
||||||
e := c.order.PushFront(thumbnailCacheEntry{key: key, data: append([]byte(nil), data...)})
|
e := c.order.PushFront(thumbnailCacheEntry{key: key, data: data})
|
||||||
c.items[key] = e
|
c.items[key] = e
|
||||||
c.bytes += int64(len(data))
|
c.bytes += int64(len(data))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,3 +70,19 @@ func TestThumbnailCacheEvictsByBound(t *testing.T) {
|
|||||||
t.Fatalf("cache size=%d/list=%d, want 2/2", len(c.items), c.order.Len())
|
t.Fatalf("cache size=%d/list=%d, want 2/2", len(c.items), c.order.Len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestThumbnailCacheEvictsByBytes(t *testing.T) {
|
||||||
|
c := newThumbnailCache()
|
||||||
|
c.maxBytes = 3
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
key := thumbnailCacheKey{Path: string(rune('x' + i))}
|
||||||
|
if _, err := c.Do(key, func() ([]byte, error) { return []byte("xx"), nil }); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
if c.bytes > c.maxBytes || len(c.items) != 1 {
|
||||||
|
t.Fatalf("cache bytes=%d items=%d, want <=%d/1", c.bytes, len(c.items), c.maxBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user