github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/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 98 func TestSizeCacheWithExpiry(t *testing.T) { 99 expired := []string{} 100 expire := func(key interface{}) { 101 expired = append(expired, key.(string)) 102 } 103 104 c := NewWithExpireCallback(5, expire) 105 data := []string{"a", "b", "c", "d", "e"} 106 for i, k := range data { 107 c.Add(k, 1, i) 108 } 109 110 c.Add("big", 5, "thing") 111 sort.Strings(expired) 112 assert.Equal(t, data, expired) 113 } 114 115 func concurrencySizeCacheTest(data []string) { 116 dchan := make(chan string, 128) 117 go func() { 118 for _, d := range data { 119 dchan <- d 120 } 121 close(dchan) 122 }() 123 124 cache := New(25) 125 wg := sync.WaitGroup{} 126 127 for i := 0; i < 3; i++ { 128 wg.Add(1) 129 go func() { 130 for d := range dchan { 131 cache.Add(d, uint64(len(d)), d) 132 } 133 wg.Done() 134 }() 135 } 136 wg.Wait() 137 } 138 139 // I can't guarantee this will fail if the code isn't correct, but in the 140 // previous version of SizeCache, this was able to reliably repro bug #2663. 141 func TestConcurrency(t *testing.T) { 142 assert := assert.New(t) 143 generateDataStrings := func(numStrings, numValues int) []string { 144 l := []string{} 145 for i := 0; len(l) < numStrings; i++ { 146 for j := 0; j < numValues && len(l) < numStrings; j++ { 147 l = append(l, fmt.Sprintf("data-%d", i)) 148 } 149 } 150 return l 151 } 152 153 data := generateDataStrings(50, 3) 154 for i := 0; i < 100; i++ { 155 assert.NotPanics(func() { concurrencySizeCacheTest(data) }) 156 } 157 } 158 159 func TestTooLargeValue(t *testing.T) { 160 assert := assert.New(t) 161 162 c := New(1024) 163 c.Add(hashFromString("big-data"), 2048, "big-data") 164 _, ok := c.Get(hashFromString("big-data")) 165 assert.False(ok) 166 } 167 168 func TestZeroSizeCache(t *testing.T) { 169 assert := assert.New(t) 170 171 c := New(0) 172 c.Add(hashFromString("data1"), 200, "data1") 173 _, ok := c.Get(hashFromString("data1")) 174 assert.False(ok) 175 }