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

From:
Stefan Sperling <stsp@stsp.name>
Subject:
Re: show base commit markers in tog log view
To:
Mark Jamsek <mark@jamsek.com>, gameoftrees@openbsd.org
Date:
Mon, 24 Jul 2023 00:37:44 +0200

Download raw body.

Thread
  • Stefan Sperling:

    show base commit markers in tog log view

  • Stefan Sperling:

    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);
    
    
  • Stefan Sperling:

    show base commit markers in tog log view

  • Stefan Sperling:

    show base commit markers in tog log view