this repo has no description
2
fork

Configure Feed

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

Reload BTree

garrison d6cd387d 5deb24f2

+100 -9
+33 -3
lib/btree/btree.ex
··· 58 58 btree = %BTree{ 59 59 opts: opts, 60 60 store: Store.new(path, opts.page_size), 61 - free_list: FreeList.new(), 61 + free_list: FreeList.new(page_size: opts.page_size), 62 62 root_store: :ets.new(__MODULE__, [:ordered_set, :protected]), 63 63 64 64 mutation_log: :ets.new(__MODULE__, [:ordered_set, :private]), ··· 85 85 opts: opts, 86 86 store: store, 87 87 88 - free_list: FreeList.new(), 88 + free_list: FreeList.new(page_size: opts.page_size), 89 89 root_store: :ets.new(__MODULE__, [:ordered_set, :protected]), 90 90 91 91 mutation_log: :ets.new(__MODULE__, [:ordered_set, :private]), ··· 95 95 free_list_tail_address: btree_pairs.free_list_tail_address, 96 96 free_list_max_index: btree_pairs.free_list_max_index, 97 97 } 98 - # TODO: load FreeList 98 + 99 + :ok = FreeList.load(btree) 100 + :ets.insert(btree.root_store, {:root_address, btree_pairs.root_address}) 99 101 100 102 btree 103 + end 104 + 105 + @spec close(t) :: :ok 106 + def close(%BTree{} = btree) do 107 + %{ 108 + free_list: free_list, 109 + root_store: root_store, 110 + mutation_log: mutation_log, 111 + versioned_tree: versioned_tree, 112 + write_buffer: write_buffer, 113 + } = btree 114 + 115 + :ok = FreeList.destroy(free_list) 116 + 117 + :ets.delete(root_store) 118 + :ets.delete(mutation_log) 119 + :ets.delete(versioned_tree) 120 + :ets.delete(write_buffer) 121 + 122 + :ok 123 + end 124 + 125 + @doc false 126 + def reload(%BTree{} = btree) do 127 + %{store: store} = btree 128 + :ok = close(btree) 129 + 130 + %BTree{} = load_from_store(store) 101 131 end 102 132 103 133 def commit(%BTree{} = btree) do
+27 -3
lib/btree/free_list.ex
··· 9 9 10 10 @type t :: :ets.table 11 11 12 - @spec new :: t 13 - def new do 12 + @spec new(keyword) :: t 13 + def new(opts) do 14 + opt_page_size = Keyword.fetch!(opts, :page_size) 14 15 free_list = :ets.new(__MODULE__, [:ordered_set, :private]) 15 - :ets.insert(free_list, {:max_index, 0}) 16 + 17 + # Reserve enough pages up-front to fit the superblocks so that their space is never reserved 18 + # by the database 19 + superblock_reserved_pages = ceil((c_superblock_size() * c_superblock_copies()) / opt_page_size) 20 + assert superblock_reserved_pages >= 1 21 + :ets.insert(free_list, {:max_index, superblock_reserved_pages}) 16 22 17 23 free_list 18 24 end 19 25 26 + @spec destroy(t) :: :ok 27 + def destroy(free_list) do 28 + :ets.delete(free_list) 29 + :ok 30 + end 31 + 32 + @spec load(BTree.t) :: :ok 33 + def load(%BTree{} = btree) do 34 + %{ 35 + free_list: free_list, 36 + free_list_max_index: free_list_max_index, 37 + } = btree 38 + 39 + :ets.insert(free_list, {:max_index, free_list_max_index}) 40 + :ok 41 + end 42 + 43 + @spec flush(BTree.t) :: %{free_list_tail_address: {non_neg_integer, binary}, free_list_max_index: non_neg_integer} 20 44 def flush(%BTree{} = btree) do 21 45 %{ 22 46 store: store,
+27 -2
lib/btree/fuzz/model_fuzz.ex
··· 10 10 :btree, 11 11 :simple_kv, 12 12 :version, 13 + :floor_version, 13 14 14 15 :key_cache, 15 16 ··· 41 42 btree: BTree.new(opts.btree_opts), 42 43 simple_kv: SimpleKV.new(), 43 44 version: 0, 45 + floor_version: 0, 44 46 45 47 key_cache: :ets.new(__MODULE__, [:ordered_set, :private]), 46 48 ··· 77 79 defp random_op do 78 80 case Enum.random(1..20) do 79 81 1 -> :commit 82 + 2 -> :reload 80 83 _ -> 81 84 case Enum.random(1..3) do 82 85 1 -> :apply_batch ··· 100 103 101 104 %{state | 102 105 btree: btree, 106 + floor_version: floor_version, 107 + } 108 + end 109 + 110 + defp execute(:reload, %State{} = state) do 111 + %{ 112 + btree: btree, 113 + version: version, 114 + } = state 115 + 116 + :ok = BTree.Writer.apply_logged_batches_to_storage(btree, version) 117 + :ok = BTree.Writer.flush_storage_buffer(btree) 118 + btree = BTree.commit(btree) 119 + btree = BTree.reload(btree) 120 + 121 + %{state | 122 + btree: btree, 123 + floor_version: version, 103 124 } 104 125 end 105 126 ··· 128 149 simple_kv: simple_kv, 129 150 btree: btree, 130 151 version: version, 152 + floor_version: floor_version, 153 + 131 154 key_cache: key_cache, 132 155 opts: %{ 133 156 key_bits: opt_key_bits, 134 157 }, 135 158 } = state 136 159 137 - read_version = Enum.random(max(version - 5000, 0)..version) 160 + read_version = Enum.random(floor_version..version) 138 161 # TODO: too sparse, literally always nil 139 162 key = make_key(key_cache, opt_key_bits) 140 163 ··· 150 173 simple_kv: simple_kv, 151 174 btree: btree, 152 175 version: version, 176 + floor_version: floor_version, 177 + 153 178 key_cache: key_cache, 154 179 opts: %{ 155 180 key_bits: opt_key_bits, 156 181 }, 157 182 } = state 158 183 159 - read_version = Enum.random(max(version - 5000, 0)..version) 184 + read_version = Enum.random(floor_version..version) 160 185 {start_key, end_key} = make_range(key_cache, opt_key_bits) 161 186 reverse? = Enum.random([true, false]) 162 187 limit = random_limit()
+12 -1
lib/btree/superblock.ex
··· 18 18 defp write_copy(%BTree{} = btree, copy) do 19 19 %{ 20 20 store: store, 21 + root_store: root_store, 21 22 22 23 free_list_tail_address: {free_list_tail_index, free_list_tail_checksum}, 23 24 free_list_max_index: free_list_max_index, ··· 25 26 opts: opts, 26 27 } = btree 27 28 sequence = 0 29 + [{:root_address, {root_index, root_checksum}}] = :ets.lookup(root_store, :root_address) 28 30 29 31 opts_data = encode_opts(opts) 30 32 opts_data_size = byte_size(opts_data) ··· 32 34 block_data = << 33 35 copy::integer-64, 34 36 sequence::integer-64, 37 + 38 + root_index::integer-64, 39 + root_checksum::binary-16, 35 40 36 41 free_list_tail_index::integer-64, 37 42 free_list_tail_checksum::binary-16, ··· 71 76 received_copy::integer-64, 72 77 _sequence::integer-64, 73 78 79 + root_index::integer-64, 80 + root_checksum::binary-16, 81 + 74 82 free_list_tail_index::integer-64, 75 83 free_list_tail_checksum::binary-16, 76 84 free_list_max_index::integer-64, ··· 85 93 assert received_copy == requested_copy 86 94 87 95 btree_pairs = %{ 96 + root_address: {root_index, root_checksum}, 97 + 88 98 free_list_tail_address: {free_list_tail_index, free_list_tail_checksum}, 89 99 free_list_max_index: free_list_max_index, 90 100 } ··· 100 110 @opts_keys [ 101 111 page_size: 0, 102 112 ] 113 + @opts_keys_lookup Map.new(@opts_keys, fn {k, v} -> {v, k} end) 103 114 104 115 @spec encode_opts(BTree.Opts.t) :: binary 105 116 defp encode_opts(%BTree.Opts{} = opts) do ··· 124 135 125 136 defp do_decode_opts("", opts_acc), do: opts_acc 126 137 defp do_decode_opts(<<id::integer-16, value::signed-integer-64, data_rest::binary>>, opts_acc) do 127 - key = Keyword.fetch!(@opts_keys, id) 138 + key = Map.fetch!(@opts_keys_lookup, id) 128 139 opts_acc = [{key, value} | opts_acc] 129 140 do_decode_opts(data_rest, opts_acc) 130 141 end
+1
lib/btree/utils.ex
··· 2 2 defmacro c_null_address, do: {0, <<0::integer-128>>} 3 3 4 4 defmacro c_superblock_size, do: 4 * 1024 5 + defmacro c_superblock_copies, do: 4 5 6 6 7 defmacro c_checksum_bytes, do: 16 7 8 # index + checksum