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  }