"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
Re: tag -l is too slow
To:
Christian Weisgerber <naddy@mips.inka.de>
Cc:
gameoftrees@openbsd.org
Date:
Fri, 15 Mar 2024 22:11:34 +0100

Download raw body.

Thread
On Fri, Mar 15, 2024 at 05:27:43PM +0100, Christian Weisgerber wrote:
> There must be an algorithmic inefficiency in "got tag -l".  In a
> large repository with a lot of tags, like FreeBSD src.git with 3446,
> the command is painfully slow:
> 
> $ got clone ssh://anongit@git.FreeBSD.org/src.git freebsd-src.git
> $ cd freebsd-src.git
> $ time got tag -l >/dev/null
>     4m25.10s real     2m43.31s user     2m29.50s system

Could you try again with this diff please?

diff /home/stsp/src/got
commit - 5737d679619ac7bfa357277e0508f62d544d8385
path + /home/stsp/src/got
blob - 15e5b266956d19bd23a769396c8fff3d1be22e22
file + lib/reference.c
--- lib/reference.c
+++ lib/reference.c
@@ -89,7 +89,10 @@ struct got_reference {
 	struct got_lockfile *lf;
 	time_t mtime;
 
-	/* Cached timestamp for got_ref_cmp_by_commit_timestamp_descending() */
+	/*
+	 * Cached timestamp for got_ref_cmp_by_commit_timestamp_descending()
+	 * and got_ref_cmp_tags().
+	 */
 	time_t committer_time;
 };
 
@@ -650,70 +653,6 @@ got_ref_cmp_by_name(void *arg, int *cmp, struct got_re
 	return NULL;
 }
 
-const struct got_error *
-got_ref_cmp_tags(void *arg, int *cmp, struct got_reference *ref1,
-    struct got_reference *ref2)
-{
-	const struct got_error *err = NULL;
-	struct got_repository *repo = arg;
-	struct got_object_id *id1, *id2 = NULL;
-	struct got_tag_object *tag1 = NULL, *tag2 = NULL;
-	struct got_commit_object *commit1 = NULL, *commit2 = NULL;
-	time_t time1, time2;
-
-	*cmp = 0;
-
-	err = got_ref_resolve(&id1, repo, ref1);
-	if (err)
-		return err;
-	err = got_object_open_as_tag(&tag1, repo, id1);
-	if (err) {
-		if (err->code != GOT_ERR_OBJ_TYPE)
-			goto done;
-		/* "lightweight" tag */
-		err = got_object_open_as_commit(&commit1, repo, id1);
-		if (err)
-			goto done;
-		time1 = got_object_commit_get_committer_time(commit1);
-	} else
-		time1 = got_object_tag_get_tagger_time(tag1);
-
-	err = got_ref_resolve(&id2, repo, ref2);
-	if (err)
-		goto done;
-	err = got_object_open_as_tag(&tag2, repo, id2);
-	if (err) {
-		if (err->code != GOT_ERR_OBJ_TYPE)
-			goto done;
-		/* "lightweight" tag */
-		err = got_object_open_as_commit(&commit2, repo, id2);
-		if (err)
-			goto done;
-		time2 = got_object_commit_get_committer_time(commit2);
-	} else
-		time2 = got_object_tag_get_tagger_time(tag2);
-
-	/* Put latest tags first. */
-	if (time1 < time2)
-		*cmp = 1;
-	else if (time1 > time2)
-		*cmp = -1;
-	else
-		err = got_ref_cmp_by_name(NULL, cmp, ref2, ref1);
-done:
-	free(id1);
-	free(id2);
-	if (tag1)
-		got_object_tag_close(tag1);
-	if (tag2)
-		got_object_tag_close(tag2);
-	if (commit1)
-		got_object_commit_close(commit1);
-	if (commit2)
-		got_object_commit_close(commit2);
-	return err;
-}
-
 static const struct got_error *
 get_committer_time(struct got_reference *ref, struct got_repository *repo)
 {
@@ -760,6 +699,37 @@ done:
 }
 
 const struct got_error *
+got_ref_cmp_tags(void *arg, int *cmp, struct got_reference *ref1,
+    struct got_reference *ref2)
+{
+	const struct got_error *err = NULL;
+	struct got_repository *repo = arg;
+
+	*cmp = 0;
+
+	if (ref1->committer_time == 0) {
+		err = get_committer_time(ref1, repo);
+		if (err)
+			return err;
+	}
+	if (ref2->committer_time == 0) {
+		err = get_committer_time(ref2, repo);
+		if (err)
+			return err;
+	}
+
+	/* Put latest tags first. */
+	if (ref1->committer_time < ref2->committer_time)
+		*cmp = 1;
+	else if (ref1->committer_time > ref2->committer_time)
+		*cmp = -1;
+	else
+		err = got_ref_cmp_by_name(NULL, cmp, ref2, ref1);
+
+	return err;
+}
+
+const struct got_error *
 got_ref_cmp_by_commit_timestamp_descending(void *arg, int *cmp,
     struct got_reference *ref1, struct got_reference *ref2)
 {