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>
This commit is contained in:
Siege Lion
2022-11-09 16:08:57 +08:00
committed by GitHub
parent afd363b896
commit 522efff188
6 changed files with 81 additions and 54 deletions
+1
View File
@@ -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
+1
View File
@@ -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=
+1 -3
View File
@@ -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)
}
}
}()
@@ -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
@@ -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) {
+2 -2
View File
@@ -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()
}
}