Fix potential deadlock in ByParam

Fixes #11039
This commit is contained in:
Bjørn Erik Pedersen 2023-05-29 12:58:22 +02:00
parent d47225ce9e
commit 32585696be
4 changed files with 29 additions and 13 deletions

View file

@ -41,7 +41,10 @@ type Language struct {
translator locales.Translator translator locales.Translator
timeFormatter htime.TimeFormatter timeFormatter htime.TimeFormatter
tag language.Tag tag language.Tag
collator *Collator // collator1 and collator2 are the same, we have 2 to prevent deadlocks.
collator1 *Collator
collator2 *Collator
location *time.Location location *time.Location
// This is just an alias of Site.Params. // This is just an alias of Site.Params.
@ -58,14 +61,20 @@ func NewLanguage(lang, defaultContentLanguage, timeZone string, languageConfig L
} }
} }
var coll *Collator var coll1, coll2 *Collator
tag, err := language.Parse(lang) tag, err := language.Parse(lang)
if err == nil { if err == nil {
coll = &Collator{ coll1 = &Collator{
c: collate.New(tag),
}
coll2 = &Collator{
c: collate.New(tag), c: collate.New(tag),
} }
} else { } else {
coll = &Collator{ coll1 = &Collator{
c: collate.New(language.English),
}
coll2 = &Collator{
c: collate.New(language.English), c: collate.New(language.English),
} }
} }
@ -76,7 +85,8 @@ func NewLanguage(lang, defaultContentLanguage, timeZone string, languageConfig L
translator: translator, translator: translator,
timeFormatter: htime.NewTimeFormatter(translator), timeFormatter: htime.NewTimeFormatter(translator),
tag: tag, tag: tag,
collator: coll, collator1: coll1,
collator2: coll2,
} }
return l, l.loadLocation(timeZone) return l, l.loadLocation(timeZone)
@ -165,8 +175,12 @@ func GetLocation(l *Language) *time.Location {
return l.location return l.location
} }
func GetCollator(l *Language) *Collator { func GetCollator1(l *Language) *Collator {
return l.collator return l.collator1
}
func GetCollator2(l *Language) *Collator {
return l.collator2
} }
type Collator struct { type Collator struct {

View file

@ -161,7 +161,7 @@ var collatorStringSort = func(getString func(Page) string) func(p Pages) {
// Pages may be a mix of multiple languages, so we need to use the language // Pages may be a mix of multiple languages, so we need to use the language
// for the currently rendered Site. // for the currently rendered Site.
currentSite := p[0].Site().Current() currentSite := p[0].Site().Current()
coll := langs.GetCollator(currentSite.Language()) coll := langs.GetCollator1(currentSite.Language())
coll.Lock() coll.Lock()
defer coll.Unlock() defer coll.Unlock()
@ -173,7 +173,7 @@ var collatorStringSort = func(getString func(Page) string) func(p Pages) {
var collatorStringCompare = func(getString func(Page) string, p1, p2 Page) int { var collatorStringCompare = func(getString func(Page) string, p1, p2 Page) int {
currentSite := p1.Site().Current() currentSite := p1.Site().Current()
coll := langs.GetCollator(currentSite.Language()) coll := langs.GetCollator1(currentSite.Language())
coll.Lock() coll.Lock()
c := coll.CompareStrings(getString(p1), getString(p2)) c := coll.CompareStrings(getString(p1), getString(p2))
coll.Unlock() coll.Unlock()
@ -182,7 +182,9 @@ var collatorStringCompare = func(getString func(Page) string, p1, p2 Page) int {
var collatorStringLess = func(p Page) (less func(s1, s2 string) bool, close func()) { var collatorStringLess = func(p Page) (less func(s1, s2 string) bool, close func()) {
currentSite := p.Site().Current() currentSite := p.Site().Current()
coll := langs.GetCollator(currentSite.Language()) // Make sure to use the second collator to prevent deadlocks.
// See issue 11039.
coll := langs.GetCollator2(currentSite.Language())
coll.Lock() coll.Lock()
return func(s1, s2 string) bool { return func(s1, s2 string) bool {
return coll.CompareStrings(s1, s2) < 1 return coll.CompareStrings(s1, s2) < 1

View file

@ -83,7 +83,7 @@ func (i Taxonomy) Alphabetical() OrderedTaxonomy {
return ia return ia
} }
currentSite := p.Site().Current() currentSite := p.Site().Current()
coll := langs.GetCollator(currentSite.Language()) coll := langs.GetCollator1(currentSite.Language())
coll.Lock() coll.Lock()
defer coll.Unlock() defer coll.Unlock()
name := func(i1, i2 *OrderedTaxonomyEntry) bool { name := func(i1, i2 *OrderedTaxonomyEntry) bool {

View file

@ -46,7 +46,7 @@ func (ns *Namespace) Sort(l any, args ...any) (any, error) {
return nil, errors.New("can't sort " + reflect.ValueOf(l).Type().String()) return nil, errors.New("can't sort " + reflect.ValueOf(l).Type().String())
} }
collator := langs.GetCollator(ns.deps.Conf.Language()) collator := langs.GetCollator1(ns.deps.Conf.Language())
// Create a list of pairs that will be used to do the sort // Create a list of pairs that will be used to do the sort
p := pairList{Collator: collator, sortComp: ns.sortComp, SortAsc: true, SliceType: sliceType} p := pairList{Collator: collator, sortComp: ns.sortComp, SortAsc: true, SliceType: sliceType}