internal/lsp: use a background context for the background worker

A detatched context ends up attributing all background work to the initialize
function.

Change-Id: I81206462752228d5ac81408fb1e3fb86ab36796e
Reviewed-on: https://go-review.googlesource.com/c/tools/+/186457
Run-TryBot: Ian Cottrell <iancottrell@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Ian Cottrell 2019-07-16 22:20:43 -04:00
parent 128ec6dfca
commit f2838559cb
3 changed files with 20 additions and 13 deletions

View File

@ -305,7 +305,7 @@ type combined struct {
// caused the termination. // caused the termination.
// It must be called exactly once for each Conn. // It must be called exactly once for each Conn.
// It returns only when the reader is closed or there is an error in the stream. // It returns only when the reader is closed or there is an error in the stream.
func (c *Conn) Run(ctx context.Context) error { func (c *Conn) Run(runCtx context.Context) error {
// we need to make the next request "lock" in an unlocked state to allow // we need to make the next request "lock" in an unlocked state to allow
// the first incoming request to proceed. All later requests are unlocked // the first incoming request to proceed. All later requests are unlocked
// by the preceding request going to parallel mode. // by the preceding request going to parallel mode.
@ -313,7 +313,7 @@ func (c *Conn) Run(ctx context.Context) error {
close(nextRequest) close(nextRequest)
for { for {
// get the data for a message // get the data for a message
data, n, err := c.stream.Read(ctx) data, n, err := c.stream.Read(runCtx)
if err != nil { if err != nil {
// the stream failed, we cannot continue // the stream failed, we cannot continue
return err return err
@ -324,7 +324,7 @@ func (c *Conn) Run(ctx context.Context) error {
// a badly formed message arrived, log it and continue // a badly formed message arrived, log it and continue
// we trust the stream to have isolated the error to just this message // we trust the stream to have isolated the error to just this message
for _, h := range c.handlers { for _, h := range c.handlers {
h.Error(ctx, fmt.Errorf("unmarshal failed: %v", err)) h.Error(runCtx, fmt.Errorf("unmarshal failed: %v", err))
} }
continue continue
} }
@ -332,7 +332,7 @@ func (c *Conn) Run(ctx context.Context) error {
switch { switch {
case msg.Method != "": case msg.Method != "":
// if method is set it must be a request // if method is set it must be a request
ctx, cancelReq := context.WithCancel(ctx) reqCtx, cancelReq := context.WithCancel(runCtx)
thisRequest := nextRequest thisRequest := nextRequest
nextRequest = make(chan struct{}) nextRequest = make(chan struct{})
req := &Request{ req := &Request{
@ -347,8 +347,8 @@ func (c *Conn) Run(ctx context.Context) error {
}, },
} }
for _, h := range c.handlers { for _, h := range c.handlers {
ctx = h.Request(ctx, Receive, &req.WireRequest) reqCtx = h.Request(reqCtx, Receive, &req.WireRequest)
ctx = h.Read(ctx, n) reqCtx = h.Read(reqCtx, n)
} }
c.setHandling(req, true) c.setHandling(req, true)
go func() { go func() {
@ -357,17 +357,17 @@ func (c *Conn) Run(ctx context.Context) error {
defer func() { defer func() {
c.setHandling(req, false) c.setHandling(req, false)
if !req.IsNotify() && req.state < requestReplied { if !req.IsNotify() && req.state < requestReplied {
req.Reply(ctx, nil, NewErrorf(CodeInternalError, "method %q did not reply", req.Method)) req.Reply(reqCtx, nil, NewErrorf(CodeInternalError, "method %q did not reply", req.Method))
} }
req.Parallel() req.Parallel()
for _, h := range c.handlers { for _, h := range c.handlers {
h.Done(ctx, err) h.Done(reqCtx, err)
} }
cancelReq() cancelReq()
}() }()
delivered := false delivered := false
for _, h := range c.handlers { for _, h := range c.handlers {
if h.Deliver(ctx, req, delivered) { if h.Deliver(reqCtx, req, delivered) {
delivered = true delivered = true
} }
} }
@ -390,7 +390,7 @@ func (c *Conn) Run(ctx context.Context) error {
close(rchan) close(rchan)
default: default:
for _, h := range c.handlers { for _, h := range c.handlers {
h.Error(ctx, fmt.Errorf("message not a call, notify or response, ignoring")) h.Error(runCtx, fmt.Errorf("message not a call, notify or response, ignoring"))
} }
} }
} }

View File

@ -16,6 +16,7 @@ import (
"golang.org/x/tools/internal/lsp/debug" "golang.org/x/tools/internal/lsp/debug"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/lsp/telemetry/trace"
"golang.org/x/tools/internal/lsp/xlog" "golang.org/x/tools/internal/lsp/xlog"
"golang.org/x/tools/internal/span" "golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/xcontext" "golang.org/x/tools/internal/xcontext"
@ -67,12 +68,14 @@ func (s *session) NewView(ctx context.Context, name string, folder span.URI) sou
index := atomic.AddInt64(&viewIndex, 1) index := atomic.AddInt64(&viewIndex, 1)
s.viewMu.Lock() s.viewMu.Lock()
defer s.viewMu.Unlock() defer s.viewMu.Unlock()
ctx = xcontext.Detach(ctx) // We want a true background context and not a detatched context here
backgroundCtx, cancel := context.WithCancel(ctx) // the spans need to be unrelated and no tag values should pollute it.
baseCtx := trace.Detach(xcontext.Detach(ctx))
backgroundCtx, cancel := context.WithCancel(baseCtx)
v := &view{ v := &view{
session: s, session: s,
id: strconv.FormatInt(index, 10), id: strconv.FormatInt(index, 10),
baseCtx: ctx, baseCtx: baseCtx,
backgroundCtx: backgroundCtx, backgroundCtx: backgroundCtx,
cancel: cancel, cancel: cancel,
name: name, name: name,

View File

@ -14,3 +14,7 @@ import (
func StartSpan(ctx context.Context, name string, tags ...tag.Tag) (context.Context, func()) { func StartSpan(ctx context.Context, name string, tags ...tag.Tag) (context.Context, func()) {
return tag.With(ctx, tags...), func() {} return tag.With(ctx, tags...), func() {}
} }
// Detach returns a context without an associated span.
// This allows the creation of spans that are not children of the current span.
func Detach(ctx context.Context) context.Context { return ctx }