* [PATCH v2 14/51] repack_without_ref(): remove temporary
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 7 ++-----
1 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/refs.c b/refs.c
index ba7a8b0..2e7bc0c 100644
--- a/refs.c
+++ b/refs.c
@@ -1278,12 +1278,10 @@ static struct lock_file packlock;
static int repack_without_ref(const char *refname)
{
struct ref_array *packed;
- struct ref_entry *ref;
int fd, i;
packed = get_packed_refs(get_ref_cache(NULL));
- ref = search_ref_array(packed, refname);
- if (ref == NULL)
+ if (search_ref_array(packed, refname) == NULL)
return 0;
fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
if (fd < 0) {
@@ -1294,8 +1292,7 @@ static int repack_without_ref(const char *refname)
for (i = 0; i < packed->nr; i++) {
char line[PATH_MAX + 100];
int len;
-
- ref = packed->refs[i];
+ struct ref_entry *ref = packed->refs[i];
if (!strcmp(refname, ref->name))
continue;
--
1.7.8
^ permalink raw reply related
* [PATCH v2 22/51] names_conflict(): simplify implementation
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Save a bunch of lines of code and a couple of strlen() calls.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 17 ++++-------------
1 files changed, 4 insertions(+), 13 deletions(-)
diff --git a/refs.c b/refs.c
index c33e94a..12a70c1 100644
--- a/refs.c
+++ b/refs.c
@@ -1094,19 +1094,10 @@ static int remove_empty_directories(const char *file)
*/
static int names_conflict(const char *refname1, const char *refname2)
{
- int len1 = strlen(refname1);
- int len2 = strlen(refname2);
- int cmplen;
- const char *lead;
-
- if (len1 < len2) {
- cmplen = len1;
- lead = refname2;
- } else {
- cmplen = len2;
- lead = refname1;
- }
- return !strncmp(refname1, refname2, cmplen) && lead[cmplen] == '/';
+ for (; *refname1 && *refname1 == *refname2; refname1++, refname2++)
+ ;
+ return (*refname1 == '\0' && *refname2 == '/')
+ || (*refname1 == '/' && *refname2 == '\0');
}
/*
--
1.7.8
^ permalink raw reply related
* [PATCH v2 30/51] sort_ref_dir(): do not sort if already sorted
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Keep track of how many entries in a ref_dir are already sorted. In
sort_ref_dir(), only call qsort() if the dir contains unsorted
entries.
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_dir(), 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_dir() 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_dir() 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>
---
refs.c | 29 ++++++++++++++++++++++++-----
1 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/refs.c b/refs.c
index ccd2806..ce141ea 100644
--- a/refs.c
+++ b/refs.c
@@ -108,6 +108,10 @@ struct ref_value {
struct ref_dir {
int nr, alloc;
+
+ /* How many of the entries in this directory are sorted? */
+ int sorted;
+
struct ref_entry **entries;
};
@@ -210,7 +214,7 @@ static void clear_ref_dir(struct ref_dir *dir)
for (i = 0; i < dir->nr; i++)
free_ref_entry(dir->entries[i]);
free(dir->entries);
- dir->nr = dir->alloc = 0;
+ dir->sorted = dir->nr = dir->alloc = 0;
dir->entries = NULL;
}
@@ -252,8 +256,9 @@ static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname
/*
* We need dir to be sorted so that binary search works.
- * FIXME: Sorting the array each time is terribly inefficient,
- * and has to be changed.
+ * Calling sort_ref_dir() here is not quite as terribly
+ * inefficient as it looks, because directories that are
+ * already sorted are not re-sorted.
*/
sort_ref_dir(dir);
@@ -358,13 +363,27 @@ static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2
return 1;
}
+/*
+ * Sort the entries in dir and its subdirectories (if they are not
+ * already sorted).
+ */
static void sort_ref_dir(struct ref_dir *dir)
{
int i, j;
struct ref_entry *last = NULL;
- if (!dir->nr)
+ if (dir->sorted == dir->nr) {
+ /*
+ * This directory is already sorted and de-duped, but
+ * we still have to sort subdirectories.
+ */
+ for (i = 0; i < dir->nr; i++) {
+ struct ref_entry *entry = dir->entries[i];
+ if (entry->flag & REF_DIR)
+ sort_ref_dir(&entry->u.subdir);
+ }
return;
+ }
qsort(dir->entries, dir->nr, sizeof(*dir->entries), ref_entry_cmp);
@@ -381,7 +400,7 @@ static void sort_ref_dir(struct ref_dir *dir)
last = dir->entries[i++] = entry;
}
}
- dir->nr = i;
+ dir->sorted = dir->nr = i;
}
#define DO_FOR_EACH_INCLUDE_BROKEN 01
--
1.7.8
^ permalink raw reply related
* [PATCH v2 19/51] do_for_each_ref_in_arrays(): new function
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
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>
---
refs.c | 71 +++++++++++++++++++++++++++++++++++++--------------------------
1 files changed, 42 insertions(+), 29 deletions(-)
diff --git a/refs.c b/refs.c
index bc14437..601665b 100644
--- a/refs.c
+++ b/refs.c
@@ -714,45 +714,58 @@ static int do_for_each_ref_in_array(struct ref_array *array, int offset,
return 0;
}
-static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn fn,
- int trim, int flags, void *cb_data)
+static int do_for_each_ref_in_arrays(struct ref_array *array1,
+ struct ref_array *array2,
+ const char *base, each_ref_fn fn, int trim,
+ int flags, void *cb_data)
{
- int retval = 0, p = 0, l = 0;
- struct ref_cache *refs = get_ref_cache(submodule);
- struct ref_array *packed = get_packed_refs(refs);
- struct ref_array *loose = get_loose_refs(refs);
+ int retval;
+ int i1 = 0, i2 = 0;
- retval = do_for_each_ref_in_array(&extra_refs, 0,
- base, fn, trim, flags, cb_data);
- if (retval)
- goto end_each;
-
- while (p < packed->nr && l < loose->nr) {
- struct ref_entry *entry;
- int cmp = strcmp(packed->refs[p]->name, loose->refs[l]->name);
- if (!cmp) {
- p++;
+ while (1) {
+ struct ref_entry *e1, *e2;
+ int cmp;
+ if (i1 == array1->nr) {
+ return do_for_each_ref_in_array(array2, i2,
+ base, fn, trim, flags, cb_data);
+ }
+ if (i2 == array2->nr) {
+ return do_for_each_ref_in_array(array1, i1,
+ base, fn, trim, flags, cb_data);
+ }
+ e1 = array1->refs[i1];
+ e2 = array2->refs[i2];
+ cmp = strcmp(e1->name, e2->name);
+ if (cmp == 0) {
+ /* Two refs with the same name; ignore the one from array1. */
+ i1++;
continue;
}
- if (cmp > 0) {
- entry = loose->refs[l++];
+ if (cmp < 0) {
+ retval = do_one_ref(base, fn, trim, flags, cb_data, e1);
+ i1++;
} else {
- entry = packed->refs[p++];
+ retval = do_one_ref(base, fn, trim, flags, cb_data, e2);
+ i2++;
}
- retval = do_one_ref(base, fn, trim, flags, cb_data, entry);
if (retval)
- goto end_each;
+ return retval;
}
+}
- if (l < loose->nr) {
- retval = do_for_each_ref_in_array(loose, l,
- base, fn, trim, flags, cb_data);
- } else {
- retval = do_for_each_ref_in_array(packed, p,
- base, fn, trim, flags, cb_data);
- }
+static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn fn,
+ int trim, int flags, void *cb_data)
+{
+ int retval = 0;
+ struct ref_cache *refs = get_ref_cache(submodule);
+
+ retval = do_for_each_ref_in_array(&extra_refs, 0,
+ base, fn, trim, flags, cb_data);
+ if (!retval)
+ retval = do_for_each_ref_in_arrays(get_packed_refs(refs),
+ get_loose_refs(refs),
+ base, fn, trim, flags, cb_data);
-end_each:
current_ref = NULL;
return retval;
}
--
1.7.8
^ permalink raw reply related
* [PATCH v2 32/51] do_for_each_ref(): only iterate over the subtree that was requested
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
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>
---
refs.c | 33 +++++++++++++++++++++++++++------
1 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/refs.c b/refs.c
index f01da78..6a11235 100644
--- a/refs.c
+++ b/refs.c
@@ -1121,13 +1121,34 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn
{
int retval = 0;
struct ref_cache *refs = get_ref_cache(submodule);
-
- retval = do_for_each_ref_in_dir(&extra_refs, 0,
+ struct ref_dir *extra_dir = &extra_refs;
+ struct ref_dir *packed_dir = get_packed_refs(refs);
+ struct ref_dir *loose_dir = get_loose_refs(refs);
+
+ if (base && *base) {
+ extra_dir = find_containing_dir(extra_dir, base, 0);
+ packed_dir = find_containing_dir(packed_dir, base, 0);
+ loose_dir = find_containing_dir(loose_dir, base, 0);
+ }
+
+ if (extra_dir)
+ retval = do_for_each_ref_in_dir(
+ extra_dir, 0,
+ base, fn, trim, flags, cb_data);
+ if (!retval) {
+ if (packed_dir && loose_dir)
+ retval = do_for_each_ref_in_dirs(
+ packed_dir, loose_dir,
+ base, fn, trim, flags, cb_data);
+ else if (packed_dir)
+ retval = do_for_each_ref_in_dir(
+ packed_dir, 0,
base, fn, trim, flags, cb_data);
- if (!retval)
- retval = do_for_each_ref_in_dirs(get_packed_refs(refs),
- get_loose_refs(refs),
- base, fn, trim, flags, cb_data);
+ else if (loose_dir)
+ retval = do_for_each_ref_in_dir(
+ loose_dir, 0,
+ base, fn, trim, flags, cb_data);
+ }
current_ref = NULL;
return retval;
--
1.7.8
^ permalink raw reply related
* [PATCH v2 42/51] search_ref_dir(): take (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/refs.c b/refs.c
index d89c3d0..30ff9b8 100644
--- a/refs.c
+++ b/refs.c
@@ -246,11 +246,14 @@ static void sort_ref_dir(struct ref_dir *dir);
* Return the entry with the given refname from the ref_dir
* (non-recursively). Return NULL if no such entry is found.
*/
-static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname)
+static struct ref_entry *search_ref_dir(struct ref_entry *direntry, const char *refname)
{
struct ref_entry *e, **r;
int len;
+ struct ref_dir *dir;
+ assert(direntry->flag & REF_DIR);
+ dir = &direntry->u.subdir;
if (refname == NULL || !dir->nr)
return NULL;
@@ -300,7 +303,7 @@ static struct ref_entry *find_containing_direntry(struct ref_entry *direntry,
char tmp = slash[1];
struct ref_entry *entry;
slash[1] = '\0';
- entry = search_ref_dir(&direntry->u.subdir, refname_copy);
+ entry = search_ref_dir(direntry, refname_copy);
if (!entry) {
if (!mkdir) {
direntry = NULL;
@@ -330,7 +333,7 @@ static struct ref_entry *find_ref(struct ref_entry *direntry, const char *refnam
direntry = find_containing_direntry(direntry, refname, 0);
if (!direntry)
return NULL;
- entry = search_ref_dir(&direntry->u.subdir, refname);
+ entry = search_ref_dir(direntry, refname);
return (entry && !(entry->flag & REF_DIR)) ? entry : NULL;
}
--
1.7.8
^ permalink raw reply related
* [PATCH v2 48/51] refs: read loose references lazily
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
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 value REF_DIR_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>
---
refs.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++--------------
1 files changed, 88 insertions(+), 24 deletions(-)
diff --git a/refs.c b/refs.c
index a85a8a5..3cd8e04 100644
--- a/refs.c
+++ b/refs.c
@@ -101,6 +101,12 @@ int check_refname_format(const char *refname, int flags)
struct ref_entry;
+/*
+ * Information used (along with the information in ref_entry) to
+ * describe a single cached reference. This data structure only
+ * occurs embedded in a union in struct ref_entry, and only when
+ * (ref_entry->flag & REF_DIR) is zero.
+ */
struct ref_value {
unsigned char sha1[20];
unsigned char peeled[20];
@@ -108,6 +114,34 @@ struct ref_value {
struct ref_cache;
+/*
+ * Information used (along with the information in ref_entry) to
+ * describe a level in the hierarchy of references. This data
+ * structure only occurs embedded in a union in struct ref_entry, and
+ * only when (ref_entry.flag & REF_DIR) is nonzero. In that case,
+ * (ref_entry.flag & REF_DIR) can take the following values:
+ *
+ * REF_DIR_COMPLETE -- a directory of loose or packed references,
+ * already read.
+ *
+ * REF_DIR_INCOMPLETE -- a directory of loose references that
+ * hasn't been read yet (nor has any of its subdirectories).
+ *
+ * Entries within a directory are stored within a growable array of
+ * pointers to ref_entries (entries, nr, alloc). Entries 0 <= i <
+ * sorted are sorted by their component name in strcmp() order and the
+ * remaining entries are unsorted.
+ *
+ * Loose references are read lazily, one directory at a time. When a
+ * directory of loose references is read, then all of the references
+ * in that directory are stored, and REF_DIR_INCOMPLETE stubs are
+ * created for any subdirectories, but the subdirectories themselves
+ * are not read. The reading is triggered either by search_ref_dir()
+ * (called when single references are added or interrogated), by
+ * sort_ref_dir(), or by iteration over a subdirectory of references
+ * using one of the for_each_ref*() functions (which calls
+ * sort_ref_dir() for each subdirectory).
+ */
struct ref_dir {
int nr, alloc;
@@ -125,19 +159,33 @@ struct ref_dir {
/* ISSYMREF=0x01, ISPACKED=0x02, and ISBROKEN=0x04 are public interfaces */
#define REF_KNOWS_PEELED 0x08
-#define REF_DIR 0x10
+
+/* If any of these bits are set, the entry represents a directory: */
+#define REF_DIR 0x30
+
+/* A directory that has already been fully read. */
+#define REF_DIR_COMPLETE 0x10
+
+/* A directory of loose references that has not yet been fully read. */
+#define REF_DIR_INCOMPLETE 0x20
/*
* A ref_entry represents either a reference or a "subdirectory" of
- * references. Each directory in the reference namespace is
- * represented by a ref_entry with (flags & REF_DIR) set and
- * containing a subdir member that holds the entries in that
- * directory. References are represented by a ref_entry with (flags &
- * REF_DIR) unset and a value member that describes the reference's
- * value. The flag member is at the ref_entry level, but it is also
- * needed to interpret the contents of the value field (in other
- * words, a ref_value object is not very much use without the
- * enclosing ref_entry).
+ * references.
+ *
+ * Each directory in the reference namespace is represented by a
+ * ref_entry with (flags & REF_DIR) set and containing a subdir member
+ * that holds the entries in that directory that have been read so
+ * far. If (flags & REF_DIR) == REF_DIR_INCOMPLETE, then the
+ * directory and its subdirectories haven't been read yet.
+ * REF_DIR_INCOMPLETE is only used for loose references.
+ *
+ * References are represented by a ref_entry with (flags & REF_DIR) ==
+ * 0 and a value member that describes the reference's value. The
+ * flag member is at the ref_entry level, but it is also needed to
+ * interpret the contents of the value field (in other words, a
+ * ref_value object is not very much use without the enclosing
+ * ref_entry).
*
* Reference names cannot end with slash and directories' names are
* always stored with a trailing slash (except for the top-level
@@ -229,19 +277,21 @@ static void clear_ref_dir(struct ref_dir *dir)
dir->entries = NULL;
}
+static void read_loose_refs(struct ref_entry *direntry);
+
/*
* Create a struct ref_entry object for the specified dirname.
* dirname is the name of the directory with a trailing slash (e.g.,
* "refs/heads/") or "" for the top-level directory.
*/
static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,
- const char *dirname)
+ const char *dirname, int flag)
{
struct ref_entry *direntry;
int len = strlen(dirname);
direntry = xcalloc(1, sizeof(struct ref_entry) + len + 1);
memcpy(direntry->name, dirname, len + 1);
- direntry->flag = REF_DIR;
+ direntry->flag = flag;
direntry->u.subdir.ref_cache = ref_cache;
return direntry;
}
@@ -266,6 +316,7 @@ static struct ref_entry *search_ref_dir(struct ref_entry *direntry, const char *
struct ref_dir *dir;
assert(direntry->flag & REF_DIR);
+ read_loose_refs(direntry);
dir = &direntry->u.subdir;
if (refname == NULL || !dir->nr)
return NULL;
@@ -322,8 +373,14 @@ static struct ref_entry *find_containing_direntry(struct ref_entry *direntry,
direntry = NULL;
break;
}
+ /*
+ * If search_ref_dir() above didn't make the
+ * entry spring into existence, then this must
+ * not be an unread loose reference tree, so
+ * the correct flag is REF_DIR_COMPLETE.
+ */
entry = create_dir_entry(direntry->u.subdir.ref_cache,
- refname_copy);
+ refname_copy, REF_DIR_COMPLETE);
add_entry(direntry, entry);
}
slash[1] = tmp;
@@ -399,6 +456,7 @@ static void sort_ref_dir(struct ref_entry *direntry)
struct ref_entry *last = NULL;
struct ref_dir *dir;
assert(direntry->flag & REF_DIR);
+ read_loose_refs(direntry);
dir = &direntry->u.subdir;
if (dir->sorted == dir->nr)
return; /* This directory is already sorted and de-duped */
@@ -449,8 +507,8 @@ static int do_for_each_ref_in_dir(struct ref_entry *direntry, int offset,
int i;
struct ref_dir *dir;
assert(direntry->flag & REF_DIR);
- dir = &direntry->u.subdir;
sort_ref_dir(direntry);
+ dir = &direntry->u.subdir;
for (i = offset; i < dir->nr; i++) {
struct ref_entry *entry = dir->entries[i];
int retval;
@@ -477,10 +535,10 @@ static int do_for_each_ref_in_dirs(struct ref_entry *direntry1,
assert(direntry1->flag & REF_DIR);
assert(direntry2->flag & REF_DIR);
- dir1 = &direntry1->u.subdir;
- dir2 = &direntry2->u.subdir;
sort_ref_dir(direntry1);
sort_ref_dir(direntry2);
+ dir1 = &direntry1->u.subdir;
+ dir2 = &direntry2->u.subdir;
while (1) {
struct ref_entry *e1, *e2, *entry;
int cmp;
@@ -737,7 +795,7 @@ static void read_packed_refs(FILE *f, struct ref_entry *direntry)
void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
{
if (!extra_refs)
- extra_refs = create_dir_entry(NULL, "");
+ extra_refs = create_dir_entry(NULL, "", REF_DIR_COMPLETE);
add_ref(extra_refs, create_ref_entry(refname, sha1, flag, 0));
}
@@ -755,7 +813,7 @@ static struct ref_entry *get_packed_refs(struct ref_cache *refs)
const char *packed_refs_file;
FILE *f;
- refs->packed = create_dir_entry(refs, "");
+ refs->packed = create_dir_entry(refs, "", REF_DIR_COMPLETE);
if (*refs->name)
packed_refs_file = git_path_submodule(refs->name, "packed-refs");
else
@@ -777,11 +835,14 @@ static void read_loose_refs(struct ref_entry *direntry)
DIR *d;
char *path;
char *dirname = direntry->name;
- int dirnamelen = strlen(dirname);
+ int dirnamelen;
int pathlen;
struct ref_cache *refs;
assert(direntry->flag & REF_DIR);
+ if ((direntry->flag & REF_DIR) != REF_DIR_INCOMPLETE)
+ return;
+ dirnamelen = strlen(dirname);
assert(dirnamelen && direntry->name[dirnamelen - 1] == '/');
refs = direntry->u.subdir.ref_cache;
if (*refs->name)
@@ -819,11 +880,12 @@ static void read_loose_refs(struct ref_entry *direntry)
if (stat(refdir, &st) < 0)
continue;
if (S_ISDIR(st.st_mode)) {
+ struct ref_entry *subdirentry;
refname[dirnamelen + namelen] = '/';
refname[dirnamelen + namelen + 1] = '\0';
- read_loose_refs(find_containing_direntry(
- refs->loose,
- refname, 1));
+ subdirentry = create_dir_entry(direntry->u.subdir.ref_cache,
+ refname, REF_DIR_INCOMPLETE);
+ add_entry(direntry, subdirentry);
continue;
}
if (*refs->name) {
@@ -842,13 +904,15 @@ static void read_loose_refs(struct ref_entry *direntry)
free(refname);
closedir(d);
}
+ direntry->flag = REF_DIR_COMPLETE;
}
static struct ref_entry *get_loose_refs(struct ref_cache *refs)
{
if (!refs->loose) {
- refs->loose = create_dir_entry(refs, "");
- read_loose_refs(find_containing_direntry(refs->loose, "refs/", 1));
+ refs->loose = create_dir_entry(refs, "", REF_DIR_COMPLETE);
+ add_entry(refs->loose,
+ create_dir_entry(refs, "refs/", REF_DIR_INCOMPLETE));
}
return refs->loose;
}
--
1.7.8
^ permalink raw reply related
* [PATCH v2 51/51] repack_without_ref(): call clear_packed_ref_cache()
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Call clear_packed_ref_cache() from repack_without_ref(). This is a
more logical place to call it than from delete_ref(). Also,
repack_without_ref() is smart enough to know that it doesn't have to
invalidate the cache if the reference was not found among the packed
refs.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/refs.c b/refs.c
index 92523fd..3541a73 100644
--- a/refs.c
+++ b/refs.c
@@ -1736,7 +1736,9 @@ static struct lock_file packlock;
static int repack_without_ref(const char *refname)
{
struct repack_without_ref_sb data;
- struct ref_entry *packed = get_packed_refs(get_ref_cache(NULL));
+ struct ref_cache *refs = get_ref_cache(NULL);
+ struct ref_entry *packed = get_packed_refs(refs);
+
if (find_ref(packed, refname) == NULL)
return 0;
data.refname = refname;
@@ -1746,6 +1748,7 @@ static int repack_without_ref(const char *refname)
return error("cannot delete '%s' from packed refs", refname);
}
do_for_each_ref_in_dir(packed, 0, "", repack_without_ref_fn, 0, 0, &data);
+ clear_packed_ref_cache(refs);
return commit_lock_file(&packlock);
}
@@ -1774,6 +1777,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
if (!(delopt & REF_NODEREF))
lock->lk->filename[i] = '.';
+ clear_loose_ref_cache(get_ref_cache(NULL));
}
/* removing the loose one could have resurrected an earlier
* packed one. Also, if it was not loose we need to repack
@@ -1782,7 +1786,6 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
ret |= repack_without_ref(refname);
unlink_or_warn(git_path("logs/%s", lock->ref_name));
- invalidate_ref_cache(NULL);
unlock_ref(lock);
return ret;
}
--
1.7.8
^ permalink raw reply related
* [PATCH v2 47/51] read_loose_refs(): take a (ref_entry *) as argument
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Rename get_ref_dir() to read_loose_refs(), and change its signature.
This is another step towards reading loose references one directory
at a time.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 21 +++++++++++----------
1 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/refs.c b/refs.c
index 4088167..a85a8a5 100644
--- a/refs.c
+++ b/refs.c
@@ -770,21 +770,20 @@ static struct ref_entry *get_packed_refs(struct ref_cache *refs)
}
/*
- * dirname must match the name associated with dir; in particular, it
- * must end with '/'.
+ * Fill direntry with loose references read from the filesystem.
*/
-static void get_ref_dir(struct ref_cache *refs, const char *dirname)
+static void read_loose_refs(struct ref_entry *direntry)
{
DIR *d;
char *path;
+ char *dirname = direntry->name;
int dirnamelen = strlen(dirname);
int pathlen;
- struct ref_entry *direntry;
-
- assert(dirnamelen && dirname[dirnamelen - 1] == '/');
-
- direntry = find_containing_direntry(refs->loose, dirname, 1);
+ struct ref_cache *refs;
+ assert(direntry->flag & REF_DIR);
+ assert(dirnamelen && direntry->name[dirnamelen - 1] == '/');
+ refs = direntry->u.subdir.ref_cache;
if (*refs->name)
path = git_path_submodule(refs->name, "%s", dirname);
else
@@ -822,7 +821,9 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname)
if (S_ISDIR(st.st_mode)) {
refname[dirnamelen + namelen] = '/';
refname[dirnamelen + namelen + 1] = '\0';
- get_ref_dir(refs, refname);
+ read_loose_refs(find_containing_direntry(
+ refs->loose,
+ refname, 1));
continue;
}
if (*refs->name) {
@@ -847,7 +848,7 @@ static struct ref_entry *get_loose_refs(struct ref_cache *refs)
{
if (!refs->loose) {
refs->loose = create_dir_entry(refs, "");
- get_ref_dir(refs, "refs/");
+ read_loose_refs(find_containing_direntry(refs->loose, "refs/", 1));
}
return refs->loose;
}
--
1.7.8
^ permalink raw reply related
* [PATCH v2 33/51] get_ref_dir(): keep track of the current ref_dir
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Look up the ref_dir that will hold the new entries once at the start
of processing of a directory. This eliminates the need to search down
the reference tree to find the place to put each new reference.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 43 ++++++++++++++++++++++++++-----------------
1 files changed, 26 insertions(+), 17 deletions(-)
diff --git a/refs.c b/refs.c
index 6a11235..6912db3 100644
--- a/refs.c
+++ b/refs.c
@@ -730,29 +730,36 @@ static struct ref_dir *get_packed_refs(struct ref_cache *refs)
return &refs->packed;
}
-static void get_ref_dir(struct ref_cache *refs, const char *base,
- struct ref_dir *dir)
+/*
+ * dirname must match the name associated with dir; in particular, it
+ * must end with '/'.
+ */
+static void get_ref_dir(struct ref_cache *refs, const char *dirname)
{
DIR *d;
- const char *path;
+ char *path;
+ int dirnamelen = strlen(dirname);
+ int pathlen;
+ struct ref_dir *dir;
+
+ assert(dirnamelen && dirname[dirnamelen - 1] == '/');
+
+ dir = find_containing_dir(&refs->loose, dirname, 1);
if (*refs->name)
- path = git_path_submodule(refs->name, "%s", base);
+ path = git_path_submodule(refs->name, "%s", dirname);
else
- path = git_path("%s", base);
-
+ path = git_path("%s", dirname);
+ pathlen = strlen(path);
+ assert(pathlen && path[pathlen - 1] == '/');
+ path[pathlen - 1] = '\0';
d = opendir(path);
if (d) {
struct dirent *de;
- int baselen = strlen(base);
- char *refname = xmalloc(baselen + 257);
-
- memcpy(refname, base, baselen);
- if (baselen && base[baselen-1] != '/')
- refname[baselen++] = '/';
-
+ char *refname = xmalloc(dirnamelen + 257);
+ memcpy(refname, dirname, dirnamelen);
while ((de = readdir(d)) != NULL) {
unsigned char sha1[20];
struct stat st;
@@ -767,14 +774,16 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
continue;
if (has_extension(de->d_name, ".lock"))
continue;
- memcpy(refname + baselen, de->d_name, namelen+1);
+ memcpy(refname + dirnamelen, de->d_name, namelen+1);
refdir = *refs->name
? git_path_submodule(refs->name, "%s", refname)
: git_path("%s", refname);
if (stat(refdir, &st) < 0)
continue;
if (S_ISDIR(st.st_mode)) {
- get_ref_dir(refs, refname, dir);
+ refname[dirnamelen + namelen] = '/';
+ refname[dirnamelen + namelen + 1] = '\0';
+ get_ref_dir(refs, refname);
continue;
}
if (*refs->name) {
@@ -788,7 +797,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
hashclr(sha1);
flag |= REF_ISBROKEN;
}
- add_ref(dir, create_ref_entry(refname, sha1, flag, 1));
+ add_entry_to_dir(dir, create_ref_entry(refname, sha1, flag, 1));
}
free(refname);
closedir(d);
@@ -798,7 +807,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
static struct ref_dir *get_loose_refs(struct ref_cache *refs)
{
if (!refs->did_loose) {
- get_ref_dir(refs, "refs", &refs->loose);
+ get_ref_dir(refs, "refs/");
refs->did_loose = 1;
}
return &refs->loose;
--
1.7.8
^ permalink raw reply related
* [PATCH v2 20/51] repack_without_ref(): reimplement using do_for_each_ref_in_array()
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
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>
---
refs.c | 46 ++++++++++++++++++++++++++++------------------
1 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/refs.c b/refs.c
index 601665b..2cdedf8 100644
--- a/refs.c
+++ b/refs.c
@@ -1299,36 +1299,46 @@ struct ref_lock *lock_any_ref_for_update(const char *refname,
return lock_ref_sha1_basic(refname, old_sha1, flags, NULL);
}
+struct repack_without_ref_sb {
+ const char *refname;
+ int fd;
+};
+
+static int repack_without_ref_fn(const char *refname, const unsigned char *sha1,
+ int flags, void *cb_data)
+{
+ struct repack_without_ref_sb *data = cb_data;
+ char line[PATH_MAX + 100];
+ int len;
+
+ if (!strcmp(data->refname, refname))
+ return 0;
+ len = snprintf(line, sizeof(line), "%s %s\n",
+ sha1_to_hex(sha1), refname);
+ /* this should not happen but just being defensive */
+ if (len > sizeof(line))
+ die("too long a refname '%s'", refname);
+ write_or_die(data->fd, line, len);
+ return 0;
+}
+
static struct lock_file packlock;
static int repack_without_ref(const char *refname)
{
+ struct repack_without_ref_sb data;
struct ref_array *packed;
- int fd, i;
packed = get_packed_refs(get_ref_cache(NULL));
if (search_ref_array(packed, refname) == NULL)
return 0;
- fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
- if (fd < 0) {
+ data.refname = refname;
+ data.fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
+ if (data.fd < 0) {
unable_to_lock_error(git_path("packed-refs"), errno);
return error("cannot delete '%s' from packed refs", refname);
}
-
- for (i = 0; i < packed->nr; i++) {
- char line[PATH_MAX + 100];
- int len;
- struct ref_entry *ref = packed->refs[i];
-
- if (!strcmp(refname, ref->name))
- continue;
- len = snprintf(line, sizeof(line), "%s %s\n",
- sha1_to_hex(ref->sha1), ref->name);
- /* this should not happen but just being defensive */
- if (len > sizeof(line))
- die("too long a refname '%s'", ref->name);
- write_or_die(fd, line, len);
- }
+ do_for_each_ref_in_array(packed, 0, "", repack_without_ref_fn, 0, 0, &data);
return commit_lock_file(&packlock);
}
--
1.7.8
^ permalink raw reply related
* [PATCH v2 49/51] is_refname_available(): query only possibly-conflicting references
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Instead of iterating through all of the references, inquire more
pointedly about the references that could conflict with the new name.
This requires checking for a few individual references, plus iterating
through a small subtree of the rest of the references (and usually the
subtree iteration ends without having to recurse). A big benefit is
that populating the whole loose reference cache (which can be very
expensive) can usually be avoided.
Also, simplify name_conflict_fn(). Since it now will only be called
for possibly-conflicting references, there is necessarily a conflict
if it is called for *any* reference besides "oldrefname".
Remove function names_conflict(), which is now unused.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 74 ++++++++++++++++++++++++++++++++++++++++-----------------------
1 files changed, 47 insertions(+), 27 deletions(-)
diff --git a/refs.c b/refs.c
index 3cd8e04..312ca3b 100644
--- a/refs.c
+++ b/refs.c
@@ -591,23 +591,7 @@ static int do_for_each_ref_in_dirs(struct ref_entry *direntry1,
}
}
-/*
- * Return true iff refname1 and refname2 conflict with each other.
- * Two reference names conflict if one of them exactly matches the
- * leading components of the other; e.g., "foo/bar" conflicts with
- * both "foo" and with "foo/bar/baz" but not with "foo/bar" or
- * "foo/barbados".
- */
-static int names_conflict(const char *refname1, const char *refname2)
-{
- for (; *refname1 && *refname1 == *refname2; refname1++, refname2++)
- ;
- return (*refname1 == '\0' && *refname2 == '/')
- || (*refname1 == '/' && *refname2 == '\0');
-}
-
struct name_conflict_cb {
- const char *refname;
const char *oldrefname;
const char *conflicting_refname;
};
@@ -616,31 +600,67 @@ static int name_conflict_fn(const char *existingrefname, const unsigned char *sh
int flags, void *cb_data)
{
struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data;
- if (data->oldrefname && !strcmp(data->oldrefname, existingrefname))
+ if (!strcmp(data->oldrefname, existingrefname))
return 0;
- if (names_conflict(data->refname, existingrefname)) {
- data->conflicting_refname = existingrefname;
- return 1;
- }
- return 0;
+
+ /*
+ * Since we are only iterating over the subtree that has the
+ * new refname as prefix, *any* reference found is a conflict.
+ */
+ data->conflicting_refname = existingrefname;
+ return 1;
}
/*
* Return true iff a reference named refname could be created without
- * conflicting with the name of an existing reference. If oldrefname
- * is non-NULL, ignore potential conflicts with oldrefname (e.g.,
- * because oldrefname is scheduled for deletion in the same
+ * conflicting with the name of an existing reference in direntry. If
+ * oldrefname is non-NULL, ignore potential conflicts with oldrefname
+ * (e.g., because oldrefname is scheduled for deletion in the same
* operation).
+ *
+ * Two reference names conflict if one of them exactly matches the
+ * leading components of the other; e.g., "foo/bar" conflicts with
+ * both "foo" and with "foo/bar/baz" but not with "foo/bar" or
+ * "foo/barbados".
*/
static int is_refname_available(const char *refname, const char *oldrefname,
struct ref_entry *direntry)
{
+ int prefixlen = strlen(refname);
+ char *prefix;
+ char *slash;
struct name_conflict_cb data;
- data.refname = refname;
+
+ assert(direntry->flag & REF_DIR);
+
+ if (!oldrefname)
+ oldrefname = ""; /* invalid; cannot match any existing refname */
+
+ /* Check whether a prefix of refname is an existing reference: */
+ prefix = xmalloc(prefixlen + 2);
+ memcpy(prefix, refname, prefixlen + 1);
+ for (slash = strchr(prefix, '/'); slash; slash = strchr(slash + 1, '/')) {
+ *slash = '\0';
+ if (strcmp(oldrefname, prefix)) {
+ struct ref_entry *entry = find_ref(direntry, prefix);
+ if (entry) {
+ error("'%s' exists; cannot create '%s'", prefix, refname);
+ free(prefix);
+ return 0;
+ }
+ }
+ *slash = '/';
+ }
+
+ /* Check whether refname is a proper prefix of an existing reference: */
+ prefix[prefixlen++] = '/';
+ prefix[prefixlen] = '\0';
data.oldrefname = oldrefname;
data.conflicting_refname = NULL;
- assert(direntry->flag & REF_DIR);
+ direntry = find_containing_direntry(direntry, prefix, 0);
+ if (!direntry)
+ return 1;
if (do_for_each_ref_in_dir(direntry, 0, "", name_conflict_fn,
0, DO_FOR_EACH_INCLUDE_BROKEN,
--
1.7.8
^ permalink raw reply related
* [PATCH v2 50/51] read_packed_refs(): keep track of the directory being worked in
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Packed references are stored in $GIT_DIR/packed-refs sorted, so
adjacent ones are pretty likely to be in the same directory. So while
reading them, keep track of the last directory used, and reuse it if
possible to avoid searching the reference namespace from the root each
time.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)
diff --git a/refs.c b/refs.c
index 312ca3b..92523fd 100644
--- a/refs.c
+++ b/refs.c
@@ -780,6 +780,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
static void read_packed_refs(FILE *f, struct ref_entry *direntry)
{
struct ref_entry *last = NULL;
+ struct ref_entry *current_direntry = NULL;
char refline[PATH_MAX];
int flag = REF_ISPACKED;
@@ -799,8 +800,21 @@ static void read_packed_refs(FILE *f, struct ref_entry *direntry)
refname = parse_ref_line(refline, sha1);
if (refname) {
+ if (current_direntry) {
+ char *slash = strrchr(refname, '/');
+ if (!slash
+ || strncmp(current_direntry->name, refname,
+ slash - refname + 1)
+ || current_direntry->name[slash - refname + 1] != '\0')
+ /* The new refname does not go in current_direntry */
+ current_direntry = NULL;
+ }
+ if (!current_direntry)
+ current_direntry = find_containing_direntry(
+ direntry, refname, 1);
+
last = create_ref_entry(refname, sha1, flag, 1);
- add_ref(direntry, last);
+ add_entry(current_direntry, last);
continue;
}
if (last &&
--
1.7.8
^ permalink raw reply related
* [PATCH v2 46/51] struct ref_dir: store a reference to the enclosing ref_cache
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
This means that it contains enough information to serve as the sole
argument to get_ref_dir(), which will be changed in the next commit.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 21 ++++++++++++++++-----
1 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/refs.c b/refs.c
index 4a3546b..4088167 100644
--- a/refs.c
+++ b/refs.c
@@ -106,6 +106,8 @@ struct ref_value {
unsigned char peeled[20];
};
+struct ref_cache;
+
struct ref_dir {
int nr, alloc;
@@ -113,6 +115,12 @@ struct ref_dir {
int sorted;
struct ref_entry **entries;
+
+ /*
+ * A pointer to the ref_cache that contains this ref_dir, or
+ * NULL if this ref_dir is used for extra_refs.
+ */
+ struct ref_cache *ref_cache;
};
/* ISSYMREF=0x01, ISPACKED=0x02, and ISBROKEN=0x04 are public interfaces */
@@ -226,13 +234,15 @@ static void clear_ref_dir(struct ref_dir *dir)
* dirname is the name of the directory with a trailing slash (e.g.,
* "refs/heads/") or "" for the top-level directory.
*/
-static struct ref_entry *create_dir_entry(const char *dirname)
+static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,
+ const char *dirname)
{
struct ref_entry *direntry;
int len = strlen(dirname);
direntry = xcalloc(1, sizeof(struct ref_entry) + len + 1);
memcpy(direntry->name, dirname, len + 1);
direntry->flag = REF_DIR;
+ direntry->u.subdir.ref_cache = ref_cache;
return direntry;
}
@@ -312,7 +322,8 @@ static struct ref_entry *find_containing_direntry(struct ref_entry *direntry,
direntry = NULL;
break;
}
- entry = create_dir_entry(refname_copy);
+ entry = create_dir_entry(direntry->u.subdir.ref_cache,
+ refname_copy);
add_entry(direntry, entry);
}
slash[1] = tmp;
@@ -726,7 +737,7 @@ static void read_packed_refs(FILE *f, struct ref_entry *direntry)
void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
{
if (!extra_refs)
- extra_refs = create_dir_entry("");
+ extra_refs = create_dir_entry(NULL, "");
add_ref(extra_refs, create_ref_entry(refname, sha1, flag, 0));
}
@@ -744,7 +755,7 @@ static struct ref_entry *get_packed_refs(struct ref_cache *refs)
const char *packed_refs_file;
FILE *f;
- refs->packed = create_dir_entry("");
+ refs->packed = create_dir_entry(refs, "");
if (*refs->name)
packed_refs_file = git_path_submodule(refs->name, "packed-refs");
else
@@ -835,7 +846,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname)
static struct ref_entry *get_loose_refs(struct ref_cache *refs)
{
if (!refs->loose) {
- refs->loose = create_dir_entry("");
+ refs->loose = create_dir_entry(refs, "");
get_ref_dir(refs, "refs/");
}
return refs->loose;
--
1.7.8
^ permalink raw reply related
* [PATCH v2 45/51] sort_ref_dir(): take (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 16 +++++++++-------
1 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/refs.c b/refs.c
index f6d9fe7..4a3546b 100644
--- a/refs.c
+++ b/refs.c
@@ -243,7 +243,7 @@ static int ref_entry_cmp(const void *a, const void *b)
return strcmp(one->name, two->name);
}
-static void sort_ref_dir(struct ref_dir *dir);
+static void sort_ref_dir(struct ref_entry *direntry);
/*
* Return the entry with the given refname from the ref_dir
@@ -271,7 +271,7 @@ static struct ref_entry *search_ref_dir(struct ref_entry *direntry, const char *
* references one after the other to a single subdirectory
* doesn't require *any* intermediate sorting.
*/
- sort_ref_dir(dir);
+ sort_ref_dir(direntry);
len = strlen(refname) + 1;
e = xmalloc(sizeof(struct ref_entry) + len);
@@ -382,11 +382,13 @@ static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2
* Sort the entries in dir (if they are not already sorted). Sort
* only dir itself, not its subdirectories.
*/
-static void sort_ref_dir(struct ref_dir *dir)
+static void sort_ref_dir(struct ref_entry *direntry)
{
int i, j;
struct ref_entry *last = NULL;
-
+ struct ref_dir *dir;
+ assert(direntry->flag & REF_DIR);
+ dir = &direntry->u.subdir;
if (dir->sorted == dir->nr)
return; /* This directory is already sorted and de-duped */
@@ -437,7 +439,7 @@ static int do_for_each_ref_in_dir(struct ref_entry *direntry, int offset,
struct ref_dir *dir;
assert(direntry->flag & REF_DIR);
dir = &direntry->u.subdir;
- sort_ref_dir(dir);
+ sort_ref_dir(direntry);
for (i = offset; i < dir->nr; i++) {
struct ref_entry *entry = dir->entries[i];
int retval;
@@ -466,8 +468,8 @@ static int do_for_each_ref_in_dirs(struct ref_entry *direntry1,
assert(direntry2->flag & REF_DIR);
dir1 = &direntry1->u.subdir;
dir2 = &direntry2->u.subdir;
- sort_ref_dir(dir1);
- sort_ref_dir(dir2);
+ sort_ref_dir(direntry1);
+ sort_ref_dir(direntry2);
while (1) {
struct ref_entry *e1, *e2, *entry;
int cmp;
--
1.7.8
^ permalink raw reply related
* [PATCH v2 44/51] do_for_each_ref_in_dir*(): take (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 38 ++++++++++++++++++++++----------------
1 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/refs.c b/refs.c
index 54f65e3..f6d9fe7 100644
--- a/refs.c
+++ b/refs.c
@@ -429,17 +429,20 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,
return fn(entry->name + trim, entry->u.value.sha1, entry->flag, cb_data);
}
-static int do_for_each_ref_in_dir(struct ref_dir *dir, int offset,
+static int do_for_each_ref_in_dir(struct ref_entry *direntry, int offset,
const char *base,
each_ref_fn fn, int trim, int flags, void *cb_data)
{
int i;
+ struct ref_dir *dir;
+ assert(direntry->flag & REF_DIR);
+ dir = &direntry->u.subdir;
sort_ref_dir(dir);
for (i = offset; i < dir->nr; i++) {
struct ref_entry *entry = dir->entries[i];
int retval;
if (entry->flag & REF_DIR) {
- retval = do_for_each_ref_in_dir(&entry->u.subdir, 0,
+ retval = do_for_each_ref_in_dir(entry, 0,
base, fn, trim, flags, cb_data);
} else {
retval = do_one_ref(base, fn, trim, flags, cb_data, entry);
@@ -450,25 +453,30 @@ static int do_for_each_ref_in_dir(struct ref_dir *dir, int offset,
return 0;
}
-static int do_for_each_ref_in_dirs(struct ref_dir *dir1,
- struct ref_dir *dir2,
+static int do_for_each_ref_in_dirs(struct ref_entry *direntry1,
+ struct ref_entry *direntry2,
const char *base, each_ref_fn fn, int trim,
int flags, void *cb_data)
{
int retval;
int i1 = 0, i2 = 0;
+ struct ref_dir *dir1, *dir2;
+ assert(direntry1->flag & REF_DIR);
+ assert(direntry2->flag & REF_DIR);
+ dir1 = &direntry1->u.subdir;
+ dir2 = &direntry2->u.subdir;
sort_ref_dir(dir1);
sort_ref_dir(dir2);
while (1) {
struct ref_entry *e1, *e2, *entry;
int cmp;
if (i1 == dir1->nr) {
- return do_for_each_ref_in_dir(dir2, i2,
+ return do_for_each_ref_in_dir(direntry2, i2,
base, fn, trim, flags, cb_data);
}
if (i2 == dir2->nr) {
- return do_for_each_ref_in_dir(dir1, i1,
+ return do_for_each_ref_in_dir(direntry1, i1,
base, fn, trim, flags, cb_data);
}
e1 = dir1->entries[i1];
@@ -478,7 +486,7 @@ static int do_for_each_ref_in_dirs(struct ref_dir *dir1,
if ((e1->flag & REF_DIR) && (e2->flag & REF_DIR)) {
/* Both are directories; descend them in parallel. */
retval = do_for_each_ref_in_dirs(
- &e1->u.subdir, &e2->u.subdir,
+ e1, e2,
base, fn, trim, flags, cb_data);
i1++;
i2++;
@@ -501,7 +509,7 @@ static int do_for_each_ref_in_dirs(struct ref_dir *dir1,
}
if (entry->flag & REF_DIR) {
retval = do_for_each_ref_in_dir(
- &entry->u.subdir, 0,
+ entry, 0,
base, fn, trim, flags, cb_data);
} else {
retval = do_one_ref(base, fn, trim, flags, cb_data, entry);
@@ -563,7 +571,7 @@ static int is_refname_available(const char *refname, const char *oldrefname,
assert(direntry->flag & REF_DIR);
- if (do_for_each_ref_in_dir(&direntry->u.subdir, 0, "", name_conflict_fn,
+ if (do_for_each_ref_in_dir(direntry, 0, "", name_conflict_fn,
0, DO_FOR_EACH_INCLUDE_BROKEN,
&data)) {
error("'%s' exists; cannot create '%s'",
@@ -1161,21 +1169,20 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn
if (extra_direntry)
retval = do_for_each_ref_in_dir(
- &extra_direntry->u.subdir, 0,
+ extra_direntry, 0,
base, fn, trim, flags, cb_data);
if (!retval) {
if (packed_direntry && loose_direntry)
retval = do_for_each_ref_in_dirs(
- &packed_direntry->u.subdir,
- &loose_direntry->u.subdir,
+ packed_direntry, loose_direntry,
base, fn, trim, flags, cb_data);
else if (packed_direntry)
retval = do_for_each_ref_in_dir(
- &packed_direntry->u.subdir, 0,
+ packed_direntry, 0,
base, fn, trim, flags, cb_data);
else if (loose_direntry)
retval = do_for_each_ref_in_dir(
- &loose_direntry->u.subdir, 0,
+ loose_direntry, 0,
base, fn, trim, flags, cb_data);
}
@@ -1626,8 +1633,7 @@ static int repack_without_ref(const char *refname)
unable_to_lock_error(git_path("packed-refs"), errno);
return error("cannot delete '%s' from packed refs", refname);
}
- do_for_each_ref_in_dir(&packed->u.subdir, 0,
- "", repack_without_ref_fn, 0, 0, &data);
+ do_for_each_ref_in_dir(packed, 0, "", repack_without_ref_fn, 0, 0, &data);
return commit_lock_file(&packlock);
}
--
1.7.8
^ permalink raw reply related
* [PATCH v2 43/51] add_entry(): take (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 12 +++++++-----
1 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/refs.c b/refs.c
index 30ff9b8..54f65e3 100644
--- a/refs.c
+++ b/refs.c
@@ -199,8 +199,11 @@ static void free_ref_entry(struct ref_entry *entry)
* stored directly in dir; no recursion into subdirectories is
* done.
*/
-static void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry)
+static void add_entry(struct ref_entry *direntry, struct ref_entry *entry)
{
+ struct ref_dir *dir;
+ assert(direntry->flag & REF_DIR);
+ dir = &direntry->u.subdir;
ALLOC_GROW(dir->entries, dir->nr + 1, dir->alloc);
dir->entries[dir->nr++] = entry;
}
@@ -310,7 +313,7 @@ static struct ref_entry *find_containing_direntry(struct ref_entry *direntry,
break;
}
entry = create_dir_entry(refname_copy);
- add_entry_to_dir(&direntry->u.subdir, entry);
+ add_entry(direntry, entry);
}
slash[1] = tmp;
assert(entry->flag & REF_DIR);
@@ -348,7 +351,7 @@ static int add_ref(struct ref_entry *direntry, struct ref_entry *ref)
direntry = find_containing_direntry(direntry, ref->name, 1);
if (!direntry)
return -1;
- add_entry_to_dir(&direntry->u.subdir, ref);
+ add_entry(direntry, ref);
return 0;
}
@@ -812,8 +815,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname)
hashclr(sha1);
flag |= REF_ISBROKEN;
}
- add_entry_to_dir(&direntry->u.subdir,
- create_ref_entry(refname, sha1, flag, 1));
+ add_entry(direntry, create_ref_entry(refname, sha1, flag, 1));
}
free(refname);
closedir(d);
--
1.7.8
^ permalink raw reply related
* [PATCH v2 41/51] find_containing_direntry(): use (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Change type of both argument and return value.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 78 ++++++++++++++++++++++++++++++++--------------------------------
1 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/refs.c b/refs.c
index 439545b..d89c3d0 100644
--- a/refs.c
+++ b/refs.c
@@ -282,38 +282,40 @@ static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname
}
/*
- * If refname is a reference name, find the ref_dir within the dir
+ * If refname is a reference name, find the ref_entry within the dir
* tree that should hold refname. If refname is a directory name
- * (i.e., ends in '/'), then return that ref_dir itself. dir must
- * represent the top-level directory. Recurse into subdirectories as
- * necessary. If mkdir is set, then create any missing directories;
- * otherwise, return NULL if the desired directory cannot be found.
+ * (i.e., "" or ends in '/'), then return that ref_entry itself. dir
+ * must represent the top-level directory. Recurse into
+ * subdirectories as necessary. If mkdir is set, then create any
+ * missing directories; otherwise, return NULL if the desired
+ * directory cannot be found.
*/
-static struct ref_dir *find_containing_dir(struct ref_dir *dir,
- const char *refname, int mkdir)
+static struct ref_entry *find_containing_direntry(struct ref_entry *direntry,
+ const char *refname, int mkdir)
{
char *refname_copy = xstrdup(refname);
char *slash;
- struct ref_entry *entry;
+ assert(direntry->flag & REF_DIR);
for (slash = strchr(refname_copy, '/'); slash; slash = strchr(slash + 1, '/')) {
char tmp = slash[1];
+ struct ref_entry *entry;
slash[1] = '\0';
- entry = search_ref_dir(dir, refname_copy);
+ entry = search_ref_dir(&direntry->u.subdir, refname_copy);
if (!entry) {
if (!mkdir) {
- dir = NULL;
+ direntry = NULL;
break;
}
entry = create_dir_entry(refname_copy);
- add_entry_to_dir(dir, entry);
+ add_entry_to_dir(&direntry->u.subdir, entry);
}
slash[1] = tmp;
assert(entry->flag & REF_DIR);
- dir = &entry->u.subdir;
+ direntry = entry;
}
free(refname_copy);
- return dir;
+ return direntry;
}
/*
@@ -324,12 +326,11 @@ static struct ref_dir *find_containing_dir(struct ref_dir *dir,
static struct ref_entry *find_ref(struct ref_entry *direntry, const char *refname)
{
struct ref_entry *entry;
- struct ref_dir *dir;
assert(direntry->flag & REF_DIR);
- dir = find_containing_dir(&direntry->u.subdir, refname, 0);
- if (!dir)
+ direntry = find_containing_direntry(direntry, refname, 0);
+ if (!direntry)
return NULL;
- entry = search_ref_dir(dir, refname);
+ entry = search_ref_dir(&direntry->u.subdir, refname);
return (entry && !(entry->flag & REF_DIR)) ? entry : NULL;
}
@@ -340,12 +341,11 @@ static struct ref_entry *find_ref(struct ref_entry *direntry, const char *refnam
*/
static int add_ref(struct ref_entry *direntry, struct ref_entry *ref)
{
- struct ref_dir *dir;
assert(direntry->flag & REF_DIR);
- dir = find_containing_dir(&direntry->u.subdir, ref->name, 1);
- if (!dir)
+ direntry = find_containing_direntry(direntry, ref->name, 1);
+ if (!direntry)
return -1;
- add_entry_to_dir(dir, ref);
+ add_entry_to_dir(&direntry->u.subdir, ref);
return 0;
}
@@ -752,11 +752,11 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname)
char *path;
int dirnamelen = strlen(dirname);
int pathlen;
- struct ref_dir *dir;
+ struct ref_entry *direntry;
assert(dirnamelen && dirname[dirnamelen - 1] == '/');
- dir = find_containing_dir(&refs->loose->u.subdir, dirname, 1);
+ direntry = find_containing_direntry(refs->loose, dirname, 1);
if (*refs->name)
path = git_path_submodule(refs->name, "%s", dirname);
@@ -809,7 +809,8 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname)
hashclr(sha1);
flag |= REF_ISBROKEN;
}
- add_entry_to_dir(dir, create_ref_entry(refname, sha1, flag, 1));
+ add_entry_to_dir(&direntry->u.subdir,
+ create_ref_entry(refname, sha1, flag, 1));
}
free(refname);
closedir(d);
@@ -1142,35 +1143,34 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn
{
int retval = 0;
struct ref_cache *refs = get_ref_cache(submodule);
- struct ref_dir *extra_dir = extra_refs ? &extra_refs->u.subdir : NULL;
+ struct ref_entry *extra_direntry = extra_refs;
struct ref_entry *packed_direntry = get_packed_refs(refs);
- struct ref_dir *packed_dir = &packed_direntry->u.subdir;
struct ref_entry *loose_direntry = get_loose_refs(refs);
- struct ref_dir *loose_dir = &loose_direntry->u.subdir;
if (base && *base) {
- if (extra_dir)
- extra_dir = find_containing_dir(extra_dir, base, 0);
- packed_dir = find_containing_dir(packed_dir, base, 0);
- loose_dir = find_containing_dir(loose_dir, base, 0);
+ if (extra_direntry)
+ extra_direntry = find_containing_direntry(extra_direntry, base, 0);
+ packed_direntry = find_containing_direntry(packed_direntry, base, 0);
+ loose_direntry = find_containing_direntry(loose_direntry, base, 0);
}
- if (extra_dir)
+ if (extra_direntry)
retval = do_for_each_ref_in_dir(
- extra_dir, 0,
+ &extra_direntry->u.subdir, 0,
base, fn, trim, flags, cb_data);
if (!retval) {
- if (packed_dir && loose_dir)
+ if (packed_direntry && loose_direntry)
retval = do_for_each_ref_in_dirs(
- packed_dir, loose_dir,
+ &packed_direntry->u.subdir,
+ &loose_direntry->u.subdir,
base, fn, trim, flags, cb_data);
- else if (packed_dir)
+ else if (packed_direntry)
retval = do_for_each_ref_in_dir(
- packed_dir, 0,
+ &packed_direntry->u.subdir, 0,
base, fn, trim, flags, cb_data);
- else if (loose_dir)
+ else if (loose_direntry)
retval = do_for_each_ref_in_dir(
- loose_dir, 0,
+ &loose_direntry->u.subdir, 0,
base, fn, trim, flags, cb_data);
}
--
1.7.8
^ permalink raw reply related
* [PATCH v2 40/51] add_ref(): take (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/refs.c b/refs.c
index 0d8fdf0..439545b 100644
--- a/refs.c
+++ b/refs.c
@@ -338,9 +338,11 @@ static struct ref_entry *find_ref(struct ref_entry *direntry, const char *refnam
* subdirectories as necessary. dir must represent the top-level
* directory. Return 0 on success.
*/
-static int add_ref(struct ref_dir *dir, struct ref_entry *ref)
+static int add_ref(struct ref_entry *direntry, struct ref_entry *ref)
{
- dir = find_containing_dir(dir, ref->name, 1);
+ struct ref_dir *dir;
+ assert(direntry->flag & REF_DIR);
+ dir = find_containing_dir(&direntry->u.subdir, ref->name, 1);
if (!dir)
return -1;
add_entry_to_dir(dir, ref);
@@ -693,7 +695,7 @@ static void read_packed_refs(FILE *f, struct ref_entry *direntry)
refname = parse_ref_line(refline, sha1);
if (refname) {
last = create_ref_entry(refname, sha1, flag, 1);
- add_ref(&direntry->u.subdir, last);
+ add_ref(direntry, last);
continue;
}
if (last &&
@@ -709,7 +711,7 @@ void add_extra_ref(const char *refname, const unsigned char *sha1, int flag)
{
if (!extra_refs)
extra_refs = create_dir_entry("");
- add_ref(&extra_refs->u.subdir, create_ref_entry(refname, sha1, flag, 0));
+ add_ref(extra_refs, create_ref_entry(refname, sha1, flag, 0));
}
void clear_extra_refs(void)
--
1.7.8
^ permalink raw reply related
* [PATCH v2 39/51] read_packed_refs(): take (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/refs.c b/refs.c
index df7416f..0d8fdf0 100644
--- a/refs.c
+++ b/refs.c
@@ -670,12 +670,13 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
return line;
}
-static void read_packed_refs(FILE *f, struct ref_dir *dir)
+static void read_packed_refs(FILE *f, struct ref_entry *direntry)
{
struct ref_entry *last = NULL;
char refline[PATH_MAX];
int flag = REF_ISPACKED;
+ assert(direntry->flag & REF_DIR);
while (fgets(refline, sizeof(refline), f)) {
unsigned char sha1[20];
const char *refname;
@@ -692,7 +693,7 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
refname = parse_ref_line(refline, sha1);
if (refname) {
last = create_ref_entry(refname, sha1, flag, 1);
- add_ref(dir, last);
+ add_ref(&direntry->u.subdir, last);
continue;
}
if (last &&
@@ -732,7 +733,7 @@ static struct ref_entry *get_packed_refs(struct ref_cache *refs)
packed_refs_file = git_path("packed-refs");
f = fopen(packed_refs_file, "r");
if (f) {
- read_packed_refs(f, &refs->packed->u.subdir);
+ read_packed_refs(f, refs->packed);
fclose(f);
}
}
--
1.7.8
^ permalink raw reply related
* [PATCH v2 38/51] find_ref(): take (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 14 ++++++++------
1 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/refs.c b/refs.c
index 6b7d374..df7416f 100644
--- a/refs.c
+++ b/refs.c
@@ -321,10 +321,12 @@ static struct ref_dir *find_containing_dir(struct ref_dir *dir,
* subdirectories as necessary. If the name is not found or it
* corresponds to a directory entry, return NULL.
*/
-static struct ref_entry *find_ref(struct ref_dir *dir, const char *refname)
+static struct ref_entry *find_ref(struct ref_entry *direntry, const char *refname)
{
struct ref_entry *entry;
- dir = find_containing_dir(dir, refname, 0);
+ struct ref_dir *dir;
+ assert(direntry->flag & REF_DIR);
+ dir = find_containing_dir(&direntry->u.subdir, refname, 0);
if (!dir)
return NULL;
entry = search_ref_dir(dir, refname);
@@ -835,7 +837,7 @@ static int resolve_gitlink_packed_ref(struct ref_cache *refs,
struct ref_entry *ref;
struct ref_entry *direntry = get_packed_refs(refs);
- ref = find_ref(&direntry->u.subdir, refname);
+ ref = find_ref(direntry, refname);
if (ref == NULL)
return -1;
@@ -907,7 +909,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
static int get_packed_ref(const char *refname, unsigned char *sha1)
{
struct ref_entry *packed = get_packed_refs(get_ref_cache(NULL));
- struct ref_entry *entry = find_ref(&packed->u.subdir, refname);
+ struct ref_entry *entry = find_ref(packed, refname);
if (entry) {
hashcpy(sha1, entry->u.value.sha1);
return 0;
@@ -1078,7 +1080,7 @@ int peel_ref(const char *refname, unsigned char *sha1)
if ((flag & REF_ISPACKED)) {
struct ref_entry *direntry = get_packed_refs(get_ref_cache(NULL));
- struct ref_entry *r = find_ref(&direntry->u.subdir, refname);
+ struct ref_entry *r = find_ref(direntry, refname);
if (r != NULL && r->flag & REF_KNOWS_PEELED) {
hashcpy(sha1, r->u.value.peeled);
@@ -1608,7 +1610,7 @@ static int repack_without_ref(const char *refname)
{
struct repack_without_ref_sb data;
struct ref_entry *packed = get_packed_refs(get_ref_cache(NULL));
- if (find_ref(&packed->u.subdir, refname) == NULL)
+ if (find_ref(packed, refname) == NULL)
return 0;
data.refname = refname;
data.fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
--
1.7.8
^ permalink raw reply related
* [PATCH v2 37/51] is_refname_available(): take (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 12 +++++++-----
1 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/refs.c b/refs.c
index 918b787..6b7d374 100644
--- a/refs.c
+++ b/refs.c
@@ -544,14 +544,16 @@ static int name_conflict_fn(const char *existingrefname, const unsigned char *sh
* operation).
*/
static int is_refname_available(const char *refname, const char *oldrefname,
- struct ref_dir *dir)
+ struct ref_entry *direntry)
{
struct name_conflict_cb data;
data.refname = refname;
data.oldrefname = oldrefname;
data.conflicting_refname = NULL;
- if (do_for_each_ref_in_dir(dir, 0, "", name_conflict_fn,
+ assert(direntry->flag & REF_DIR);
+
+ if (do_for_each_ref_in_dir(&direntry->u.subdir, 0, "", name_conflict_fn,
0, DO_FOR_EACH_INCLUDE_BROKEN,
&data)) {
error("'%s' exists; cannot create '%s'",
@@ -1525,7 +1527,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
*/
if (missing &&
!is_refname_available(refname, NULL,
- &get_packed_refs(get_ref_cache(NULL))->u.subdir)) {
+ get_packed_refs(get_ref_cache(NULL)))) {
last_errno = ENOTDIR;
goto error_return;
}
@@ -1686,10 +1688,10 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
if (!symref)
return error("refname %s not found", oldrefname);
- if (!is_refname_available(newrefname, oldrefname, &get_packed_refs(refs)->u.subdir))
+ if (!is_refname_available(newrefname, oldrefname, get_packed_refs(refs)))
return 1;
- if (!is_refname_available(newrefname, oldrefname, &get_loose_refs(refs)->u.subdir))
+ if (!is_refname_available(newrefname, oldrefname, get_loose_refs(refs)))
return 1;
if (log && rename(git_path("logs/%s", oldrefname), git_path(TMP_RENAMED_LOG)))
--
1.7.8
^ permalink raw reply related
* [PATCH v2 35/51] get_packed_refs(): return (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 33 +++++++++++++++++----------------
1 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/refs.c b/refs.c
index b4019e6..6a65a21 100644
--- a/refs.c
+++ b/refs.c
@@ -715,7 +715,7 @@ void clear_extra_refs(void)
}
}
-static struct ref_dir *get_packed_refs(struct ref_cache *refs)
+static struct ref_entry *get_packed_refs(struct ref_cache *refs)
{
if (!refs->packed) {
const char *packed_refs_file;
@@ -732,7 +732,7 @@ static struct ref_dir *get_packed_refs(struct ref_cache *refs)
fclose(f);
}
}
- return &refs->packed->u.subdir;
+ return refs->packed;
}
/*
@@ -831,9 +831,9 @@ static int resolve_gitlink_packed_ref(struct ref_cache *refs,
const char *refname, unsigned char *sha1)
{
struct ref_entry *ref;
- struct ref_dir *dir = get_packed_refs(refs);
+ struct ref_entry *direntry = get_packed_refs(refs);
- ref = find_ref(dir, refname);
+ ref = find_ref(&direntry->u.subdir, refname);
if (ref == NULL)
return -1;
@@ -904,8 +904,8 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
*/
static int get_packed_ref(const char *refname, unsigned char *sha1)
{
- struct ref_dir *packed = get_packed_refs(get_ref_cache(NULL));
- struct ref_entry *entry = find_ref(packed, refname);
+ struct ref_entry *packed = get_packed_refs(get_ref_cache(NULL));
+ struct ref_entry *entry = find_ref(&packed->u.subdir, refname);
if (entry) {
hashcpy(sha1, entry->u.value.sha1);
return 0;
@@ -1075,8 +1075,8 @@ int peel_ref(const char *refname, unsigned char *sha1)
return -1;
if ((flag & REF_ISPACKED)) {
- struct ref_dir *dir = get_packed_refs(get_ref_cache(NULL));
- struct ref_entry *r = find_ref(dir, refname);
+ struct ref_entry *direntry = get_packed_refs(get_ref_cache(NULL));
+ struct ref_entry *r = find_ref(&direntry->u.subdir, refname);
if (r != NULL && r->flag & REF_KNOWS_PEELED) {
hashcpy(sha1, r->u.value.peeled);
@@ -1136,7 +1136,8 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn
int retval = 0;
struct ref_cache *refs = get_ref_cache(submodule);
struct ref_dir *extra_dir = extra_refs ? &extra_refs->u.subdir : NULL;
- struct ref_dir *packed_dir = get_packed_refs(refs);
+ struct ref_entry *packed_direntry = get_packed_refs(refs);
+ struct ref_dir *packed_dir = &packed_direntry->u.subdir;
struct ref_dir *loose_dir = get_loose_refs(refs);
if (base && *base) {
@@ -1522,7 +1523,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
* name is a proper prefix of our refname.
*/
if (missing &&
- !is_refname_available(refname, NULL, get_packed_refs(get_ref_cache(NULL)))) {
+ !is_refname_available(refname, NULL,
+ &get_packed_refs(get_ref_cache(NULL))->u.subdir)) {
last_errno = ENOTDIR;
goto error_return;
}
@@ -1602,10 +1604,8 @@ static struct lock_file packlock;
static int repack_without_ref(const char *refname)
{
struct repack_without_ref_sb data;
- struct ref_dir *packed;
-
- packed = get_packed_refs(get_ref_cache(NULL));
- if (find_ref(packed, refname) == NULL)
+ struct ref_entry *packed = get_packed_refs(get_ref_cache(NULL));
+ if (find_ref(&packed->u.subdir, refname) == NULL)
return 0;
data.refname = refname;
data.fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
@@ -1613,7 +1613,8 @@ static int repack_without_ref(const char *refname)
unable_to_lock_error(git_path("packed-refs"), errno);
return error("cannot delete '%s' from packed refs", refname);
}
- do_for_each_ref_in_dir(packed, 0, "", repack_without_ref_fn, 0, 0, &data);
+ do_for_each_ref_in_dir(&packed->u.subdir, 0,
+ "", repack_without_ref_fn, 0, 0, &data);
return commit_lock_file(&packlock);
}
@@ -1684,7 +1685,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
if (!symref)
return error("refname %s not found", oldrefname);
- if (!is_refname_available(newrefname, oldrefname, get_packed_refs(refs)))
+ if (!is_refname_available(newrefname, oldrefname, &get_packed_refs(refs)->u.subdir))
return 1;
if (!is_refname_available(newrefname, oldrefname, get_loose_refs(refs)))
--
1.7.8
^ permalink raw reply related
* [PATCH v2 36/51] get_loose_refs(): return (ref_entry *) instead of (ref_dir *)
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/refs.c b/refs.c
index 6a65a21..918b787 100644
--- a/refs.c
+++ b/refs.c
@@ -809,13 +809,13 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname)
}
}
-static struct ref_dir *get_loose_refs(struct ref_cache *refs)
+static struct ref_entry *get_loose_refs(struct ref_cache *refs)
{
if (!refs->loose) {
refs->loose = create_dir_entry("");
get_ref_dir(refs, "refs/");
}
- return &refs->loose->u.subdir;
+ return refs->loose;
}
/* We allow "recursive" symbolic refs. Only within reason, though */
@@ -1138,7 +1138,8 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn
struct ref_dir *extra_dir = extra_refs ? &extra_refs->u.subdir : NULL;
struct ref_entry *packed_direntry = get_packed_refs(refs);
struct ref_dir *packed_dir = &packed_direntry->u.subdir;
- struct ref_dir *loose_dir = get_loose_refs(refs);
+ struct ref_entry *loose_direntry = get_loose_refs(refs);
+ struct ref_dir *loose_dir = &loose_direntry->u.subdir;
if (base && *base) {
if (extra_dir)
@@ -1688,7 +1689,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
if (!is_refname_available(newrefname, oldrefname, &get_packed_refs(refs)->u.subdir))
return 1;
- if (!is_refname_available(newrefname, oldrefname, get_loose_refs(refs)))
+ if (!is_refname_available(newrefname, oldrefname, &get_loose_refs(refs)->u.subdir))
return 1;
if (log && rename(git_path("logs/%s", oldrefname), git_path(TMP_RENAMED_LOG)))
--
1.7.8
^ permalink raw reply related
* [PATCH v2 29/51] refs: store references hierarchically
From: mhagger @ 2011-12-12 5:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Jeff King, Drew Northup, Jakub Narebski, Heiko Voigt,
Johan Herland, Julian Phillips, Michael Haggerty
In-Reply-To: <1323668338-1764-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>
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.
Please note that this change causes some extra sorting to be required,
and therefore a performance regression. The old performance will be
regained in the next couple of commits by (1) keeping track of when a
directory is already sorted and not re-sorting it; (2) only sorting a
directory when the correct order needed; and (3) not sorting
directories recursively.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
refs.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 220 insertions(+), 45 deletions(-)
diff --git a/refs.c b/refs.c
index b74ef80..ccd2806 100644
--- a/refs.c
+++ b/refs.c
@@ -111,15 +111,54 @@ struct ref_dir {
struct ref_entry **entries;
};
-/* ISSYMREF=0x01, ISPACKED=0x02 and ISBROKEN=0x04 are public interfaces */
-#define REF_KNOWS_PEELED 0x10
+/* ISSYMREF=0x01, ISPACKED=0x02, and ISBROKEN=0x04 are public interfaces */
+#define REF_KNOWS_PEELED 0x08
+#define REF_DIR 0x10
+/*
+ * A ref_entry represents either a reference or a "subdirectory" of
+ * references. Each directory in the reference namespace is
+ * represented by a ref_entry with (flags & REF_DIR) set and
+ * containing a subdir member that holds the entries in that
+ * directory. References are represented by a ref_entry with (flags &
+ * REF_DIR) unset and a value member that describes the reference's
+ * value. The flag member is at the ref_entry level, but it is also
+ * needed to interpret the contents of the value field (in other
+ * words, a ref_value object is not very much use without the
+ * enclosing ref_entry).
+ *
+ * Reference names cannot end with slash and directories' names are
+ * always stored with a trailing slash (except for the top-level
+ * directory, which is always denoted by ""). This has two nice
+ * consequences: (1) when the entries in each subdir are sorted
+ * lexicographically by name (as they usually are), the references in
+ * a whole tree can be generated in lexicographic order by traversing
+ * the tree in left-to-right, depth-first order; (2) the names of
+ * references and subdirectories cannot conflict, and therefore the
+ * presence of an empty subdirectory does not block the creation of a
+ * similarly-named reference. (The fact that reference names with the
+ * same leading components can conflict *with each other* is a
+ * separate issue that is regulated by is_refname_available().)
+ *
+ * Please note that the name field contains the fully-qualified
+ * reference (or subdirectory) name. Space could be saved by only
+ * storing the relative names. But that would require the full names
+ * to be generated on the fly when iterating in do_for_each_ref(), and
+ * would break callback functions, who have always been able to assume
+ * that the name strings that they are passed will not be freed during
+ * the iteration.
+ */
struct ref_entry {
unsigned char flag; /* ISSYMREF? ISPACKED? */
union {
- struct ref_value value;
+ struct ref_value value; /* if not (flags&REF_DIR) */
+ struct ref_dir subdir; /* if (flags&REF_DIR) */
} u;
- /* The full name of the reference (e.g., "refs/heads/master"): */
+ /*
+ * The full name of the reference (e.g., "refs/heads/master")
+ * or the full name of the directory with a trailing slash
+ * (e.g., "refs/heads/"):
+ */
char name[FLEX_ARRAY];
};
@@ -142,18 +181,29 @@ static struct ref_entry *create_ref_entry(const char *refname,
return ref;
}
+static void clear_ref_dir(struct ref_dir *dir);
+
static void free_ref_entry(struct ref_entry *entry)
{
+ if (entry->flag & REF_DIR)
+ clear_ref_dir(&entry->u.subdir);
free(entry);
}
-/* Add a ref_entry to the end of the ref_dir (unsorted). */
-static void add_ref(struct ref_dir *refs, struct ref_entry *ref)
+/*
+ * Add a ref_entry to the end of dir (unsorted). Entry is always
+ * stored directly in dir; no recursion into subdirectories is
+ * done.
+ */
+static void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry)
{
- ALLOC_GROW(refs->entries, refs->nr + 1, refs->alloc);
- refs->entries[refs->nr++] = ref;
+ ALLOC_GROW(dir->entries, dir->nr + 1, dir->alloc);
+ dir->entries[dir->nr++] = entry;
}
+/*
+ * Clear and free all entries in dir, recursively.
+ */
static void clear_ref_dir(struct ref_dir *dir)
{
int i;
@@ -164,6 +214,21 @@ static void clear_ref_dir(struct ref_dir *dir)
dir->entries = NULL;
}
+/*
+ * Create a struct ref_entry object for the specified dirname.
+ * dirname is the name of the directory with a trailing slash (e.g.,
+ * "refs/heads/") or "" for the top-level directory.
+ */
+static struct ref_entry *create_dir_entry(const char *dirname)
+{
+ struct ref_entry *direntry;
+ int len = strlen(dirname);
+ direntry = xcalloc(1, sizeof(struct ref_entry) + len + 1);
+ memcpy(direntry->name, dirname, len + 1);
+ direntry->flag = REF_DIR;
+ return direntry;
+}
+
static int ref_entry_cmp(const void *a, const void *b)
{
struct ref_entry *one = *(struct ref_entry **)a;
@@ -171,16 +236,26 @@ static int ref_entry_cmp(const void *a, const void *b)
return strcmp(one->name, two->name);
}
+static void sort_ref_dir(struct ref_dir *dir);
+
+/*
+ * Return the entry with the given refname from the ref_dir
+ * (non-recursively). Return NULL if no such entry is found.
+ */
static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname)
{
struct ref_entry *e, **r;
int len;
- if (refname == NULL)
+ if (refname == NULL || !dir->nr)
return NULL;
- if (!dir->nr)
- return NULL;
+ /*
+ * We need dir to be sorted so that binary search works.
+ * FIXME: Sorting the array each time is terribly inefficient,
+ * and has to be changed.
+ */
+ sort_ref_dir(dir);
len = strlen(refname) + 1;
e = xmalloc(sizeof(struct ref_entry) + len);
@@ -197,44 +272,116 @@ static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname
}
/*
+ * If refname is a reference name, find the ref_dir within the dir
+ * tree that should hold refname. If refname is a directory name
+ * (i.e., ends in '/'), then return that ref_dir itself. dir must
+ * represent the top-level directory. Recurse into subdirectories as
+ * necessary. If mkdir is set, then create any missing directories;
+ * otherwise, return NULL if the desired directory cannot be found.
+ */
+static struct ref_dir *find_containing_dir(struct ref_dir *dir,
+ const char *refname, int mkdir)
+{
+ char *refname_copy = xstrdup(refname);
+ char *slash;
+ struct ref_entry *entry;
+ for (slash = strchr(refname_copy, '/'); slash; slash = strchr(slash + 1, '/')) {
+ char tmp = slash[1];
+ slash[1] = '\0';
+ entry = search_ref_dir(dir, refname_copy);
+ if (!entry) {
+ if (!mkdir) {
+ dir = NULL;
+ break;
+ }
+ entry = create_dir_entry(refname_copy);
+ add_entry_to_dir(dir, entry);
+ }
+ slash[1] = tmp;
+ assert(entry->flag & REF_DIR);
+ dir = &entry->u.subdir;
+ }
+
+ free(refname_copy);
+ return dir;
+}
+
+/*
+ * Find the value entry with the given name in dir, recursing into
+ * subdirectories as necessary. If the name is not found or it
+ * corresponds to a directory entry, return NULL.
+ */
+static struct ref_entry *find_ref(struct ref_dir *dir, const char *refname)
+{
+ struct ref_entry *entry;
+ dir = find_containing_dir(dir, refname, 0);
+ if (!dir)
+ return NULL;
+ entry = search_ref_dir(dir, refname);
+ return (entry && !(entry->flag & REF_DIR)) ? entry : NULL;
+}
+
+/*
+ * Add a ref_entry to the ref_dir (unsorted), recursing into
+ * subdirectories as necessary. dir must represent the top-level
+ * directory. Return 0 on success.
+ */
+static int add_ref(struct ref_dir *dir, struct ref_entry *ref)
+{
+ dir = find_containing_dir(dir, ref->name, 1);
+ if (!dir)
+ return -1;
+ add_entry_to_dir(dir, ref);
+ return 0;
+}
+
+/*
* Emit a warning and return true iff ref1 and ref2 have the same name
* and the same sha1. Die if they have the same name but different
* sha1s.
*/
static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2)
{
- if (!strcmp(ref1->name, ref2->name)) {
- /* Duplicate name; make sure that the SHA1s match: */
- if (hashcmp(ref1->u.value.sha1, ref2->u.value.sha1))
- die("Duplicated ref, and SHA1s don't match: %s",
- ref1->name);
- warning("Duplicated ref: %s", ref1->name);
- return 1;
- } else {
+ if (strcmp(ref1->name, ref2->name))
return 0;
- }
+
+ /* Duplicate name; make sure that they don't conflict: */
+
+ if ((ref1->flag & REF_DIR) || (ref2->flag & REF_DIR))
+ /* This is impossible by construction */
+ die("Reference directory conflict: %s", ref1->name);
+
+ if (hashcmp(ref1->u.value.sha1, ref2->u.value.sha1))
+ die("Duplicated ref, and SHA1s don't match: %s", ref1->name);
+
+ warning("Duplicated ref: %s", ref1->name);
+ return 1;
}
static void sort_ref_dir(struct ref_dir *dir)
{
int i, j;
+ struct ref_entry *last = NULL;
- /* Nothing to sort unless there are at least two entries */
- if (dir->nr < 2)
+ if (!dir->nr)
return;
qsort(dir->entries, dir->nr, sizeof(*dir->entries), ref_entry_cmp);
- /* Remove any duplicates from the ref_array */
- i = 0;
- for (j = 1; j < dir->nr; j++) {
- if (is_dup_ref(dir->entries[i], dir->entries[j])) {
- free_ref_entry(dir->entries[j]);
- continue;
+ /* Remove any duplicates and sort subdirectories: */
+ for (i = 0, j = 0; j < dir->nr; j++) {
+ struct ref_entry *entry = dir->entries[j];
+ if (last && is_dup_ref(last, entry)) {
+ free_ref_entry(entry);
+ } else if (entry->flag & REF_DIR) {
+ sort_ref_dir(&entry->u.subdir);
+ dir->entries[i++] = entry;
+ last = NULL;
+ } else {
+ last = dir->entries[i++] = entry;
}
- dir->entries[++i] = dir->entries[j];
}
- dir->nr = i + 1;
+ dir->nr = i;
}
#define DO_FOR_EACH_INCLUDE_BROKEN 01
@@ -265,7 +412,14 @@ static int do_for_each_ref_in_dir(struct ref_dir *dir, int offset,
{
int i;
for (i = offset; i < dir->nr; i++) {
- int retval = do_one_ref(base, fn, trim, flags, cb_data, dir->entries[i]);
+ struct ref_entry *entry = dir->entries[i];
+ int retval;
+ if (entry->flag & REF_DIR) {
+ retval = do_for_each_ref_in_dir(&entry->u.subdir, 0,
+ base, fn, trim, flags, cb_data);
+ } else {
+ retval = do_one_ref(base, fn, trim, flags, cb_data, entry);
+ }
if (retval)
return retval;
}
@@ -281,7 +435,7 @@ static int do_for_each_ref_in_dirs(struct ref_dir *dir1,
int i1 = 0, i2 = 0;
while (1) {
- struct ref_entry *e1, *e2;
+ struct ref_entry *e1, *e2, *entry;
int cmp;
if (i1 == dir1->nr) {
return do_for_each_ref_in_dir(dir2, i2,
@@ -295,16 +449,37 @@ static int do_for_each_ref_in_dirs(struct ref_dir *dir1,
e2 = dir2->entries[i2];
cmp = strcmp(e1->name, e2->name);
if (cmp == 0) {
- /* Two refs with the same name; ignore the one from dir1. */
- i1++;
- continue;
- }
- if (cmp < 0) {
- retval = do_one_ref(base, fn, trim, flags, cb_data, e1);
- i1++;
+ if ((e1->flag & REF_DIR) && (e2->flag & REF_DIR)) {
+ /* Both are directories; descend them in parallel. */
+ retval = do_for_each_ref_in_dirs(
+ &e1->u.subdir, &e2->u.subdir,
+ base, fn, trim, flags, cb_data);
+ i1++;
+ i2++;
+ } else if (!(e1->flag & REF_DIR) && !(e2->flag & REF_DIR)) {
+ /* Both are references; ignore the one from dir1. */
+ retval = do_one_ref(base, fn, trim, flags, cb_data, e2);
+ i1++;
+ i2++;
+ } else {
+ die("conflict between reference and directory: %s",
+ e1->name);
+ }
} else {
- retval = do_one_ref(base, fn, trim, flags, cb_data, e2);
- i2++;
+ if (cmp < 0) {
+ entry = e1;
+ i1++;
+ } else {
+ entry = e2;
+ i2++;
+ }
+ if (entry->flag & REF_DIR) {
+ retval = do_for_each_ref_in_dir(
+ &entry->u.subdir, 0,
+ base, fn, trim, flags, cb_data);
+ } else {
+ retval = do_one_ref(base, fn, trim, flags, cb_data, entry);
+ }
}
if (retval)
return retval;
@@ -630,7 +805,7 @@ static int resolve_gitlink_packed_ref(struct ref_cache *refs,
struct ref_entry *ref;
struct ref_dir *dir = get_packed_refs(refs);
- ref = search_ref_dir(dir, refname);
+ ref = find_ref(dir, refname);
if (ref == NULL)
return -1;
@@ -702,7 +877,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
static int get_packed_ref(const char *refname, unsigned char *sha1)
{
struct ref_dir *packed = get_packed_refs(get_ref_cache(NULL));
- struct ref_entry *entry = search_ref_dir(packed, refname);
+ struct ref_entry *entry = find_ref(packed, refname);
if (entry) {
hashcpy(sha1, entry->u.value.sha1);
return 0;
@@ -873,7 +1048,7 @@ int peel_ref(const char *refname, unsigned char *sha1)
if ((flag & REF_ISPACKED)) {
struct ref_dir *dir = get_packed_refs(get_ref_cache(NULL));
- struct ref_entry *r = search_ref_dir(dir, refname);
+ struct ref_entry *r = find_ref(dir, refname);
if (r != NULL && r->flag & REF_KNOWS_PEELED) {
hashcpy(sha1, r->u.value.peeled);
@@ -1380,7 +1555,7 @@ static int repack_without_ref(const char *refname)
struct ref_dir *packed;
packed = get_packed_refs(get_ref_cache(NULL));
- if (search_ref_dir(packed, refname) == NULL)
+ if (find_ref(packed, refname) == NULL)
return 0;
data.refname = refname;
data.fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
--
1.7.8
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox