internal/lsp: using memoize for all file contents

Change-Id: I7293bbcfea33c0df90f7b6df8e991aae9a03f2ab
Reviewed-on: https://go-review.googlesource.com/c/tools/+/180846
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Ian Cottrell 2019-05-30 09:03:31 -04:00
parent 5b939d657d
commit ce2cddb08b
3 changed files with 58 additions and 2 deletions

View File

@ -5,6 +5,7 @@
package cache package cache
import ( import (
"context"
"crypto/sha1" "crypto/sha1"
"fmt" "fmt"
"go/token" "go/token"
@ -14,6 +15,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/xlog" "golang.org/x/tools/internal/lsp/xlog"
"golang.org/x/tools/internal/memoize"
"golang.org/x/tools/internal/span" "golang.org/x/tools/internal/span"
) )
@ -32,10 +34,42 @@ type cache struct {
fs source.FileSystem fs source.FileSystem
id string id string
fset *token.FileSet fset *token.FileSet
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 { func (c *cache) GetFile(uri span.URI) source.FileHandle {
return c.fs.GetFile(uri) 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(log xlog.Logger) source.Session { func (c *cache) NewSession(log xlog.Logger) source.Session {
@ -55,6 +89,23 @@ func (c *cache) FileSet() *token.FileSet {
return c.fset 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 { func hashContents(contents []byte) string {
// TODO: consider whether sha1 is the best choice here // TODO: consider whether sha1 is the best choice here
// This hash is used for internal identity detection only // This hash is used for internal identity detection only

View File

@ -42,6 +42,7 @@ func (h *nativeFileHandle) Identity() source.FileIdentity {
} }
func (h *nativeFileHandle) Read(ctx context.Context) ([]byte, string, error) { func (h *nativeFileHandle) Read(ctx context.Context) ([]byte, string, error) {
//TODO: this should fail if the version is not the same as the handle
data, err := ioutil.ReadFile(h.identity.URI.Filename()) data, err := ioutil.ReadFile(h.identity.URI.Filename())
if err != nil { if err != nil {
return nil, "", err return nil, "", err

View File

@ -225,7 +225,11 @@ func (v *view) SetContent(ctx context.Context, uri span.URI, content []byte) err
// including any position and type information that depends on it. // including any position and type information that depends on it.
func (f *goFile) invalidateContent() { func (f *goFile) invalidateContent() {
f.view.pcache.mu.Lock() f.view.pcache.mu.Lock()
defer f.view.pcache.mu.Unlock() f.handleMu.Lock()
defer func() {
f.handleMu.Unlock()
f.view.pcache.mu.Unlock()
}()
f.ast = nil f.ast = nil
f.token = nil f.token = nil