this repo has no description
1
fork

Configure Feed

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

Add reads to BlockDevice and optimize single-block write

+68 -8
+68 -8
lib/btree/block_device.ex
··· 11 11 12 12 @spec read(t, non_neg_integer, non_neg_integer) :: binary 13 13 def read({:block_device, opt_block_size, _table} = bd, pos, bytes) do 14 - # TODO 15 - assert rem(pos, opt_block_size) == 0 16 - assert bytes == opt_block_size 14 + block_index = div(pos, opt_block_size) 15 + start_offset = rem(pos, opt_block_size) 16 + end_offset = start_offset + bytes 17 + 18 + cond do 19 + start_offset == 0 and bytes == opt_block_size -> 20 + # The read is for exactly one block, return it directly 21 + get(bd, block_index) 22 + 23 + end_offset <= opt_block_size -> 24 + # The read is contained within one block, slice it out and return it 25 + block_data = get(bd, block_index) 17 26 18 - block_index = div(pos, opt_block_size) 19 - get(bd, block_index) 27 + << 28 + _prefix::binary-size(start_offset), 29 + middle::binary-size(end_offset), 30 + _::binary, 31 + >> = block_data 32 + # Probably not worth calling :binary.copy() 33 + middle 34 + 35 + true -> 36 + # The read covers multiple blocks 37 + block_data = get(bd, block_index) 38 + 39 + << 40 + _prefix::binary-size(start_offset), 41 + block_part::binary, 42 + >> = block_data 43 + 44 + bytes_remaining = bytes - (opt_block_size - start_offset) 45 + do_read_blocks(bd, opt_block_size, block_index + 1, bytes_remaining, block_part) 46 + end 47 + end 48 + 49 + defp do_read_blocks(_bd, _opt_block_size, _block_index_acc, 0 = _bytes_remaining, data_acc) do 50 + data_acc 51 + end 52 + 53 + defp do_read_blocks(bd, opt_block_size, block_index_acc, bytes_remaining, data_acc) 54 + when bytes_remaining < opt_block_size do 55 + block_data = get(bd, block_index_acc) 56 + 57 + << 58 + block_part::binary-size(bytes_remaining), 59 + _rest::binary, 60 + >> = block_data 61 + 62 + <<data_acc::binary, block_part::binary>> 63 + end 64 + 65 + defp do_read_blocks(bd, opt_block_size, block_index_acc, bytes_remaining, data_acc) do 66 + block_data = get(bd, block_index_acc) 67 + 68 + block_index_acc = block_index_acc + 1 69 + bytes_remaining = bytes_remaining - opt_block_size 70 + data_acc = <<data_acc::binary, block_data::binary>> 71 + do_read_blocks(bd, opt_block_size, block_index_acc, bytes_remaining, data_acc) 20 72 end 21 73 22 74 @spec write(t, non_neg_integer, binary) :: :ok ··· 27 79 start_offset = rem(pos, opt_block_size) 28 80 end_offset = start_offset + bin_size 29 81 30 - case end_offset <= opt_block_size do 31 - true -> 82 + cond do 83 + start_offset == 0 and bin_size == opt_block_size -> 84 + # The write is for exactly one block, we don't have to read or splice anything 85 + bin = :binary.copy(bin) 86 + put(table, block_index, bin) 87 + 88 + end_offset <= opt_block_size -> 89 + # The write is contained within one block, read the existing block and splice it 32 90 old_block = get(bd, block_index) 33 91 34 92 << ··· 46 104 47 105 put(table, block_index, new_block) 48 106 49 - false -> 107 + true -> 108 + # The write covers multiple blocks 50 109 old_block = get(bd, block_index) 51 110 52 111 << ··· 64 123 bin_part::binary, 65 124 >> 66 125 assert byte_size(new_block) == opt_block_size 126 + put(table, block_index, new_block) 67 127 68 128 do_write_blocks(bin_rest, bd, table, opt_block_size, block_index + 1) 69 129 end