mirror of
https://github.com/golang/go
synced 2024-11-18 22:24:50 -07:00
ca0407e66b
Eliminate the file watcher, since it led to a lot of confusion and difficulty reasoning about the flow of a file action. This change splits a file invalidation into the two logical steps - 1) things that affect the overlay, and 2) things that affect the view. It is based on top of CL 211757, so the diffs will look better once that CL is merged. Change-Id: I277475569b61f3c80feaa6b6fe457b4bace82e35 Reviewed-on: https://go-review.googlesource.com/c/tools/+/211777 Run-TryBot: Rebecca Stambler <rstambler@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
121 lines
2.6 KiB
Go
121 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"
|
|
"strconv"
|
|
"sync/atomic"
|
|
|
|
"golang.org/x/tools/internal/lsp/debug"
|
|
"golang.org/x/tools/internal/lsp/source"
|
|
"golang.org/x/tools/internal/memoize"
|
|
"golang.org/x/tools/internal/span"
|
|
)
|
|
|
|
func New(options func(*source.Options)) source.Cache {
|
|
index := atomic.AddInt64(&cacheIndex, 1)
|
|
c := &cache{
|
|
fs: &nativeFileSystem{},
|
|
id: strconv.FormatInt(index, 10),
|
|
fset: token.NewFileSet(),
|
|
options: options,
|
|
}
|
|
debug.AddCache(debugCache{c})
|
|
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, kind source.FileKind) source.FileHandle {
|
|
underlying := c.fs.GetFile(uri, kind)
|
|
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) source.Session {
|
|
index := atomic.AddInt64(&sessionIndex, 1)
|
|
s := &session{
|
|
cache: c,
|
|
id: strconv.FormatInt(index, 10),
|
|
options: source.DefaultOptions,
|
|
overlays: make(map[span.URI]*overlay),
|
|
}
|
|
debug.AddSession(debugSession{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
|
|
|
|
type debugCache struct{ *cache }
|
|
|
|
func (c *cache) ID() string { return c.id }
|
|
func (c debugCache) FileSet() *token.FileSet { return c.fset }
|