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

Re: [PATCH v2 12/17] chunk-format: create read chunk API

From
Junio C Hamano <gitster@pobox.com>
Date
Feb 4, 2021, 23:40 UTC
Message-ID
<xmqqczxf4d2k.fsf@gitster.c.googlers.com>
In-Reply-To
<d8d8e9e2aa3faf0fdda5dc688fb92e924fec423a.1611759716.git.gitgitgadget@gmail.com>
"Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com> writes:
> We are re-using the anonymous 'struct chunkfile' data, as it is internal
> to the chunk-format API. This gives it essentially two modes: write and
> read. If the same struct instance was used for both reads and writes,
> then there would be failures.

Writing it here won't help future developers very much. I think that belongs to API/function doc for init_chunkfile().

Show 23 quoted lines
> diff --git a/chunk-format.c b/chunk-format.c
> index ab914c55856..74501084cf8 100644
> --- a/chunk-format.c
> +++ b/chunk-format.c
> @@ -12,6 +12,8 @@ struct chunk_info {
>  	uint32_t id;
>  	uint64_t size;
>  	chunk_write_fn write_fn;
> +
> +	const void *start;
>  };
>  
>  struct chunkfile {
> @@ -89,3 +91,81 @@ int write_chunkfile(struct chunkfile *cf, void *data)
>  
>  	return 0;
>  }
> +
> +int read_table_of_contents(struct chunkfile *cf,
> +			   const unsigned char *mfile,
> +			   size_t mfile_size,
> +			   uint64_t toc_offset,
> +			   int toc_length)

It's a bit of mystery, having seen how the table-of-contents is laid out by reading the writing side of the code, how toc_offset and toc_length are discovered by the caller. IIRC, the size to cover everything from the beginning of the file to the end of the table-of-contents was recorded as the length of a non-existent chunk with id 0, but we need to be able to somehow find it to use that as a way to get to the (end of) table-of-contents from the beginning of the file. I guess we'll learn enough when we get to read the code that calls this function.

