summaryrefslogtreecommitdiff
path: root/refs.c
AgeCommit message (Collapse)AuthorFilesLines
2012-12-21refs: do not use cached refs in repack_without_refLibravatar Jeff King1-1/+4
When we delete a ref that is packed, we rewrite the whole packed-refs file and simply omit the ref that no longer exists. However, we base the rewrite on whatever happens to be in our refs cache, not what is necessarily on disk. That opens us up to a race condition if another process is simultaneously packing the refs, as we will overwrite their newly-made pack-refs file with our potentially stale data, losing commits. You can demonstrate the race like this: # setup some repositories git init --bare parent && (cd parent && git config core.logallrefupdates true) && git clone parent child && (cd child && git commit --allow-empty -m base) # in one terminal, repack the refs repeatedly cd parent && while true; do git pack-refs --all done # in another terminal, simultaneously push updates to # master, and create and delete an unrelated ref cd child && while true; do git push origin HEAD:newbranch && git commit --allow-empty -m foo us=`git rev-parse master` && git push origin master && git push origin :newbranch && them=`git --git-dir=../parent rev-parse master` && if test "$them" != "$us"; then echo >&2 "$them" != "$us" exit 1 fi done In many cases the two processes will conflict over locking the packed-refs file, and the deletion of newbranch will simply fail. But eventually you will hit the race, which happens like this: 1. We push a new commit to master. It is already packed (from the looping pack-refs call). We write the new value (let us call it B) to $GIT_DIR/refs/heads/master, but the old value (call it A) remains in the packed-refs file. 2. We push the deletion of newbranch, spawning a receive-pack process. Receive-pack advertises all refs to the client, causing it to iterate over each ref; it caches the packed refs in memory, which points at the stale value A. 3. Meanwhile, a separate pack-refs process is running. It runs to completion, updating the packed-refs file to point master at B, and deleting $GIT_DIR/refs/heads/master which also pointed at B. 4. Back in the receive-pack process, we get the instruction to delete :newbranch. We take a lock on packed-refs (which works, as the other pack-refs process has already finished). We then rewrite the contents using the cached refs, which contain the stale value A. The resulting packed-refs file points master once again at A. The loose ref which would override it to point at B was deleted (rightfully) in step 3. As a result, master now points at A. The only trace that B ever existed in the parent is in the reflog: the final entry will show master moving from A to B, even though the ref still points at A (so you can detect this race after the fact, because the next reflog entry will move from A to C). We can fix this by invalidating the packed-refs cache after we have taken the lock. This means that we will re-read the packed-refs file, and since we have the lock, we will be sure that what we read will be atomically up-to-date when we write (it may be out of date with respect to loose refs, but that is OK, as loose refs take precedence). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-29Merge branch 'rs/refs-string-slice'Libravatar Junio C Hamano1-29/+41
Avoid unnecessary temporary allocations while looking for matching refs inside refs API. By René Scharfe (3) and Junio C Hamano (1) * rs/refs-string-slice: refs: do not create ref_entry when searching refs: use strings directly in find_containing_dir() refs: convert parameter of create_dir_entry() to length-limited string refs: convert parameter of search_ref_dir() to length-limited string
2012-05-29Merge branch 'mh/ref-api-lazy-loose'Libravatar Junio C Hamano1-2/+7
The code to lazily read loose refs unnecessarily read the refs in a subhierarchy by mistake when we free the data for the subhierarchy. By Michael Haggerty * mh/ref-api-lazy-loose: free_ref_entry(): do not trigger reading of loose refs
2012-05-25Merge branch 'mh/ref-api'Libravatar Junio C Hamano1-0/+6
Fixes a performance regression in the earlier series.
2012-05-24Avoid sorting if references are added to ref_cache in orderLibravatar Michael Haggerty1-0/+6
The old code allowed many references to be efficiently added to a single directory, because it just appended the references to the containing directory unsorted without doing any searching (and therefore without requiring any intermediate sorting). But the old code was inefficient when a large number of subdirectories were added to a directory, because the directory always had to be searched to see if the new subdirectory already existed, and this search required the directory to be sorted first. The same was repeated for every new subdirectory, so the time scaled like O(N^2), where N is the number of subdirectories within a single directory. In practice, references are often added to the ref_cache in lexicographic order, for example when reading the packed-refs file. So build some intelligence into add_entry_to_dir() to optimize for the case of references and/or subdirectories being added in lexicographic order: if the existing entries were already sorted, and the new entry comes after the last existing entry, then adjust ref_dir::sorted to reflect the fact that the ref_dir is still sorted. Thanks to Peff for pointing out the performance regression that inspired this change. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-22refs: do not create ref_entry when searchingLibravatar Junio C Hamano1-9/+23
The search_ref_dir() function is about looking up an existing ref_entry in a sorted array of ref_entry stored in dir->entries, but it still allocates a new ref_entry and frees it before returning. This is only because the call to bsearch(3) was coded in a suboptimal way. Unlike the comparison function given to qsort(3), the first parameter to its comparison function does not need to point at an object that is shaped like an element in the array. Introduce a new comparison function that takes a counted string as the key and an element in an array of ref_entry and give it to bsearch(), so that we do not have to allocate a new ref_entry that we will never return to the caller anyway. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-22refs: use strings directly in find_containing_dir()Libravatar René Scharfe1-9/+4
Convert the parameter subdirname of search_for_subdir() to a length-limted string and then simply pass the interesting slice of the refname from find_containing_dir(), thereby avoiding to duplicate the string. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-22refs: convert parameter of create_dir_entry() to length-limited stringLibravatar René Scharfe1-8/+10
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-22refs: convert parameter of search_ref_dir() to length-limited stringLibravatar René Scharfe1-6/+7
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-20free_ref_entry(): do not trigger reading of loose refsLibravatar Michael Haggerty1-2/+7
Do not call get_ref_dir() from within free_ref_entry(), because that triggers the reading of loose refs, only for them to be freed immediately. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-10Merge branch 'mh/ref-api-lazy-loose'Libravatar Junio C Hamano1-134/+242
Refs API is updated to lazily read sub-hierarchies of refs/ namespace, so that we do not have to grab everything from the filesystem when we are only interested in listing branches, for example. By Michael Haggerty (17) and Junio C Hamano (1) * mh/ref-api-lazy-loose: refs: fix find_containing_dir() regression refs: read loose references lazily read_loose_refs(): eliminate ref_cache argument struct ref_dir: store a reference to the enclosing ref_cache search_for_subdir(): return (ref_dir *) instead of (ref_entry *) get_ref_dir(): add function for getting a ref_dir from a ref_entry read_loose_refs(): rename function from get_ref_dir() refs: wrap top-level ref_dirs in ref_entries find_containing_dir(): use strbuf in implementation of this function bisect: copy filename string obtained from git_path() do_for_each_reflog(): use a strbuf to hold logfile name do_for_each_reflog(): return early on error get_ref_dir(): take the containing directory as argument refs.c: extract function search_for_subdir() get_ref_dir(): require that the dirname argument ends in '/' get_ref_dir(): rename "base" parameter to "dirname" get_ref_dir(): use a strbuf to hold refname get_ref_dir(): return early if directory cannot be read
2012-05-04refs: fix find_containing_dir() regressionLibravatar Junio C Hamano1-1/+3
The function used to return NULL when asked to find the containing directory for a ref that does not exist, allowing the caller to omit iteration altogether. But a misconversion in an earlier change "refs.c: extract function search_for_subdir()" started returning the top-level directory entry, forcing callers to walk everything. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03refs: read loose references lazilyLibravatar Michael Haggerty1-29/+96
Instead of reading the whole directory of loose references the first time any are needed, only read them on demand, one directory at a time. Use a new ref_entry flag bit REF_INCOMPLETE to indicate that the entry represents a REF_DIR that hasn't been read yet. Whenever any entries from such a directory are needed, read all of the loose references from that directory. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03read_loose_refs(): eliminate ref_cache argumentLibravatar Michael Haggerty1-4/+4
The ref_cache can now be read from the ref_dir. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03struct ref_dir: store a reference to the enclosing ref_cacheLibravatar Michael Haggerty1-4/+11
This means that a directory ref_entry contains all of the information needed by read_loose_refs(). Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03search_for_subdir(): return (ref_dir *) instead of (ref_entry *)Libravatar Michael Haggerty1-11/+10
That is what all the callers want, so give it to them. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03get_ref_dir(): add function for getting a ref_dir from a ref_entryLibravatar Michael Haggerty1-15/+25
Convert all accesses of a ref_dir within a ref_entry to use this function. This function will later be responsible for reading loose references from disk on demand. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03read_loose_refs(): rename function from get_ref_dir()Libravatar Michael Haggerty1-7/+7
The new name better describes the function's purpose, and also makes the old name available for a more suitable purpose. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03refs: wrap top-level ref_dirs in ref_entriesLibravatar Michael Haggerty1-18/+19
Make it turtles all the way down. This affects the loose and packed fields of ref_cache instances. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03find_containing_dir(): use strbuf in implementation of this functionLibravatar Michael Haggerty1-9/+10
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03do_for_each_reflog(): use a strbuf to hold logfile nameLibravatar Michael Haggerty1-29/+31
This simplifies the bookkeeping and allows an (artificial) restriction on refname component length to be removed. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03do_for_each_reflog(): return early on errorLibravatar Michael Haggerty1-35/+35
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03get_ref_dir(): take the containing directory as argumentLibravatar Michael Haggerty1-4/+8
Previously, the "dir" argument to get_ref_dir() was a pointer to the top-level ref_dir. Change the function to expect a pointer to the ref_dir corresponding to dirname. This allows entries to be added directly to dir, without having to recurse through the reference trie each time (i.e., we can use add_entry_to_dir() instead of add_ref()). Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03refs.c: extract function search_for_subdir()Libravatar Michael Haggerty1-10/+24
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03get_ref_dir(): require that the dirname argument ends in '/'Libravatar Michael Haggerty1-7/+7
This removes some conditional code and makes it consistent with the way that direntry names are stored. Please note that this function is never used on the top-level .git directory; it is always called for directories at level .git/refs or deeper. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03get_ref_dir(): rename "base" parameter to "dirname"Libravatar Michael Haggerty1-10/+10
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-03get_ref_dir(): use a strbuf to hold refnameLibravatar Michael Haggerty1-28/+26
This simplifies the bookkeeping and allows an (artificial) restriction on refname component length to be removed. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-02Merge branch 'nd/i18n'Libravatar Junio C Hamano1-0/+1
More message strings marked for i18n. By Nguyễn Thái Ngọc Duy (10) and Jonathan Nieder (1) * nd/i18n: help: replace underlining "help -a" headers using hyphens with a blank line i18n: bundle: mark strings for translation i18n: index-pack: mark strings for translation i18n: apply: update say_patch_name to give translators complete sentence i18n: apply: mark strings for translation i18n: remote: mark strings for translation i18n: make warn_dangling_symref() automatically append \n i18n: help: mark strings for translation i18n: mark relative dates for translation strbuf: convenience format functions with \n automatically appended Makefile: feed all header files to xgettext
2012-04-25get_ref_dir(): return early if directory cannot be readLibravatar Michael Haggerty1-41/+44
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-24i18n: make warn_dangling_symref() automatically append \nLibravatar Nguyễn Thái Ngọc Duy1-0/+1
This helps remove \n from translatable strings Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10do_for_each_ref(): only iterate over the subtree that was requestedLibravatar Michael Haggerty1-7/+28
If the base argument has a "/" chararacter, then only iterate over the reference subdir whose name is the part up to the last "/". Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10refs: store references hierarchicallyLibravatar Michael Haggerty1-47/+227
Store references hierarchically in a tree that matches the pseudo-directory structure of the reference names. Add a new kind of ref_entry (with flag REF_DIR) to represent a whole subdirectory of references. Sort ref_dirs one subdirectory at a time. NOTE: the dirs can now be sorted as a side-effect of other function calls. Therefore, it would be problematic to do something from a each_ref_fn callback that could provoke the sorting of a directory that is currently being iterated over (i.e., the directory containing the entry that is being processed or any of its parents). This is a bit far-fetched, because a directory is always sorted just before being iterated over. Therefore, read-only accesses cannot trigger the sorting of a directory whose iteration has already started. But if a callback function would add a reference to a parent directory of the reference in the iteration, then try to resolve a reference under that directory, a re-sort could be triggered and cause the iteration to work incorrectly. Nevertheless...add a comment in refs.h warning against modifications during iteration. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10sort_ref_dir(): simplify logicLibravatar Michael Haggerty1-10/+11
Use the more usual indexing idiom for clarity. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10refs.c: rename ref_array -> ref_dirLibravatar Michael Haggerty1-98/+97
This purely textual change is in preparation for storing references hierarchically, when the old ref_array structure will represent one "directory" of references. Rename functions that deal with this structure analogously, and also rename the structure's "refs" member to "entries". Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10struct ref_entry: nest the value part in a unionLibravatar Michael Haggerty1-13/+19
This change is obviously silly by itself, but it is a step towards adding a second member to the union. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10check_refname_component(): return 0 for zero-length componentsLibravatar Michael Haggerty1-2/+2
Return 0 (instead of -1) for zero-length components. Move the interpretation of zero-length components as illegal to check_refname_format(). This will make it easier to extend check_refname_format() to also check whether directory names are valid. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10free_ref_entry(): new functionLibravatar Michael Haggerty1-2/+7
Add a function free_ref_entry(). This function will become nontrivial when ref_entry (soon) becomes polymorphic. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10names_conflict(): simplify implementationLibravatar Michael Haggerty1-25/+37
Save a bunch of lines of code and a couple of strlen() calls. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10repack_without_ref(): reimplement using do_for_each_ref_in_array()Libravatar Michael Haggerty1-33/+61
It costs a bit of boilerplate, but it means that the function can be ignorant of how cached refs are stored. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10do_for_each_ref_in_arrays(): new functionLibravatar Michael Haggerty1-29/+53
Extract function do_for_each_ref_in_arrays() from do_for_each_ref(). The new function will be a useful building block for storing refs hierarchically. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10do_for_each_ref_in_array(): new functionLibravatar Michael Haggerty1-10/+23
Extract function do_for_each_ref_in_array() from do_for_each_ref(). The new function will be a useful building block for storing refs hierarchically. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10refs: manage current_ref within do_one_ref()Libravatar Michael Haggerty1-6/+7
Set and clear current_ref within do_one_ref() instead of setting it here and leaving it to somebody else to clear it. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-10refs.c: reorder definitions more logicallyLibravatar Michael Haggerty1-253/+256
Reorder definitions in file: first check_refname_format() and helper functions, then the functions for managing the ref_entry and ref_array data structures, then ref_cache, then the more "business-logicky" stuff. No code is changed. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-12refs: remove the extra_refs APILibravatar Michael Haggerty1-22/+1
The extra_refs provided a kludgy way to create fake references at a global level in the hope that they would only affect some particular code path. The last user of this API been rewritten, so strip this stuff out before somebody else gets the bad idea of using it. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-01-17add_packed_ref(): new function in the refs API.Libravatar Michael Haggerty1-0/+6
Add a new function add_packed_ref() that adds a reference directly to the in-memory packed reference cache. This will be useful for creating local references while cloning. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-01-17ref_array: keep track of whether references are sortedLibravatar Michael Haggerty1-7/+26
Keep track of how many entries at the beginning of a ref_array are already sorted. In sort_ref_array(), return early if the the array is already sorted (i.e., if no new references has been appended to the end of the list since the last call to sort_ref_array()). Sort ref_arrays only when needed, namely in search_ref_array() and in do_for_each_ref(). However, never call sort_ref_array() on the extra_refs, because extra_refs can contain multiple entries with the same name and because sort_ref_array() not only sorts, but de-dups its contents. This change is currently not useful, because entries are not added to ref_arrays after they are created. But in a moment they will be... Implementation note: we could store a binary "sorted" value instead of an integer, but storing the number of sorted entries leaves the way open for a couple of possible future optimizations: * In sort_ref_array(), sort *only* the unsorted entries, then merge them with the sorted entries. This should be faster if most of the entries are already sorted. * Teach search_ref_array() to do a binary search of any sorted entries, and if unsuccessful do a linear search of any unsorted entries. This would avoid the need to sort the list every time that search_ref_array() is called, and (given some intelligence about how often to sort) could significantly improve the speed in certain hypothetical usage patterns. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-20Merge branch 'mh/ref-api'Libravatar Junio C Hamano1-243/+261
* mh/ref-api: add_ref(): take a (struct ref_entry *) parameter create_ref_entry(): extract function from add_ref() repack_without_ref(): remove temporary resolve_gitlink_ref_recursive(): change to work with struct ref_cache Pass a (ref_cache *) to the resolve_gitlink_*() helper functions resolve_gitlink_ref(): improve docstring get_ref_dir(): change signature refs: change signatures of get_packed_refs() and get_loose_refs() is_dup_ref(): extract function from sort_ref_array() add_ref(): add docstring parse_ref_line(): add docstring is_refname_available(): remove the "quiet" argument clear_ref_array(): rename from free_ref_array() refs: rename parameters result -> sha1 refs: rename "refname" variables struct ref_entry: document name member Conflicts: cache.h refs.c
2011-12-13Rename resolve_ref() to resolve_ref_unsafe()Libravatar Nguyễn Thái Ngọc Duy1-11/+11
resolve_ref() may return a pointer to a shared buffer and can be overwritten by the next resolve_ref() calls. Callers need to pay attention, not to keep the pointer when the next call happens. Rename with "_unsafe" suffix to warn developers (or reviewers) before introducing new call sites. This patch is generated using the following command git grep -l 'resolve_ref(' -- '*.[ch]'|xargs sed -i 's/resolve_ref(/resolve_ref_unsafe(/g' Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-13Convert resolve_ref+xstrdup to new resolve_refdup functionLibravatar Nguyễn Thái Ngọc Duy1-0/+6
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-12add_ref(): take a (struct ref_entry *) parameterLibravatar Michael Haggerty1-9/+5
Take a pointer to the ref_entry to add to the array, rather than creating the ref_entry within the function. This opens the way to having multiple kinds of ref_entries. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>