diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2020-03-28 11:22:11 +1100 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2020-03-28 11:59:45 +1100 |
commit | 3f7ec3f3b801f33ca8b2bc436d8f047cdf57b4f0 (patch) | |
tree | 7d300178ab6d053c867deb2aaac28c0dcbd86cbf /pkg/gui | |
parent | 19604214d7da76a685085961095c1d7b2ad5f5cb (diff) |
load reflog commits in two stages to speed up startup time
Diffstat (limited to 'pkg/gui')
-rw-r--r-- | pkg/gui/branches_panel.go | 2 | ||||
-rw-r--r-- | pkg/gui/commits_panel.go | 33 | ||||
-rw-r--r-- | pkg/gui/gui.go | 7 | ||||
-rw-r--r-- | pkg/gui/reflog_panel.go | 11 |
4 files changed, 43 insertions, 10 deletions
diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index 330329fd0..45b86a546 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -64,6 +64,8 @@ func (gui *Gui) refreshBranches() { if gui.getBranchesView().Context == "local-branches" { gui.renderLocalBranchesWithSelection() } + + gui.refreshStatus() } func (gui *Gui) renderLocalBranchesWithSelection() error { diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 01e006829..9ea551451 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -71,21 +71,40 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error { return nil } +// during startup, the bottleneck is fetching the reflog entries. We need these +// on startup to sort the branches by recency. So we have two phases: INITIAL, and COMPLETE. +// In the initial phase we get a small set of reflog entries so that we can ensure +// the first couple of branches are correctly positioned. Then we asynchronously +// refresh the reflog again, without a limit, and refresh the branches again when that's done. +// When we're complete, we can begin recycling reflog entries because we know we've got +// everything down to the oldest entry. +func (gui *Gui) refreshReflogCommitsConsideringStartup() { + switch gui.State.StartupStage { + case INITIAL: + gui.refreshReflogCommits(refreshReflogOptions{Limit: 100, Recycle: false}) + + go func() { + gui.refreshReflogCommits(refreshReflogOptions{Recycle: false}) + gui.refreshBranches() + gui.State.StartupStage = COMPLETE + }() + + case COMPLETE: + gui.refreshReflogCommits(refreshReflogOptions{Recycle: true}) + } +} + // whenever we change commits, we should update branches because the upstream/downstream // counts can change. Whenever we change branches we should probably also change commits -// e.g. in the case of switching branches. We also need the status to be refreshed whenever -// the working tree status changes or the branch upstream/downstream value changes. -// Given how fast the refreshStatus method is, we should really just call it every time -// we refresh, but I'm not sure how to do that asynchronously that prevents a race condition -// other than a mutex. +// e.g. in the case of switching branches. func (gui *Gui) refreshCommits() error { wg := sync.WaitGroup{} wg.Add(2) go func() { - gui.refreshReflogCommits() + gui.refreshReflogCommitsConsideringStartup() + gui.refreshBranches() - gui.refreshStatus() wg.Done() }() diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index bb8121a2d..7f7e040f0 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -178,6 +178,12 @@ type searchingState struct { searchString string } +// startup stages so we don't need to load everything at once +const ( + INITIAL = iota + COMPLETE +) + type guiState struct { Files []*commands.File Branches []*commands.Branch @@ -208,6 +214,7 @@ type guiState struct { PrevMainWidth int PrevMainHeight int OldInformation string + StartupStage int // one of INITIAL and COMPLETE. Allows us to not load everything at once } // for now the split view will always be on diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index d40467b28..3d9ecf01c 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -46,18 +46,23 @@ func (gui *Gui) handleReflogCommitSelect(g *gocui.Gui, v *gocui.View) error { return nil } -func (gui *Gui) refreshReflogCommits() error { +type refreshReflogOptions struct { + Limit int + Recycle bool +} + +func (gui *Gui) refreshReflogCommits(options refreshReflogOptions) error { var lastReflogCommit *commands.Commit if len(gui.State.ReflogCommits) > 0 { lastReflogCommit = gui.State.ReflogCommits[0] } - commits, foundLastReflogCommit, err := gui.GitCommand.GetNewReflogCommits(lastReflogCommit) + commits, onlyObtainedNewReflogCommits, err := gui.GitCommand.GetReflogCommits(lastReflogCommit, commands.GetReflogCommitsOptions(options)) if err != nil { return gui.createErrorPanel(gui.g, err.Error()) } - if foundLastReflogCommit { + if onlyObtainedNewReflogCommits { gui.State.ReflogCommits = append(commits, gui.State.ReflogCommits...) } else { // if we haven't found it we're probably in a new repo so we don't want to |