this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Randomly choose existing keys in fuzzer to improve BTree coverage

garrison cfa7a611 89bc38f2

+54 -18
+53 -17
lib/btree/fuzz/model_fuzz.ex
··· 11 11 :simple_kv, 12 12 :version, 13 13 14 + :key_cache, 15 + 14 16 :opts, 15 17 ] 16 18 defstruct @enforce_keys ··· 40 42 simple_kv: SimpleKV.new(), 41 43 version: 0, 42 44 45 + key_cache: :ets.new(__MODULE__, [:ordered_set, :private]), 46 + 43 47 opts: opts, 44 48 } 45 49 ··· 57 61 reraise e, __STACKTRACE__ 58 62 end 59 63 end) 64 + 60 65 :ok 61 66 end 62 67 ··· 103 108 btree: btree, 104 109 simple_kv: simple_kv, 105 110 version: version, 111 + key_cache: key_cache, 106 112 opts: opts, 107 113 } = state 108 114 109 - mutations = make_batch(opts) 115 + mutations = make_batch(key_cache, opts) 110 116 111 117 :ok = BTree.Writer.apply_versioned_batch(btree, version, mutations) 112 118 :ok = BTree.Writer.log_batch(btree, version, mutations) ··· 122 128 simple_kv: simple_kv, 123 129 btree: btree, 124 130 version: version, 131 + key_cache: key_cache, 125 132 opts: %{ 126 133 key_bits: opt_key_bits, 127 134 }, ··· 129 136 130 137 read_version = Enum.random(max(version - 5000, 0)..version) 131 138 # TODO: too sparse, literally always nil 132 - key = make_key(opt_key_bits) 139 + key = make_key(key_cache, opt_key_bits) 133 140 134 141 btree_result = BTree.Reader.get(btree, read_version, key) 135 142 simple_result = SimpleKV.get(simple_kv, read_version, key) ··· 143 150 simple_kv: simple_kv, 144 151 btree: btree, 145 152 version: version, 153 + key_cache: key_cache, 146 154 opts: %{ 147 155 key_bits: opt_key_bits, 148 156 }, 149 157 } = state 150 158 151 159 read_version = Enum.random(max(version - 5000, 0)..version) 152 - {start_key, end_key} = make_range(opt_key_bits) 160 + {start_key, end_key} = make_range(key_cache, opt_key_bits) 153 161 reverse? = Enum.random([true, false]) 154 162 limit = random_limit() 155 163 #{start_key, end_key, limit, reverse?} = {"", "\xFF\xFF\xFF\xFF", :infinity, true} ··· 171 179 end 172 180 end 173 181 174 - defp make_batch(opts) do 182 + defp make_batch(key_cache, opts) do 175 183 opt_key_bits = opts.key_bits 176 184 batch_size = Enum.random(opts.batch_size_range) 177 185 178 - do_make_batch(opt_key_bits, [], batch_size) 186 + do_make_batch(key_cache, opt_key_bits, [], batch_size) 179 187 end 180 188 181 - defp do_make_batch(_opt_key_bits, acc, 0), do: acc 182 - defp do_make_batch(opt_key_bits, acc, count) do 183 - acc = [make_mutation(opt_key_bits) | acc] 189 + defp do_make_batch(_key_cache, _opt_key_bits, acc, 0), do: acc 190 + defp do_make_batch(key_cache, opt_key_bits, acc, count) do 191 + acc = [make_mutation(key_cache, opt_key_bits) | acc] 184 192 count = count - 1 185 - do_make_batch(opt_key_bits, acc, count) 193 + do_make_batch(key_cache, opt_key_bits, acc, count) 186 194 end 187 195 188 - defp make_mutation(opt_key_bits) do 196 + defp make_mutation(key_cache, opt_key_bits) do 189 197 case Enum.random(1..2) do 190 198 1 -> 191 - key = make_key(opt_key_bits) 199 + key = make_key(key_cache, opt_key_bits) 192 200 value = String.duplicate(String.reverse(key), 2) 193 201 {:write, key, value} 194 202 2 -> 195 - key = make_key(opt_key_bits) 203 + key = make_key(key_cache, opt_key_bits) 196 204 {:clear, key} 197 205 end 198 206 end 199 207 200 - defp make_range(bits) do 201 - key1 = make_key(bits) 202 - key2 = make_key(bits) 208 + defp make_range(key_cache, bits) do 209 + key1 = make_key(key_cache, bits) 210 + key2 = make_key(key_cache, bits) 203 211 cond do 204 212 key1 < key2 -> {key1, key2} 205 213 key1 > key2 -> {key2, key1} ··· 207 215 end 208 216 end 209 217 210 - defp make_key(bits) do 211 - :rand.uniform((2 ** bits) - 1) 218 + defp make_key(key_cache, opt_key_bits) do 219 + case Enum.random(1..2) do 220 + 1 -> existing_key(key_cache) 221 + 2 -> new_key(key_cache, opt_key_bits) 222 + end 223 + end 224 + 225 + defp existing_key(key_cache) do 226 + case :ets.next_lookup(key_cache, random_cache_i()) do 227 + {_, [{_, key}]} -> 228 + key 229 + _ -> 230 + case :ets.first_lookup(key_cache) do 231 + {_, [{_, key}]} -> key 232 + :"$end_of_table" -> "" 233 + end 234 + end 235 + end 236 + 237 + defp new_key(key_cache, opt_key_bits) do 238 + key = make_new_key(opt_key_bits) 239 + :ets.insert(key_cache, {random_cache_i(), key}) 240 + key 241 + end 242 + 243 + @cache_i_max (2 ** 32) - 1 244 + defp random_cache_i, do: Enum.random(0..@cache_i_max) 245 + 246 + defp make_new_key(opt_key_bits) do 247 + :rand.uniform((2 ** opt_key_bits) - 1) 212 248 |> :binary.encode_unsigned() 213 249 |> Base.encode16(case: :lower) 214 250 end
+1 -1
test/btree_test.exs
··· 13 13 14 14 test "fuzz" do 15 15 Hobbes.BTree.Fuzz.ModelFuzz.run(100, [ 16 - iterations: 400, 16 + iterations: 1000, 17 17 #key_bits: 8, 18 18 key_bits: 32, 19 19 ])