···3344 alias Hobbes.XKS.{Blocks, Memtable}
5566+ import ExUnit.Assertions, only: [assert: 1]
77+68 @memtable_level -1
79810 @spec new :: t
···6668 id = next_table_id(manifest)
6769 :ets.insert(manifest, {{level, fk_key, fk_version, epoch}, {lk_key, lk_version, block_index, block_checksum, id}})
6870 :ok
7171+ end
7272+7373+ @spec seek_table(t, non_neg_integer, non_neg_integer, binary, non_neg_integer) :: {:ok, tuple} | :error
7474+ def seek_table(manifest, epoch, level, key, version) do
7575+ seek_key = {key, version}
7676+ # version + 1 because prev() is exclusive and we need a table with start_key <= seek_key
7777+ # epoch = 0 because we are trying to seek the previous key in the manifest keyspace
7878+ # 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}
7979+ prev_key = {level, key, version + 1, 0}
8080+8181+ do_seek_table(manifest, epoch, level, seek_key, prev_key, false)
8282+ end
8383+8484+ defp do_seek_table(manifest, epoch, level, seek_key, prev_key, prev_tombstone?) do
8585+ case :ets.prev_lookup(manifest, prev_key) do
8686+ {{^level, _k, _ver, _ep} = key, _obj} when prev_tombstone? ->
8787+ # The previous entry we saw (which is *next* in the keyspace) was a tombstone,
8888+ # so this entry has been deleted at `epoch`
8989+ do_seek_table(manifest, epoch, level, seek_key, key, false)
9090+9191+ {{^level, _k, _ver, ep} = key, _obj} when ep > epoch ->
9292+ # This entry is not visible at `epoch`
9393+ do_seek_table(manifest, epoch, level, seek_key, key, false)
9494+9595+ {{^level, _k, _ver, _ep} = key, [{_key, :tombstone}]} ->
9696+ # This entry is visible and is a tombstone,
9797+ # so we set the prev_tombstone? flag to cancel out the next entry
9898+ do_seek_table(manifest, epoch, level, seek_key, key, true)
9999+100100+ {{^level, sk_key, sk_ver, _ep}, [{_key, value}]} ->
101101+ # This entry is visible and may contain `seek_key`
102102+ {ek_key, ek_ver, lb_index, lb_checksum, _id} = value
103103+104104+ # This invariant is guaranteed because we are calling prev(seek_key + 1) to get here
105105+ assert {sk_key, sk_ver} <= seek_key
106106+ case seek_key < {ek_key, ek_ver} do
107107+ true ->
108108+ # If seek_key < end_key, this table contains `seek_key`
109109+ table = {:table, lb_index, lb_checksum, {sk_key, sk_ver}, {ek_key, ek_ver}}
110110+ {:ok, table}
111111+112112+ false ->
113113+ # If seek_key >= end_key, that means there is a "hole" in the keyspace
114114+ # and there is no table which contains `seek_key`
115115+ :error
116116+ end
117117+118118+ _ ->
119119+ # Hit the end of the level without finding a table
120120+ :error
121121+ end
69122 end
7012371124 @spec list_overlapping_tables(t, non_neg_integer, non_neg_integer, {binary, non_neg_integer}, {binary, non_neg_integer}) :: [tuple]