From 522efff188b709ea43611ecf693898e765e767a7 Mon Sep 17 00:00:00 2001 From: Siege Lion <1448189829@qq.com> Date: Wed, 9 Nov 2022 16:08:57 +0800 Subject: [PATCH] Fix: fix the stuck problem and use LRU cache to promote the speed of loading topology (#5002) * Fix: fix the stuck problem and use lru cache to promote the speed of loading topology Signed-off-by: HanMengnan <1448189829@qq.com> * Fix: reuse existing lru golang library Signed-off-by: HanMengnan <1448189829@qq.com> Signed-off-by: HanMengnan <1448189829@qq.com> --- go.mod | 1 + go.sum | 1 + references/cli/top/view/app.go | 4 +- .../cli/top/view/application_topology_view.go | 117 +++++++++++------- .../view/application_topology_view_test.go | 8 +- references/cli/top/view/page_stack.go | 4 +- 6 files changed, 81 insertions(+), 54 deletions(-) diff --git a/go.mod b/go.mod index bcafe56b4..7a8fd7e8b 100644 --- a/go.mod +++ b/go.mod @@ -50,6 +50,7 @@ require ( github.com/gosuri/uilive v0.0.4 github.com/gosuri/uitable v0.0.4 github.com/hashicorp/go-version v1.3.0 + github.com/hashicorp/golang-lru v0.5.4 github.com/hashicorp/hcl/v2 v2.9.1 github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 github.com/imdario/mergo v0.3.12 diff --git a/go.sum b/go.sum index dabdd5c9f..a79af4e72 100644 --- a/go.sum +++ b/go.sum @@ -1180,6 +1180,7 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= diff --git a/references/cli/top/view/app.go b/references/cli/top/view/app.go index 66871f6b8..f5fc92946 100644 --- a/references/cli/top/view/app.go +++ b/references/cli/top/view/app.go @@ -130,9 +130,7 @@ func (a *App) Refresh() { log.Printf("SystemInfo updater canceled!") return case <-time.After(delay): - a.QueueUpdateDraw(func() { - board.UpdateInfo(a.config.RestConfig) - }) + board.UpdateInfo(a.config.RestConfig) } } }() diff --git a/references/cli/top/view/application_topology_view.go b/references/cli/top/view/application_topology_view.go index 63ebc0a29..9d6250b8e 100644 --- a/references/cli/top/view/application_topology_view.go +++ b/references/cli/top/view/application_topology_view.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/gdamore/tcell/v2" + lru "github.com/hashicorp/golang-lru" "github.com/rivo/tview" "github.com/oam-dev/kubevela/pkg/velaql/providers/query/types" @@ -32,20 +33,31 @@ import ( // TopologyView display the resource topology of application type TopologyView struct { *tview.Grid - app *App - actions model.KeyActions - ctx context.Context - focusTopology bool + app *App + actions model.KeyActions + ctx context.Context + focusTopology bool + cache *lru.Cache + appTopologyInstance *TopologyTree + resourceTopologyInstance *TopologyTree } -type topologyTree struct { +type cacheView struct { + appTopologyInstance *TopologyTree + resourceTopologyInstance *TopologyTree +} + +// TopologyTree is the abstract of topology tree +type TopologyTree struct { *tview.TreeView } +const ( + numberOfCacheView = 10 +) + var ( - topologyViewInstance = new(TopologyView) - appTopologyInstance = new(topologyTree) - resourceTopologyInstance = new(topologyTree) + topologyViewInstance = new(TopologyView) ) // NewTopologyView return a new topology view @@ -56,6 +68,10 @@ func NewTopologyView(ctx context.Context, app *App) model.View { if topologyViewInstance.Grid == nil { topologyViewInstance.Grid = tview.NewGrid() topologyViewInstance.actions = make(model.KeyActions) + topologyViewInstance.cache, _ = lru.New(numberOfCacheView) + topologyViewInstance.appTopologyInstance = new(TopologyTree) + topologyViewInstance.resourceTopologyInstance = new(TopologyTree) + topologyViewInstance.Init() } return topologyViewInstance @@ -74,13 +90,28 @@ func (v *TopologyView) Init() { // Start the topology view func (v *TopologyView) Start() { - appTopology := v.NewAppTopologyView() - resourceTopology := v.NewResourceTopologyView() + appName := v.ctx.Value(&model.CtxKeyAppName).(string) + namespace := v.ctx.Value(&model.CtxKeyNamespace).(string) + key := fmt.Sprintf("%s-%s", appName, namespace) - v.Grid.AddItem(appTopology, 0, 0, 1, 1, 0, 0, true) - v.Grid.AddItem(resourceTopology, 0, 1, 1, 1, 0, 0, true) + value, exist := v.cache.Get(key) + view, ok := value.(*cacheView) + if exist && ok { + v.appTopologyInstance = view.appTopologyInstance + v.resourceTopologyInstance = view.resourceTopologyInstance + } else { + v.resourceTopologyInstance = v.NewResourceTopologyView() + v.appTopologyInstance = v.NewAppTopologyView() + v.cache.Add(key, &cacheView{ + resourceTopologyInstance: v.resourceTopologyInstance, + appTopologyInstance: v.appTopologyInstance, + }) + } - v.app.SetFocus(appTopology) + v.Grid.AddItem(v.appTopologyInstance, 0, 0, 1, 1, 0, 0, true) + v.Grid.AddItem(v.resourceTopologyInstance, 0, 1, 1, 1, 0, 0, true) + + v.app.SetFocus(v.appTopologyInstance) } // Stop the topology view @@ -119,54 +150,49 @@ func (v *TopologyView) bindKeys() { } // NewResourceTopologyView return a new resource topology view -func (v *TopologyView) NewResourceTopologyView() tview.Primitive { - if resourceTopologyInstance.TreeView == nil { - resourceTopologyInstance.TreeView = tview.NewTreeView() - resourceTopologyInstance.SetGraphics(true) - resourceTopologyInstance.SetGraphicsColor(tcell.ColorCadetBlue) - resourceTopologyInstance.SetBorder(true) - resourceTopologyInstance.SetTitle(fmt.Sprintf("[ %s ]", "Resource")) - } - +func (v *TopologyView) NewResourceTopologyView() *TopologyTree { + newTopology := new(TopologyTree) appName := v.ctx.Value(&model.CtxKeyAppName).(string) namespace := v.ctx.Value(&model.CtxKeyNamespace).(string) + newTopology.TreeView = tview.NewTreeView() + newTopology.SetGraphics(true) + newTopology.SetGraphicsColor(tcell.ColorCadetBlue) + newTopology.SetBorder(true) + newTopology.SetTitle(fmt.Sprintf("[ %s ]", "Resource")) + root := tview.NewTreeNode(component.EmojiFormat(fmt.Sprintf("%s (%s)", appName, namespace), "app")).SetSelectable(true) - resourceTopologyInstance.SetRoot(root) + newTopology.SetRoot(root) resourceTree, err := model.ApplicationResourceTopology(v.app.client, appName, namespace) - if err != nil { - return resourceTopologyInstance + if err == nil { + for _, resource := range resourceTree { + root.AddChild(buildTopology(resource.ResourceTree)) + } } - for _, resource := range resourceTree { - root.AddChild(buildTopology(resource.ResourceTree)) - } - - return resourceTopologyInstance + return newTopology } // NewAppTopologyView return a new app topology view -func (v *TopologyView) NewAppTopologyView() tview.Primitive { - if appTopologyInstance.TreeView == nil { - appTopologyInstance.TreeView = tview.NewTreeView() - appTopologyInstance.SetGraphics(true) - appTopologyInstance.SetGraphicsColor(tcell.ColorCadetBlue) - appTopologyInstance.SetBorder(true) - appTopologyInstance.SetTitle(fmt.Sprintf("[ %s ]", "App")) - } - +func (v *TopologyView) NewAppTopologyView() *TopologyTree { + newTopology := new(TopologyTree) appName := v.ctx.Value(&model.CtxKeyAppName).(string) namespace := v.ctx.Value(&model.CtxKeyNamespace).(string) + newTopology.TreeView = tview.NewTreeView() + newTopology.SetGraphics(true) + newTopology.SetGraphicsColor(tcell.ColorCadetBlue) + newTopology.SetBorder(true) + newTopology.SetTitle(fmt.Sprintf("[ %s ]", "App")) + root := tview.NewTreeNode(component.EmojiFormat(fmt.Sprintf("%s (%s)", appName, namespace), "app")).SetSelectable(true) - appTopologyInstance.SetRoot(root) + newTopology.SetRoot(root) app, err := model.LoadApplication(v.app.client, appName, namespace) if err != nil { - return appTopologyInstance + return newTopology } - // workflow workflowNode := tview.NewTreeNode(component.EmojiFormat("WorkFlow", "workflow")).SetSelectable(true) root.AddChild(workflowNode) @@ -206,15 +232,14 @@ func (v *TopologyView) NewAppTopologyView() tview.Primitive { for _, policy := range app.Spec.Policies { policyNode.AddChild(tview.NewTreeNode(policy.Name)) } - - return appTopologyInstance + return newTopology } func (v *TopologyView) switchTopology(_ *tcell.EventKey) *tcell.EventKey { if v.focusTopology { - v.app.SetFocus(appTopologyInstance) + v.app.SetFocus(v.appTopologyInstance) } else { - v.app.SetFocus(resourceTopologyInstance) + v.app.SetFocus(v.resourceTopologyInstance) } v.focusTopology = !v.focusTopology return nil diff --git a/references/cli/top/view/application_topology_view_test.go b/references/cli/top/view/application_topology_view_test.go index a0220892f..4f8639479 100644 --- a/references/cli/top/view/application_topology_view_test.go +++ b/references/cli/top/view/application_topology_view_test.go @@ -61,10 +61,12 @@ func TestTopologyView(t *testing.T) { }) t.Run("start", func(t *testing.T) { - appTopologyView := topologyView.NewAppTopologyView() - assert.Equal(t, appTopologyView.HasFocus(), false) topologyView.Start() - assert.Equal(t, appTopologyView.HasFocus(), true) + assert.Equal(t, topologyView.appTopologyInstance.HasFocus(), true) + assert.Equal(t, topologyView.resourceTopologyInstance.HasFocus(), false) + topologyView.switchTopology(nil) + assert.Equal(t, topologyView.appTopologyInstance.HasFocus(), false) + assert.Equal(t, topologyView.resourceTopologyInstance.HasFocus(), true) }) t.Run("stop", func(t *testing.T) { diff --git a/references/cli/top/view/page_stack.go b/references/cli/top/view/page_stack.go index ad468620f..b9740a28d 100644 --- a/references/cli/top/view/page_stack.go +++ b/references/cli/top/view/page_stack.go @@ -48,7 +48,7 @@ func (ps *PageStack) StackPop(old, new model.View) { } ps.app.QueueUpdateDraw(new.Start) ps.app.SetFocus(new) - ps.app.QueueUpdate(old.Stop) + go old.Stop() } // StackPush change itself when accept "pop" notify from app's main view @@ -56,6 +56,6 @@ func (ps *PageStack) StackPush(old, new model.View) { ps.app.QueueUpdateDraw(new.Start) ps.app.SetFocus(new) if old != nil { - ps.app.QueueUpdate(old.Stop) + go old.Stop() } }