Download raw body.
show base commit markers in tog log view
On Fri, Jul 21, 2023 at 03:14:06PM +0200, Stefan Sperling wrote:
> A problem that applies to both this patch and got branch -l:
> A mixed-commit work tree will be displayed as up-to-date since the current
> logic only considers the work tree's global base commit.
> Could we iterate over the file index and check whether any file is based
> on a different commit, and if so show the out-of-date symbol ~?
The above suggestion I made results in a performance regression,
as Omar pointed out on IRC:
20:47 <@op2> one consequence of the new work tree base commit marker
in tog is that it is slower to open in src.git :/
20:48 <@op2> xterm stays blank for ~2 seconds before it start listing
commits, while in 0.90 it was istantaneous
The patch below attempts to fix this regression by letting the
log thread walk the file index once it has fetched the initial
batch of commits required to fill the display. In my testing this
lets tog start up as fast at it did before and already accept input
before the marker appears in a large work tree.
The delay is still noticable in some cases, e.g. when pressing page-down
right after starting tog, the display will only scroll further once the
commit marker has been drawn. But this is a small one-time lag and I could
live with it.
Regarding 'got branch -l' I am podering moving mixed-commit detection
to 'got status' since this command is already walking the file index.
Or will we accept branch -l being slower now?
-----------------------------------------------
load tog's worktree base commit marker in the log thread for startup speed
diff ccdddf69864eb9ac5c10c0f5d58b68df1cf26ea1 762988f1190e744a7116962daa9baf8d00f8c1ec
commit - ccdddf69864eb9ac5c10c0f5d58b68df1cf26ea1
commit + 762988f1190e744a7116962daa9baf8d00f8c1ec
blob - 07cb22fd98f7b10c110a8a5d0c0627770c5b7e76
blob + 02e203f9626eba60a84658a1f9e7a8d0fb043418
--- include/got_worktree.h
+++ include/got_worktree.h
@@ -137,13 +137,14 @@ const struct got_error *got_worktree_set_base_commit_i
* Get the state of the work tree. If the work tree's global base commit is
* the tip of the work tree's current branch, and each file in the index is
* based on this same commit, the char out parameter will be
- * GOT_WORKTREE_UPTODATE, else it will be GOT_WORKTREE_OUTOFDATE.
+ * GOT_WORKTREE_STATE_UPTODATE, else it will be GOT_WORKTREE_STATE_OUTOFDATE.
*/
const struct got_error *got_worktree_get_state(char *,
struct got_repository *, struct got_worktree *);
-#define GOT_WORKTREE_UPTODATE '*'
-#define GOT_WORKTREE_OUTOFDATE '~'
+#define GOT_WORKTREE_STATE_UNKNOWN ' '
+#define GOT_WORKTREE_STATE_UPTODATE '*'
+#define GOT_WORKTREE_STATE_OUTOFDATE '~'
/*
* Obtain a parsed representation of this worktree's got.conf file.
blob - 6b14bc178bf5fbc6065088656b0ecae4a8fd2aad
blob + e0c7318204bffd754947e3848dcb9e7b6ad3ae9e
--- lib/worktree.c
+++ lib/worktree.c
@@ -3273,7 +3273,7 @@ got_worktree_get_state(char *state, struct got_reposit
if (err)
goto done;
- *state = GOT_WORKTREE_OUTOFDATE;
+ *state = GOT_WORKTREE_STATE_UNKNOWN;
base_id = got_worktree_get_base_commit_id(worktree);
if (got_object_id_cmp(base_id, head_id) == 0) {
@@ -3284,10 +3284,13 @@ got_worktree_get_state(char *state, struct got_reposit
err = got_fileindex_for_each_entry_safe(fileindex,
check_mixed_commits, worktree);
if (err == NULL)
- *state = GOT_WORKTREE_UPTODATE;
- else if (err->code == GOT_ERR_MIXED_COMMITS)
+ *state = GOT_WORKTREE_STATE_UPTODATE;
+ else if (err->code == GOT_ERR_MIXED_COMMITS) {
+ *state = GOT_WORKTREE_STATE_OUTOFDATE;
err = NULL;
- }
+ }
+ } else
+ *state = GOT_WORKTREE_STATE_OUTOFDATE;
done:
free(head_id);
blob - 897b0c14098c0b8440dbdfbedd2bb8c0792e6efb
blob + 118398e8a4c1738580fccf502b243173d3cd685a
--- tog/tog.c
+++ tog/tog.c
@@ -380,6 +380,8 @@ struct tog_log_thread_args {
int limit_match;
regex_t *limit_regex;
struct commit_queue *limit_commits;
+ struct got_worktree *worktree;
+ int need_commit_marker;
};
struct tog_log_view_state {
@@ -730,7 +732,7 @@ static const struct got_error *open_log_view(struct to
static const struct got_error *open_log_view(struct tog_view *,
struct got_object_id *, struct got_repository *,
- const char *, const char *, int);
+ const char *, const char *, int, struct got_worktree *);
static const struct got_error * show_log_view(struct tog_view *);
static const struct got_error *input_log_view(struct tog_view **,
struct tog_view *, int);
@@ -2423,6 +2425,10 @@ draw_commit(struct tog_view *view, struct commit_queue
struct tog_color *tc;
struct got_reflist_head *refs;
+ if (tog_base_commit.id != NULL && tog_base_commit.idx == -1 &&
+ got_object_id_cmp(id, tog_base_commit.id) == 0)
+ tog_base_commit.idx = entry->idx;
+
committer_time = got_object_commit_get_committer_time(commit);
if (gmtime_r(&committer_time, &tm) == NULL)
return got_error_from_errno("gmtime_r");
@@ -2482,7 +2488,7 @@ draw_commit(struct tog_view *view, struct commit_queue
waddwstr(view->window, wauthor);
col += author_width;
while (col < avail && author_width < author_display_cols + 2) {
- if (tog_base_commit.id != NULL &&
+ if (tog_base_commit.marker != GOT_WORKTREE_STATE_UNKNOWN &&
author_width == marker_column &&
entry->idx == tog_base_commit.idx) {
tc = get_color(&s->colors, TOG_COLOR_COMMIT);
@@ -2709,10 +2715,6 @@ queue_commits(struct tog_log_thread_args *a)
TAILQ_INSERT_TAIL(&a->real_commits->head, entry, entry);
a->real_commits->ncommits++;
- if (tog_base_commit.id != NULL && tog_base_commit.idx == -1 &&
- got_object_id_cmp(&id, tog_base_commit.id) == 0)
- tog_base_commit.idx = entry->idx;
-
if (*a->limiting) {
err = match_commit(&limit_match, &id, commit,
a->limit_regex);
@@ -3360,6 +3362,34 @@ log_thread(void *arg)
goto done;
}
+ if (a->commits_needed == 0 &&
+ a->need_commit_marker && a->worktree) {
+ errcode = pthread_mutex_unlock(&tog_mutex);
+ if (errcode) {
+ err = got_error_set_errno(errcode,
+ "pthread_mutex_unlock");
+ goto done;
+ }
+ err = got_worktree_get_state(
+ &tog_base_commit.marker,
+ a->repo, a->worktree);
+ if (err)
+ goto done;
+ errcode = pthread_mutex_lock(&tog_mutex);
+ if (errcode) {
+ err = got_error_set_errno(errcode,
+ "pthread_mutex_lock");
+ goto done;
+ }
+ a->need_commit_marker = 0;
+ /*
+ * The main thread did not close this
+ * work tree yet. Close it now.
+ */
+ got_worktree_close(a->worktree);
+ a->worktree = NULL;
+ }
+
if (done)
a->commits_needed = 0;
else {
@@ -3385,6 +3415,10 @@ done:
if (err) {
tog_thread_error = 1;
pthread_cond_signal(&a->commit_loaded);
+ if (a->worktree) {
+ got_worktree_close(a->worktree);
+ a->worktree = NULL;
+ }
}
return (void *)err;
}
@@ -3705,7 +3739,8 @@ open_log_view(struct tog_view *view, struct got_object
static const struct got_error *
open_log_view(struct tog_view *view, struct got_object_id *start_id,
struct got_repository *repo, const char *head_ref_name,
- const char *in_repo_path, int log_branches)
+ const char *in_repo_path, int log_branches,
+ struct got_worktree *worktree)
{
const struct got_error *err = NULL;
struct tog_log_view_state *s = &view->state.log;
@@ -3820,6 +3855,9 @@ done:
s->thread_args.limiting = &s->limit_view;
s->thread_args.limit_regex = &s->limit_regex;
s->thread_args.limit_commits = &s->limit_commits;
+ s->thread_args.worktree = worktree;
+ if (worktree)
+ s->thread_args.need_commit_marker = 1;
done:
if (err) {
if (view->close == NULL)
@@ -4394,9 +4432,8 @@ set_tog_base_commit(struct got_repository *repo, struc
return got_error_from_errno( "got_object_id_dup");
tog_base_commit.idx = -1;
-
- return got_worktree_get_state(&tog_base_commit.marker, repo,
- worktree);
+ tog_base_commit.marker = GOT_WORKTREE_STATE_UNKNOWN;
+ return NULL;
}
static const struct got_error *
@@ -4551,18 +4588,20 @@ cmd_log(int argc, char *argv[])
error = got_error_from_errno("view_open");
goto done;
}
+
+ if (worktree) {
+ error = set_tog_base_commit(repo, worktree);
+ if (error != NULL)
+ goto done;
+ }
+
error = open_log_view(view, start_id, repo, head_ref_name,
- in_repo_path, log_branches);
+ in_repo_path, log_branches, worktree);
if (error)
goto done;
if (worktree) {
- error = set_tog_base_commit(repo, worktree);
- if (error != NULL)
- goto done;
-
- /* Release work tree lock. */
- got_worktree_close(worktree);
+ /* The work tree will be closed by the log thread. */
worktree = NULL;
}
@@ -6814,7 +6853,7 @@ log_annotated_line(struct tog_view **new_view, int beg
if (log_view == NULL)
return got_error_from_errno("view_open");
- err = open_log_view(log_view, id, repo, GOT_REF_HEAD, "", 0);
+ err = open_log_view(log_view, id, repo, GOT_REF_HEAD, "", 0, NULL);
if (err)
view_close(log_view);
else
@@ -7616,7 +7655,7 @@ log_selected_tree_entry(struct tog_view **new_view, in
return err;
err = open_log_view(log_view, s->commit_id, s->repo, s->head_ref_name,
- path, 0);
+ path, 0, NULL);
if (err)
view_close(log_view);
else
@@ -8474,7 +8513,7 @@ log_ref_entry(struct tog_view **new_view, int begin_y,
}
err = open_log_view(log_view, commit_id, repo,
- got_ref_get_name(re->ref), "", 0);
+ got_ref_get_name(re->ref), "", 0, NULL);
done:
if (err)
view_close(log_view);
show base commit markers in tog log view