From b00d2abacf393de62f801d885f89c14cfc4de610 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Thu, 4 Jun 2020 00:16:21 +0200 Subject: [PATCH] Implement packetcache resizing. --- packetcache/packetcache.go | 54 +++++++++++++++++++++++++++++++++ packetcache/packetcache_test.go | 43 ++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/packetcache/packetcache.go b/packetcache/packetcache.go index 215c183..aa1e040 100644 --- a/packetcache/packetcache.go +++ b/packetcache/packetcache.go @@ -139,6 +139,9 @@ func (cache *Cache) GetAt(seqno uint16, index uint16, result []byte) uint16 { cache.mu.Lock() defer cache.mu.Unlock() + if int(index) > len(cache.entries) { + return 0 + } if cache.entries[index].seqno != seqno { return 0 } @@ -148,6 +151,57 @@ func (cache *Cache) GetAt(seqno uint16, index uint16, result []byte) uint16 { ) } +func (cache *Cache) resize(capacity int) { + if len(cache.entries) == capacity { + return + } + + entries := make([]entry, capacity) + + if capacity > len(cache.entries) { + copy(entries, cache.entries[:cache.tail]) + copy(entries[int(cache.tail)+capacity-len(cache.entries):], + cache.entries[cache.tail:]) + } else if capacity > int(cache.tail) { + copy(entries, cache.entries[:cache.tail]) + copy(entries[cache.tail:], + cache.entries[int(cache.tail)+ + len(cache.entries)-capacity:]) + } else { + // too bad, invalidate all indices + copy(entries, + cache.entries[int(cache.tail)-capacity:cache.tail]) + cache.tail = 0 + } + cache.entries = entries +} + +func (cache *Cache) Resize(capacity int) { + cache.mu.Lock() + defer cache.mu.Unlock() + + cache.resize(capacity) +} + +func (cache *Cache) ResizeCond(capacity int) bool { + cache.mu.Lock() + defer cache.mu.Unlock() + + current := len(cache.entries) + + if current >= capacity/2 && current < capacity*2 { + return false + } + + if int(cache.tail) > current/2 && int(cache.tail) > capacity/2 { + // bad time to resize, this would invalidate too many indices + return false + } + + cache.resize(capacity) + return true +} + // Shift 17 bits out of the bitmap. Return a boolean indicating if any // were 0, the index of the first 0 bit, and a bitmap indicating any // 0 bits after the first one. diff --git a/packetcache/packetcache_test.go b/packetcache/packetcache_test.go index 2119bf1..6680842 100644 --- a/packetcache/packetcache_test.go +++ b/packetcache/packetcache_test.go @@ -81,6 +81,49 @@ func TestCacheOverflow(t *testing.T) { } } +func TestCacheGrow(t *testing.T) { + cache := New(16) + + for i := 0; i < 24; i++ { + cache.Store(uint16(i), []byte{uint8(i)}) + } + + cache.Resize(32) + for i := 0; i < 32; i++ { + expected := uint16(0) + if i < 8 { + expected = uint16(i + 16) + } + if i >= 24 { + expected = uint16(i - 16) + } + if cache.entries[i].seqno != expected { + t.Errorf("At %v, got %v, expected %v", + i, cache.entries[i].seqno, expected) + } + } +} + +func TestCacheShrink(t *testing.T) { + cache := New(16) + + for i := 0; i < 24; i++ { + cache.Store(uint16(i), []byte{uint8(i)}) + } + + cache.Resize(12) + for i := 0; i < 12; i++ { + expected := uint16(i + 16) + if i >= 8 { + expected = uint16(i + 4) + } + if cache.entries[i].seqno != expected { + t.Errorf("At %v, got %v, expected %v", + i, cache.entries[i].seqno, expected) + } + } +} + func TestBitmap(t *testing.T) { value := uint64(0xcdd58f1e035379c0) packet := make([]byte, 1)