Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c4bbc28

Browse files
committed
all: Replace RWMutex struct caches with ConcurrentMap
1 parent d8c7021 commit c4bbc28

13 files changed

Lines changed: 66 additions & 168 deletions

File tree

cache/filecache/filecache.go

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/gohugoio/hugo/helpers"
3232

3333
"github.com/BurntSushi/locker"
34+
"github.com/bep/helpers/maphelpers"
3435
"github.com/spf13/afero"
3536
)
3637

@@ -56,25 +57,15 @@ type Cache struct {
5657
}
5758

5859
type lockTracker struct {
59-
seenMu sync.RWMutex
60-
seen map[string]struct{}
60+
seen *maphelpers.ConcurrentSet[string]
6161

6262
*locker.Locker
6363
}
6464

6565
// Lock tracks the ids in use. We use this information to do garbage collection
6666
// after a Hugo build.
6767
func (l *lockTracker) Lock(id string) {
68-
l.seenMu.RLock()
69-
if _, seen := l.seen[id]; !seen {
70-
l.seenMu.RUnlock()
71-
l.seenMu.Lock()
72-
l.seen[id] = struct{}{}
73-
l.seenMu.Unlock()
74-
} else {
75-
l.seenMu.RUnlock()
76-
}
77-
68+
l.seen.AddIfAbsent(id)
7869
l.Locker.Lock(id)
7970
}
8071

@@ -92,7 +83,7 @@ func NewCache(fs afero.Fs, cfg FileCacheConfig) *Cache {
9283

9384
return &Cache{
9485
Fs: fs,
95-
entryLocker: &lockTracker{Locker: locker.NewLocker(), seen: make(map[string]struct{})},
86+
entryLocker: &lockTracker{Locker: locker.NewLocker(), seen: maphelpers.NewConcurrentSet[string]()},
9687
cfg: cfg,
9788
}
9889
}

