···187187 }
188188 end
189189190190- @spec list_overlapping_tables(t, non_neg_integer, non_neg_integer, {binary, non_neg_integer}, {binary, non_neg_integer}) :: [tuple]
191191- def list_overlapping_tables(manifest, epoch, level, start_key, end_key) do
192192- {sk_key, sk_ver} = start_key
193193- # Scan backwards to find the first table visible at `epoch` which is outside of the range (below)
194194- prev_key =
195195- case find_prev_table_key(manifest, epoch, level, start_key, {level, sk_key, sk_ver, epoch + 1}, false) do
196196- {:ok, key} -> key
197197- # If we hit the start of the level, we use a sentinel at epoch -1
198198- :error -> {level, "", 0, -1}
199199- end
200200-201201- # Start the scan at the `prev_key` found above, which guarantees
202202- # that any overlapping tables will be found by `next()`
203203- scan_tables(manifest, epoch, level, end_key, prev_key, [])
204204- |> Enum.reverse()
205205- end
206206-207207- # Scan backwards to find the key of the first table *below* (disjoint from) `start_key` that is visible at `epoch`
208208- # This key can then be used to start a forward scan and accumulate
209209- #
210210- # TODO: there is absolutely no way this is correct right now
211211- defp find_prev_table_key(manifest, epoch, level, start_key, prev_key, prev_tombstone?) do
212212- case :ets.prev_lookup(manifest, prev_key) do
213213- {key, _obj} when prev_tombstone? ->
214214- # The previous key we saw (i.e. the next key in the keyspace) was a tombstone,
215215- # so this entry has been deleted
216216- find_prev_table_key(manifest, epoch, level, start_key, key, false)
217217-218218- {{^level, _k, _ver, ep} = key, _obj} when ep > epoch ->
219219- # This entry is not visible at `epoch`
220220- find_prev_table_key(manifest, epoch, level, start_key, key, false)
221221-222222- {{^level, _k, _ver, _ep} = key, [{_key, :tombstone}]} ->
223223- # This entry is a tombstone, so we will ignore the next entry we see (which is previous in the keyspace)
224224- find_prev_table_key(manifest, epoch, level, start_key, key, true)
225225-226226- {{^level, _k, _ver, _ep} = key, [{_key, {ek_key, ek_ver, _i, _ck, _id}}]} when {ek_key, ek_ver} > start_key ->
227227- # This table actually *contains* `start_key`:
228228- # - table_sk < start_key due to prev()
229229- # - table_ek > start_key due to guard
230230- # Therefore: sk < start_key < ek
231231- find_prev_table_key(manifest, epoch, level, start_key, key, false)
232232-233233- {{^level, _k, _ver, _ep} = key, _obj} ->
234234- # This is the first table found which has an ek <= `start_key`,
235235- # which means it is the first table with a range *below* (disjoint) start_key
236236- {:ok, key}
237237-238238- _ ->
239239- :error
240240- end
241241- end
242242-243243- defp scan_tables(manifest, epoch, level, end_key, prev_key, acc) do
244244- case :ets.next_lookup(manifest, prev_key) do
245245- {{^level, _k, _ver, ep} = key, [{_key, _value}]} when ep > epoch ->
246246- # This entry is not visible at epoch
247247- scan_tables(manifest, epoch, level, end_key, key, acc)
248248-249249- {{^level, _k, _ver, _ep} = key, [{_key, :tombstone}]} ->
250250- # This entry is a tombstone and cancels out the previous entry
251251- # TODO: assert that it was the same key?
252252- [_deleted | acc] = acc
253253- scan_tables(manifest, epoch, level, end_key, key, acc)
254254-255255- {{^level, sk_key, sk_ver, _ep} = key, [{_key, value}]} when {sk_key, sk_ver} < end_key ->
256256- # This entry is visible and overlaps, accumulate
257257- {ek_key, ek_ver, block_index, block_checksum, _id} = value
258258- table = {:table, block_index, block_checksum, {sk_key, sk_ver}, {ek_key, ek_ver}}
259259-260260- acc = [table | acc]
261261- scan_tables(manifest, epoch, level, end_key, key, acc)
262262-263263- _ ->
264264- # Reached the end of either the ets table, the level, or the range (end_key)
265265- acc
266266- end
267267- end
268268-269190 @doc false
270191 def dump(manifest) do
271192 :ets.tab2list(manifest)
-4
lib/xks/xks.ex
···8686 %XKS{manifest: manifest, block_store: block_store} = xks
8787 epoch = :atomics.get(xks.epoch_atomic, 1)
88888989- # start_key has version=0 because we have no way of knowing its latest version in the DB
9090- # end_key has version=0 because the end key is exclusive so we won't actually read it
9191- _tables = Manifest.list_overlapping_tables(manifest, epoch, 1, {start_key, 0}, {end_key, 0})
9292-9389 memtable_iterators =
9490 Manifest.list_memtables(xks.manifest, epoch)
9591 |> Enum.map(fn {_id, memtable} ->