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

Re: [PATCH 17/33] repack_without_ref(): silence errors for dangling packed refs

From
Michael Haggerty <mhagger@alum.mit.edu>
Date
Apr 17, 2013, 08:41 UTC
Message-ID
<516E602F.3090703@alum.mit.edu>
In-Reply-To
<7vhaj7vgk6.fsf@alter.siamese.dyndns.org>
On 04/15/2013 07:39 PM, Junio C Hamano wrote:
Show 22 quoted lines
> Michael Haggerty <mhagger@alum.mit.edu> writes:
> 
>> Stop emitting an error message for dangling packed references found
>> when deleting another packed reference.  See the previous commit for a
>> longer explanation of the issue.
>>
>> Change repack_without_ref_fn() to silently ignore dangling packed
>> references.
>>
>> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
> 
> Somehow this feels as if it is sweeping the problem under the rug.
> 
> If you ignore a ref for which a loose ref exists when you update a
> packed refs file, whether the stale "packed" one points at an object
> that is still there or an object that has been garbage collected,
> you would not even have to check if the "ref" resolves to object or
> anything like that, no?
> 
> Am I missing something?
> 
> This one feels iffy in the otherwise pleasant-to-read series.

The usual situation when this code would be triggered would be that the packed reference is overridden by a loose ref and points at an object that has been garbage collected. In that case it is definitely incorrect to emit an error message.

But the fact that we don't explicitly verify that there is an overriding loose reference means that it is possible that the failure to resolve the packed ref comes from some kind of repository corruption, and you are correct that such a problem would be swept under the rug by my change.

I've been trying to minimize the extra work that repack_without_ref() needs to do to write peeled references, to avoid stretching out the delay that can now occur when deleting a reference. Thus I was trying to save a check of loose references during this operation. But I guess I agree that a little bit more caution would be prudent.

I can think of a few ways to avoid sweeping possible indications of repo corruption under the rug, in order of increasing run-time:

1. If a packed ref's SHA-1 cannot be resolved, write the packed ref to
the new packed-refs file anyway with SHA-1 but without a peeled value.
This would avoid having to check the loose references and avoid erasing
possible evidence of corruption, but would delay an actual check for
corruption until a later time.  It would be a quick fix, effectively
kicking the can down the road instead of sweeping it under the rug.

Minor pitfall: a reference that is listed without a peeled value in a fully-peeled pack-refs file tells future readers that the corresponding SHA-1 *cannot* be peeled. IF the named object would somehow reappear in the repository (e.g., via a fetch) and IF the object is peelable and IF there is in fact no loose ref overriding the packed ref, then the final result would be that one form of corruption (reference points to non-existent object) would be converted to another form (reference falsely believed to be non-peelable). I think this is an acceptable risk because (a) it would only happen in an unlikely series of events in a repo that was already corrupt, and (b) because falsely believing a reference to be non-peelable wouldn't have terrible consequences.

2. Whenever a packed reference cannot be resolved to an object, verify
that there is indeed a loose reference overriding it; if not, emit an
error and in either case omit the packed ref from the output.
3. Check for an overriding loose reference *before* trying to peel a
packed reference, and omit any overridden loose references from the
output packed-refs file.  This would be close to running "pack-refs
--no-prune" without the "is_tag_ref" test and with reuse of available
peeled values.  This approach would tidy up the packed-refs file a bit
more than (2) because it would cause the deletion of more overridden
packed refs, but only as part of first peeling them, which should only
happen once in a repo, and only if the first peeling occurs within
repack_without_ref() as opposed to an explicit pack_refs().  So it's a
negligible improvement over (2).
4. Further along the "correctness" spectrum, one could check for
overriding loose references *every* time the packed-refs file is
rewritten by repack_without_ref(), even for references whose peeled
values are already known.  But this would add overhead to every deletion
of a packed reference, which is probably not justified.

I'm worried that implementing 2-4 would introduce new race conditions of the type that Peff discovered recently, unless we fix the locking policy first (which is also on my TODO list). So my suggestion is to implement 1 now and implement 2 sometime in the future.

