Fix data race in non-renderable pages
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 18 Dec 2015 08:54:46 +0000 (09:54 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 18 Dec 2015 10:24:35 +0000 (11:24 +0100)
Fixes #1601

hugolib/page.go
hugolib/site.go
hugolib/site_test.go

index 13a3c283e71f09d553108cf859f29a13b82b951d..0a2a4a5e9a76040dee788a3de6bc120be7e5c9c5 100644 (file)
@@ -66,6 +66,7 @@ type Page struct {
        contentType         string
        renderable          bool
        Layout              string
+       layoutsCalculated   []string
        linkTitle           string
        frontmatter         []byte
        rawContent          []byte
@@ -288,6 +289,10 @@ func (p *Page) Section() string {
 }
 
 func (p *Page) layouts(l ...string) []string {
+       if len(p.layoutsCalculated) > 0 {
+               return p.layoutsCalculated
+       }
+
        if p.Layout != "" {
                return layouts(p.Type(), p.Layout)
        }
index 4e46879c91e52443c57c6c930eaff950359247df..aedba14ced2a287ec0f3c9ef3811d0eeeb25f3a6 100644 (file)
@@ -920,6 +920,26 @@ func (s *Site) RenderPages() error {
 
        procs := getGoMaxProcs()
 
+       // this cannot be fanned out to multiple Go routines
+       // See issue #1601
+       // TODO(bep): Check the IsRenderable logic.
+       for _, p := range s.Pages {
+               var layouts []string
+               if !p.IsRenderable() {
+                       self := "__" + p.TargetPath()
+                       _, err := s.Tmpl.New(self).Parse(string(p.Content))
+                       if err != nil {
+                               results <- err
+                               continue
+                       }
+                       layouts = append(layouts, self)
+               } else {
+                       layouts = append(layouts, p.layouts()...)
+                       layouts = append(layouts, "_default/single.html")
+               }
+               p.layoutsCalculated = layouts
+       }
+
        wg := &sync.WaitGroup{}
 
        for i := 0; i < procs*4; i++ {
@@ -951,22 +971,7 @@ func (s *Site) RenderPages() error {
 func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.WaitGroup) {
        defer wg.Done()
        for p := range pages {
-               var layouts []string
-
-               if !p.IsRenderable() {
-                       self := "__" + p.TargetPath()
-                       _, err := s.Tmpl.New(self).Parse(string(p.Content))
-                       if err != nil {
-                               results <- err
-                               continue
-                       }
-                       layouts = append(layouts, self)
-               } else {
-                       layouts = append(layouts, p.layouts()...)
-                       layouts = append(layouts, "_default/single.html")
-               }
-
-               err := s.renderAndWritePage("page "+p.FullFilePath(), p.TargetPath(), p, s.appendThemeTemplates(layouts)...)
+               err := s.renderAndWritePage("page "+p.FullFilePath(), p.TargetPath(), p, s.appendThemeTemplates(p.layouts())...)
                if err != nil {
                        results <- err
                }
index 1405210ccf234ec3c9f2b37d1bfe504904a6c2c0..1c0729c09b3128ede4f2ef1670a9f1bc33f3487f 100644 (file)
@@ -158,7 +158,7 @@ func TestRenderThing(t *testing.T) {
                templateName := fmt.Sprintf("foobar%d", i)
                err = s.addTemplate(templateName, test.template)
                if err != nil {
-                       t.Fatalf("Unable to add template")
+                       t.Fatalf("Unable to add template: %s", err)
                }
 
                p.Content = template.HTML(p.Content)
@@ -203,7 +203,7 @@ func TestRenderThingOrDefault(t *testing.T) {
                templateName := fmt.Sprintf("default%d", i)
                err = s.addTemplate(templateName, test.template)
                if err != nil {
-                       t.Fatalf("Unable to add template")
+                       t.Fatalf("Unable to add template: %s", err)
                }
 
                var err2 error