mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-24 15:28:54 +00:00
all: Replace RWMutex struct caches with ConcurrentMap
This commit is contained in:
Vendored
+4
-13
@@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
|
|
||||||
"github.com/BurntSushi/locker"
|
"github.com/BurntSushi/locker"
|
||||||
|
"github.com/bep/helpers/maphelpers"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -56,8 +57,7 @@ type Cache struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type lockTracker struct {
|
type lockTracker struct {
|
||||||
seenMu sync.RWMutex
|
seen *maphelpers.ConcurrentSet[string]
|
||||||
seen map[string]struct{}
|
|
||||||
|
|
||||||
*locker.Locker
|
*locker.Locker
|
||||||
}
|
}
|
||||||
@@ -65,16 +65,7 @@ type lockTracker struct {
|
|||||||
// Lock tracks the ids in use. We use this information to do garbage collection
|
// Lock tracks the ids in use. We use this information to do garbage collection
|
||||||
// after a Hugo build.
|
// after a Hugo build.
|
||||||
func (l *lockTracker) Lock(id string) {
|
func (l *lockTracker) Lock(id string) {
|
||||||
l.seenMu.RLock()
|
l.seen.AddIfAbsent(id)
|
||||||
if _, seen := l.seen[id]; !seen {
|
|
||||||
l.seenMu.RUnlock()
|
|
||||||
l.seenMu.Lock()
|
|
||||||
l.seen[id] = struct{}{}
|
|
||||||
l.seenMu.Unlock()
|
|
||||||
} else {
|
|
||||||
l.seenMu.RUnlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
l.Locker.Lock(id)
|
l.Locker.Lock(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +83,7 @@ func NewCache(fs afero.Fs, cfg FileCacheConfig) *Cache {
|
|||||||
|
|
||||||
return &Cache{
|
return &Cache{
|
||||||
Fs: fs,
|
Fs: fs,
|
||||||
entryLocker: &lockTracker{Locker: locker.NewLocker(), seen: make(map[string]struct{})},
|
entryLocker: &lockTracker{Locker: locker.NewLocker(), seen: maphelpers.NewConcurrentSet[string]()},
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+2
-3
@@ -93,10 +93,9 @@ func (c *Cache) Prune(force bool) (int, error) {
|
|||||||
|
|
||||||
shouldRemove := force || c.isExpired(info.ModTime())
|
shouldRemove := force || c.isExpired(info.ModTime())
|
||||||
|
|
||||||
if !shouldRemove && len(c.entryLocker.seen) > 0 {
|
if !shouldRemove && c.entryLocker.seen.Len() > 0 {
|
||||||
// Remove it if it's not been touched/used in the last build.
|
// Remove it if it's not been touched/used in the last build.
|
||||||
_, seen := c.entryLocker.seen[name]
|
shouldRemove = !c.entryLocker.seen.Has(name)
|
||||||
shouldRemove = !seen
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldRemove {
|
if shouldRemove {
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
|
"github.com/bep/helpers/maphelpers"
|
||||||
"github.com/gohugoio/hugo/compare"
|
"github.com/gohugoio/hugo/compare"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -55,46 +55,17 @@ func EqualAny(a string, b ...string) bool {
|
|||||||
return slices.Contains(b, a)
|
return slices.Contains(b, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// regexpCache represents a cache of regexp objects protected by a mutex.
|
var reCache = *maphelpers.NewConcurrentMap[string, *regexp.Regexp]()
|
||||||
type regexpCache struct {
|
|
||||||
mu sync.RWMutex
|
|
||||||
re map[string]*regexp.Regexp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *regexpCache) getOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
|
|
||||||
var ok bool
|
|
||||||
|
|
||||||
if re, ok = rc.get(pattern); !ok {
|
|
||||||
re, err = regexp.Compile(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rc.set(pattern, re)
|
|
||||||
}
|
|
||||||
|
|
||||||
return re, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *regexpCache) get(key string) (re *regexp.Regexp, ok bool) {
|
|
||||||
rc.mu.RLock()
|
|
||||||
re, ok = rc.re[key]
|
|
||||||
rc.mu.RUnlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *regexpCache) set(key string, re *regexp.Regexp) {
|
|
||||||
rc.mu.Lock()
|
|
||||||
rc.re[key] = re
|
|
||||||
rc.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
var reCache = regexpCache{re: make(map[string]*regexp.Regexp)}
|
|
||||||
|
|
||||||
// GetOrCompileRegexp retrieves a regexp object from the cache based upon the pattern.
|
// GetOrCompileRegexp retrieves a regexp object from the cache based upon the pattern.
|
||||||
// If the pattern is not found in the cache, the pattern is compiled and added to
|
// If the pattern is not found in the cache, the pattern is compiled and added to
|
||||||
// the cache.
|
// the cache.
|
||||||
func GetOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
|
func GetOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
|
||||||
return reCache.getOrCompileRegexp(pattern)
|
return reCache.GetOrCreate(pattern,
|
||||||
|
func() (*regexp.Regexp, error) {
|
||||||
|
return regexp.Compile(pattern)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasAnyPrefix checks if the string s has any of the prefixes given.
|
// HasAnyPrefix checks if the string s has any of the prefixes given.
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ require (
|
|||||||
github.com/bep/golibsass v1.2.0
|
github.com/bep/golibsass v1.2.0
|
||||||
github.com/bep/golocales v0.1.0
|
github.com/bep/golocales v0.1.0
|
||||||
github.com/bep/goportabletext v0.2.0
|
github.com/bep/goportabletext v0.2.0
|
||||||
github.com/bep/helpers v0.8.0
|
github.com/bep/helpers v0.12.0
|
||||||
github.com/bep/imagemeta v0.17.2
|
github.com/bep/imagemeta v0.17.2
|
||||||
github.com/bep/lazycache v0.8.1
|
github.com/bep/lazycache v0.8.1
|
||||||
github.com/bep/logg v0.4.0
|
github.com/bep/logg v0.4.0
|
||||||
|
|||||||
@@ -162,8 +162,8 @@ github.com/bep/golocales v0.1.0 h1:rjWf1S4basIje+G+je5WMW8G+yzaoz4gEDFolrFVdvA=
|
|||||||
github.com/bep/golocales v0.1.0/go.mod h1:Hl78nje8mNL3LzLeJvYN9NsIZgyFJGrGfvgO9r1+mwE=
|
github.com/bep/golocales v0.1.0/go.mod h1:Hl78nje8mNL3LzLeJvYN9NsIZgyFJGrGfvgO9r1+mwE=
|
||||||
github.com/bep/goportabletext v0.2.0 h1:CZ9f8jADBWqHwBymQiJJPCTSV/tHSA+PYzlUf86Yze0=
|
github.com/bep/goportabletext v0.2.0 h1:CZ9f8jADBWqHwBymQiJJPCTSV/tHSA+PYzlUf86Yze0=
|
||||||
github.com/bep/goportabletext v0.2.0/go.mod h1:xDeA5+qcgKzJq6Q6XjAiBKtxLD3Yn7f6XP4joD3J3qU=
|
github.com/bep/goportabletext v0.2.0/go.mod h1:xDeA5+qcgKzJq6Q6XjAiBKtxLD3Yn7f6XP4joD3J3qU=
|
||||||
github.com/bep/helpers v0.8.0 h1:plg2BFgA9AgIHF2XemyZdZLqixjzQk3uyyArV48FngQ=
|
github.com/bep/helpers v0.12.0 h1:tD6V2DQW0B+FUynF2etR/106S/TO9akm+vA/Hk24GxY=
|
||||||
github.com/bep/helpers v0.8.0/go.mod h1:PfE7MGdA8sSQ19nyDh4tYbs5rAlStlJaDI21f/fnNps=
|
github.com/bep/helpers v0.12.0/go.mod h1:PfE7MGdA8sSQ19nyDh4tYbs5rAlStlJaDI21f/fnNps=
|
||||||
github.com/bep/imagemeta v0.17.2 h1:fDyXM1eAqCfBeqGLqS6UsN4OfuLM0cdu70KuLCehjOg=
|
github.com/bep/imagemeta v0.17.2 h1:fDyXM1eAqCfBeqGLqS6UsN4OfuLM0cdu70KuLCehjOg=
|
||||||
github.com/bep/imagemeta v0.17.2/go.mod h1:+Hlp195TfZpzsqCxtDKTG6eWdyz2+F2V/oCYfr3CZKA=
|
github.com/bep/imagemeta v0.17.2/go.mod h1:+Hlp195TfZpzsqCxtDKTG6eWdyz2+F2V/oCYfr3CZKA=
|
||||||
github.com/bep/lazycache v0.8.1 h1:ko6ASLjkPxyV5DMWoNNZ8B2M0weyjqXX8IZkjBoBtvg=
|
github.com/bep/lazycache v0.8.1 h1:ko6ASLjkPxyV5DMWoNNZ8B2M0weyjqXX8IZkjBoBtvg=
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bep/debounce"
|
"github.com/bep/debounce"
|
||||||
|
"github.com/bep/helpers/maphelpers"
|
||||||
"github.com/bep/logg"
|
"github.com/bep/logg"
|
||||||
"github.com/gohugoio/go-radix"
|
"github.com/gohugoio/go-radix"
|
||||||
"github.com/gohugoio/hugo/bufferpool"
|
"github.com/gohugoio/hugo/bufferpool"
|
||||||
@@ -692,7 +693,7 @@ func (h *HugoSites) postProcess(l logg.LevelLogger) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var toPostProcess []postpub.PostPublishedResource
|
var toPostProcess []postpub.PostPublishedResource
|
||||||
for _, r := range h.ResourceSpec.PostProcessResources {
|
for _, r := range h.ResourceSpec.PostProcessResources.All() {
|
||||||
toPostProcess = append(toPostProcess, r)
|
toPostProcess = append(toPostProcess, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -758,7 +759,7 @@ func (h *HugoSites) postProcess(l logg.LevelLogger) error {
|
|||||||
|
|
||||||
// Prepare for a new build.
|
// Prepare for a new build.
|
||||||
for _, s := range h.Sites {
|
for _, s := range h.Sites {
|
||||||
s.ResourceSpec.PostProcessResources = make(map[string]postpub.PostPublishedResource)
|
s.ResourceSpec.PostProcessResources = maphelpers.NewConcurrentMap[string, postpub.PostPublishedResource]()
|
||||||
}
|
}
|
||||||
|
|
||||||
return g.Wait()
|
return g.Wait()
|
||||||
|
|||||||
+5
-10
@@ -27,6 +27,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/bep/helpers/maphelpers"
|
||||||
"github.com/gohugoio/hugo/common/herrors"
|
"github.com/gohugoio/hugo/common/herrors"
|
||||||
"github.com/gohugoio/hugo/common/hstore"
|
"github.com/gohugoio/hugo/common/hstore"
|
||||||
"github.com/gohugoio/hugo/common/types"
|
"github.com/gohugoio/hugo/common/types"
|
||||||
@@ -286,24 +287,18 @@ type shortcodeParseInfo struct {
|
|||||||
shortcodes []*shortcode
|
shortcodes []*shortcode
|
||||||
|
|
||||||
// All the shortcode names in this set.
|
// All the shortcode names in this set.
|
||||||
nameSetMu sync.RWMutex
|
nameSet *maphelpers.ConcurrentSet[string]
|
||||||
nameSet map[string]bool
|
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
enableInlineShortcodes bool
|
enableInlineShortcodes bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *shortcodeParseInfo) addName(name string) {
|
func (s *shortcodeParseInfo) addName(name string) {
|
||||||
s.nameSetMu.Lock()
|
s.nameSet.Add(name)
|
||||||
defer s.nameSetMu.Unlock()
|
|
||||||
s.nameSet[name] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *shortcodeParseInfo) hasName(name string) bool {
|
func (s *shortcodeParseInfo) hasName(name string) bool {
|
||||||
s.nameSetMu.RLock()
|
return s.nameSet.Has(name)
|
||||||
defer s.nameSetMu.RUnlock()
|
|
||||||
_, ok := s.nameSet[name]
|
|
||||||
return ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newShortcodeHandler(filename string, d *deps.Deps) *shortcodeParseInfo {
|
func newShortcodeHandler(filename string, d *deps.Deps) *shortcodeParseInfo {
|
||||||
@@ -312,7 +307,7 @@ func newShortcodeHandler(filename string, d *deps.Deps) *shortcodeParseInfo {
|
|||||||
firstTemplateStore: d.TemplateStore,
|
firstTemplateStore: d.TemplateStore,
|
||||||
enableInlineShortcodes: d.ExecHelper.Sec().EnableInlineShortcodes,
|
enableInlineShortcodes: d.ExecHelper.Sec().EnableInlineShortcodes,
|
||||||
shortcodes: make([]*shortcode, 0, 4),
|
shortcodes: make([]*shortcode, 0, 4),
|
||||||
nameSet: make(map[string]bool),
|
nameSet: maphelpers.NewConcurrentSet[string](),
|
||||||
}
|
}
|
||||||
|
|
||||||
return sh
|
return sh
|
||||||
|
|||||||
@@ -14,37 +14,21 @@
|
|||||||
package chromalexers
|
package chromalexers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/alecthomas/chroma/v2"
|
"github.com/alecthomas/chroma/v2"
|
||||||
"github.com/alecthomas/chroma/v2/lexers"
|
"github.com/alecthomas/chroma/v2/lexers"
|
||||||
|
"github.com/bep/helpers/maphelpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
type lexersMap struct {
|
var lexerCache = *maphelpers.NewConcurrentMap[string, chroma.Lexer]()
|
||||||
lexers map[string]chroma.Lexer
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
var lexerCache = &lexersMap{lexers: make(map[string]chroma.Lexer)}
|
|
||||||
|
|
||||||
// Get returns a lexer for the given language name, nil if not found.
|
// Get returns a lexer for the given language name, nil if not found.
|
||||||
// This is just a wrapper around chromalexers.Get that caches the result.
|
// This is just a wrapper around chromalexers.Get that caches the result.
|
||||||
// Reasoning for this is that chromalexers.Get is slow in the case where the lexer is not found,
|
// Reasoning for this is that chromalexers.Get is slow in the case where the lexer is not found,
|
||||||
// which is a common case in Hugo.
|
// which is a common case in Hugo.
|
||||||
func Get(name string) chroma.Lexer {
|
func Get(name string) chroma.Lexer {
|
||||||
lexerCache.mu.RLock()
|
l, _ := lexerCache.GetOrCreate(name, func() (chroma.Lexer, error) {
|
||||||
lexer, found := lexerCache.lexers[name]
|
l := lexers.Get(name)
|
||||||
lexerCache.mu.RUnlock()
|
return l, nil
|
||||||
|
})
|
||||||
if found {
|
return l
|
||||||
return lexer
|
|
||||||
}
|
|
||||||
|
|
||||||
lexer = lexers.Get(name)
|
|
||||||
|
|
||||||
lexerCache.mu.Lock()
|
|
||||||
lexerCache.lexers[name] = lexer
|
|
||||||
lexerCache.mu.Unlock()
|
|
||||||
|
|
||||||
return lexer
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,59 +16,47 @@ package jsconfig
|
|||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
|
||||||
|
"github.com/bep/helpers/maphelpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Builder builds a jsconfig.json file that, currently, is used only to assist
|
// Builder builds a jsconfig.json file that, currently, is used only to assist
|
||||||
// IntelliSense in editors.
|
// IntelliSense in editors.
|
||||||
type Builder struct {
|
type Builder struct {
|
||||||
sourceRootsMu sync.RWMutex
|
sourceRoots *maphelpers.ConcurrentSet[string]
|
||||||
sourceRoots map[string]bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBuilder creates a new Builder.
|
// NewBuilder creates a new Builder.
|
||||||
func NewBuilder() *Builder {
|
func NewBuilder() *Builder {
|
||||||
return &Builder{sourceRoots: make(map[string]bool)}
|
return &Builder{sourceRoots: maphelpers.NewConcurrentSet[string]()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build builds a new Config with paths relative to dir.
|
// Build builds a new Config with paths relative to dir.
|
||||||
// This method is thread safe.
|
// This method is thread safe.
|
||||||
func (b *Builder) Build(dir string) *Config {
|
func (b *Builder) Build(dir string) *Config {
|
||||||
b.sourceRootsMu.RLock()
|
if b.sourceRoots.Len() == 0 {
|
||||||
defer b.sourceRootsMu.RUnlock()
|
|
||||||
|
|
||||||
if len(b.sourceRoots) == 0 {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
conf := newJSConfig()
|
|
||||||
|
|
||||||
var roots []string
|
var roots []string
|
||||||
for root := range b.sourceRoots {
|
for root := range b.sourceRoots.All() {
|
||||||
rel, err := filepath.Rel(dir, filepath.Join(root, "*"))
|
rel, err := filepath.Rel(dir, filepath.Join(root, "*"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
roots = append(roots, rel)
|
roots = append(roots, rel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(roots) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
sort.Strings(roots)
|
sort.Strings(roots)
|
||||||
|
conf := newJSConfig()
|
||||||
conf.CompilerOptions.Paths["*"] = roots
|
conf.CompilerOptions.Paths["*"] = roots
|
||||||
|
|
||||||
return conf
|
return conf
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSourceRoot adds a new source root.
|
// AddSourceRoot adds a new source root.
|
||||||
// This method is thread safe.
|
// This method is thread safe.
|
||||||
func (b *Builder) AddSourceRoot(root string) {
|
func (b *Builder) AddSourceRoot(root string) {
|
||||||
b.sourceRootsMu.RLock()
|
b.sourceRoots.AddIfAbsent(root)
|
||||||
found := b.sourceRoots[root]
|
|
||||||
b.sourceRootsMu.RUnlock()
|
|
||||||
|
|
||||||
if found {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
b.sourceRootsMu.Lock()
|
|
||||||
b.sourceRoots[root] = true
|
|
||||||
b.sourceRootsMu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompilerOptions holds compilerOptions for jsonconfig.json.
|
// CompilerOptions holds compilerOptions for jsonconfig.json.
|
||||||
|
|||||||
@@ -25,27 +25,11 @@ type transformationKeyer interface {
|
|||||||
// PostProcess wraps the given Resource for later processing.
|
// PostProcess wraps the given Resource for later processing.
|
||||||
func (spec *Spec) PostProcess(r resource.Resource) (postpub.PostPublishedResource, error) {
|
func (spec *Spec) PostProcess(r resource.Resource) (postpub.PostPublishedResource, error) {
|
||||||
key := r.(transformationKeyer).TransformationKey()
|
key := r.(transformationKeyer).TransformationKey()
|
||||||
spec.postProcessMu.RLock()
|
return spec.PostProcessResources.GetOrCreate(key, func() (postpub.PostPublishedResource, error) {
|
||||||
result, found := spec.PostProcessResources[key]
|
result := postpub.NewPostPublishResource(spec.incr.Incr(), r)
|
||||||
spec.postProcessMu.RUnlock()
|
if result == nil {
|
||||||
if found {
|
panic("got nil result")
|
||||||
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
})
|
||||||
|
|
||||||
spec.postProcessMu.Lock()
|
|
||||||
defer spec.postProcessMu.Unlock()
|
|
||||||
|
|
||||||
// Double check
|
|
||||||
result, found = spec.PostProcessResources[key]
|
|
||||||
if found {
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
result = postpub.NewPostPublishResource(spec.incr.Incr(), r)
|
|
||||||
if result == nil {
|
|
||||||
panic("got nil result")
|
|
||||||
}
|
|
||||||
spec.PostProcessResources[key] = result
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/bep/helpers/maphelpers"
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/config/allconfig"
|
"github.com/gohugoio/hugo/config/allconfig"
|
||||||
"github.com/gohugoio/hugo/internal/warpc"
|
"github.com/gohugoio/hugo/internal/warpc"
|
||||||
@@ -88,7 +89,7 @@ func NewSpec(
|
|||||||
incr: incr,
|
incr: incr,
|
||||||
FileCaches: fileCaches,
|
FileCaches: fileCaches,
|
||||||
PostBuildAssets: &PostBuildAssets{
|
PostBuildAssets: &PostBuildAssets{
|
||||||
PostProcessResources: make(map[string]postpub.PostPublishedResource),
|
PostProcessResources: maphelpers.NewConcurrentMap[string, postpub.PostPublishedResource](),
|
||||||
JSConfigBuilder: jsconfig.NewBuilder(),
|
JSConfigBuilder: jsconfig.NewBuilder(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -155,8 +156,7 @@ type SpecCommon struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PostBuildAssets struct {
|
type PostBuildAssets struct {
|
||||||
postProcessMu sync.RWMutex
|
PostProcessResources *maphelpers.ConcurrentMap[string, postpub.PostPublishedResource]
|
||||||
PostProcessResources map[string]postpub.PostPublishedResource
|
|
||||||
JSConfigBuilder *jsconfig.Builder
|
JSConfigBuilder *jsconfig.Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-29
@@ -20,8 +20,8 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
|
||||||
|
|
||||||
|
"github.com/bep/helpers/maphelpers"
|
||||||
"github.com/bep/overlayfs"
|
"github.com/bep/overlayfs"
|
||||||
"github.com/gohugoio/hugo/common/hashing"
|
"github.com/gohugoio/hugo/common/hashing"
|
||||||
"github.com/gohugoio/hugo/common/hugio"
|
"github.com/gohugoio/hugo/common/hugio"
|
||||||
@@ -52,7 +52,7 @@ func New(d *deps.Deps) *Namespace {
|
|||||||
return &Namespace{
|
return &Namespace{
|
||||||
readFileFs: readFileFs,
|
readFileFs: readFileFs,
|
||||||
Filters: &images.Filters{},
|
Filters: &images.Filters{},
|
||||||
cache: map[string]image.Config{},
|
cache: maphelpers.NewConcurrentMap[string, image.Config](),
|
||||||
deps: d,
|
deps: d,
|
||||||
createClient: create.New(d.ResourceSpec),
|
createClient: create.New(d.ResourceSpec),
|
||||||
}
|
}
|
||||||
@@ -62,8 +62,7 @@ func New(d *deps.Deps) *Namespace {
|
|||||||
type Namespace struct {
|
type Namespace struct {
|
||||||
*images.Filters
|
*images.Filters
|
||||||
readFileFs afero.Fs
|
readFileFs afero.Fs
|
||||||
cacheMu sync.RWMutex
|
cache *maphelpers.ConcurrentMap[string, image.Config]
|
||||||
cache map[string]image.Config
|
|
||||||
deps *deps.Deps
|
deps *deps.Deps
|
||||||
createClient *create.Client
|
createClient *create.Client
|
||||||
}
|
}
|
||||||
@@ -80,34 +79,19 @@ func (ns *Namespace) Config(path any) (image.Config, error) {
|
|||||||
return image.Config{}, errors.New("config needs a filename")
|
return image.Config{}, errors.New("config needs a filename")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check cache for image config.
|
return ns.cache.GetOrCreate(filename, func() (image.Config, error) {
|
||||||
ns.cacheMu.RLock()
|
f, err := ns.readFileFs.Open(filename)
|
||||||
config, ok := ns.cache[filename]
|
if err != nil {
|
||||||
ns.cacheMu.RUnlock()
|
return image.Config{}, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
if ok {
|
ext := filepath.Ext(filename)
|
||||||
return config, nil
|
format, _ := images.ImageFormatFromExt(ext)
|
||||||
}
|
|
||||||
|
|
||||||
f, err := ns.readFileFs.Open(filename)
|
config, _, err := ns.deps.ResourceSpec.Imaging.Codec.DecodeConfig(format, f)
|
||||||
if err != nil {
|
|
||||||
return image.Config{}, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
ext := filepath.Ext(filename)
|
|
||||||
format, _ := images.ImageFormatFromExt(ext)
|
|
||||||
|
|
||||||
config, _, err = ns.deps.ResourceSpec.Imaging.Codec.DecodeConfig(format, f)
|
|
||||||
if err != nil {
|
|
||||||
return config, err
|
return config, err
|
||||||
}
|
})
|
||||||
|
|
||||||
ns.cacheMu.Lock()
|
|
||||||
ns.cache[filename] = config
|
|
||||||
ns.cacheMu.Unlock()
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter applies the given filters to the image given as the last element in args.
|
// Filter applies the given filters to the image given as the last element in args.
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ func TestNSConfig(t *testing.T) {
|
|||||||
|
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
c.Assert(result, qt.Equals, test.expect)
|
c.Assert(result, qt.Equals, test.expect)
|
||||||
c.Assert(len(ns.cache), qt.Not(qt.Equals), 0)
|
_, cached := ns.cache.Lookup(sp)
|
||||||
|
c.Assert(cached, qt.IsTrue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user