github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/util/sizecache/size_cache_test.go (about) 1 // Copyright 2019 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // This file incorporates work covered by the following copyright and 16 // permission notice: 17 // 18 // Copyright 2016 Attic Labs, Inc. All rights reserved. 19 // Licensed under the Apache License, version 2.0: 20 // http://www.apache.org/licenses/LICENSE-2.0 21 22 package sizecache 23 24 import ( 25 "fmt" 26 "sort" 27 "sync" 28 "testing" 29 30 "github.com/stretchr/testify/assert" 31 32 "github.com/dolthub/dolt/go/store/hash" 33 ) 34 35 func hashFromString(s string) hash.Hash { 36 return hash.Of([]byte(s)) 37 } 38 39 func TestSizeCache(t *testing.T) { 40 assert := assert.New(t) 41 defSize := uint64(200) 42 43 c := New(1024) 44 for i, v := range []string{"data-1", "data-2", "data-3", "data-4", "data-5", "data-6", "data-7", "data-8", "data-9"} { 45 c.Add(hashFromString(v), defSize, v) 46 maxElements := uint64(i + 1) 47 if maxElements >= uint64(5) { 48 maxElements = uint64(5) 49 } 50 assert.Equal(maxElements*defSize, c.totalSize) 51 } 52 53 _, ok := c.Get(hashFromString("data-1")) 54 assert.False(ok) 55 assert.Equal(hashFromString("data-5"), c.lru.Front().Value) 56 57 v, ok := c.Get(hashFromString("data-5")) 58 assert.True(ok) 59 assert.Equal("data-5", v.(string)) 60 assert.Equal(hashFromString("data-5"), c.lru.Back().Value) 61 assert.Equal(hashFromString("data-6"), c.lru.Front().Value) 62 63 c.Add(hashFromString("data-7"), defSize, "data-7") 64 assert.Equal(hashFromString("data-7"), c.lru.Back().Value) 65 assert.Equal(uint64(1000), c.totalSize) 66 67 c.Add(hashFromString("no-data"), 0, nil) 68 v, ok = c.Get(hashFromString("no-data")) 69 assert.True(ok) 70 assert.Nil(v) 71 assert.Equal(hashFromString("no-data"), c.lru.Back().Value) 72 assert.Equal(uint64(1000), c.totalSize) 73 assert.Equal(6, c.lru.Len()) 74 assert.Equal(6, len(c.cache)) 75 76 for _, v := range []string{"data-5", "data-6", "data-7", "data-8", "data-9"} { 77 c.Get(hashFromString(v)) 78 assert.Equal(hashFromString(v), c.lru.Back().Value) 79 } 80 assert.Equal(hashFromString("no-data"), c.lru.Front().Value) 81 82 c.Add(hashFromString("data-10"), 200, "data-10") 83 assert.Equal(uint64(1000), c.totalSize) 84 assert.Equal(5, c.lru.Len()) 85 assert.Equal(5, len(c.cache)) 86 87 _, ok = c.Get(hashFromString("no-data")) 88 assert.False(ok) 89 _, ok = c.Get(hashFromString("data-5")) 90 assert.False(ok) 91 92 c.Drop(hashFromString("data-10")) 93 assert.Equal(uint64(800), c.totalSize) 94 assert.Equal(4, c.lru.Len()) 95 assert.Equal(4, len(c.cache)) 96 97 c.Purge() 98 assert.Equal(uint64(0), c.totalSize) 99 for i, v := range []string{"data-1", "data-2", "data-3", "data-4", "data-5", "data-6", "data-7", "data-8", "data-9"} { 100 c.Add(hashFromString(v), defSize, v) 101 maxElements := uint64(i + 1) 102 if maxElements >= uint64(5) { 103 maxElements = uint64(5) 104 } 105 assert.Equal(maxElements*defSize, c.totalSize) 106 } 107 } 108 109 func TestSizeCacheWithExpiry(t *testing.T) { 110 expired := []string{} 111 expire := func(key interface{}) { 112 expired = append(expired, key.(string)) 113 } 114 115 c := NewWithExpireCallback(5, expire) 116 data := []string{"a", "b", "c", "d", "e"} 117 for i, k := range data { 118 c.Add(k, 1, i) 119 } 120 121 c.Add("big", 5, "thing") 122 sort.Strings(expired) 123 assert.Equal(t, data, expired) 124 } 125 126 func concurrencySizeCacheTest(data []string) { 127 dchan := make(chan string, 128) 128 go func() { 129 for _, d := range data { 130 dchan <- d 131 } 132 close(dchan) 133 }() 134 135 cache := New(25) 136 wg := sync.WaitGroup{} 137 138 for i := 0; i < 3; i++ { 139 wg.Add(1) 140 go func() { 141 for d := range dchan { 142 cache.Add(d, uint64(len(d)), d) 143 } 144 wg.Done() 145 }() 146 } 147 wg.Wait() 148 } 149 150 // I can't guarantee this will fail if the code isn't correct, but in the 151 // previous version of SizeCache, this was able to reliably repro bug #2663. 152 func TestConcurrency(t *testing.T) { 153 assert := assert.New(t) 154 generateDataStrings := func(numStrings, numValues int) []string { 155 l := []string{} 156 for i := 0; len(l) < numStrings; i++ { 157 for j := 0; j < numValues && len(l) < numStrings; j++ { 158 l = append(l, fmt.Sprintf("data-%d", i)) 159 } 160 } 161 return l 162 } 163 164 data := generateDataStrings(50, 3) 165 for i := 0; i < 100; i++ { 166 assert.NotPanics(func() { concurrencySizeCacheTest(data) }) 167 } 168 } 169 170 func TestTooLargeValue(t *testing.T) { 171 assert := assert.New(t) 172 173 c := New(1024) 174 c.Add(hashFromString("big-data"), 2048, "big-data") 175 _, ok := c.Get(hashFromString("big-data")) 176 assert.False(ok) 177 } 178 179 func TestZeroSizeCache(t *testing.T) { 180 assert := assert.New(t) 181 182 c := New(0) 183 c.Add(hashFromString("data1"), 200, "data1") 184 _, ok := c.Get(hashFromString("data1")) 185 assert.False(ok) 186 }