Skip to content

Commit 9b8b6d3

Browse files
committed
tpl/partials: Fix partialCached deadlock regression
This is a rollback of 0927cf7 We cannot do that change until we either completes #9570 or possibly also use the new TryLock in GO 1.18. Fixes #9588 Opens #4086
1 parent 376704d commit 9b8b6d3

File tree

2 files changed

+57
-19
lines changed

2 files changed

+57
-19
lines changed

tpl/partials/integration_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,44 @@ P2
103103
`)
104104
}
105105

106+
// Issue #588
107+
func TestIncludeCachedRecursionShortcode(t *testing.T) {
108+
t.Parallel()
109+
110+
files := `
111+
-- config.toml --
112+
baseURL = 'http://example.com/'
113+
-- content/_index.md --
114+
---
115+
title: "Index"
116+
---
117+
{{< short >}}
118+
-- layouts/index.html --
119+
{{ partials.IncludeCached "p1.html" . }}
120+
-- layouts/partials/p1.html --
121+
{{ .Content }}
122+
{{ partials.IncludeCached "p2.html" . }}
123+
-- layouts/partials/p2.html --
124+
-- layouts/shortcodes/short.html --
125+
SHORT
126+
{{ partials.IncludeCached "p2.html" . }}
127+
P2
128+
129+
`
130+
131+
b := hugolib.NewIntegrationTestBuilder(
132+
hugolib.IntegrationTestConfig{
133+
T: t,
134+
TxtarString: files,
135+
},
136+
).Build()
137+
138+
b.AssertFileContent("public/index.html", `
139+
SHORT
140+
P2
141+
`)
142+
}
143+
106144
func TestIncludeCacheHints(t *testing.T) {
107145
t.Parallel()
108146

tpl/partials/partials.go

+19-19
Original file line numberDiff line numberDiff line change
@@ -233,21 +233,14 @@ func (ns *Namespace) getOrCreate(ctx context.Context, key partialCacheKey, conte
233233
}
234234
}()
235235

236-
// We may already have a write lock.
237-
hasLock := tpl.GetHasLockFromContext(ctx)
238-
239-
if !hasLock {
240-
ns.cachedPartials.RLock()
241-
}
236+
ns.cachedPartials.RLock()
242237
p, ok := ns.cachedPartials.p[key]
243-
if !hasLock {
244-
ns.cachedPartials.RUnlock()
245-
}
238+
ns.cachedPartials.RUnlock()
246239

247240
if ok {
248241
if ns.deps.Metrics != nil {
249242
ns.deps.Metrics.TrackValue(key.templateName(), p, true)
250-
// The templates that gets executed is measued in Execute.
243+
// The templates that gets executed is measured in Execute.
251244
// We need to track the time spent in the cache to
252245
// get the totals correct.
253246
ns.deps.Metrics.MeasureSince(key.templateName(), start)
@@ -256,21 +249,28 @@ func (ns *Namespace) getOrCreate(ctx context.Context, key partialCacheKey, conte
256249
return p, nil
257250
}
258251

259-
if !hasLock {
260-
ns.cachedPartials.Lock()
261-
defer ns.cachedPartials.Unlock()
262-
ctx = tpl.SetHasLockInContext(ctx, true)
263-
}
264-
265-
var name string
266-
name, p, err = ns.include(ctx, key.name, context)
252+
// This needs to be done outside the lock.
253+
// See #9588
254+
_, p, err = ns.include(ctx, key.name, context)
267255
if err != nil {
268256
return nil, err
269257
}
270258

259+
ns.cachedPartials.Lock()
260+
defer ns.cachedPartials.Unlock()
261+
// Double-check.
262+
if p2, ok := ns.cachedPartials.p[key]; ok {
263+
if ns.deps.Metrics != nil {
264+
ns.deps.Metrics.TrackValue(key.templateName(), p, true)
265+
ns.deps.Metrics.MeasureSince(key.templateName(), start)
266+
}
267+
return p2, nil
268+
269+
}
271270
if ns.deps.Metrics != nil {
272-
ns.deps.Metrics.TrackValue(name, p, false)
271+
ns.deps.Metrics.TrackValue(key.templateName(), p, false)
273272
}
273+
274274
ns.cachedPartials.p[key] = p
275275

276276
return p, nil

0 commit comments

Comments
 (0)