github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/cmn/prob/dyn_cuckoo_test.go (about) 1 // Package prob implements fully features dynamic probabilistic filter. 2 /* 3 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package prob_test 6 7 import ( 8 "math/rand" 9 "sync" 10 "testing" 11 12 "github.com/NVIDIA/aistore/cmn/prob" 13 "github.com/NVIDIA/aistore/tools/trand" 14 . "github.com/onsi/ginkgo/v2" 15 . "github.com/onsi/gomega" 16 ) 17 18 const ( 19 testFilterInitSize = 100 * 1000 20 objNameLength = 5 21 ) 22 23 // Predefined buckets. 24 var buckets = []string{ 25 "test", "imagenet", "cifar", "secret", "something-t1-d1345", 26 } 27 28 func randObjName(n int) []byte { 29 return []byte(buckets[rand.Intn(len(buckets))] + "/" + trand.String(n)) 30 } 31 32 func genKeys(keysNum int) [][]byte { 33 keys := make([][]byte, keysNum) 34 for i := range keysNum { 35 keys[i] = randObjName(objNameLength) 36 } 37 return keys 38 } 39 40 var _ = Describe("Filter", func() { 41 filter := prob.NewFilter(testFilterInitSize) 42 43 BeforeEach(func() { 44 filter.Reset() 45 }) 46 47 Context("Lookup", func() { 48 It("should correctly lookup a key in filter", func() { 49 key := []byte("key") 50 filter.Insert(key) 51 Expect(filter.Lookup(key)).To(BeTrue()) 52 }) 53 54 It("should lookup the keys in filter with no more than 0.06% failure rate", func() { 55 keys := genKeys(testFilterInitSize * 10) 56 total := float64(len(keys)) 57 for _, key := range keys { 58 filter.Insert(key) 59 } 60 61 failures := 0 62 for _, key := range keys { 63 if !filter.Lookup(key) { 64 failures++ 65 } 66 } 67 68 Expect(float64(failures) / total * 100).To(BeNumerically("<=", 0.006*total)) 69 }) 70 }) 71 72 Context("Delete", func() { 73 It("should correctly delete a key from filter", func() { 74 key := []byte("key") 75 filter.Insert(key) 76 Expect(filter.Lookup(key)).To(BeTrue()) 77 filter.Delete(key) 78 Expect(filter.Lookup(key)).To(BeFalse()) 79 filter.Delete(key) // try to delete already deleted key 80 Expect(filter.Lookup(key)).To(BeFalse()) 81 82 // do it again to check if the filter wasn't broken 83 filter.Insert(key) 84 Expect(filter.Lookup(key)).To(BeTrue()) 85 filter.Delete(key) 86 Expect(filter.Lookup(key)).To(BeFalse()) 87 }) 88 }) 89 }) 90 91 func BenchmarkInsert(b *testing.B) { 92 b.Run("preallocated", func(b *testing.B) { 93 keys := genKeys(b.N) 94 filter := prob.NewFilter(uint(b.N)) 95 96 b.ResetTimer() 97 for n := range b.N { 98 filter.Insert(keys[n]) 99 } 100 }) 101 102 b.Run("empty", func(b *testing.B) { 103 keys := genKeys(b.N) 104 filter := prob.NewFilter(10) 105 106 b.ResetTimer() 107 for n := range b.N { 108 filter.Insert(keys[n]) 109 } 110 }) 111 } 112 113 func BenchmarkLookup(b *testing.B) { 114 b.Run("single filter", func(b *testing.B) { 115 keys := genKeys(b.N) 116 filter := prob.NewFilter(uint(b.N)) 117 for n := range b.N { 118 filter.Insert(keys[n]) 119 } 120 121 b.ResetTimer() 122 for n := range b.N { 123 filter.Lookup(keys[n]) 124 } 125 }) 126 127 b.Run("multiple filters", func(b *testing.B) { 128 keys := genKeys(b.N) 129 filter := prob.NewFilter(10) 130 for n := range b.N { 131 filter.Insert(keys[n]) 132 } 133 134 b.ResetTimer() 135 for n := range b.N { 136 filter.Lookup(keys[n]) 137 } 138 }) 139 } 140 141 func BenchmarkDelete(b *testing.B) { 142 b.Run("single filter", func(b *testing.B) { 143 keys := genKeys(b.N) 144 filter := prob.NewFilter(uint(b.N)) 145 for n := range b.N { 146 filter.Insert(keys[n]) 147 } 148 149 b.ResetTimer() 150 for n := range b.N { 151 filter.Delete(keys[n]) 152 } 153 }) 154 155 b.Run("multiple filters", func(b *testing.B) { 156 keys := genKeys(b.N) 157 filter := prob.NewFilter(10) 158 for n := range b.N { 159 filter.Insert(keys[n]) 160 } 161 162 b.ResetTimer() 163 for n := range b.N { 164 filter.Delete(keys[n]) 165 } 166 }) 167 } 168 169 func BenchmarkInsertAndDeleteAndLookupParallel(b *testing.B) { 170 b.Run("preallocated", func(b *testing.B) { 171 keys := genKeys(b.N) 172 filter := prob.NewFilter(uint(b.N)) 173 174 b.ResetTimer() 175 176 wg := &sync.WaitGroup{} 177 wg.Add(3) 178 go func() { 179 for n := range b.N { 180 filter.Insert(keys[n]) 181 } 182 wg.Done() 183 }() 184 go func() { 185 for n := range b.N { 186 filter.Lookup(keys[n]) 187 } 188 wg.Done() 189 }() 190 go func() { 191 for n := range b.N { 192 filter.Delete(keys[n]) 193 } 194 wg.Done() 195 }() 196 wg.Wait() 197 }) 198 199 b.Run("empty", func(b *testing.B) { 200 keys := genKeys(b.N) 201 filter := prob.NewFilter(10) 202 203 b.ResetTimer() 204 205 wg := &sync.WaitGroup{} 206 wg.Add(3) 207 go func() { 208 for n := range b.N { 209 filter.Insert(keys[n]) 210 } 211 wg.Done() 212 }() 213 go func() { 214 for n := range b.N { 215 filter.Lookup(keys[n]) 216 } 217 wg.Done() 218 }() 219 go func() { 220 for n := range b.N { 221 filter.Delete(keys[n]) 222 } 223 wg.Done() 224 }() 225 wg.Wait() 226 }) 227 }