this repo has no description
2
fork

Configure Feed

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

Seek to table containing key (regaining some hope)

garrison ba832a38 5c131f51

+55 -1
+53
lib/xks/manifest.ex
··· 3 3 4 4 alias Hobbes.XKS.{Blocks, Memtable} 5 5 6 + import ExUnit.Assertions, only: [assert: 1] 7 + 6 8 @memtable_level -1 7 9 8 10 @spec new :: t ··· 66 68 id = next_table_id(manifest) 67 69 :ets.insert(manifest, {{level, fk_key, fk_version, epoch}, {lk_key, lk_version, block_index, block_checksum, id}}) 68 70 :ok 71 + end 72 + 73 + @spec seek_table(t, non_neg_integer, non_neg_integer, binary, non_neg_integer) :: {:ok, tuple} | :error 74 + def seek_table(manifest, epoch, level, key, version) do 75 + seek_key = {key, version} 76 + # version + 1 because prev() is exclusive and we need a table with start_key <= seek_key 77 + # epoch = 0 because we are trying to seek the previous key in the manifest keyspace 78 + # E.g. if we passed epoch=10 we could get {level, key, version + 1, 9} when we want to get {level, key, version, some_epoch} 79 + prev_key = {level, key, version + 1, 0} 80 + 81 + do_seek_table(manifest, epoch, level, seek_key, prev_key, false) 82 + end 83 + 84 + defp do_seek_table(manifest, epoch, level, seek_key, prev_key, prev_tombstone?) do 85 + case :ets.prev_lookup(manifest, prev_key) do 86 + {{^level, _k, _ver, _ep} = key, _obj} when prev_tombstone? -> 87 + # The previous entry we saw (which is *next* in the keyspace) was a tombstone, 88 + # so this entry has been deleted at `epoch` 89 + do_seek_table(manifest, epoch, level, seek_key, key, false) 90 + 91 + {{^level, _k, _ver, ep} = key, _obj} when ep > epoch -> 92 + # This entry is not visible at `epoch` 93 + do_seek_table(manifest, epoch, level, seek_key, key, false) 94 + 95 + {{^level, _k, _ver, _ep} = key, [{_key, :tombstone}]} -> 96 + # This entry is visible and is a tombstone, 97 + # so we set the prev_tombstone? flag to cancel out the next entry 98 + do_seek_table(manifest, epoch, level, seek_key, key, true) 99 + 100 + {{^level, sk_key, sk_ver, _ep}, [{_key, value}]} -> 101 + # This entry is visible and may contain `seek_key` 102 + {ek_key, ek_ver, lb_index, lb_checksum, _id} = value 103 + 104 + # This invariant is guaranteed because we are calling prev(seek_key + 1) to get here 105 + assert {sk_key, sk_ver} <= seek_key 106 + case seek_key < {ek_key, ek_ver} do 107 + true -> 108 + # If seek_key < end_key, this table contains `seek_key` 109 + table = {:table, lb_index, lb_checksum, {sk_key, sk_ver}, {ek_key, ek_ver}} 110 + {:ok, table} 111 + 112 + false -> 113 + # If seek_key >= end_key, that means there is a "hole" in the keyspace 114 + # and there is no table which contains `seek_key` 115 + :error 116 + end 117 + 118 + _ -> 119 + # Hit the end of the level without finding a table 120 + :error 121 + end 69 122 end 70 123 71 124 @spec list_overlapping_tables(t, non_neg_integer, non_neg_integer, {binary, non_neg_integer}, {binary, non_neg_integer}) :: [tuple]
+2 -1
lib/xks/xks.ex
··· 63 63 manifest = xks.manifest 64 64 epoch = :atomics.get(xks.epoch_atomic, 1) 65 65 66 - _tables = Manifest.list_overlapping_tables(manifest, epoch, 1, {key, version}, {key, version + 1}) 66 + Manifest.seek_table(manifest, epoch, 1, key, version) 67 + |> dbg() 67 68 68 69 Manifest.list_memtables(xks.manifest, epoch) 69 70 |> Enum.find_value(:error, fn {_id, memtable} ->