Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/gohugoio/hugo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-03-02 12:04:29 +0300
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-03-02 13:16:21 +0300
commit9b8b6d34e2d039bfc040fd865a2e77ce2c278587 (patch)
treec8324f237e7de24a50f83034e254f44d50bd20dc
parent376704d382df163c7a0db066900f021ea5f7894d (diff)
tpl/partials: Fix partialCached deadlock regression
This is a rollback of 0927cf739fee9646c7fb917965799d9acf080922 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
-rw-r--r--tpl/partials/integration_test.go38
-rw-r--r--tpl/partials/partials.go38
2 files changed, 57 insertions, 19 deletions
diff --git a/tpl/partials/integration_test.go b/tpl/partials/integration_test.go
index 446e47118..bda5ddbd5 100644
--- a/tpl/partials/integration_test.go
+++ b/tpl/partials/integration_test.go
@@ -103,6 +103,44 @@ P2
`)
}
+// Issue #588
+func TestIncludeCachedRecursionShortcode(t *testing.T) {
+ t.Parallel()
+
+ files := `
+-- config.toml --
+baseURL = 'http://example.com/'
+-- content/_index.md --
+---
+title: "Index"
+---
+{{< short >}}
+-- layouts/index.html --
+{{ partials.IncludeCached "p1.html" . }}
+-- layouts/partials/p1.html --
+{{ .Content }}
+{{ partials.IncludeCached "p2.html" . }}
+-- layouts/partials/p2.html --
+-- layouts/shortcodes/short.html --
+SHORT
+{{ partials.IncludeCached "p2.html" . }}
+P2
+
+ `
+
+ b := hugolib.NewIntegrationTestBuilder(
+ hugolib.IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ },
+ ).Build()
+
+ b.AssertFileContent("public/index.html", `
+SHORT
+P2
+`)
+}
+
func TestIncludeCacheHints(t *testing.T) {
t.Parallel()
diff --git a/tpl/partials/partials.go b/tpl/partials/partials.go
index 500f5d1a3..b18e280ca 100644
--- a/tpl/partials/partials.go
+++ b/tpl/partials/partials.go
@@ -233,21 +233,14 @@ func (ns *Namespace) getOrCreate(ctx context.Context, key partialCacheKey, conte
}
}()
- // We may already have a write lock.
- hasLock := tpl.GetHasLockFromContext(ctx)
-
- if !hasLock {
- ns.cachedPartials.RLock()
- }
+ ns.cachedPartials.RLock()
p, ok := ns.cachedPartials.p[key]
- if !hasLock {
- ns.cachedPartials.RUnlock()
- }
+ ns.cachedPartials.RUnlock()
if ok {
if ns.deps.Metrics != nil {
ns.deps.Metrics.TrackValue(key.templateName(), p, true)
- // The templates that gets executed is measued in Execute.
+ // The templates that gets executed is measured in Execute.
// We need to track the time spent in the cache to
// get the totals correct.
ns.deps.Metrics.MeasureSince(key.templateName(), start)
@@ -256,21 +249,28 @@ func (ns *Namespace) getOrCreate(ctx context.Context, key partialCacheKey, conte
return p, nil
}
- if !hasLock {
- ns.cachedPartials.Lock()
- defer ns.cachedPartials.Unlock()
- ctx = tpl.SetHasLockInContext(ctx, true)
- }
-
- var name string
- name, p, err = ns.include(ctx, key.name, context)
+ // This needs to be done outside the lock.
+ // See #9588
+ _, p, err = ns.include(ctx, key.name, context)
if err != nil {
return nil, err
}
+ ns.cachedPartials.Lock()
+ defer ns.cachedPartials.Unlock()
+ // Double-check.
+ if p2, ok := ns.cachedPartials.p[key]; ok {
+ if ns.deps.Metrics != nil {
+ ns.deps.Metrics.TrackValue(key.templateName(), p, true)
+ ns.deps.Metrics.MeasureSince(key.templateName(), start)
+ }
+ return p2, nil
+
+ }
if ns.deps.Metrics != nil {
- ns.deps.Metrics.TrackValue(name, p, false)
+ ns.deps.Metrics.TrackValue(key.templateName(), p, false)
}
+
ns.cachedPartials.p[key] = p
return p, nil