github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/nbs/fd_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 2017 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 nbs 23 24 import ( 25 "fmt" 26 "io/ioutil" 27 "os" 28 "path/filepath" 29 "sort" 30 "sync" 31 "testing" 32 33 "github.com/stretchr/testify/assert" 34 "github.com/stretchr/testify/require" 35 ) 36 37 func TestFDCache(t *testing.T) { 38 dir := makeTempDir(t) 39 defer os.RemoveAll(dir) 40 41 paths := [3]string{} 42 for i := range paths { 43 name := fmt.Sprintf("file%d", i) 44 paths[i] = filepath.Join(dir, name) 45 err := ioutil.WriteFile(paths[i], []byte(name), 0644) 46 require.NoError(t, err) 47 } 48 49 refNoError := func(fc *fdCache, p string, assert *assert.Assertions) *os.File { 50 f, err := fc.RefFile(p) 51 require.NoError(t, err) 52 assert.NotNil(f) 53 return f 54 } 55 56 t.Run("ConcurrentOpen", func(t *testing.T) { 57 assert := assert.New(t) 58 concurrency := 3 59 fc := newFDCache(3) 60 defer fc.Drop() 61 62 trigger := make(chan struct{}) 63 wg := sync.WaitGroup{} 64 for i := 0; i < concurrency; i++ { 65 wg.Add(1) 66 go func() { 67 defer wg.Done() 68 <-trigger 69 fc.RefFile(paths[0]) 70 }() 71 } 72 close(trigger) 73 wg.Wait() 74 75 present := fc.reportEntries() 76 if assert.Len(present, 1) { 77 ce := fc.cache[present[0]] 78 assert.EqualValues(concurrency, ce.refCount) 79 } 80 }) 81 82 t.Run("NoEvictions", func(t *testing.T) { 83 assert := assert.New(t) 84 fc := newFDCache(2) 85 defer fc.Drop() 86 f := refNoError(fc, paths[0], assert) 87 88 f2 := refNoError(fc, paths[1], assert) 89 assert.NotEqual(f, f2) 90 91 dup := refNoError(fc, paths[0], assert) 92 assert.Equal(f, dup) 93 }) 94 95 t.Run("Evictions", func(t *testing.T) { 96 assert := assert.New(t) 97 fc := newFDCache(1) 98 defer fc.Drop() 99 100 f0 := refNoError(fc, paths[0], assert) 101 f1 := refNoError(fc, paths[1], assert) 102 assert.NotEqual(f0, f1) 103 104 // f0 wasn't evicted, because that doesn't happen until UnrefFile() 105 dup := refNoError(fc, paths[0], assert) 106 assert.Equal(f0, dup) 107 108 expected := sort.StringSlice(paths[:2]) 109 sort.Sort(expected) 110 assert.EqualValues(expected, fc.reportEntries()) 111 112 // Unreffing f1 now should evict it 113 err := fc.UnrefFile(paths[1]) 114 require.NoError(t, err) 115 assert.EqualValues(paths[:1], fc.reportEntries()) 116 117 // Bring f1 back so we can test multiple evictions in a row 118 f1 = refNoError(fc, paths[1], assert) 119 assert.NotEqual(f0, f1) 120 121 // After adding f3, we should be able to evict both f0 and f1 122 f2 := refNoError(fc, paths[2], assert) 123 assert.NotEqual(f0, f2) 124 assert.NotEqual(f1, f2) 125 126 err = fc.UnrefFile(paths[0]) 127 require.NoError(t, err) 128 err = fc.UnrefFile(paths[0]) 129 require.NoError(t, err) 130 err = fc.UnrefFile(paths[1]) 131 require.NoError(t, err) 132 133 assert.EqualValues(paths[2:], fc.reportEntries()) 134 }) 135 }