Async search with cancel - significant speed-up

pull/195/head
Šimon Let 3 years ago
parent bb66c58d48
commit 9b48218662
  1. 98
      cmd/cli/main.go

@ -2,6 +2,7 @@ package main
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -105,6 +106,7 @@ func runReshCli(out *output.Output, config cfg.Config) (string, int) {
st := state{ st := state{
// lock sync.Mutex // lock sync.Mutex
gui: g,
cliRecords: resp.Records, cliRecords: resp.Records,
initialQuery: *query, initialQuery: *query,
} }
@ -158,8 +160,9 @@ func runReshCli(out *output.Output, config cfg.Config) (string, int) {
out.FatalE(errMsg, err) out.FatalE(errMsg, err)
} }
layout.UpdateData(*query) ctx := context.Background()
layout.UpdateRawData(*query) layout.updateData(ctx, *query)
layout.updateRawData(ctx, *query)
err = g.MainLoop() err = g.MainLoop()
if err != nil && !errors.Is(err, gocui.ErrQuit) { if err != nil && !errors.Is(err, gocui.ErrQuit) {
out.FatalE("Main application loop finished with error", err) out.FatalE("Main application loop finished with error", err)
@ -168,8 +171,13 @@ func runReshCli(out *output.Output, config cfg.Config) (string, int) {
} }
type state struct { type state struct {
lock sync.Mutex gui *gocui.Gui
cliRecords []recordint.SearchApp
cliRecords []recordint.SearchApp
lock sync.Mutex
cancelUpdate *context.CancelFunc
data []searchapp.Item data []searchapp.Item
rawData []searchapp.RawItem rawData []searchapp.RawItem
highlightedItem int highlightedItem int
@ -244,7 +252,8 @@ func (m manager) AbortPaste(g *gocui.Gui, v *gocui.View) error {
return nil return nil
} }
func (m manager) UpdateData(input string) { func (m manager) updateData(ctx context.Context, input string) {
timeStart := time.Now()
sugar := m.out.Logger.Sugar() sugar := m.out.Logger.Sugar()
sugar.Debugw("Starting data update ...", sugar.Debugw("Starting data update ...",
"recordCount", len(m.s.cliRecords), "recordCount", len(m.s.cliRecords),
@ -253,9 +262,14 @@ func (m manager) UpdateData(input string) {
query := searchapp.NewQueryFromString(sugar, input, m.host, m.pwd, m.gitOriginRemote, m.config.Debug) query := searchapp.NewQueryFromString(sugar, input, m.host, m.pwd, m.gitOriginRemote, m.config.Debug)
var data []searchapp.Item var data []searchapp.Item
itemSet := make(map[string]int) itemSet := make(map[string]int)
m.s.lock.Lock()
defer m.s.lock.Unlock()
for _, rec := range m.s.cliRecords { for _, rec := range m.s.cliRecords {
if shouldCancel(ctx) {
timeEnd := time.Now()
sugar.Infow("Update got canceled",
"duration", timeEnd.Sub(timeStart),
)
return
}
itm, err := searchapp.NewItemFromRecordForQuery(rec, query, m.config.Debug) itm, err := searchapp.NewItemFromRecordForQuery(rec, query, m.config.Debug)
if err != nil { if err != nil {
// records didn't match the query // records didn't match the query
@ -282,6 +296,9 @@ func (m manager) UpdateData(input string) {
sort.SliceStable(data, func(p, q int) bool { sort.SliceStable(data, func(p, q int) bool {
return data[p].Score > data[q].Score return data[p].Score > data[q].Score
}) })
m.s.lock.Lock()
defer m.s.lock.Unlock()
m.s.data = nil m.s.data = nil
for _, itm := range data { for _, itm := range data {
if len(m.s.data) > 420 { if len(m.s.data) > 420 {
@ -290,13 +307,17 @@ func (m manager) UpdateData(input string) {
m.s.data = append(m.s.data, itm) m.s.data = append(m.s.data, itm)
} }
m.s.highlightedItem = 0 m.s.highlightedItem = 0
timeEnd := time.Now()
sugar.Debugw("Done with data update", sugar.Debugw("Done with data update",
"duration", timeEnd.Sub(timeStart),
"recordCount", len(m.s.cliRecords), "recordCount", len(m.s.cliRecords),
"itemCount", len(m.s.data), "itemCount", len(m.s.data),
"input", input,
) )
} }
func (m manager) UpdateRawData(input string) { func (m manager) updateRawData(ctx context.Context, input string) {
timeStart := time.Now()
sugar := m.out.Logger.Sugar() sugar := m.out.Logger.Sugar()
sugar.Debugw("Starting RAW data update ...", sugar.Debugw("Starting RAW data update ...",
"recordCount", len(m.s.cliRecords), "recordCount", len(m.s.cliRecords),
@ -305,9 +326,14 @@ func (m manager) UpdateRawData(input string) {
query := searchapp.GetRawTermsFromString(input, m.config.Debug) query := searchapp.GetRawTermsFromString(input, m.config.Debug)
var data []searchapp.RawItem var data []searchapp.RawItem
itemSet := make(map[string]bool) itemSet := make(map[string]bool)
m.s.lock.Lock()
defer m.s.lock.Unlock()
for _, rec := range m.s.cliRecords { for _, rec := range m.s.cliRecords {
if shouldCancel(ctx) {
timeEnd := time.Now()
sugar.Debugw("Update got canceled",
"duration", timeEnd.Sub(timeStart),
)
return
}
itm, err := searchapp.NewRawItemFromRecordForQuery(rec, query, m.config.Debug) itm, err := searchapp.NewRawItemFromRecordForQuery(rec, query, m.config.Debug)
if err != nil { if err != nil {
// records didn't match the query // records didn't match the query
@ -328,6 +354,8 @@ func (m manager) UpdateRawData(input string) {
sort.SliceStable(data, func(p, q int) bool { sort.SliceStable(data, func(p, q int) bool {
return data[p].Score > data[q].Score return data[p].Score > data[q].Score
}) })
m.s.lock.Lock()
defer m.s.lock.Unlock()
m.s.rawData = nil m.s.rawData = nil
for _, itm := range data { for _, itm := range data {
if len(m.s.rawData) > 420 { if len(m.s.rawData) > 420 {
@ -336,18 +364,52 @@ func (m manager) UpdateRawData(input string) {
m.s.rawData = append(m.s.rawData, itm) m.s.rawData = append(m.s.rawData, itm)
} }
m.s.highlightedItem = 0 m.s.highlightedItem = 0
timeEnd := time.Now()
sugar.Debugw("Done with RAW data update", sugar.Debugw("Done with RAW data update",
"duration", timeEnd.Sub(timeStart),
"recordCount", len(m.s.cliRecords), "recordCount", len(m.s.cliRecords),
"itemCount", len(m.s.data), "itemCount", len(m.s.data),
) )
} }
func (m manager) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
gocui.DefaultEditor.Edit(v, key, ch, mod) func shouldCancel(ctx context.Context) bool {
select {
case <-ctx.Done():
return true
default:
return false
}
}
func (m manager) getCtxAndCancel() context.Context {
m.s.lock.Lock()
defer m.s.lock.Unlock()
if m.s.cancelUpdate != nil {
(*m.s.cancelUpdate)()
}
ctx, cancel := context.WithCancel(context.Background())
m.s.cancelUpdate = &cancel
return ctx
}
func (m manager) update(input string) {
ctx := m.getCtxAndCancel()
if m.s.rawMode { if m.s.rawMode {
m.UpdateRawData(v.Buffer()) m.updateRawData(ctx, input)
return } else {
m.updateData(ctx, input)
} }
m.UpdateData(v.Buffer()) m.flush()
}
func (m manager) flush() {
f := func(_ *gocui.Gui) error { return nil }
m.s.gui.Update(f)
}
func (m manager) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
gocui.DefaultEditor.Edit(v, key, ch, mod)
go m.update(v.Buffer())
} }
func (m manager) Next(g *gocui.Gui, v *gocui.View) error { func (m manager) Next(g *gocui.Gui, v *gocui.View) error {
@ -373,11 +435,7 @@ func (m manager) SwitchModes(g *gocui.Gui, v *gocui.View) error {
m.s.rawMode = !m.s.rawMode m.s.rawMode = !m.s.rawMode
m.s.lock.Unlock() m.s.lock.Unlock()
if m.s.rawMode { go m.update(v.Buffer())
m.UpdateRawData(v.Buffer())
return nil
}
m.UpdateData(v.Buffer())
return nil return nil
} }

Loading…
Cancel
Save