1
0
mirror of https://github.com/golang/go synced 2024-11-19 11:44:45 -07:00
go/internal/lsp/cache/cache.go
Ian Cottrell 54cf04ef09 internal/lsp: decouple client and server debug
This uses log messages to convey information to the debug system, which
has the benefit of logging even if the debug pages are not active and
also not requiring systems to reach into the debug system or require
extra lifetime tracking Not all things are decoupled yet as there are a
couple of places (notably the handshaker) that read information out of
the debug system.

Change-Id: Iec1f81c34ab3b11b3e3d6e6eb39b98ee5ed0d849
Reviewed-on: https://go-review.googlesource.com/c/tools/+/236337
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-06-11 13:49:48 +00:00

119 lines
2.6 KiB
Go

// Copyright 2019 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 cache
import (
"context"
"crypto/sha1"
"fmt"
"go/token"
"reflect"
"strconv"
"sync/atomic"
"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/memoize"
"golang.org/x/tools/internal/span"
)
func New(ctx context.Context, options func(*source.Options)) *Cache {
index := atomic.AddInt64(&cacheIndex, 1)
c := &Cache{
fs: &nativeFileSystem{},
id: strconv.FormatInt(index, 10),
fset: token.NewFileSet(),
options: options,
}
return c
}
type Cache struct {
fs source.FileSystem
id string
fset *token.FileSet
options func(*source.Options)
store memoize.Store
}
type fileKey struct {
identity source.FileIdentity
}
type fileHandle struct {
cache *Cache
underlying source.FileHandle
handle *memoize.Handle
}
type fileData struct {
memoize.NoCopy
bytes []byte
hash string
err error
}
func (c *Cache) GetFile(uri span.URI) source.FileHandle {
underlying := c.fs.GetFile(uri)
key := fileKey{
identity: underlying.Identity(),
}
h := c.store.Bind(key, func(ctx context.Context) interface{} {
data := &fileData{}
data.bytes, data.hash, data.err = underlying.Read(ctx)
return data
})
return &fileHandle{
cache: c,
underlying: underlying,
handle: h,
}
}
func (c *Cache) NewSession(ctx context.Context) *Session {
index := atomic.AddInt64(&sessionIndex, 1)
s := &Session{
cache: c,
id: strconv.FormatInt(index, 10),
options: source.DefaultOptions(),
overlays: make(map[span.URI]*overlay),
}
event.Log(ctx, "New session", KeyCreateSession.Of(s))
return s
}
func (c *Cache) FileSet() *token.FileSet {
return c.fset
}
func (h *fileHandle) FileSystem() source.FileSystem {
return h.cache
}
func (h *fileHandle) Identity() source.FileIdentity {
return h.underlying.Identity()
}
func (h *fileHandle) Read(ctx context.Context) ([]byte, string, error) {
v := h.handle.Get(ctx)
if v == nil {
return nil, "", ctx.Err()
}
data := v.(*fileData)
return data.bytes, data.hash, data.err
}
func hashContents(contents []byte) string {
// TODO: consider whether sha1 is the best choice here
// This hash is used for internal identity detection only
return fmt.Sprintf("%x", sha1.Sum(contents))
}
var cacheIndex, sessionIndex, viewIndex int64
func (c *Cache) ID() string { return c.id }
func (c *Cache) MemStats() map[reflect.Type]int { return c.store.Stats() }