-
-
Notifications
You must be signed in to change notification settings - Fork 7.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure page translation CPs are initialized #9398
Conversation
hugolib/page.go
Outdated
if !ok { | ||
continue | ||
} | ||
if tp.pageOutput.cp == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this.
But I don't think we can solve this like this. Most notably is the data race which, if it's not already failing the build, it will if you move the .Translations
into the single template.
I suspect that the cleanest, working solution we will find without doing too much work is to expand on the patch we added a few days ago: Make sure that the lazy content provider is triggered on all access to cp
(including RenderString
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback. Would you mind explaining the data race a bit more? Which goroutines, processes, I/O, etc. would be racing?
I'll spend some time early this week implementing the approach you've suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- We render pages in parallel.
- Given the below,
AllTranslations
may be called from multiple go routines on the same page. - Any of the code lines reading or writing mutable page state below will be a potential data race (e.g.
if tp.pageOutput.cp == nil
andtp.initContentProvider(cp)
). Go's race detector will fail the tests when run withgo test -race
(which we do on the CI server), but I guess you need to have test cases that trigger it.
func (p *pageState) AllTranslations() page.Pages {
p.s.h.init.translations.Do()
// Hugo attempts to reuse content providers while preparing each page for
// rendering. This approach means that sometimes, content providers for
// translations are not initialized. If needed, initialize them here.
for _, tr := range p.allTranslations {
tp, ok := tr.(*pageState)
if !ok {
continue
}
if tp.pageOutput.cp == nil {
cp, err := newPageContentOutput(tp, tp.pageOutput)
if err != nil {
// This will be caught by texttemplate.safeCall
panic(fmt.Errorf("error rendering page translation: %w", err))
}
tp.initContentProvider(cp)
}
}
return p.allTranslations
}
501015e
to
10118f4
Compare
@bep I've suggested initializing a |
hugolib/page.go
Outdated
var cp *pageContentOutput | ||
|
||
// If the current content provider is not yet initialized, do so now. | ||
if lcp, ok := p.pageOutput.ContentProvider.(*page.LazyContentProvider); ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this is conceptually what we need, but I would love if we could do this in one place. I think that if we use the same "interface approach" for RenderString (and potentially others) and make LazyContentProvider implement that interface, that should work.
I have some time today and will look closer at this PR -- again, much appreciated. |
10118f4
to
c67e487
Compare
@ptgott I have added a commit to your PR which is a little bit more elaborate, but it's just moving the |
c67e487
to
490deb6
Compare
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
PR #9342 introduced a regression in which calling .Translations in a
template and calling RenderString on a translated Page caused a nil
pointer dereference. The issue was that some Pages returned from
.Translations had a nil cp field at the time the calling template was
being executed.
While PR #9342 had attempted to ensure that all ContentProviders were
initialized for translations at build time, it only performed the
initialization for receivers of ContentProvider methods such as
.Summary. However, the ContentProvider's *pageState.pageOutput.cp would
remain uninitialized, causing the nil pointer dereference.
This change edits the .Translations and .AllTranslations methods to
ensure that all of a page's translations have an initialized
content provider in time for a template to be executed.
Since LazyContentProvider is no longer needed with this approach, this
change also reverts the following commits:
Fixes #9383