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

Re: [PATCH] packed_ref_cache: don't use mmap() for small files

From
Kim Gybels <kgybels@infogroep.be>
Date
Jan 15, 2018, 23:37 UTC
Message-ID
<20180115233751.GA1781@infogroep.be>
In-Reply-To
<20180115211505.GA4778@sigill.intra.peff.net>
On (15/01/18 16:15), Jeff King wrote:
Show 13 quoted lines
> On Sat, Jan 13, 2018 at 05:11:49PM +0100, Kim Gybels wrote:
> 
> > Take a hint from commit ea68b0ce9f8ce8da3e360aed3cbd6720159ffbee and use
> > read() instead of mmap() for small packed-refs files.
> > 
> > This also fixes the problem[1] where xmmap() returns NULL for zero
> > length[2], for which munmap() later fails.
> > 
> > Alternatively, we could simply check for NULL before munmap(), or
> > introduce an xmunmap() that could be used together with xmmap().
> 
> This looks good to me, and since it's a recent-ish regression, I think
> we should take the minimal fix here.
The minimal fix being a simple NULL check before munmap()?
Show 5 quoted lines
> But it does make me wonder whether xmmap() ought to be doing this "small
> mmap" optimization for us. Obviously that only works when we do
> MAP_PRIVATE and never write to the result. But that's how we always use
> it anyway, and we're restricted to that to work with the NO_MMAP wrapper
> in compat/mmap.c.

Maybe I should have left the optimization for small files out of the patch for the zero length regression. After all, read() vs mmap() performance might depend on other factors than just size.

Show 23 quoted lines
> > @@ -489,21 +491,21 @@ static int load_contents(struct snapshot *snapshot)
> >  		die_errno("couldn't stat %s", snapshot->refs->path);
> >  	size = xsize_t(st.st_size);
> >  
> > -	switch (mmap_strategy) {
> > -	case MMAP_NONE:
> > +	if (!size) {
> > +		snapshot->buf = NULL;
> > +		snapshot->eof = NULL;
> > +		snapshot->mmapped = 0;
> > +	} else if (size <= SMALL_FILE_SIZE || mmap_strategy == MMAP_NONE) {
> >  		snapshot->buf = xmalloc(size);
> >  		bytes_read = read_in_full(fd, snapshot->buf, size);
> >  		if (bytes_read < 0 || bytes_read != size)
> >  			die_errno("couldn't read %s", snapshot->refs->path);
> >  		snapshot->eof = snapshot->buf + size;
> >  		snapshot->mmapped = 0;
> 
> If the "!size" case is just lumped in with "size <= SMALL_FILE_SIZE",
> then we'd try to xmalloc(0), which is guaranteed to work (we fallback to
> a 1-byte allocation if necessary). Would that make things simpler and
> more consistent for the rest of the code to always have snapshot->buf be
> a valid pointer (just based on seeing Michael's follow-up patches)?

Indeed, all those patches are to avoid using the NULL pointers in ways that are undefined. We could also copy index_core's way of handling the zero length case: ret = index_mem(sha1, "", size, type, path, flags);

Point to some static memory instead of NULL, then all the pointer arithmetic is defined.
-Kim
Previous: Jeff KingNext: Jeff King
Message 11 of 33 in “packed_ref_cache: don't use mmap() for small files”
  1. packed_ref_cache: don't use mmap() for small filesKim Gybels, Jan 13, 2018
  2. Johannes SchindelinJan 13, 2018
  3. packed_ref_cache: don't use mmap() for small filesKim Gybels, Jan 14, 2018
  4. 0/3 Supplements to "packed_ref_cache: don't use mmap() for small files"Michael Haggerty, Jan 15, 2018
  5. Johannes SchindelinJan 17, 2018
  6. Junio C HamanoJan 17, 2018
  7. 1/3 SQUASH? Mention that `snapshot::buf` can be NULL for empty filesMichael Haggerty, Jan 15, 2018
  8. 2/3 create_snapshot(): exit early if the file was emptyMichael Haggerty, Jan 15, 2018
  9. 3/3 find_reference_location(): don't invoke if `snapshot->buf` is NULLMichael Haggerty, Jan 15, 2018
  10. Jeff KingJan 15, 2018
  11. Kim GybelsJan 15, 2018
  12. Jeff KingJan 15, 2018
  13. packed_ref_cache: don't use mmap() for small filesKim Gybels, Jan 16, 2018
  14. Jeff KingJan 17, 2018
  15. Michael HaggertyJan 21, 2018
  16. Junio C HamanoJan 22, 2018
  17. Michael HaggertyJan 24, 2018
  18. 0/6 Yet another approach to handling empty snapshotsMichael Haggerty, Jan 24, 2018
  19. Jeff KingJan 24, 2018
  20. Junio C HamanoJan 24, 2018
  21. Johannes SchindelinFeb 15, 2018
  22. 1/6 struct snapshot: store `start` rather than `header_len`Michael Haggerty, Jan 24, 2018
  23. Jeff KingJan 24, 2018
  24. 3/6 find_reference_location(): make function safe for empty snapshotsMichael Haggerty, Jan 24, 2018
  25. Jeff KingJan 24, 2018
  26. Junio C HamanoJan 24, 2018
  27. Jeff KingJan 24, 2018
  28. 2/6 create_snapshot(): use `xmemdupz()` rather than a strbufMichael Haggerty, Jan 24, 2018
  29. 5/6 load_contents(): don't try to mmap an empty fileMichael Haggerty, Jan 24, 2018
  30. 4/6 packed_ref_iterator_begin(): make optimization more generalMichael Haggerty, Jan 24, 2018
  31. Jeff KingJan 24, 2018
  32. 6/6 packed_ref_cache: don't use mmap() for small filesMichael Haggerty, Jan 24, 2018
  33. Junio C HamanoJan 24, 2018

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.