mirror of
https://github.com/gohugoio/hugo.git
synced 2025-03-19 15:42:55 +00:00
output: Speed up layout calculations
``` BenchmarkLayout-4 4883 497 -89.82% benchmark old allocs new allocs delta BenchmarkLayout-4 18 1 -94.44% benchmark old bytes new bytes delta BenchmarkLayout-4 1624 32 -98.03% ```
This commit is contained in:
parent
df95383914
commit
6178238a0b
4 changed files with 42 additions and 4 deletions
|
@ -190,6 +190,8 @@ type Page struct {
|
||||||
permalink string
|
permalink string
|
||||||
relPermalink string
|
relPermalink string
|
||||||
|
|
||||||
|
layoutDescriptor output.LayoutDescriptor
|
||||||
|
|
||||||
scratch *Scratch
|
scratch *Scratch
|
||||||
|
|
||||||
// It would be tempting to use the language set on the Site, but in they way we do
|
// It would be tempting to use the language set on the Site, but in they way we do
|
||||||
|
@ -666,7 +668,7 @@ func (p *Page) layouts(layouts ...string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.s.layoutHandler.For(
|
return p.s.layoutHandler.For(
|
||||||
p.createLayoutDescriptor(),
|
p.layoutDescriptor,
|
||||||
layoutOverride,
|
layoutOverride,
|
||||||
output.HTMLType)
|
output.HTMLType)
|
||||||
}
|
}
|
||||||
|
@ -880,6 +882,7 @@ func (p *Page) initURLs() error {
|
||||||
p.permalink = p.s.permalink(rel)
|
p.permalink = p.s.permalink(rel)
|
||||||
rel = p.s.PathSpec.PrependBasePath(rel)
|
rel = p.s.PathSpec.PrependBasePath(rel)
|
||||||
p.relPermalink = rel
|
p.relPermalink = rel
|
||||||
|
p.layoutDescriptor = p.createLayoutDescriptor()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1558,7 +1561,7 @@ func (p *Page) Hugo() *HugoInfo {
|
||||||
func (p *Page) RSSlink() template.URL {
|
func (p *Page) RSSlink() template.URL {
|
||||||
// TODO(bep) we cannot have two of these
|
// TODO(bep) we cannot have two of these
|
||||||
// Remove in Hugo 0.20
|
// Remove in Hugo 0.20
|
||||||
helpers.Deprecated(".Page", "Use RSSlink", "RSSLink", true)
|
helpers.Deprecated(".Page", "RSSlink", "Use RSSLink", true)
|
||||||
return p.RSSLink
|
return p.RSSLink
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1656,7 +1656,7 @@ func (s *Site) kindFromSections(sections []string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Site) layouts(p *PageOutput) []string {
|
func (s *Site) layouts(p *PageOutput) []string {
|
||||||
return s.layoutHandler.For(p.createLayoutDescriptor(), "", p.outputFormat)
|
return s.layoutHandler.For(p.layoutDescriptor, "", p.outputFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Site) preparePages() error {
|
func (s *Site) preparePages() error {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LayoutDescriptor describes how a layout should be chosen. This is
|
// LayoutDescriptor describes how a layout should be chosen. This is
|
||||||
|
@ -32,10 +33,19 @@ type LayoutDescriptor struct {
|
||||||
// TODO(bep) output improve names
|
// TODO(bep) output improve names
|
||||||
type LayoutHandler struct {
|
type LayoutHandler struct {
|
||||||
hasTheme bool
|
hasTheme bool
|
||||||
|
|
||||||
|
mu sync.RWMutex
|
||||||
|
cache map[layoutCacheKey][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type layoutCacheKey struct {
|
||||||
|
d LayoutDescriptor
|
||||||
|
layoutOverride string
|
||||||
|
f Format
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLayoutHandler(hasTheme bool) *LayoutHandler {
|
func NewLayoutHandler(hasTheme bool) *LayoutHandler {
|
||||||
return &LayoutHandler{hasTheme: hasTheme}
|
return &LayoutHandler{hasTheme: hasTheme, cache: make(map[layoutCacheKey][]string)}
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -62,6 +72,16 @@ indexes/indexes.NAME.SUFFIX indexes/indexes.SUFFIX
|
||||||
)
|
)
|
||||||
|
|
||||||
func (l *LayoutHandler) For(d LayoutDescriptor, layoutOverride string, f Format) []string {
|
func (l *LayoutHandler) For(d LayoutDescriptor, layoutOverride string, f Format) []string {
|
||||||
|
|
||||||
|
// We will get lots of requests for the same layouts, so avoid recalculations.
|
||||||
|
key := layoutCacheKey{d, layoutOverride, f}
|
||||||
|
l.mu.RLock()
|
||||||
|
if cacheVal, found := l.cache[key]; found {
|
||||||
|
l.mu.RUnlock()
|
||||||
|
return cacheVal
|
||||||
|
}
|
||||||
|
l.mu.RUnlock()
|
||||||
|
|
||||||
var layouts []string
|
var layouts []string
|
||||||
|
|
||||||
layout := d.Layout
|
layout := d.Layout
|
||||||
|
@ -110,6 +130,10 @@ func (l *LayoutHandler) For(d LayoutDescriptor, layoutOverride string, f Format)
|
||||||
return layoutsWithThemeLayouts
|
return layoutsWithThemeLayouts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l.mu.Lock()
|
||||||
|
l.cache[key] = layouts
|
||||||
|
l.mu.Unlock()
|
||||||
|
|
||||||
return layouts
|
return layouts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,4 +73,15 @@ func TestLayout(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLayout(b *testing.B) {
|
||||||
|
descriptor := LayoutDescriptor{Kind: "taxonomyTerm", Section: "categories"}
|
||||||
|
l := NewLayoutHandler(false)
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
layouts := l.For(descriptor, "", HTMLType)
|
||||||
|
require.NotEmpty(b, layouts)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue