Re: [WISH] Store also tag dereferences in packed-refs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Linus Torvalds <torvalds@xxxxxxxx> writes:

> On Sun, 19 Nov 2006, Marco Costalba wrote:
>> 
>> Tested also with show-ref only, not useful to me, but just as a comparison.
>> 
>> - git tree 1420ms
>> - linux tree 1021ms
>> 
>> Better, but still slower then what I would expected.
>
> MUCH slower than expected.

This is still a WIP and for discussion only (I have to leave to
pick up my wife now so I won't be making any further progress
tonight), but I think parse_object() in show-ref is costing us.

One worry is that existing git will misinterpret packed-refs
file prepared with this version.

If you say "git show-ref -d --tags" to this version, it takes
the fast path which seems to shave about 1/3 of the runtime.

---

diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c
index 042d271..0c770f5 100644
--- a/builtin-pack-refs.c
+++ b/builtin-pack-refs.c
@@ -1,5 +1,7 @@
 #include "cache.h"
 #include "refs.h"
+#include "object.h"
+#include "tag.h"
 
 static const char builtin_pack_refs_usage[] =
 "git-pack-refs [--all] [--prune]";
@@ -29,12 +31,24 @@ static int handle_one_ref(const char *pa
 			  int flags, void *cb_data)
 {
 	struct pack_refs_cb_data *cb = cb_data;
+	int is_tag_ref;
 
-	if (!cb->all && strncmp(path, "refs/tags/", 10))
-		return 0;
 	/* Do not pack the symbolic refs */
-	if (!(flags & REF_ISSYMREF))
-		fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
+	if ((flags & REF_ISSYMREF))
+		return 0;
+	is_tag_ref = !strncmp(path, "refs/tags/", 10);
+	if (!cb->all && !is_tag_ref)
+		return 0;
+
+	fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
+	if (is_tag_ref) {
+		struct object *o = parse_object(sha1);
+		o = deref_tag(o, path, 0);
+		if (o)
+			fprintf(cb->refs_file, "%s %s^{}\n",
+				sha1_to_hex(o->sha1), path);
+	}
+
 	if (cb->prune && !do_not_prune(flags)) {
 		int namelen = strlen(path) + 1;
 		struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
diff --git a/builtin-show-ref.c b/builtin-show-ref.c
index 06ec400..32cbcb8 100644
--- a/builtin-show-ref.c
+++ b/builtin-show-ref.c
@@ -13,6 +13,7 @@ static int show_ref(const char *refname,
 {
 	struct object *obj;
 	const char *hex;
+	unsigned char peeled[20];
 
 	if (tags_only || heads_only) {
 		int match;
@@ -44,6 +45,17 @@ static int show_ref(const char *refname,
 
 match:
 	found_match++;
+
+	/* Fastpath for demonstration only */
+	if (deref_tags && (flag & REF_ISPACKED) &&
+	    !peel_ref(refname, peeled) && !quiet && !hash_only) {
+		hex = find_unique_abbrev(sha1, abbrev);
+		printf("%s %s\n", hex, refname);
+		hex = find_unique_abbrev(peeled, abbrev);
+		printf("%s %s^{}\n", hex, refname);
+		return 0;
+	}
+
 	obj = parse_object(sha1);
 	if (!obj) {
 		if (quiet)
@@ -59,8 +71,13 @@ match:
 	else
 		printf("%s %s\n", hex, refname);
 	if (deref_tags && obj->type == OBJ_TAG) {
-		obj = deref_tag(obj, refname, 0);
-		hex = find_unique_abbrev(obj->sha1, abbrev);
+		unsigned char sha1[20];
+		if ((flag & REF_ISPACKED) && !peel_ref(refname, sha1))
+			hex = find_unique_abbrev(sha1, abbrev);
+		else {
+			obj = deref_tag(obj, refname, 0);
+			hex = find_unique_abbrev(obj->sha1, abbrev);
+		}
 		printf("%s %s^{}\n", hex, refname);
 	}
 	return 0;
diff --git a/refs.c b/refs.c
index f003a0b..347c9b7 100644
--- a/refs.c
+++ b/refs.c
@@ -1,16 +1,18 @@
 #include "refs.h"
 #include "cache.h"
+#include "object.h"
+#include "tag.h"
 
 #include <errno.h>
 
 struct ref_list {
 	struct ref_list *next;
-	unsigned char flag; /* ISSYMREF? ISPACKED? */
+	unsigned char flag; /* ISSYMREF? ISPACKED? ISPEELED? */
 	unsigned char sha1[20];
 	char name[FLEX_ARRAY];
 };
 
-static const char *parse_ref_line(char *line, unsigned char *sha1)
+static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag)
 {
 	/*
 	 * 42: the answer to everything.
@@ -34,6 +36,10 @@ static const char *parse_ref_line(char *
 	if (line[len] != '\n')
 		return NULL;
 	line[len] = 0;
+	if (len < 3 || strcmp(line + len - 3, "^{}"))
+	    *flag &= ~REF_ISPEELED;
+	else
+	    *flag |= REF_ISPEELED;
 	return line;
 }
 
@@ -108,10 +114,12 @@ static struct ref_list *get_packed_refs(
 			char refline[PATH_MAX];
 			while (fgets(refline, sizeof(refline), f)) {
 				unsigned char sha1[20];
-				const char *name = parse_ref_line(refline, sha1);
+				int flag = REF_ISPACKED;
+				const char *name =
+					parse_ref_line(refline, sha1, &flag);
 				if (!name)
 					continue;
-				list = add_ref(name, sha1, REF_ISPACKED, list);
+				list = add_ref(name, sha1, flag, list);
 			}
 			fclose(f);
 			refs = list;
@@ -207,7 +215,8 @@ const char *resolve_ref(const char *ref,
 		if (lstat(path, &st) < 0) {
 			struct ref_list *list = get_packed_refs();
 			while (list) {
-				if (!strcmp(ref, list->name)) {
+				if (!(list->flag & REF_ISPEELED) &&
+				    !strcmp(ref, list->name)) {
 					hashcpy(sha1, list->sha1);
 					if (flag)
 						*flag |= REF_ISPACKED;
@@ -322,6 +331,41 @@ int read_ref(const char *ref, unsigned c
 	return -1;
 }
 
+int peel_ref(const char *ref, unsigned char *sha1)
+{
+	int flag;
+	unsigned char base[20];
+	struct object *o;
+
+	if (!resolve_ref(ref, base, 1, &flag))
+		return -1;
+
+	if ((flag & REF_ISPACKED)) {
+		struct ref_list *list = get_packed_refs();		
+		int len = strlen(ref);
+		while (list) {
+			if ((list->flag & REF_ISPEELED) &&
+			    !strncmp(list->name, ref, len) &&
+			    strlen(list->name) == len + 3 &&
+			    !strcmp(list->name + len, "^{}")) {
+				hashcpy(sha1, list->sha1);
+				return 0;
+			}
+			list = list->next;
+		}
+		/* older pack-refs did not leave peeled ones in */
+	}
+
+	/* otherwise ... */
+	o = parse_object(sha1);
+	o = deref_tag(o, ref, 0);
+	if (o) {
+		hashcpy(sha1, o->sha1);
+		return 0;
+	}
+	return -1;
+}
+
 static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
 			   void *cb_data)
 {
@@ -347,6 +391,8 @@ static int do_for_each_ref(const char *b
 			continue;
 		if (is_null_sha1(entry->sha1))
 			continue;
+		if (entry->flag & REF_ISPEELED)
+			continue;
 		if (!has_sha1_file(entry->sha1)) {
 			error("%s does not point to a valid object!", entry->name);
 			continue;
@@ -357,15 +403,22 @@ static int do_for_each_ref(const char *b
 			return retval;
 	}
 
-	packed = packed ? packed : loose;
-	while (packed) {
-		if (!strncmp(base, packed->name, trim)) {
-			retval = fn(packed->name + trim, packed->sha1,
-				    packed->flag, cb_data);
-			if (retval)
-				return retval;
+	for (packed = packed ? packed : loose; packed; packed = packed->next) {
+		if (strncmp(base, packed->name, trim))
+			continue;
+		if (is_null_sha1(packed->sha1))
+			continue;
+		if (packed->flag & REF_ISPEELED)
+			continue;
+		if (!has_sha1_file(packed->sha1)) {
+			error("%s does not point to a valid object!",
+			      packed->name);
+			continue;
 		}
-		packed = packed->next;
+		retval = fn(packed->name + trim, packed->sha1,
+			    packed->flag, cb_data);
+		if (retval)
+			return retval;
 	}
 	return 0;
 }
diff --git a/refs.h b/refs.h
index a57d437..40048a6 100644
--- a/refs.h
+++ b/refs.h
@@ -16,6 +16,8 @@ struct ref_lock {
  */
 #define REF_ISSYMREF 01
 #define REF_ISPACKED 02
+#define REF_ISPEELED 04 /* internal use */
+
 typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data);
 extern int head_ref(each_ref_fn, void *);
 extern int for_each_ref(each_ref_fn, void *);
@@ -23,6 +25,8 @@ extern int for_each_tag_ref(each_ref_fn,
 extern int for_each_branch_ref(each_ref_fn, void *);
 extern int for_each_remote_ref(each_ref_fn, void *);
 
+extern int peel_ref(const char *, unsigned char *);
+
 /** Reads the refs file specified into sha1 **/
 extern int get_ref_sha1(const char *ref, unsigned char *sha1);
 

-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]