this repo has no description
2
fork

Configure Feed

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

Fix improper trailer parsing leaking table blocks

garrison 85a6593a 6d4d0195

+29 -19
+1
lib/xks/fuzz/write_info.ex
··· 50 50 51 51 dbg XKS.info_manifest(xks, 0) 52 52 #dbg XKS.FreeList.dump(xks.free_list), limit: :infinity 53 + #dbg XKS.WAL.dump(xks.wal), limit: :infinity 53 54 end 54 55 55 56
+17 -9
lib/xks/merge.ex
··· 411 411 @spec load_table(LevelIterator.t, TableInfo.t) :: LevelIterator.t 412 412 defp load_table(%LevelIterator{} = iterator, %TableInfo{} = table) do 413 413 {lb_index, lb_checksum} = table.last_block_address 414 - trailer_data = do_load_trailer(iterator.block_store, lb_index, lb_checksum, []) 414 + {trailer_data, _addresses} = do_load_trailer(iterator.block_store, lb_index, lb_checksum, [], []) 415 415 416 416 prefix_size = byte_size(trailer_data) - c_table_metadata_bytes() 417 417 # See constant: c_table_metadata_bytes() ··· 425 425 } 426 426 end 427 427 428 - defp do_load_trailer(_block_store, 0 = _block_index, _block_checksum, segments_acc) do 428 + defp do_load_trailer(_block_store, 0 = _block_index, _block_checksum, segments_acc, addresses_acc) do 429 429 case segments_acc do 430 - [segment] -> 431 - segment 430 + [trailer_data] -> 431 + {trailer_data, addresses_acc} 432 432 [_ | _] = segments_reversed -> 433 433 # TODO: probe 434 - segments_reversed 435 - |> Enum.reverse() 436 - |> IO.iodata_to_binary() 434 + trailer_data = 435 + segments_reversed 436 + |> Enum.reverse() 437 + |> IO.iodata_to_binary() 438 + {trailer_data, addresses_acc} 437 439 end 438 440 end 439 441 440 - defp do_load_trailer(block_store, block_index, block_checksum, segments_acc) do 442 + defp do_load_trailer(block_store, block_index, block_checksum, segments_acc, addresses_acc) do 441 443 block_data = Blocks.read(block_store, block_index, block_checksum) 442 444 prefix_size = byte_size(block_data) - c_table_trailer_overhead_bytes() 443 445 # See constant: c_table_trailer_overhead_bytes() ··· 454 456 >> = block_data 455 457 456 458 segments_acc = [segment | segments_acc] 457 - do_load_trailer(block_store, prev_index, prev_checksum, segments_acc) 459 + addresses_acc = [{block_index, block_checksum} | addresses_acc] 460 + do_load_trailer(block_store, prev_index, prev_checksum, segments_acc, addresses_acc) 458 461 end 459 462 460 463 @spec load_subtable(LevelIterator.t, non_neg_integer) :: LevelIterator.t ··· 601 604 iterator = Map.put(iterator, cache_key, {block_index, block_checksum, block_data}) 602 605 {iterator, block_data} 603 606 end 607 + end 608 + 609 + @spec load_table_trailer(XKS.block_store, non_neg_integer, Blocks.checksum) :: {binary, [{non_neg_integer, binary}]} 610 + def load_table_trailer(block_store, last_block_index, last_block_checksum) do 611 + do_load_trailer(block_store, last_block_index, last_block_checksum, [], []) 604 612 end 605 613 606 614 # Debug/Fuzz
+11 -10
lib/xks/table.ex
··· 1 1 defmodule Hobbes.XKS.Table do 2 - alias Hobbes.XKS.{Blocks, FreeList} 2 + alias Hobbes.XKS.FreeList 3 3 alias Hobbes.XKS.Manifest.TableInfo 4 4 5 5 import Hobbes.XKS.Utils ··· 7 7 @spec release_table(term, FreeList.t, TableInfo.t) :: :ok 8 8 def release_table(block_store, free_list, %TableInfo{} = table_info) do 9 9 {lb_index, lb_checksum} = table_info.last_block_address 10 - last_block_data = Blocks.read(block_store, lb_index, lb_checksum) 11 10 12 - prefix_size = byte_size(last_block_data) - c_table_metadata_bytes() 11 + {trailer_data, trailer_block_addresses} = Hobbes.XKS.Merge.load_table_trailer(block_store, lb_index, lb_checksum) 12 + 13 + prefix_size = byte_size(trailer_data) - c_table_metadata_bytes() 13 14 # See constant: c_table_metadata_bytes() 14 - <<_::binary-size(prefix_size), block_count::integer-32, subtable_count::integer-32>> = last_block_data 15 + <<_::binary-size(prefix_size), block_count::integer-32, subtable_count::integer-32>> = trailer_data 15 16 16 - scan_and_release_blocks(free_list, last_block_data, block_count, subtable_count, 0) 17 - FreeList.release_block(free_list, lb_index) 17 + :ok = scan_and_release_blocks(free_list, trailer_data, block_count, subtable_count, 0) 18 + Enum.each(trailer_block_addresses, fn {block_index, _checksum} -> FreeList.release_block(free_list, block_index) end) 18 19 19 20 :ok 20 21 end 21 22 22 - defp scan_and_release_blocks(_free_list, _lb_data, block_count, _subtable_count, block_i) 23 + defp scan_and_release_blocks(_free_list, _trailer_data, block_count, _subtable_count, block_i) 23 24 when block_i >= block_count do 24 25 :ok 25 26 end 26 27 27 - defp scan_and_release_blocks(free_list, lb_data, block_count, subtable_count, block_i) do 28 + defp scan_and_release_blocks(free_list, trailer_data, block_count, subtable_count, block_i) do 28 29 address_offset = (subtable_count * c_index_slot_bytes()) + (block_i * c_address_bytes()) 29 30 # See constant: c_address_bytes() 30 - <<_::binary-size(address_offset), block_index::integer-64, _block_checksum::binary-16, _::binary>> = lb_data 31 + <<_::binary-size(address_offset), block_index::integer-64, _block_checksum::binary-16, _::binary>> = trailer_data 31 32 32 33 FreeList.release_block(free_list, block_index) 33 - scan_and_release_blocks(free_list, lb_data, block_count, subtable_count, block_i + 1) 34 + scan_and_release_blocks(free_list, trailer_data, block_count, subtable_count, block_i + 1) 34 35 end 35 36 end