Show 22 quoted lines
> +{
> +	uint32_t chunk_id;
> +	const unsigned char *table_of_contents = mfile + toc_offset;
> +
> +	ALLOC_GROW(cf->chunks, toc_length, cf->chunks_alloc);
> +
> +	while (toc_length--) {
> +		uint64_t chunk_offset, next_chunk_offset;
> +
> +		chunk_id = get_be32(table_of_contents);
> +		chunk_offset = get_be64(table_of_contents + 4);
> +
> +		if (!chunk_id) {
> +			error(_("terminating chunk id appears earlier than expected"));
> +			return 1;
> +		}
> +
> +		table_of_contents += CHUNK_LOOKUP_WIDTH;
> +		next_chunk_offset = get_be64(table_of_contents + 4);
> +
> +		if (next_chunk_offset < chunk_offset ||
> +		    next_chunk_offset > mfile_size - the_hash_algo->rawsz) {

The chunks have to be recorded in toc in the order they appear, and there must be enough room to store the hashfile trailer checksum after the last chunk. OK.

Show 16 quoted lines
> +			error(_("improper chunk offset(s) %"PRIx64" and %"PRIx64""),
> +			      chunk_offset, next_chunk_offset);
> +			return -1;
> +		}
> +
> +		cf->chunks[cf->chunks_nr].id = chunk_id;
> +		cf->chunks[cf->chunks_nr].start = mfile + chunk_offset;
> +		cf->chunks[cf->chunks_nr].size = next_chunk_offset - chunk_offset;
> +		cf->chunks_nr++;
> +	}
> +
> +	chunk_id = get_be32(table_of_contents);
> +	if (chunk_id) {
> +		error(_("final chunk has non-zero id %"PRIx32""), chunk_id);
> +		return -1;
> +	}

Shouldn't we be validating the size component associated with this "id=0" fake chunk that appears at the end as well? IIRC, the size field should be pointing at the byte immediately after the TOC entry for the last true chunk, immediately before this zero chunk id?

Show 11 quoted lines
> +int pair_chunk(struct chunkfile *cf,
> +	       uint32_t chunk_id,
> +	       const unsigned char **p)
> +{
> +	int i;
> +
> +	for (i = 0; i < cf->chunks_nr; i++) {
> +		if (cf->chunks[i].id == chunk_id) {
> +			*p = cf->chunks[i].start;
> +			return 0;
> +		}

OK, the assumption here is that there will be at most one chunk that has the chunk_id we seek to find (or putting it differently, second and subsequent chunks with the same ID are ignored). We may want to write it down somewhere.

Show 15 quoted lines
> +	}
> +
> +	return CHUNK_NOT_FOUND;
> +}
> +
> +int read_chunk(struct chunkfile *cf,
> +	       uint32_t chunk_id,
> +	       chunk_read_fn fn,
> +	       void *data)
> +{
> +	int i;
> +
> +	for (i = 0; i < cf->chunks_nr; i++) {
> +		if (cf->chunks[i].id == chunk_id)
> +			return fn(cf->chunks[i].start, cf->chunks[i].size, data);

It is curious why pair_chunk() exists in the first place. With something like this:

        int pair_chunk_fn(const unsigned char *chunk_start,
                          size_t chunk_size,
                          void *data)
        {
                const unsigned char **p = data;
                *p = chunk_start;
                return 0;
        }
instead of
	const unsigned char *location;
	pair_chunk(cf, chunk_id, &location);
we can write
	const unsigned char *location;
	read_chunk(cf, chunk_id, pair_chunk_fn, &location);

no? That would allow us to reorganize the in-core TOC more easily if it turns out to be necessary in the future.

Show 29 quoted lines
> diff --git a/chunk-format.h b/chunk-format.h
> index bfaed672813..b62c9bf8ba1 100644
> --- a/chunk-format.h
> +++ b/chunk-format.h
> @@ -17,4 +17,37 @@ void add_chunk(struct chunkfile *cf,
>  	       size_t size);
>  int write_chunkfile(struct chunkfile *cf, void *data);
>  
> +int read_table_of_contents(struct chunkfile *cf,
> +			   const unsigned char *mfile,
> +			   size_t mfile_size,
> +			   uint64_t toc_offset,
> +			   int toc_length);
> +
> +#define CHUNK_NOT_FOUND (-2)
> +
> +/*
> + * Find 'chunk_id' in the given chunkfile and assign the
> + * given pointer to the position in the mmap'd file where
> + * that chunk begins.
> + *
> + * Returns CHUNK_NOT_FOUND if the chunk does not exist.
> + */
> +int pair_chunk(struct chunkfile *cf,
> +	       uint32_t chunk_id,
> +	       const unsigned char **p);
> +
> +typedef int (*chunk_read_fn)(const unsigned char *chunk_start,
> +			     size_t chunk_size, void *data);

Is the assumption throughout the chunked file API that reading is actually not done as a "seek+read+process", but as a normal memory access over mmapped region? The reason I ask is because the answer affects the choice of the right type for the offset. The function signature of read_table_of_contents() uses size_t to represent the length of the entire mmapped region that holds the data from the file, and that is better than off_t, especially if size_t were smaller than off_t (i.e. we may not be able to mmap a huge size that filesystem can handle and let us access with seek+read).

But the assumption that the whole mfile can be mmapped in as a whole is only in read_table_of_contents(), and users of read_chunk() API can be oblivious, I think---IOW, we could "page in" the chunk's data in read_chunk() while the callback function works on it in-core, and then discard it, if we wanted to change the implementation [*].

	Side note: for that to work, the API must say that the
	callback function MUST NOT assume that the memory region
	starting at chunk_start it is given will stay in memory
	after it returns.  Otherwise, we cannot "page in" and "page
	out".

I am not advocating that we should not assume the entire file can be mapped in. I would however advocate to be explicit in documenting what the users of API can and cannot do (e.g. if we want the "read" callbacks to take advantage of the fact that mfile will stay mapped until the chunkfile is discarded, we should say so, so that they will not make unnecessary copies out of the mmapped region).

Show 11 quoted lines
> +/*
> + * Find 'chunk_id' in the given chunkfile and call the
> + * given chunk_read_fn method with the information for
> + * that chunk.
> + *
> + * Returns CHUNK_NOT_FOUND if the chunk does not exist.
> + */
> +int read_chunk(struct chunkfile *cf,
> +	       uint32_t chunk_id,
> +	       chunk_read_fn fn,
> +	       void *data);

Did I miss an update to free_chunkfile() to release resources used to read this file? For some reason, unlike the writing side, the reading side of this API feels a bit incomplete to me.

Thanks.
Previous: Derrick Stolee via GitGitGadgetNext: Derrick Stolee
Message 57 of 120 in “Refactor chunk-format into an API”
  1. 00/17 Refactor chunk-format into an APIDerrick Stolee via GitGitGadget, Jan 26, 2021
  2. 02/17 chunk-format: create chunk format write APIDerrick Stolee via GitGitGadget, Jan 26, 2021
  3. Taylor BlauJan 27, 2021
  4. Derrick StoleeJan 27, 2021
  5. 01/17 commit-graph: anonymize data in chunk_write_fnDerrick Stolee via GitGitGadget, Jan 26, 2021
  6. Chris TorekJan 27, 2021
  7. Taylor BlauJan 27, 2021
  8. 05/17 midx: use context in write_midx_pack_names()Derrick Stolee via GitGitGadget, Jan 26, 2021
  9. 06/17 midx: add entries to write_midx_contextDerrick Stolee via GitGitGadget, Jan 26, 2021
  10. 04/17 midx: rename pack_info to write_midx_contextDerrick Stolee via GitGitGadget, Jan 26, 2021
  11. Taylor BlauJan 27, 2021
  12. 03/17 commit-graph: use chunk-format write APIDerrick Stolee via GitGitGadget, Jan 26, 2021
  13. Taylor BlauJan 27, 2021
  14. 14/17 midx: use chunk-format read APIDerrick Stolee via GitGitGadget, Jan 26, 2021
  15. Taylor BlauJan 27, 2021
  16. Derrick StoleeJan 27, 2021
  17. 17/17 chunk-format: add technical docsDerrick Stolee via GitGitGadget, Jan 26, 2021
  18. 11/17 midx: use chunk-format API in write_midx_internal()Derrick Stolee via GitGitGadget, Jan 26, 2021
  19. 16/17 chunk-format: restore duplicate chunk checksDerrick Stolee via GitGitGadget, Jan 26, 2021
  20. 15/17 midx: use 64-bit multiplication for chunk sizesDerrick Stolee via GitGitGadget, Jan 26, 2021
  21. 07/17 midx: add pack_perm to write_midx_contextDerrick Stolee via GitGitGadget, Jan 26, 2021
  22. 10/17 midx: drop chunk progress during writeDerrick Stolee via GitGitGadget, Jan 26, 2021
  23. 09/17 midx: return success/failure in chunk write methodsDerrick Stolee via GitGitGadget, Jan 26, 2021
  24. 08/17 midx: add num_large_offsets to write_midx_contextDerrick Stolee via GitGitGadget, Jan 26, 2021
  25. 13/17 commit-graph: use chunk-format read APIDerrick Stolee via GitGitGadget, Jan 26, 2021
  26. 12/17 chunk-format: create read chunk APIDerrick Stolee via GitGitGadget, Jan 26, 2021
  27. Taylor BlauJan 27, 2021
  28. Taylor BlauJan 27, 2021
  29. Junio C HamanoJan 26, 2021
  30. 00/17 Refactor chunk-format into an APIDerrick Stolee via GitGitGadget, Jan 27, 2021
  31. 05/17 midx: use context in write_midx_pack_names()Derrick Stolee via GitGitGadget, Jan 27, 2021
  32. 03/17 commit-graph: use chunk-format write APIDerrick Stolee via GitGitGadget, Jan 27, 2021
  33. 07/17 midx: add pack_perm to write_midx_contextDerrick Stolee via GitGitGadget, Jan 27, 2021
  34. 02/17 chunk-format: create chunk format write APIDerrick Stolee via GitGitGadget, Jan 27, 2021
  35. Junio C HamanoFeb 4, 2021
  36. Junio C HamanoFeb 4, 2021
  37. Derrick StoleeFeb 5, 2021
  38. Junio C HamanoFeb 5, 2021
  39. 15/17 midx: use 64-bit multiplication for chunk sizesDerrick Stolee via GitGitGadget, Jan 27, 2021
  40. Junio C HamanoFeb 5, 2021
  41. Chris TorekFeb 5, 2021
  42. Junio C HamanoFeb 5, 2021
  43. Chris TorekFeb 6, 2021
  44. Derrick StoleeFeb 5, 2021
  45. Junio C HamanoFeb 5, 2021
  46. SZEDER GáborFeb 7, 2021
  47. Junio C HamanoFeb 8, 2021
  48. 17/17 chunk-format: add technical docsDerrick Stolee via GitGitGadget, Jan 27, 2021
  49. Junio C HamanoFeb 5, 2021
  50. 14/17 midx: use chunk-format read APIDerrick Stolee via GitGitGadget, Jan 27, 2021
  51. 13/17 commit-graph: use chunk-format read APIDerrick Stolee via GitGitGadget, Jan 27, 2021
  52. 16/17 chunk-format: restore duplicate chunk checksDerrick Stolee via GitGitGadget, Jan 27, 2021
  53. Junio C HamanoFeb 5, 2021
  54. Derrick StoleeFeb 5, 2021
  55. 11/17 midx: use chunk-format API in write_midx_internal()Derrick Stolee via GitGitGadget, Jan 27, 2021
  56. 12/17 chunk-format: create read chunk APIDerrick Stolee via GitGitGadget, Jan 27, 2021
  57. Junio C HamanoFeb 4, 2021
  58. Derrick StoleeFeb 5, 2021
  59. Junio C HamanoFeb 5, 2021
  60. Junio C HamanoFeb 8, 2021
  61. Derrick StoleeFeb 9, 2021
  62. Junio C HamanoFeb 9, 2021
  63. 09/17 midx: return success/failure in chunk write methodsDerrick Stolee via GitGitGadget, Jan 27, 2021
  64. Junio C HamanoFeb 4, 2021
  65. Derrick StoleeFeb 5, 2021
  66. 10/17 midx: drop chunk progress during writeDerrick Stolee via GitGitGadget, Jan 27, 2021
  67. 06/17 midx: add entries to write_midx_contextDerrick Stolee via GitGitGadget, Jan 27, 2021
  68. 08/17 midx: add num_large_offsets to write_midx_contextDerrick Stolee via GitGitGadget, Jan 27, 2021
  69. 04/17 midx: rename pack_info to write_midx_contextDerrick Stolee via GitGitGadget, Jan 27, 2021
  70. 01/17 commit-graph: anonymize data in chunk_write_fnDerrick Stolee via GitGitGadget, Jan 27, 2021
  71. Taylor BlauJan 27, 2021
  72. Junio C HamanoFeb 5, 2021
  73. Derrick StoleeFeb 5, 2021
  74. 00/17 Refactor chunk-format into an APIDerrick Stolee via GitGitGadget, Feb 5, 2021
  75. 10/17 midx: drop chunk progress during writeDerrick Stolee via GitGitGadget, Feb 5, 2021
  76. 17/17 chunk-format: add technical docsDerrick Stolee via GitGitGadget, Feb 5, 2021
  77. 09/17 midx: return success/failure in chunk write methodsDerrick Stolee via GitGitGadget, Feb 5, 2021
  78. 15/17 midx: use 64-bit multiplication for chunk sizesDerrick Stolee via GitGitGadget, Feb 5, 2021
  79. 02/17 chunk-format: create chunk format write APIDerrick Stolee via GitGitGadget, Feb 5, 2021
  80. SZEDER GáborFeb 7, 2021
  81. Derrick StoleeFeb 8, 2021
  82. SZEDER GáborFeb 11, 2021
  83. 08/17 midx: add num_large_offsets to write_midx_contextDerrick Stolee via GitGitGadget, Feb 5, 2021
  84. 05/17 midx: use context in write_midx_pack_names()Derrick Stolee via GitGitGadget, Feb 5, 2021
  85. 14/17 midx: use chunk-format read APIDerrick Stolee via GitGitGadget, Feb 5, 2021
  86. 07/17 midx: add pack_perm to write_midx_contextDerrick Stolee via GitGitGadget, Feb 5, 2021
  87. 06/17 midx: add entries to write_midx_contextDerrick Stolee via GitGitGadget, Feb 5, 2021
  88. 16/17 chunk-format: restore duplicate chunk checksDerrick Stolee via GitGitGadget, Feb 5, 2021
  89. 13/17 commit-graph: use chunk-format read APIDerrick Stolee via GitGitGadget, Feb 5, 2021
  90. 01/17 commit-graph: anonymize data in chunk_write_fnDerrick Stolee via GitGitGadget, Feb 5, 2021
  91. 03/17 commit-graph: use chunk-format write APIDerrick Stolee via GitGitGadget, Feb 5, 2021
  92. 04/17 midx: rename pack_info to write_midx_contextDerrick Stolee via GitGitGadget, Feb 5, 2021
  93. 11/17 midx: use chunk-format API in write_midx_internal()Derrick Stolee via GitGitGadget, Feb 5, 2021
  94. 12/17 chunk-format: create read chunk APIDerrick Stolee via GitGitGadget, Feb 5, 2021
  95. SZEDER GáborFeb 7, 2021
  96. Derrick StoleeFeb 8, 2021
  97. 00/17 Refactor chunk-format into an APIDerrick Stolee via GitGitGadget, Feb 18, 2021
  98. 07/17 midx: add pack_perm to write_midx_contextDerrick Stolee via GitGitGadget, Feb 18, 2021
  99. 05/17 midx: use context in write_midx_pack_names()Derrick Stolee via GitGitGadget, Feb 18, 2021
  100. 03/17 commit-graph: use chunk-format write APIDerrick Stolee via GitGitGadget, Feb 18, 2021
  101. SZEDER GáborFeb 24, 2021
  102. Taylor BlauFeb 24, 2021
  103. Derrick StoleeFeb 24, 2021
  104. Junio C HamanoFeb 24, 2021
  105. 04/17 midx: rename pack_info to write_midx_contextDerrick Stolee via GitGitGadget, Feb 18, 2021
  106. 06/17 midx: add entries to write_midx_contextDerrick Stolee via GitGitGadget, Feb 18, 2021
  107. 02/17 chunk-format: create chunk format write APIDerrick Stolee via GitGitGadget, Feb 18, 2021
  108. 01/17 commit-graph: anonymize data in chunk_write_fnDerrick Stolee via GitGitGadget, Feb 18, 2021
  109. 08/17 midx: add num_large_offsets to write_midx_contextDerrick Stolee via GitGitGadget, Feb 18, 2021
  110. 09/17 midx: return success/failure in chunk write methodsDerrick Stolee via GitGitGadget, Feb 18, 2021
  111. 10/17 midx: drop chunk progress during writeDerrick Stolee via GitGitGadget, Feb 18, 2021
  112. 11/17 midx: use chunk-format API in write_midx_internal()Derrick Stolee via GitGitGadget, Feb 18, 2021
  113. 12/17 chunk-format: create read chunk APIDerrick Stolee via GitGitGadget, Feb 18, 2021
  114. 17/17 chunk-format: add technical docsDerrick Stolee via GitGitGadget, Feb 18, 2021
  115. Junio C HamanoFeb 18, 2021
  116. Derrick StoleeFeb 19, 2021
  117. 15/17 midx: use 64-bit multiplication for chunk sizesDerrick Stolee via GitGitGadget, Feb 18, 2021
  118. 14/17 midx: use chunk-format read APIDerrick Stolee via GitGitGadget, Feb 18, 2021
  119. 13/17 commit-graph: use chunk-format read APIDerrick Stolee via GitGitGadget, Feb 18, 2021
  120. 16/17 chunk-format: restore duplicate chunk checksDerrick Stolee via GitGitGadget, Feb 18, 2021

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.