···7979 {fk_key, fk_version} = first_key
8080 {lk_key, lk_version} = last_key
81818282- id = next_table_id(manifest)
8383- :ets.insert(manifest, {{level, fk_key, fk_version, epoch}, {lk_key, lk_version, block_index, block_checksum, id}})
8282+ epoch_max = :infinity
8383+ :ets.insert(manifest, {{level, fk_key, fk_version, epoch}, {lk_key, lk_version, block_index, block_checksum, epoch_max}})
8484 :ok
8585 end
86868787+ @spec delete_table(t, non_neg_integer, Table.t) :: :ok
8888+ def delete_table(manifest, epoch, %{manifest_key: manifest_key}) do
8989+ case :ets.lookup(manifest, manifest_key) do
9090+ [{_key, {lk_key, lk_version, block_index, block_checksum, :infinity}}] ->
9191+ # Mark table as deleted at `epoch` by updating the table's `epoch_max`
9292+ new_value = {lk_key, lk_version, block_index, block_checksum, epoch}
9393+ :ets.insert(manifest, {manifest_key, new_value})
9494+ :ok
9595+9696+ [] ->
9797+ raise "Table not found"
9898+ end
9999+ end
100100+87101 def level_start_sentinel(level), do: {level, "", 0, -1}
88102 # TODO: standardize last key of keyspace
89103 def level_end_sentinel(level), do: {level, "\xFF\xFF\xFF\xFF", :infinity, :infinity}
···95109 # 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}
96110 prev_key = {level, key, version + 1, 0}
971119898- do_seek_prev_table(manifest, epoch, level, prev_key, false)
112112+ do_seek_prev_table(manifest, epoch, level, prev_key)
99113 end
100114101101- defp do_seek_prev_table(manifest, epoch, level, prev_key, prev_tombstone?) do
115115+ defp do_seek_prev_table(manifest, epoch, level, prev_key) do
102116 case :ets.prev_lookup(manifest, prev_key) do
103103- {{^level, _k, _ver, _ep} = key, _obj} when prev_tombstone? ->
104104- # The previous entry we saw (which is *next* in the keyspace) was a tombstone,
105105- # so this entry has been deleted at `epoch`
106106- do_seek_prev_table(manifest, epoch, level, key, false)
107107-108108- {{^level, _k, _ver, ep} = key, _obj} when ep > epoch ->
117117+ {{^level, _k, _ver, ep} = key, [{_key, {_, _, _, _, ep_max}}]} when epoch < ep or epoch >= ep_max ->
109118 # This entry is not visible at `epoch`
110110- do_seek_prev_table(manifest, epoch, level, key, false)
111111-112112- {{^level, _k, _ver, _ep} = key, [{_key, :tombstone}]} ->
113113- # This entry is visible and is a tombstone,
114114- # so we set the prev_tombstone? flag to cancel out the next (previous in the keyspace) entry
115115- do_seek_prev_table(manifest, epoch, level, key, true)
119119+ do_seek_prev_table(manifest, epoch, level, key)
116120117121 {{^level, _sk_key, _sk_ver, _ep} = key, [{_key, value}]} ->
118118- # This entry is visible
122122+ # This is the first visible entry we have seen
119123 {:ok, table_from_kv(key, value)}
120124121125 _ ->
122122- # Hit the start of the level without finding a table
126126+ # Hit the start of the level without finding a visible entry
123127 :error
124128 end
125129 end
126130127131 @spec seek_next_table(t, non_neg_integer, non_neg_integer, binary, non_neg_integer) :: {:ok, Table.t} | :error
128132 def seek_next_table(manifest, epoch, level, key, version) do
129129- prev_key =
130130- case seek_prev_table(manifest, epoch, level, key, version) do
131131- {:ok, %{manifest_key: key}} -> key
132132- :error -> level_start_sentinel(level)
133133- end
133133+ # We first seek backwards to see if there is a table containing `{key, version}`
134134+ #
135135+ # We have to look back because tables are keyed by `start_key`
136136+ # If tables were keyed by `end_key` then we would have to look forward in `seek_prev_table`
137137+ # (i.e. it's mirrored one way or the other)
138138+ case seek_prev_table(manifest, epoch, level, key, version) do
139139+ {:ok, %Table{} = table} ->
140140+ seek_key = {key, version}
141141+ case seek_key >= table.start_key and seek_key < table.end_key do
142142+ # We have already found the table containing the key
143143+ true -> {:ok, table}
144144+ # There was no table containing the key, so we return the *next* table
145145+ # (because this is `seek_next_table`)
146146+ false -> next_table(manifest, epoch, level, table)
147147+ end
134148135135- next_table(manifest, epoch, level, %{manifest_key: prev_key})
149149+ :error ->
150150+ # There was no table containing the key *or any previous table*,
151151+ # so we return the first table in the level
152152+ # (Note that if the level is empty next_table() will also return :error)
153153+ next_table(manifest, epoch, level, %{manifest_key: level_start_sentinel(level)})
154154+ end
136155 end
137156138157 @spec next_table(t, non_neg_integer, non_neg_integer, map) :: {:ok, Table.t} | :error
···142161143162 defp do_next_table(manifest, epoch, level, prev_key) do
144163 case :ets.next_lookup(manifest, prev_key) do
145145- {{^level, _k, _ver, ep} = key, _obj} when ep > epoch ->
164164+ {{^level, _k, _ver, ep} = key, [{_key, {_, _, _, _, ep_max}}]} when epoch < ep or epoch >= ep_max ->
146165 # This entry is not visible at `epoch`
147166 do_next_table(manifest, epoch, level, key)
148167149149- {{^level, sk_key, sk_ver, _ep} = key, [{_key, value}]} ->
150150- case :ets.next_lookup(manifest, key) do
151151- {{^level, ^sk_key, ^sk_ver, _ep} = next_key, [{_key, :tombstone}]} ->
152152- # The entry was deleted, skip past the tombstone
153153- do_next_table(manifest, epoch, level, next_key)
154154-155155- _ ->
156156- # The next entry is *not* a tombstone, so this entry is the next table visible at `epoch`
157157- {:ok, table_from_kv(key, value)}
158158- end
168168+ {{^level, _sk_key, _sk_ver, _ep} = key, [{_key, value}]} ->
169169+ # This is the first visible entry we have seen
170170+ {:ok, table_from_kv(key, value)}
159171160172 _ ->
161173 # Hit the end of the level without finding a table