cache/filecache/filecache_pruner.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,9 @@ func (c *Cache) Prune(force bool) (int, error) {
9393

9494
shouldRemove := force || c.isExpired(info.ModTime())
9595

96-
if !shouldRemove && len(c.entryLocker.seen) > 0 {
96+
if !shouldRemove && c.entryLocker.seen.Len() > 0 {
9797
// Remove it if it's not been touched/used in the last build.
98-
_, seen := c.entryLocker.seen[name]
99-
shouldRemove = !seen
98+
shouldRemove = !c.entryLocker.seen.Has(name)
10099
}
101100

102101
if shouldRemove {

common/hstrings/strings.go

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import (
1919
"slices"
2020
"sort"
2121
"strings"
22-
"sync"
2322

23+
"github.com/bep/helpers/maphelpers"
2424
"github.com/gohugoio/hugo/compare"
2525
)
2626

@@ -55,46 +55,17 @@ func EqualAny(a string, b ...string) bool {
5555
return slices.Contains(b, a)
5656
}
5757

58-
// regexpCache represents a cache of regexp objects protected by a mutex.
59-
type regexpCache struct {
60-
mu sync.RWMutex
61-
re map[string]*regexp.Regexp
62-
}
63-
64-
func (rc *regexpCache) getOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
65-
var ok bool
66-
67-
if re, ok = rc.get(pattern); !ok {
68-
re, err = regexp.Compile(pattern)
69-
if err != nil {
70-
return nil, err
71-
}
72-
rc.set(pattern, re)
73-
}
74-
75-
return re, nil
76-
}
77-
78-
func (rc *regexpCache) get(key string) (re *regexp.Regexp, ok bool) {
79-
rc.mu.RLock()
80-
re, ok = rc.re[key]
81-
rc.mu.RUnlock()
82-
return
83-
}
84-
85-
func (rc *regexpCache) set(key string, re *regexp.Regexp) {
86-
rc.mu.Lock()
87-
rc.re[key] = re
88-
rc.mu.Unlock()
89-
}
90-
91-
var reCache = regexpCache{re: make(map[string]*regexp.Regexp)}
58+
var reCache = *maphelpers.NewConcurrentMap[string, *regexp.Regexp]()
9259

9360
// GetOrCompileRegexp retrieves a regexp object from the cache based upon the pattern.
9461
// If the pattern is not found in the cache, the pattern is compiled and added to
9562
// the cache.
9663
func GetOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
97-
return reCache.getOrCompileRegexp(pattern)
64+
return reCache.GetOrCreate(pattern,
65+
func() (*regexp.Regexp, error) {
66+
return regexp.Compile(pattern)
67+
},
68+
)
9869
}
9970

10071
// HasAnyPrefix checks if the string s has any of the prefixes given.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ require (
1414
github.com/bep/golibsass v1.2.0
1515
github.com/bep/golocales v0.1.0
1616
github.com/bep/goportabletext v0.2.0
17-
github.com/bep/helpers v0.8.0
17+
github.com/bep/helpers v0.12.0
1818
github.com/bep/imagemeta v0.17.2
1919
github.com/bep/lazycache v0.8.1
2020
github.com/bep/logg v0.4.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ github.com/bep/golocales v0.1.0 h1:rjWf1S4basIje+G+je5WMW8G+yzaoz4gEDFolrFVdvA=
162162
github.com/bep/golocales v0.1.0/go.mod h1:Hl78nje8mNL3LzLeJvYN9NsIZgyFJGrGfvgO9r1+mwE=
163163
github.com/bep/goportabletext v0.2.0 h1:CZ9f8jADBWqHwBymQiJJPCTSV/tHSA+PYzlUf86Yze0=
164164
github.com/bep/goportabletext v0.2.0/go.mod h1:xDeA5+qcgKzJq6Q6XjAiBKtxLD3Yn7f6XP4joD3J3qU=
165-
github.com/bep/helpers v0.8.0 h1:plg2BFgA9AgIHF2XemyZdZLqixjzQk3uyyArV48FngQ=
166-
github.com/bep/helpers v0.8.0/go.mod h1:PfE7MGdA8sSQ19nyDh4tYbs5rAlStlJaDI21f/fnNps=
165+
github.com/bep/helpers v0.12.0 h1:tD6V2DQW0B+FUynF2etR/106S/TO9akm+vA/Hk24GxY=
166+
github.com/bep/helpers v0.12.0/go.mod h1:PfE7MGdA8sSQ19nyDh4tYbs5rAlStlJaDI21f/fnNps=
167167
github.com/bep/imagemeta v0.17.2 h1:fDyXM1eAqCfBeqGLqS6UsN4OfuLM0cdu70KuLCehjOg=
168168
github.com/bep/imagemeta v0.17.2/go.mod h1:+Hlp195TfZpzsqCxtDKTG6eWdyz2+F2V/oCYfr3CZKA=
169169
github.com/bep/lazycache v0.8.1 h1:ko6ASLjkPxyV5DMWoNNZ8B2M0weyjqXX8IZkjBoBtvg=

hugolib/hugo_sites_build.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"time"
2727

2828
"github.com/bep/debounce"
29+
"github.com/bep/helpers/maphelpers"
2930
"github.com/bep/logg"
3031
"github.com/gohugoio/go-radix"
3132
"github.com/gohugoio/hugo/bufferpool"
@@ -692,7 +693,7 @@ func (h *HugoSites) postProcess(l logg.LevelLogger) error {
692693
}
693694

694695
var toPostProcess []postpub.PostPublishedResource
695-
for _, r := range h.ResourceSpec.PostProcessResources {
696+
for _, r := range h.ResourceSpec.PostProcessResources.All() {
696697
toPostProcess = append(toPostProcess, r)
697698
}
698699

@@ -758,7 +759,7 @@ func (h *HugoSites) postProcess(l logg.LevelLogger) error {
758759

759760
// Prepare for a new build.
760761
for _, s := range h.Sites {
761-
s.ResourceSpec.PostProcessResources = make(map[string]postpub.PostPublishedResource)
762+
s.ResourceSpec.PostProcessResources = maphelpers.NewConcurrentMap[string, postpub.PostPublishedResource]()
762763
}
763764

764765
return g.Wait()

hugolib/shortcode.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"strings"
2828
"sync"
2929

30+
"github.com/bep/helpers/maphelpers"
3031
"github.com/gohugoio/hugo/common/herrors"
3132
"github.com/gohugoio/hugo/common/hstore"
3233
"github.com/gohugoio/hugo/common/types"
@@ -286,24 +287,18 @@ type shortcodeParseInfo struct {
286287
shortcodes []*shortcode
287288

288289
// All the shortcode names in this set.
289-
nameSetMu sync.RWMutex
290-
nameSet map[string]bool
290+
nameSet *maphelpers.ConcurrentSet[string]
291291

292292
// Configuration
293293
enableInlineShortcodes bool
294294
}
295295

296296
func (s *shortcodeParseInfo) addName(name string) {
297-
s.nameSetMu.Lock()
298-
defer s.nameSetMu.Unlock()
299-
s.nameSet[name] = true
297+
s.nameSet.Add(name)
300298
}
301299

302300
func (s *shortcodeParseInfo) hasName(name string) bool {
303-
s.nameSetMu.RLock()
304-
defer s.nameSetMu.RUnlock()
305-
_, ok := s.nameSet[name]
306-
return ok
301+
return s.nameSet.Has(name)
307302
}
308303

309304
func newShortcodeHandler(filename string, d *deps.Deps) *shortcodeParseInfo {
@@ -312,7 +307,7 @@ func newShortcodeHandler(filename string, d *deps.Deps) *shortcodeParseInfo {
312307
firstTemplateStore: d.TemplateStore,
313308
enableInlineShortcodes: d.ExecHelper.Sec().EnableInlineShortcodes,
314309
shortcodes: make([]*shortcode, 0, 4),
315-
nameSet: make(map[string]bool),
310+
nameSet: maphelpers.NewConcurrentSet[string](),
316311
}
317312

318313
return sh

markup/highlight/chromalexers/chromalexers.go

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,21 @@
1414
package chromalexers
1515

1616
import (
17-
"sync"
18-
1917
"github.com/alecthomas/chroma/v2"
2018
"github.com/alecthomas/chroma/v2/lexers"
19+
"github.com/bep/helpers/maphelpers"
2120
)
2221

23-
type lexersMap struct {
24-
lexers map[string]chroma.Lexer
25-
mu sync.RWMutex
26-
}
27-
28-
var lexerCache = &lexersMap{lexers: make(map[string]chroma.Lexer)}
22+
var lexerCache = *maphelpers.NewConcurrentMap[string, chroma.Lexer]()
2923

3024
// Get returns a lexer for the given language name, nil if not found.
3125
// This is just a wrapper around chromalexers.Get that caches the result.
3226
// Reasoning for this is that chromalexers.Get is slow in the case where the lexer is not found,
3327
// which is a common case in Hugo.
3428
func Get(name string) chroma.Lexer {
35-
lexerCache.mu.RLock()
36-
lexer, found := lexerCache.lexers[name]
37-
lexerCache.mu.RUnlock()
38-
39-
if found {
40-
return lexer
41-
}
42-
43-
lexer = lexers.Get(name)
44-
45-
lexerCache.mu.Lock()
46-
lexerCache.lexers[name] = lexer
47-
lexerCache.mu.Unlock()
48-
49-
return lexer
29+
l, _ := lexerCache.GetOrCreate(name, func() (chroma.Lexer, error) {
30+
l := lexers.Get(name)
31+
return l, nil
32+
})
33+
return l
5034
}

resources/jsconfig/jsconfig.go

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,59 +16,47 @@ package jsconfig
1616
import (
1717
"path/filepath"
1818
"sort"
19-
"sync"
19+
20+
"github.com/bep/helpers/maphelpers"
2021
)
2122

2223
// Builder builds a jsconfig.json file that, currently, is used only to assist
2324
// IntelliSense in editors.
2425
type Builder struct {
25-
sourceRootsMu sync.RWMutex
26-
sourceRoots map[string]bool
26+
sourceRoots *maphelpers.ConcurrentSet[string]
2727
}
2828

2929
// NewBuilder creates a new Builder.
3030
func NewBuilder() *Builder {
31-
return &Builder{sourceRoots: make(map[string]bool)}
31+
return &Builder{sourceRoots: maphelpers.NewConcurrentSet[string]()}
3232
}
3333

3434
// Build builds a new Config with paths relative to dir.
3535
// This method is thread safe.
3636
func (b *Builder) Build(dir string) *Config {
37-
b.sourceRootsMu.RLock()
38-
defer b.sourceRootsMu.RUnlock()
39-
40-
if len(b.sourceRoots) == 0 {
37+
if b.sourceRoots.Len() == 0 {
4138
return nil
4239
}
43-
conf := newJSConfig()
44-
4540
var roots []string
46-
for root := range b.sourceRoots {
41+
for root := range b.sourceRoots.All() {
4742
rel, err := filepath.Rel(dir, filepath.Join(root, "*"))
4843
if err == nil {
4944
roots = append(roots, rel)
5045
}
5146
}
47+
if len(roots) == 0 {
48+
return nil
49+
}
5250
sort.Strings(roots)
51+
conf := newJSConfig()
5352
conf.CompilerOptions.Paths["*"] = roots
54-
5553
return conf
5654
}
5755

5856
// AddSourceRoot adds a new source root.
5957
// This method is thread safe.
6058
func (b *Builder) AddSourceRoot(root string) {
61-
b.sourceRootsMu.RLock()
62-
found := b.sourceRoots[root]
63-
b.sourceRootsMu.RUnlock()
64-
65-
if found {
66-
return
67-
}
68-
69-
b.sourceRootsMu.Lock()
70-
b.sourceRoots[root] = true
71-
b.sourceRootsMu.Unlock()
59+
b.sourceRoots.AddIfAbsent(root)
7260
}
7361

7462
// CompilerOptions holds compilerOptions for jsonconfig.json.

resources/post_publish.go

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,11 @@ type transformationKeyer interface {
2525
// PostProcess wraps the given Resource for later processing.
2626
func (spec *Spec) PostProcess(r resource.Resource) (postpub.PostPublishedResource, error) {
2727
key := r.(transformationKeyer).TransformationKey()
28-
spec.postProcessMu.RLock()
29-
result, found := spec.PostProcessResources[key]
30-
spec.postProcessMu.RUnlock()
31-
if found {
28+
return spec.PostProcessResources.GetOrCreate(key, func() (postpub.PostPublishedResource, error) {
29+
result := postpub.NewPostPublishResource(spec.incr.Incr(), r)
30+
if result == nil {
31+
panic("got nil result")
32+
}
3233
return result, nil
33-
}
34-
35-
spec.postProcessMu.Lock()
36-
defer spec.postProcessMu.Unlock()
37-
38-
// Double check
39-
result, found = spec.PostProcessResources[key]
40-
if found {
41-
return result, nil
42-
}
43-
44-
result = postpub.NewPostPublishResource(spec.incr.Incr(), r)
45-
if result == nil {
46-
panic("got nil result")
47-
}
48-
spec.PostProcessResources[key] = result
49-
50-
return result, nil
34+
})
5135
}

0 commit comments

Comments
 (0)