Repository navigation
Commit 83d4060
committed
refdb_fs: refresh packed refs after loose during iteration
There's a possible race between loose and packed refs when iterating
over refs. It works like this:
0. A loose ref X exists.
1. libgit2 reads the packed-refs file, which does not mention X.
2. A simultaneously-running `git pack-refs` commands packs X and
prunes the loose version.
3. libgit2 reads the loose directory, which no longer has X.
At this point, libgit2 claims that X does not exist, even though it
does. We can solve this by reading loose refs before packed. This works
because refs always migrate from loose to packed, but not the other way
around (technically an update to a packed ref creates a new loose file,
but it doesn't _delete_ the packed one, so we're guaranteed to always
see either the old or the new version).
See also git/git@98eeb09, which fixed
this same race in upstream Git, and discusses the race in more detail.
Note that just naively flipping the order of packed_load() and
iter_load_loose_paths() doesn't quite work. The latter expects the
packed refs to already be loaded, so that it can mark them with
PACKREF_SHADOWED. When doing it in reverse order, we have two options:
1. packed_reload() should take the "loose" vector and check to see
if refs it loads are shadowed. Doing this efficiently requires the
loose vector to be sorted, which might impact the output.
2. After loading both, take an additional pass over the loose vector
and mark shadowed packrefs. This is slightly less efficient than
(1) because of the extra pass, but it's big-O identical.
This patch does (2), since it seems less the risky route, and the
efficiency difference should be minimal. If we really care about
efficiency, then we should scrap the current PACKREF_SHADOWED bit
entirely, and instead do a sorted merge of the two lists.
Note that in this patch we do leave the existing PACKREF_SHADOWED
code in iter_load_loose_paths(). If the packed-refs file has already
been loaded, then that code would kick in (and our subsequent
packed-load would be a noop, as we only reload the file if the timestamp
indicates it has changed).1 parent e191637 commit 83d4060
1 file changed
Lines changed: 25 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
666 | 666 | | |
667 | 667 | | |
668 | 668 | | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
669 | 685 | | |
670 | 686 | | |
671 | 687 | | |
672 | 688 | | |
| 689 | + | |
673 | 690 | | |
674 | 691 | | |
675 | 692 | | |
676 | 693 | | |
677 | 694 | | |
678 | | - | |
679 | | - | |
680 | | - | |
681 | 695 | | |
682 | 696 | | |
683 | 697 | | |
| |||
697 | 711 | | |
698 | 712 | | |
699 | 713 | | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
700 | 721 | | |
701 | 722 | | |
702 | 723 | | |
703 | 724 | | |
704 | 725 | | |
705 | | - | |
| 726 | + | |
706 | 727 | | |
707 | 728 | | |
708 | 729 | | |
| |||
0 commit comments