this repo has no description
2
fork

Configure Feed

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

Remove BTree.Page

garrison 4be97387 0fc10359

-178
-178
lib/btree/page.ex
··· 1 - defmodule Hobbes.BTree.Page do 2 - import Hobbes.BTree.Utils 3 - import ExUnit.Assertions, only: [assert: 1] 4 - 5 - @type page_type :: :inner | :leaf 6 - 7 - defp encode_type(:inner), do: 0x00 8 - defp encode_type(:leaf), do: 0x01 9 - 10 - defp decode_type(0x00), do: :inner 11 - defp decode_type(0x01), do: :leaf 12 - 13 - def encode_page_from_pairs(page_type, opt_page_size, pairs, end_key) do 14 - type_byte = encode_type(page_type) 15 - {body, offsets, pair_count} = do_encode_page(pairs, "", [], 0) 16 - 17 - maybe_split(opt_page_size, type_byte, end_key, body, offsets, pair_count) 18 - end 19 - 20 - defp maybe_split(opt_page_size, type_byte, end_key, body, offsets, pair_count) do 21 - data_size = byte_size(body) + (pair_count * c_page_slot_entry_bytes()) + c_page_trailer_bytes() 22 - 23 - case data_size > opt_page_size do 24 - true -> 25 - target_midpoint_bytes = div(data_size, 2) 26 - assert target_midpoint_bytes > c_page_trailer_bytes() 27 - 28 - midpoint_i = find_midpoint(offsets, target_midpoint_bytes, 0) 29 - {offsets1, offsets2} = Enum.split(offsets, midpoint_i) 30 - 31 - # TODO: is this possible? 32 - assert offsets2 != [] 33 - body2_offset = hd(offsets2) 34 - offsets2 = Enum.map(offsets2, fn o -> o - body2_offset end) 35 - 36 - << 37 - body1::binary-size(body2_offset), 38 - body2::binary, 39 - >> = body 40 - 41 - end_key1 = 42 - case type_byte do 43 - 0x00 -> 44 - # For an inner page, the end_key is equal to the last key in the page (which is itself the end_key of the child page) 45 - offset = List.last(offsets1) 46 - <<_::binary-size(offset), key_size::integer-16, _vs::integer-16, end_key1::binary-size(key_size), _::binary>> = body1 47 - end_key1 48 - 0x01 -> 49 - # For a leaf page, the end_key is an exclusive separator key, so we choose the first key of the next page 50 - <<key_size::integer-16, _vs::integer-16, end_key1::binary-size(key_size), _::binary>> = body2 51 - end_key1 52 - end 53 - end_key2 = end_key 54 - 55 - pair_count1 = midpoint_i 56 - pair_count2 = pair_count - pair_count1 57 - 58 - pages1 = maybe_split(opt_page_size, type_byte, end_key1, body1, offsets1, pair_count1) 59 - pages2 = maybe_split(opt_page_size, type_byte, end_key2, body2, offsets2, pair_count2) 60 - pages1 ++ pages2 61 - 62 - false -> 63 - pad_bytes = opt_page_size - data_size 64 - assert pad_bytes >= 0 65 - 66 - page_data = << 67 - body::binary, 68 - 0::integer-unit(8)-size(pad_bytes), 69 - >> 70 - page_data = encode_slots(offsets, page_data) 71 - 72 - assert pair_count < (2 ** 16) 73 - # See constant: c_page_trailer_bytes() 74 - page_data = << 75 - page_data::binary, 76 - pair_count::integer-16, 77 - type_byte::integer-8, 78 - >> 79 - 80 - [{end_key, page_data}] 81 - end 82 - end 83 - 84 - defp find_midpoint([offset | offsets_rest], target, i) do 85 - size = offset + (c_page_slot_entry_bytes() * i) + c_page_trailer_bytes() 86 - case size > target do 87 - true -> 88 - assert i > 0 89 - i 90 - false -> 91 - find_midpoint(offsets_rest, target, i + 1) 92 - end 93 - end 94 - 95 - defp encode_slots([], acc), do: acc 96 - defp encode_slots([offset | offsets_rest], acc) do 97 - assert offset < (2 ** 16) 98 - # See constant: c_page_slot_entry_bytes() 99 - acc = << 100 - acc::binary, 101 - offset::integer-16, 102 - >> 103 - encode_slots(offsets_rest, acc) 104 - end 105 - 106 - defp do_encode_page([], body_acc, offsets_acc, count_acc) do 107 - {body_acc, Enum.reverse(offsets_acc), count_acc} 108 - end 109 - 110 - defp do_encode_page([{key, value} | pairs_rest], body_acc, offsets_acc, count_acc) do 111 - pair_offset = byte_size(body_acc) 112 - key_size = byte_size(key) 113 - value_size = byte_size(value) 114 - 115 - # TODO: larger 116 - assert key_size < (2 ** 16) 117 - assert value_size < (2 ** 16) 118 - # See constant: c_page_pair_overhead_bytes() 119 - body_acc = << 120 - body_acc::binary, 121 - key_size::integer-16, 122 - value_size::integer-16, 123 - key::binary, 124 - value::binary, 125 - >> 126 - 127 - offsets_acc = [pair_offset | offsets_acc] 128 - count_acc = count_acc + 1 129 - 130 - do_encode_page(pairs_rest, body_acc, offsets_acc, count_acc) 131 - end 132 - 133 - def decode_page(page_data) do 134 - page_size = byte_size(page_data) 135 - << 136 - _::binary-size(page_size - c_page_trailer_bytes()), 137 - pair_count::integer-16, 138 - type_byte::integer-8, 139 - >> = page_data 140 - assert pair_count >= 0 141 - page_type = decode_type(type_byte) 142 - 143 - slots_size = pair_count * c_page_slot_entry_bytes() 144 - << 145 - _::binary-size(page_size - slots_size - c_page_trailer_bytes()), 146 - slots_data::binary-size(slots_size), 147 - _trailer::binary, 148 - >> = page_data 149 - 150 - pairs = do_decode_pairs(slots_data, page_data, []) 151 - {page_type, pairs} 152 - end 153 - 154 - defp do_decode_pairs("", _page_data, pairs_acc) do 155 - Enum.reverse(pairs_acc) 156 - end 157 - 158 - defp do_decode_pairs(slots_data, page_data, pairs_acc) do 159 - # See constant: c_page_slot_entry_bytes() 160 - << 161 - pair_offset::integer-16, 162 - slots_rest::binary, 163 - >> = slots_data 164 - 165 - # See constant: c_page_pair_overhead_bytes() 166 - << 167 - _::binary-size(pair_offset), 168 - key_size::integer-16, 169 - value_size::integer-16, 170 - key::binary-size(key_size), 171 - value::binary-size(value_size), 172 - _::binary, 173 - >> = page_data 174 - 175 - pairs_acc = [{key, value} | pairs_acc] 176 - do_decode_pairs(slots_rest, page_data, pairs_acc) 177 - end 178 - end