aboutsummaryrefslogtreecommitdiff
path: root/internal/lsp/debug
diff options
context:
space:
mode:
authorIan Cottrell <iancottrell@google.com>2020-06-02 10:57:20 -0400
committerIan Cottrell <iancottrell@google.com>2020-06-06 01:49:14 +0000
commitce53dc44456c5b8f43ba39e7e5a4b40daaea3d74 (patch)
treea572dd1ed616f25493ff846e1be4626439b722d8 /internal/lsp/debug
parent7147197327d0bbfeed0b089b7c4df2552466dae8 (diff)
downloadgolang-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.go263
-rw-r--r--internal/lsp/debug/serve_test.go54
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{})
-}