diff options
author | Ian Cottrell <iancottrell@google.com> | 2020-06-02 10:57:20 -0400 |
---|---|---|
committer | Ian Cottrell <iancottrell@google.com> | 2020-06-06 01:49:14 +0000 |
commit | ce53dc44456c5b8f43ba39e7e5a4b40daaea3d74 (patch) | |
tree | a572dd1ed616f25493ff846e1be4626439b722d8 /internal/lsp/debug | |
parent | 7147197327d0bbfeed0b089b7c4df2552466dae8 (diff) | |
download | golang-x-tools-ce53dc44456c5b8f43ba39e7e5a4b40daaea3d74.tar.gz |
internal/lsp: clean out the debug handling
This removes all the cache/session/view hooks from the lsp and instead
uses normal introspection from the client to find all the entities
rather than keeping shadow copies of the object graph in the debug page
handler.
This required the addition only of the ability to view the sessions open
on a cache and exposing the unique identifier for all the objects, both
of which are useful and reasonable things to have in the API anyway.
Change-Id: Ic19903e7b19832ca79290954ec373d4177789742
Reviewed-on: https://go-review.googlesource.com/c/tools/+/236197
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Diffstat (limited to 'internal/lsp/debug')
-rw-r--r-- | internal/lsp/debug/serve.go | 263 | ||||
-rw-r--r-- | internal/lsp/debug/serve_test.go | 54 |
2 files changed, 92 insertions, 225 deletions
diff --git a/internal/lsp/debug/serve.go b/internal/lsp/debug/serve.go index 5ee83f4ee..4476db822 100644 --- a/internal/lsp/debug/serve.go +++ b/internal/lsp/debug/serve.go @@ -8,7 +8,6 @@ import ( "bytes" "context" "fmt" - "go/token" "html/template" "io" "log" @@ -18,7 +17,6 @@ import ( "os" "path" "path/filepath" - "reflect" "runtime" rpprof "runtime/pprof" "strconv" @@ -34,9 +32,9 @@ import ( "golang.org/x/tools/internal/event/export/prometheus" "golang.org/x/tools/internal/event/keys" "golang.org/x/tools/internal/event/label" + "golang.org/x/tools/internal/lsp/cache" "golang.org/x/tools/internal/lsp/debug/tag" "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" "golang.org/x/xerrors" ) @@ -67,12 +65,9 @@ type Instance struct { // State holds debugging information related to the server state. type State struct { - mu sync.Mutex - caches objset - sessions objset - views objset - clients objset - servers objset + mu sync.Mutex + clients objset + servers objset } type ider interface { @@ -107,38 +102,75 @@ func (s *objset) find(id string) ider { } // Caches returns the set of Cache objects currently being served. -func (st *State) Caches() []Cache { - st.mu.Lock() - defer st.mu.Unlock() - caches := make([]Cache, len(st.caches.objs)) - for i, c := range st.caches.objs { - caches[i] = c.(Cache) +func (st *State) Caches() []*cache.Cache { + var caches []*cache.Cache + seen := make(map[string]struct{}) + for _, client := range st.Clients() { + cache, ok := client.Session().Cache().(*cache.Cache) + if !ok { + continue + } + if _, found := seen[cache.ID()]; found { + continue + } + seen[cache.ID()] = struct{}{} + caches = append(caches, cache) } return caches } +// Cache returns the Cache that matches the supplied id. +func (st *State) Cache(id string) *cache.Cache { + for _, c := range st.Caches() { + if c.ID() == id { + return c + } + } + return nil +} + // Sessions returns the set of Session objects currently being served. -func (st *State) Sessions() []Session { - st.mu.Lock() - defer st.mu.Unlock() - sessions := make([]Session, len(st.sessions.objs)) - for i, s := range st.sessions.objs { - sessions[i] = s.(Session) +func (st *State) Sessions() []*cache.Session { + var sessions []*cache.Session + for _, client := range st.Clients() { + sessions = append(sessions, client.Session()) } return sessions } +// Session returns the Session that matches the supplied id. +func (st *State) Session(id string) *cache.Session { + for _, s := range st.Sessions() { + if s.ID() == id { + return s + } + } + return nil +} + // Views returns the set of View objects currently being served. -func (st *State) Views() []View { - st.mu.Lock() - defer st.mu.Unlock() - views := make([]View, len(st.views.objs)) - for i, v := range st.views.objs { - views[i] = v.(View) +func (st *State) Views() []*cache.View { + var views []*cache.View + for _, s := range st.Sessions() { + for _, v := range s.Views() { + if cv, ok := v.(*cache.View); ok { + views = append(views, cv) + } + } } return views } +// View returns the View that matches the supplied id. +func (st *State) View(id string) *cache.View { + for _, v := range st.Views() { + if v.ID() == id { + return v + } + } + return nil +} + // Clients returns the set of Clients currently being served. func (st *State) Clients() []Client { st.mu.Lock() @@ -164,7 +196,7 @@ func (st *State) Servers() []Server { // A Client is an incoming connection from a remote client. type Client interface { ID() string - Session() Session + Session() *cache.Session DebugAddress() string Logfile() string ServerID() string @@ -178,80 +210,6 @@ type Server interface { ClientID() string } -// A Cache is an in-memory cache. -type Cache interface { - ID() string - FileSet() *token.FileSet - MemStats() map[reflect.Type]int -} - -// A Session is an LSP serving session. -type Session interface { - ID() string - Cache() Cache - Files() []*File - File(hash string) *File -} - -// A View is a root directory within a Session. -type View interface { - ID() string - Name() string - Folder() span.URI - Session() Session -} - -// A File is a file within a session. -type File struct { - Session Session - URI span.URI - Data string - Error error - Hash string -} - -// AddCache adds a cache to the set being served. -func (st *State) AddCache(cache Cache) { - st.mu.Lock() - defer st.mu.Unlock() - st.caches.add(cache) -} - -// DropCache drops a cache from the set being served. -func (st *State) DropCache(cache Cache) { - st.mu.Lock() - defer st.mu.Unlock() - st.caches.drop(cache) -} - -// AddSession adds a session to the set being served. -func (st *State) AddSession(session Session) { - st.mu.Lock() - defer st.mu.Unlock() - st.sessions.add(session) -} - -// DropSession drops a session from the set being served. -func (st *State) DropSession(session Session) { - st.mu.Lock() - defer st.mu.Unlock() - st.sessions.drop(session) -} - -// AddView adds a view to the set being served. -func (st *State) AddView(view View) { - st.mu.Lock() - defer st.mu.Unlock() - st.views.add(view) -} - -// DropView drops a view from the set being served. -func (st *State) DropView(view View) { - st.mu.Lock() - defer st.mu.Unlock() - st.views.drop(view) -} - // AddClient adds a client to the set being served. func (st *State) AddClient(client Client) { st.mu.Lock() @@ -282,52 +240,11 @@ func (st *State) DropServer(server Server) { } func (i *Instance) getCache(r *http.Request) interface{} { - i.State.mu.Lock() - defer i.State.mu.Unlock() - id := path.Base(r.URL.Path) - c, ok := i.State.caches.find(id).(Cache) - if !ok { - return nil - } - result := struct { - Cache - Sessions []Session - }{ - Cache: c, - } - - // now find all the views that belong to this session - for _, vd := range i.State.sessions.objs { - v := vd.(Session) - if v.Cache().ID() == id { - result.Sessions = append(result.Sessions, v) - } - } - return result + return i.State.Cache(path.Base(r.URL.Path)) } func (i *Instance) getSession(r *http.Request) interface{} { - i.State.mu.Lock() - defer i.State.mu.Unlock() - id := path.Base(r.URL.Path) - s, ok := i.State.sessions.find(id).(Session) - if !ok { - return nil - } - result := struct { - Session - Views []View - }{ - Session: s, - } - // now find all the views that belong to this session - for _, vd := range i.State.views.objs { - v := vd.(View) - if v.Session().ID() == id { - result.Views = append(result.Views, v) - } - } - return result + return i.State.Session(path.Base(r.URL.Path)) } func (i Instance) getClient(r *http.Request) interface{} { @@ -353,26 +270,22 @@ func (i Instance) getServer(r *http.Request) interface{} { } func (i Instance) getView(r *http.Request) interface{} { - i.State.mu.Lock() - defer i.State.mu.Unlock() - id := path.Base(r.URL.Path) - v, ok := i.State.views.find(id).(View) - if !ok { - return nil - } - return v + return i.State.View(path.Base(r.URL.Path)) } func (i *Instance) getFile(r *http.Request) interface{} { - i.State.mu.Lock() - defer i.State.mu.Unlock() - hash := path.Base(r.URL.Path) + identifier := path.Base(r.URL.Path) sid := path.Base(path.Dir(r.URL.Path)) - s, ok := i.State.sessions.find(sid).(Session) - if !ok { + s := i.State.Session(sid) + if s == nil { return nil } - return s.File(hash) + for _, o := range s.Overlays() { + if o.Identity().Identifier == identifier { + return o + } + } + return nil } func (i *Instance) getInfo(r *http.Request) interface{} { @@ -625,6 +538,10 @@ func fuint32(v uint32) string { return commas(strconv.FormatUint(uint64(v), 10)) } +func fcontent(v []byte) string { + return string(v) +} + var baseTemplate = template.Must(template.New("").Parse(` <html> <head> @@ -664,10 +581,11 @@ Unknown page {{define "serverlink"}}<a href="/server/{{.}}">Server {{.}}</a>{{end}} {{define "sessionlink"}}<a href="/session/{{.}}">Session {{.}}</a>{{end}} {{define "viewlink"}}<a href="/view/{{.}}">View {{.}}</a>{{end}} -{{define "filelink"}}<a href="/file/{{.Session.ID}}/{{.Hash}}">{{.URI}}</a>{{end}} +{{define "filelink"}}<a href="/file/{{.SessionID}}/{{.Identifier}}">{{.URI}}</a>{{end}} `)).Funcs(template.FuncMap{ - "fuint64": fuint64, - "fuint32": fuint32, + "fuint64": fuint64, + "fuint32": fuint32, + "fcontent": fcontent, "localAddress": func(s string) string { // Try to translate loopback addresses to localhost, both for cosmetics and // because unspecified ipv6 addresses can break links on Windows. @@ -785,8 +703,8 @@ var sessionTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(` From: <b>{{template "cachelink" .Cache.ID}}</b><br> <h2>Views</h2> <ul>{{range .Views}}<li>{{.Name}} is {{template "viewlink" .ID}} in {{.Folder}}</li>{{end}}</ul> -<h2>Files</h2> -<ul>{{range .Files}}<li>{{template "filelink" .}}</li>{{end}}</ul> +<h2>Overlays</h2> +<ul>{{range .Overlays}}<li>{{template "filelink" .Identity}}</li>{{end}}</ul> {{end}} `)) @@ -797,18 +715,21 @@ Name: <b>{{.Name}}</b><br> Folder: <b>{{.Folder}}</b><br> From: <b>{{template "sessionlink" .Session.ID}}</b><br> <h2>Environment</h2> -<ul>{{range .Env}}<li>{{.}}</li>{{end}}</ul> +<ul>{{range .Options.Env}}<li>{{.}}</li>{{end}}</ul> {{end}} `)) var fileTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(` -{{define "title"}}File {{.Hash}}{{end}} +{{define "title"}}Overlay {{.Identity.Identifier}}{{end}} {{define "body"}} -From: <b>{{template "sessionlink" .Session.ID}}</b><br> -URI: <b>{{.URI}}</b><br> -Hash: <b>{{.Hash}}</b><br> -Error: <b>{{.Error}}</b><br> +{{with .Identity}} + From: <b>{{template "sessionlink" .SessionID}}</b><br> + URI: <b>{{.URI}}</b><br> + Identifier: <b>{{.Identifier}}</b><br> + Version: <b>{{.Version}}</b><br> + Kind: <b>{{.Kind}}</b><br> +{{end}} <h3>Contents</h3> -<pre>{{.Data}}</pre> +<pre>{{fcontent .Data}}</pre> {{end}} `)) diff --git a/internal/lsp/debug/serve_test.go b/internal/lsp/debug/serve_test.go deleted file mode 100644 index ff981e90e..000000000 --- a/internal/lsp/debug/serve_test.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package debug - -import "testing" - -type fakeCache struct { - Cache - - id string -} - -func (c fakeCache) ID() string { - return c.id -} - -func TestState(t *testing.T) { - c1 := fakeCache{id: "1"} - c2 := fakeCache{id: "2"} - c3 := fakeCache{id: "3"} - - var s State - s.AddCache(c1) - s.AddCache(c2) - s.AddCache(c3) - - compareCaches := func(desc string, want []fakeCache) { - t.Run(desc, func(t *testing.T) { - caches := s.Caches() - if gotLen, wantLen := len(caches), len(want); gotLen != wantLen { - t.Fatalf("len(Caches) = %d, want %d", gotLen, wantLen) - } - for i, got := range caches { - if got != want[i] { - t.Errorf("Caches[%d] = %v, want %v", i, got, want[i]) - } - } - }) - } - - compareCaches("initial load", []fakeCache{c1, c2, c3}) - s.DropCache(c2) - compareCaches("dropped cache 2", []fakeCache{c1, c3}) - s.DropCache(c2) - compareCaches("duplicate drop", []fakeCache{c1, c3}) - s.AddCache(c2) - compareCaches("re-add cache 2", []fakeCache{c1, c3, c2}) - s.DropCache(c1) - s.DropCache(c2) - s.DropCache(c3) - compareCaches("drop all", []fakeCache{}) -} |