Opinions?
Michael
-- 
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/
Previous: Junio C HamanoNext: Michael Haggerty
Message 46 of 64 in “Various cleanups around reference packing and peeling”
  1. 00/33 Various cleanups around reference packing and peelingMichael Haggerty, Apr 14, 2013
  2. 01/33 refs: document flags constants REF_*Michael Haggerty, Apr 14, 2013
  3. 02/33 refs: document the fields of struct ref_valueMichael Haggerty, Apr 14, 2013
  4. 03/33 refs: document do_for_each_ref() and do_one_ref()Michael Haggerty, Apr 14, 2013
  5. Junio C HamanoApr 15, 2013
  6. Michael HaggertyApr 16, 2013
  7. 04/33 refs: document how current_ref is usedMichael Haggerty, Apr 14, 2013
  8. 05/33 refs: define constant PEELED_LINE_LENGTHMichael Haggerty, Apr 14, 2013
  9. 06/33 do_for_each_ref_in_dirs(): remove dead codeMichael Haggerty, Apr 14, 2013
  10. 07/33 get_packed_ref(): return a ref_entryMichael Haggerty, Apr 14, 2013
  11. 08/33 peel_ref(): use function get_packed_ref()Michael Haggerty, Apr 14, 2013
  12. 09/33 repack_without_ref(): use function get_packed_ref()Michael Haggerty, Apr 14, 2013
  13. 10/33 refs: extract a function ref_resolves_to_object()Michael Haggerty, Apr 14, 2013
  14. Junio C HamanoApr 15, 2013
  15. Michael HaggertyApr 16, 2013
  16. Junio C HamanoApr 16, 2013
  17. 11/33 refs: extract function peel_object()Michael Haggerty, Apr 14, 2013
  18. 12/33 peel_object(): give more specific information in return valueMichael Haggerty, Apr 14, 2013
  19. Junio C HamanoApr 15, 2013
  20. 13/33 peel_ref(): fix return value for non-peelable, not-current referenceMichael Haggerty, Apr 14, 2013
  21. Junio C HamanoApr 15, 2013
  22. Michael HaggertyApr 16, 2013
  23. 14/33 refs: extract a function peel_entry()Michael Haggerty, Apr 14, 2013
  24. Junio C HamanoApr 15, 2013
  25. Michael HaggertyApr 16, 2013
  26. Junio C HamanoApr 16, 2013
  27. Michael HaggertyApr 16, 2013
  28. 15/33 refs: change the internal reference-iteration APIMichael Haggerty, Apr 14, 2013
  29. Junio C HamanoApr 15, 2013
  30. Michael HaggertyApr 16, 2013
  31. Junio C HamanoApr 16, 2013
  32. 16/33 t3210: test for spurious error messages for dangling packed refsMichael Haggerty, Apr 14, 2013
  33. Junio C HamanoApr 15, 2013
  34. Michael HaggertyApr 16, 2013
  35. Junio C HamanoApr 16, 2013
  36. Jeff KingApr 16, 2013
  37. Junio C HamanoApr 17, 2013
  38. Junio C HamanoApr 17, 2013
  39. 0/2 Add documentation for new expiry option valuesMichael Haggerty, Apr 18, 2013
  40. 1/2 git-gc.txt, git-reflog.txt: document new expiry optionsMichael Haggerty, Apr 18, 2013
  41. 2/2 api-parse-options.txt: document "no-" for non-boolean optionsMichael Haggerty, Apr 18, 2013
  42. prune: introduce OPT_EXPIRY_DATE() and use itJunio C Hamano, Apr 25, 2013
  43. Michael HaggertyApr 17, 2013
  44. 17/33 repack_without_ref(): silence errors for dangling packed refsMichael Haggerty, Apr 14, 2013
  45. Junio C HamanoApr 15, 2013
  46. Michael HaggertyApr 17, 2013
  47. 18/33 search_ref_dir(): return an index rather than a pointerMichael Haggerty, Apr 14, 2013
  48. 19/33 refs: change how packed refs are deletedMichael Haggerty, Apr 14, 2013
  49. 20/33 t3211: demonstrate loss of peeled refs if a packed ref is deletedMichael Haggerty, Apr 14, 2013
  50. 21/33 repack_without_ref(): write peeled refs in the rewritten fileMichael Haggerty, Apr 14, 2013
  51. Junio C HamanoApr 15, 2013
  52. 22/33 refs: extract a function write_packed_entry()Michael Haggerty, Apr 14, 2013
  53. 23/33 pack-refs: rename handle_one_ref() to pack_one_ref()Michael Haggerty, Apr 14, 2013
  54. 24/33 pack-refs: merge code from pack-refs.{c,h} into refs.{c,h}Michael Haggerty, Apr 14, 2013
  55. 25/33 pack_one_ref(): rename "path" parameter to "refname"Michael Haggerty, Apr 14, 2013
  56. 26/33 refs: use same lock_file object for both ref-packing functionsMichael Haggerty, Apr 14, 2013
  57. 27/33 pack_refs(): change to use do_for_each_entry()Michael Haggerty, Apr 14, 2013
  58. 28/33 refs: inline function do_not_prune()Michael Haggerty, Apr 14, 2013
  59. 29/33 pack_one_ref(): use function peel_entry()Michael Haggerty, Apr 14, 2013
  60. 30/33 pack_one_ref(): use write_packed_entry() to do the writingMichael Haggerty, Apr 14, 2013
  61. 31/33 pack_one_ref(): do some cheap tests before a more expensive oneMichael Haggerty, Apr 14, 2013
  62. 32/33 refs: change do_for_each_*() functions to take ref_cache argumentsMichael Haggerty, Apr 14, 2013
  63. Junio C HamanoApr 15, 2013
  64. 33/33 refs: handle the main ref_cache speciallyMichael Haggerty, Apr 14, 2013

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.