this repo has no description
2
fork

Configure Feed

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

Add BTree.Superblock

garrison 5deb24f2 cfa7a611

+182 -3
+32 -2
lib/btree/btree.ex
··· 1 1 defmodule Hobbes.BTree do 2 2 alias Hobbes.BTree 3 - alias Hobbes.BTree.{Store, FreeList} 3 + alias Hobbes.BTree.{Store, FreeList, Superblock} 4 4 5 5 import ExUnit.Assertions, only: [assert: 1] 6 6 ··· 73 73 btree 74 74 end 75 75 76 + defp load_from_store(store) do 77 + %{ 78 + btree_pairs: btree_pairs, 79 + opts_pairs: opts_pairs, 80 + } = Superblock.read(store) 81 + 82 + %Opts{} = opts = struct!(Opts, opts_pairs) 83 + 84 + btree = %BTree{ 85 + opts: opts, 86 + store: store, 87 + 88 + free_list: FreeList.new(), 89 + root_store: :ets.new(__MODULE__, [:ordered_set, :protected]), 90 + 91 + mutation_log: :ets.new(__MODULE__, [:ordered_set, :private]), 92 + versioned_tree: :ets.new(__MODULE__, [:ordered_set, :protected]), 93 + write_buffer: :ets.new(__MODULE__, [:ordered_set, :private]), 94 + 95 + free_list_tail_address: btree_pairs.free_list_tail_address, 96 + free_list_max_index: btree_pairs.free_list_max_index, 97 + } 98 + # TODO: load FreeList 99 + 100 + btree 101 + end 102 + 76 103 def commit(%BTree{} = btree) do 77 104 %{ 78 105 free_list_tail_address: free_list_tail_address, 79 106 free_list_max_index: free_list_max_index, 80 107 } = FreeList.flush(btree) 81 108 82 - %{btree | 109 + btree = %{btree | 83 110 free_list_tail_address: free_list_tail_address, 84 111 free_list_max_index: free_list_max_index, 85 112 } 113 + 114 + :ok = Superblock.write(btree) 115 + btree 86 116 end 87 117 88 118 defp create_root(%BTree{} = btree) do
+15
lib/btree/store.ex
··· 2 2 alias Hobbes.BTree.BlockDevice 3 3 4 4 import ExUnit.Assertions, only: [assert: 1] 5 + import Hobbes.BTree.Utils 5 6 6 7 @type t :: BlockDevice.t 7 8 @type checksum :: <<_::128>> ··· 17 18 def checksum(binary) do 18 19 <<hash::binary-16, _rest::binary-16>> = :crypto.hash(:sha256, binary) 19 20 hash 21 + end 22 + 23 + @spec read_superblock(t, non_neg_integer) :: binary 24 + def read_superblock({:block_device, _, _} = bd, copy) do 25 + pos = copy * c_superblock_size() 26 + 27 + BlockDevice.read(bd, pos, c_superblock_size()) 28 + end 29 + 30 + @spec write_superblock(t, non_neg_integer, binary) :: :ok 31 + def write_superblock({:block_device, _, _} = bd, copy, superblock_data) do 32 + assert byte_size(superblock_data) == c_superblock_size() 33 + 34 + :ok = BlockDevice.write(bd, copy * c_superblock_size(), superblock_data) 20 35 end 21 36 22 37 @spec read_page(t, non_neg_integer, checksum) :: binary
+131
lib/btree/superblock.ex
··· 1 + defmodule Hobbes.BTree.Superblock do 2 + alias Hobbes.BTree 3 + alias Hobbes.BTree.Store 4 + 5 + import ExUnit.Assertions, only: [assert: 1] 6 + import Hobbes.BTree.Utils 7 + 8 + @spec write(BTree.t) :: :ok 9 + def write(%BTree{} = btree) do 10 + :ok = write_copy(btree, 0) 11 + end 12 + 13 + def read(store) do 14 + read_copy(store, 0) 15 + end 16 + 17 + @spec write_copy(BTree.t, non_neg_integer) :: :ok 18 + defp write_copy(%BTree{} = btree, copy) do 19 + %{ 20 + store: store, 21 + 22 + free_list_tail_address: {free_list_tail_index, free_list_tail_checksum}, 23 + free_list_max_index: free_list_max_index, 24 + 25 + opts: opts, 26 + } = btree 27 + sequence = 0 28 + 29 + opts_data = encode_opts(opts) 30 + opts_data_size = byte_size(opts_data) 31 + 32 + block_data = << 33 + copy::integer-64, 34 + sequence::integer-64, 35 + 36 + free_list_tail_index::integer-64, 37 + free_list_tail_checksum::binary-16, 38 + free_list_max_index::integer-64, 39 + 40 + opts_data_size::integer-64, 41 + opts_data::binary, 42 + >> 43 + 44 + pad_bytes = c_superblock_size() - byte_size(block_data) - c_checksum_bytes() 45 + block_data = << 46 + block_data::binary, 47 + 0::integer-unit(8)-size(pad_bytes), 48 + >> 49 + 50 + checksum = Store.checksum(block_data) 51 + block_data = << 52 + block_data::binary, 53 + checksum::binary-16, 54 + >> 55 + 56 + :ok = Store.write_superblock(store, copy, block_data) 57 + end 58 + 59 + @spec read_copy(Store.t, non_neg_integer) :: %{btree_pairs: map, opts_pairs: list} 60 + defp read_copy(store, requested_copy) do 61 + superblock_data = Store.read_superblock(store, requested_copy) 62 + 63 + << 64 + checksummed_data::binary-size(c_superblock_size() - c_checksum_bytes()), 65 + checksum::binary-16, 66 + >> = superblock_data 67 + # TODO: error handling for corrupted copies 68 + assert Store.checksum(checksummed_data) == checksum 69 + 70 + << 71 + received_copy::integer-64, 72 + _sequence::integer-64, 73 + 74 + free_list_tail_index::integer-64, 75 + free_list_tail_checksum::binary-16, 76 + free_list_max_index::integer-64, 77 + 78 + opts_data_size::integer-64, 79 + opts_data::binary-size(opts_data_size), 80 + 81 + _padding_and_checksum::binary, 82 + >> = superblock_data 83 + 84 + # TODO: error handling for misdirected read 85 + assert received_copy == requested_copy 86 + 87 + btree_pairs = %{ 88 + free_list_tail_address: {free_list_tail_index, free_list_tail_checksum}, 89 + free_list_max_index: free_list_max_index, 90 + } 91 + 92 + opts_pairs = decode_opts(opts_data) 93 + 94 + %{ 95 + btree_pairs: btree_pairs, 96 + opts_pairs: opts_pairs, 97 + } 98 + end 99 + 100 + @opts_keys [ 101 + page_size: 0, 102 + ] 103 + 104 + @spec encode_opts(BTree.Opts.t) :: binary 105 + defp encode_opts(%BTree.Opts{} = opts) do 106 + do_encode_opts(@opts_keys, opts, "") 107 + end 108 + 109 + defp do_encode_opts([], _opts, opts_data_acc), do: opts_data_acc 110 + defp do_encode_opts([{key, id} | keys_rest], opts, opts_data_acc) do 111 + value = Map.fetch!(opts, key) 112 + 113 + assert value >= -(2 ** 63) 114 + assert value < (2 ** 63) 115 + 116 + opts_data_acc = <<opts_data_acc::binary, id::integer-16, value::signed-integer-64>> 117 + do_encode_opts(keys_rest, opts, opts_data_acc) 118 + end 119 + 120 + @spec decode_opts(binary) :: [{atom, integer}] 121 + defp decode_opts(opts_data) do 122 + do_decode_opts(opts_data, []) 123 + end 124 + 125 + defp do_decode_opts("", opts_acc), do: opts_acc 126 + defp do_decode_opts(<<id::integer-16, value::signed-integer-64, data_rest::binary>>, opts_acc) do 127 + key = Keyword.fetch!(@opts_keys, id) 128 + opts_acc = [{key, value} | opts_acc] 129 + do_decode_opts(data_rest, opts_acc) 130 + end 131 + end
+4 -1
lib/btree/utils.ex
··· 1 1 defmodule Hobbes.BTree.Utils do 2 2 defmacro c_null_address, do: {0, <<0::integer-128>>} 3 3 4 + defmacro c_superblock_size, do: 4 * 1024 5 + 6 + defmacro c_checksum_bytes, do: 16 4 7 # index + checksum 5 - defmacro c_address_bytes, do: 8 + 16 8 + defmacro c_address_bytes, do: 8 + c_checksum_bytes() 6 9 7 10 # index 8 11 defmacro c_free_list_entry_size, do: 8