git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 5/5] reftable: document reading and writing indices

From
Patrick Steinhardt <ps@pks.im>
Date
Jan 26, 2024, 10:31 UTC
Message-ID
<7850e65878e42c6ae5064554a3681a3ea1a7ae6e.1706263918.git.ps@pks.im>
In-Reply-To
<cover.1706263918.git.ps@pks.im>

The way the index gets written and read is not trivial at all and requires the reader to piece together a bunch of parts to figure out how it works. Add some documentation to hopefully make this easier to understand for the next reader.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 reftable/reader.c | 27 +++++++++++++++++++++++++++
 reftable/writer.c | 23 +++++++++++++++++++++++
 2 files changed, 50 insertions(+)
diff --git a/reftable/reader.c b/reftable/reader.c
index 278f727a3d..6011d0aa04 100644
--- a/reftable/reader.c
+++ b/reftable/reader.c
@@ -508,11 +508,38 @@ static int reader_seek_indexed(struct reftable_reader *r,
 	if (err < 0)
 		goto done;
 
+	/*
+	 * The index may consist of multiple levels, where each level may have
+	 * multiple index blocks. We start by doing a linear search in the
+	 * highest layer that identifies the relevant index block as well as
+	 * the record inside that block that corresponds to our wanted key.
+	 */
 	err = reader_seek_linear(&index_iter, &want_index);
 	if (err < 0)
 		goto done;
 
+	/*
+	 * Traverse down the levels until we find a non-index entry.
+	 */
 	while (1) {
+		/*
+		 * In case we seek a record that does not exist the index iter
+		 * will tell us that the iterator is over. This works because
+		 * the last index entry of the current level will contain the
+		 * last key it knows about. So in case our seeked key is larger
+		 * than the last indexed key we know that it won't exist.
+		 *
+		 * There is one subtlety in the layout of the index section
+		 * that makes this work as expected: the highest-level index is
+		 * at end of the section and will point backwards and thus we
+		 * start reading from the end of the index section, not the
+		 * beginning.
+		 *
+		 * If that wasn't the case and the order was reversed then the
+		 * linear seek would seek into the lower levels and traverse
+		 * all levels of the index only to find out that the key does
+		 * not exist.
+		 */
 		err = table_iter_next(&index_iter, &index_result);
 		table_iter_block_done(&index_iter);
 		if (err != 0)
diff --git a/reftable/writer.c b/reftable/writer.c
index 24fce5630a..6028789dee 100644
--- a/reftable/writer.c
+++ b/reftable/writer.c
@@ -391,6 +391,24 @@ static int writer_finish_section(struct reftable_writer *w)
 	if (err < 0)
 		return err;
 
+	/*
+	 * When the section we are about to index has a lot of blocks then the
+	 * index itself may span across multiple blocks, as well. This would
+	 * require a linear scan over index blocks only to find the desired
+	 * indexed block, which is inefficient. Instead, we write a multi-level
+	 * index where index records of level N+1 will refer to index blocks of
+	 * level N. This isn't constant time, either, but at least logarithmic.
+	 *
+	 * This loop handles writing this multi-level index. Note that we write
+	 * the lowest-level index pointing to the indexed blocks first. We then
+	 * continue writing additional index levels until the current level has
+	 * less blocks than the threshold so that the highest level will be at
+	 * the end of the index section.
+	 *
+	 * Readers are thus required to start reading the index section from
+	 * its end, which is why we set `index_start` to the beginning of the
+	 * last index section.
+	 */
 	while (w->index_len > threshold) {
 		struct reftable_index_record *idx = NULL;
 		size_t i, idx_len;
@@ -428,6 +446,11 @@ static int writer_finish_section(struct reftable_writer *w)
 		reftable_free(idx);
 	}
 
+	/*
+	 * The index may still contain a number of index blocks lower than the
+	 * threshold. Clear it so that these entries don't leak into the next
+	 * index section.
+	 */
 	writer_clear_index(w);
 
 	bstats = writer_reftable_block_stats(w, typ);
-- 
2.43.GIT
Previous: Patrick SteinhardtNext: Junio C Hamano
Message 10 of 21 in “reftable: fix writing multi-level indices”
  1. 0/5 reftable: fix writing multi-level indicesPatrick Steinhardt, Jan 26, 2024
  2. 1/5 reftable/reader: be more careful about errors in indexed seeksPatrick Steinhardt, Jan 26, 2024
  3. 2/5 reftable/writer: use correct type to iterate through index entriesPatrick Steinhardt, Jan 26, 2024
  4. 3/5 reftable/writer: simplify writing index recordsPatrick Steinhardt, Jan 26, 2024
  5. Toon ClaesJan 31, 2024
  6. Patrick SteinhardtFeb 1, 2024
  7. Kristoffer HaugsbakkJan 31, 2024
  8. Patrick SteinhardtFeb 1, 2024
  9. 4/5 reftable/writer: fix writing multi-level indicesPatrick Steinhardt, Jan 26, 2024
  10. 5/5 reftable: document reading and writing indicesPatrick Steinhardt, Jan 26, 2024
  11. Junio C HamanoJan 26, 2024
  12. 0/5 reftable: fix writing multi-level indicesPatrick Steinhardt, Feb 1, 2024
  13. 1/5 reftable/reader: be more careful about errors in indexed seeksPatrick Steinhardt, Feb 1, 2024
  14. 2/5 reftable/writer: use correct type to iterate through index entriesPatrick Steinhardt, Feb 1, 2024
  15. 3/5 reftable/writer: simplify writing index recordsPatrick Steinhardt, Feb 1, 2024
  16. 4/5 reftable/writer: fix writing multi-level indicesPatrick Steinhardt, Feb 1, 2024
  17. jltoblerFeb 5, 2024
  18. Patrick SteinhardtFeb 6, 2024
  19. 5/5 reftable: document reading and writing indicesPatrick Steinhardt, Feb 1, 2024
  20. jltoblerFeb 6, 2024
  21. Patrick SteinhardtFeb 6, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.