Skip to content

Commit

Permalink
perf(cmd/web/restdoc): 按目录缓存加载的结构数据
Browse files Browse the repository at this point in the history
  • Loading branch information
caixw committed Feb 26, 2024
1 parent 53534b3 commit 1f8e1bc
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 19 deletions.
36 changes: 36 additions & 0 deletions cmd/web/restdoc/pkg/bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT

package pkg

import (
"context"
"testing"

"github.com/issue9/assert/v3"

"github.com/issue9/web/cmd/web/restdoc/logger/loggertest"
)

func BenchmarkPackages_TypeOf_Int(b *testing.B) {
a := assert.New(b, false)
l := loggertest.New(a)
p := New(l.Logger)

p.ScanDir(context.Background(), "./testdir", true)
ctx := context.Background()
for range b.N {
p.TypeOf(ctx, "github.com/issue9/web/restdoc/pkg.Int")
}
}

func BenchmarkPackages_TypeOf_S(b *testing.B) {
a := assert.New(b, false)
l := loggertest.New(a)
p := New(l.Logger)

p.ScanDir(context.Background(), "./testdir", true)
ctx := context.Background()
for range b.N {
p.TypeOf(ctx, "github.com/issue9/web/restdoc/pkg.S")
}
}
7 changes: 4 additions & 3 deletions cmd/web/restdoc/pkg/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,20 @@ func (pkgs *Packages) lookup(ctx context.Context, typePath string) (types.Object
// 出于性能考虑并未加载依赖项,但是可能会依赖部分标准库的类型,
// 此处对标准库作了特殊处理:未找到标准库中的对象时会加载相应的包。
if pkgPath != "" && strings.IndexByte(pkgPath, '.') < 0 {
ps, err := pkgs.load(ctx, path.Join(build.Default.GOROOT, "src", pkgPath))
dir := path.Join(build.Default.GOROOT, "src", pkgPath)
p, err := pkgs.load(ctx, dir)
if err != nil {
pkgs.l.Error(err, "", 0)
return nil, nil, nil, false
}

return findInPkgs(ps, pkgPath, typeName)
return findInPkgs(map[string]*packages.Package{dir: p}, pkgPath, typeName)
}

return nil, nil, nil, false
}

func findInPkgs(ps []*packages.Package, pkgPath, typeName string) (types.Object, *ast.TypeSpec, *ast.File, bool) {
func findInPkgs(ps map[string]*packages.Package, pkgPath, typeName string) (types.Object, *ast.TypeSpec, *ast.File, bool) {
for _, p := range ps {
if p.PkgPath != pkgPath {
continue
Expand Down
37 changes: 22 additions & 15 deletions cmd/web/restdoc/pkg/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ package pkg

import (
"context"
"fmt"
"go/token"
"path/filepath"
"slices"
"sync"

"github.com/issue9/sliceutil"
"github.com/issue9/web"
"golang.org/x/tools/go/packages"

Expand All @@ -25,14 +24,14 @@ const Cancelled = web.StringPhrase("cancelled")
// Packages 管理加载的包
type Packages struct {
pkgsM sync.Mutex
pkgs []*packages.Package
pkgs map[string]*packages.Package // 键名为对应的目录名
fset *token.FileSet
l *logger.Logger
}

func New(l *logger.Logger) *Packages {
return &Packages{
pkgs: make([]*packages.Package, 0, 10),
pkgs: make(map[string]*packages.Package, 30),
fset: token.NewFileSet(),
l: l,
}
Expand Down Expand Up @@ -73,7 +72,15 @@ func (pkgs *Packages) ScanDir(ctx context.Context, root string, recursive bool)
wg.Wait()
}

func (pkgs *Packages) load(ctx context.Context, dir string) ([]*packages.Package, error) {
func (pkgs *Packages) load(ctx context.Context, dir string) (*packages.Package, error) {
dir = filepath.Clean(dir)

pkgs.pkgsM.Lock()
defer pkgs.pkgsM.Unlock()
if p, found := pkgs.pkgs[dir]; found {
return p, nil
}

ps, err := packages.Load(&packages.Config{
Mode: mode,
Context: ctx,
Expand All @@ -84,23 +91,23 @@ func (pkgs *Packages) load(ctx context.Context, dir string) ([]*packages.Package
return nil, err
}

pkgs.pkgsM.Lock()
defer pkgs.pkgsM.Unlock()
for _, p := range ps {
if slices.IndexFunc(pkgs.pkgs, func(e *packages.Package) bool { return p.PkgPath == e.PkgPath }) < 0 {
pkgs.pkgs = append(pkgs.pkgs, p)
}
if len(ps) > 1 {
panic(fmt.Sprintf("目录 %s 中包的数量大于 1:%d", dir, len(ps)))
}

return ps, nil
pkgs.pkgs[dir] = ps[0]
return ps[0], nil
}

func (pkgs *Packages) FileSet() *token.FileSet { return pkgs.fset }

// Package 返回指定路径的包对象
func (pkgs *Packages) Package(path string) *packages.Package {
pkg, _ := sliceutil.At(pkgs.pkgs, func(p *packages.Package, _ int) bool { return p.PkgPath == path })
return pkg
for _, p := range pkgs.pkgs {
if p.PkgPath == path {
return p
}
}
return nil
}

// Range 依次访问已经加载的包
Expand Down
3 changes: 2 additions & 1 deletion cmd/web/restdoc/pkg/pkg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package pkg

import (
"context"
"path/filepath"
"testing"

"github.com/issue9/assert/v3"
Expand All @@ -23,5 +24,5 @@ func TestPackages_ScanDir(t *testing.T) {
p = New(l.Logger)
p.ScanDir(context.Background(), "./testdir", false)
a.Length(p.pkgs, 1).
Equal(p.pkgs[0].PkgPath, "github.com/issue9/web/restdoc/pkg")
Equal(p.pkgs[filepath.Clean("./testdir")].PkgPath, "github.com/issue9/web/restdoc/pkg")
}

0 comments on commit 1f8e1bc

Please sign in to comment.