Skip to content

Commit

Permalink
internal/lsp/cache: use persistent map for storing files in the snapshot
Browse files Browse the repository at this point in the history
This on average reduces latency from 34ms to 25ms on internal codebase.

Updates golang/go#45686

Change-Id: I57b05e5679620d8481b1f1a051645cf1cc00aca5
Reviewed-on: https://go-review.googlesource.com/c/tools/+/413654
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Robert Findley <[email protected]>
gopls-CI: kokoro <[email protected]>
Reviewed-by: Alan Donovan <[email protected]>
Run-TryBot: Alan Donovan <[email protected]>
  • Loading branch information
Ruslan Nigmatullin authored and findleyr committed Jun 23, 2022
1 parent f60e9bc commit 3f5f798
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 57 deletions.
81 changes: 63 additions & 18 deletions internal/lsp/cache/maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,63 @@
package cache

import (
"golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/persistent"
"golang.org/x/tools/internal/span"
)

// TODO(euroelessar): Use generics once support for go1.17 is dropped.

type filesMap struct {
impl *persistent.Map
}

func newFilesMap() filesMap {
return filesMap{
impl: persistent.NewMap(func(a, b interface{}) bool {
return a.(span.URI) < b.(span.URI)
}),
}
}

func (m filesMap) Clone() filesMap {
return filesMap{
impl: m.impl.Clone(),
}
}

func (m filesMap) Destroy() {
m.impl.Destroy()
}

func (m filesMap) Load(key span.URI) (source.VersionedFileHandle, bool) {
value, ok := m.impl.Load(key)
if !ok {
return nil, false
}
return value.(source.VersionedFileHandle), true
}

func (m filesMap) Range(do func(key span.URI, value source.VersionedFileHandle)) {
m.impl.Range(func(key, value interface{}) {
do(key.(span.URI), value.(source.VersionedFileHandle))
})
}

func (m filesMap) Store(key span.URI, value source.VersionedFileHandle) {
m.impl.Store(key, value, nil)
}

func (m filesMap) Delete(key span.URI) {
m.impl.Delete(key)
}

type goFilesMap struct {
impl *persistent.Map
}

func newGoFilesMap() *goFilesMap {
return &goFilesMap{
func newGoFilesMap() goFilesMap {
return goFilesMap{
impl: persistent.NewMap(func(a, b interface{}) bool {
return parseKeyLess(a.(parseKey), b.(parseKey))
}),
Expand All @@ -33,80 +78,80 @@ func parseKeyLess(a, b parseKey) bool {
return a.file.URI < b.file.URI
}

func (m *goFilesMap) Clone() *goFilesMap {
return &goFilesMap{
func (m goFilesMap) Clone() goFilesMap {
return goFilesMap{
impl: m.impl.Clone(),
}
}

func (m *goFilesMap) Destroy() {
func (m goFilesMap) Destroy() {
m.impl.Destroy()
}

func (m *goFilesMap) Load(key parseKey) (*parseGoHandle, bool) {
func (m goFilesMap) Load(key parseKey) (*parseGoHandle, bool) {
value, ok := m.impl.Load(key)
if !ok {
return nil, false
}
return value.(*parseGoHandle), true
}

func (m *goFilesMap) Range(do func(key parseKey, value *parseGoHandle)) {
func (m goFilesMap) Range(do func(key parseKey, value *parseGoHandle)) {
m.impl.Range(func(key, value interface{}) {
do(key.(parseKey), value.(*parseGoHandle))
})
}

func (m *goFilesMap) Store(key parseKey, value *parseGoHandle, release func()) {
func (m goFilesMap) Store(key parseKey, value *parseGoHandle, release func()) {
m.impl.Store(key, value, func(key, value interface{}) {
release()
})
}

func (m *goFilesMap) Delete(key parseKey) {
func (m goFilesMap) Delete(key parseKey) {
m.impl.Delete(key)
}

type parseKeysByURIMap struct {
impl *persistent.Map
}

func newParseKeysByURIMap() *parseKeysByURIMap {
return &parseKeysByURIMap{
func newParseKeysByURIMap() parseKeysByURIMap {
return parseKeysByURIMap{
impl: persistent.NewMap(func(a, b interface{}) bool {
return a.(span.URI) < b.(span.URI)
}),
}
}

func (m *parseKeysByURIMap) Clone() *parseKeysByURIMap {
return &parseKeysByURIMap{
func (m parseKeysByURIMap) Clone() parseKeysByURIMap {
return parseKeysByURIMap{
impl: m.impl.Clone(),
}
}

func (m *parseKeysByURIMap) Destroy() {
func (m parseKeysByURIMap) Destroy() {
m.impl.Destroy()
}

func (m *parseKeysByURIMap) Load(key span.URI) ([]parseKey, bool) {
func (m parseKeysByURIMap) Load(key span.URI) ([]parseKey, bool) {
value, ok := m.impl.Load(key)
if !ok {
return nil, false
}
return value.([]parseKey), true
}

func (m *parseKeysByURIMap) Range(do func(key span.URI, value []parseKey)) {
func (m parseKeysByURIMap) Range(do func(key span.URI, value []parseKey)) {
m.impl.Range(func(key, value interface{}) {
do(key.(span.URI), value.([]parseKey))
})
}

func (m *parseKeysByURIMap) Store(key span.URI, value []parseKey) {
func (m parseKeysByURIMap) Store(key span.URI, value []parseKey) {
m.impl.Store(key, value, nil)
}

func (m *parseKeysByURIMap) Delete(key span.URI) {
func (m parseKeysByURIMap) Delete(key span.URI) {
m.impl.Delete(key)
}
2 changes: 1 addition & 1 deletion internal/lsp/cache/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ func (s *Session) createView(ctx context.Context, name string, folder span.URI,
generation: s.cache.store.Generation(generationName(v, 0)),
packages: make(map[packageKey]*packageHandle),
meta: &metadataGraph{},
files: make(map[span.URI]source.VersionedFileHandle),
files: newFilesMap(),
goFiles: newGoFilesMap(),
parseKeysByURI: newParseKeysByURIMap(),
symbols: make(map[span.URI]*symbolHandle),
Expand Down
Loading

0 comments on commit 3f5f798

Please sign in to comment.