Only create LazyContentProvider for the non-rendering Site
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 11 Jan 2022 16:32:58 +0000 (17:32 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 12 Jan 2022 06:45:53 +0000 (07:45 +0100)
Which saves a fair amound of allocations:

```
gobench --package ./hugolib --bench "SiteNew/Regular_D" --base master
```

Before:

```
name                                  old time/op    new time/op    delta
SiteNew/Regular_Deep_content_tree-10    40.7ms ± 3%    41.2ms ± 1%    ~     (p=0.343 n=4+4)

name                                  old alloc/op   new alloc/op   delta
SiteNew/Regular_Deep_content_tree-10    27.7MB ± 0%    28.8MB ± 0%  +3.76%  (p=0.029 n=4+4)

name                                  old allocs/op  new allocs/op  delta
SiteNew/Regular_Deep_content_tree-10      304k ± 0%      329k ± 0%  +8.07%  (p=0.029 n=4+4)
```

After:

```
name                                  old time/op    new time/op    delta
SiteNew/Regular_Deep_content_tree-10    34.2ms ± 1%    34.7ms ± 1%    ~     (p=0.114 n=4+4)

name                                  old alloc/op   new alloc/op   delta
SiteNew/Regular_Deep_content_tree-10    27.7MB ± 0%    28.1MB ± 0%  +1.38%  (p=0.029 n=4+4)

name                                  old allocs/op  new allocs/op  delta
SiteNew/Regular_Deep_content_tree-10      304k ± 0%      314k ± 0%  +3.03%  (p=0.029 n=4+4)
```

Updates #8919

hugolib/page.go
resources/page/page_lazy_contentprovider.go

index 509a083e8264cd799d77c3cf03bcdef8545d8cb2..286d210752c55fd805ff1ac07d1f30648d3d08be 100644 (file)
@@ -940,20 +940,6 @@ func (p *pageState) shiftToOutputFormat(isRenderingSite bool, idx int) error {
                panic(fmt.Sprintf("pageOutput is nil for output idx %d", idx))
        }
 
-       // We attempt to assign pageContentOutputs while preparing each site
-       // for rendering and before rendering each site. This lets us share
-       // content between page outputs to conserve resources. But if a template
-       // unexpectedly calls a method of a ContentProvider that is not yet
-       // initialized, we assign a LazyContentProvider that performs the
-       // initialization just in time.
-       p.pageOutput.ContentProvider = page.NewLazyContentProvider(func() (page.ContentProvider, error) {
-               cp, err := newPageContentOutput(p, p.pageOutput)
-               if err != nil {
-                       return nil, err
-               }
-               return cp, nil
-       })
-
        // Reset any built paginator. This will trigger when re-rendering pages in
        // server mode.
        if isRenderingSite && p.pageOutput.paginator != nil && p.pageOutput.paginator.current != nil {
@@ -985,7 +971,24 @@ func (p *pageState) shiftToOutputFormat(isRenderingSite bool, idx int) error {
                        }
                }
                p.pageOutput.initContentProvider(cp)
-               p.pageOutput.cp = cp
+       } else {
+               // We attempt to assign pageContentOutputs while preparing each site
+               // for rendering and before rendering each site. This lets us share
+               // content between page outputs to conserve resources. But if a template
+               // unexpectedly calls a method of a ContentProvider that is not yet
+               // initialized, we assign a LazyContentProvider that performs the
+               // initialization just in time.
+               if lcp, ok := (p.pageOutput.ContentProvider.(*page.LazyContentProvider)); ok {
+                       lcp.Reset()
+               } else {
+                       p.pageOutput.ContentProvider = page.NewLazyContentProvider(func() (page.ContentProvider, error) {
+                               cp, err := newPageContentOutput(p, p.pageOutput)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               return cp, nil
+                       })
+               }
        }
 
        return nil
index d8d92d7cdc453a0f71e69ce21f0d3f8830f3bc46..a513a063a16f2850ee0c037339cf565585827b8a 100644 (file)
@@ -49,6 +49,10 @@ func NewLazyContentProvider(f func() (ContentProvider, error)) *LazyContentProvi
        return &lcp
 }
 
+func (lcp *LazyContentProvider) Reset() {
+       lcp.init.Reset()
+}
+
 func (lcp *LazyContentProvider) Content() (interface{}, error) {
        lcp.init.Do()
        return lcp.cp.Content()
@@ -67,35 +71,29 @@ func (lcp *LazyContentProvider) PlainWords() []string {
 func (lcp *LazyContentProvider) Summary() template.HTML {
        lcp.init.Do()
        return lcp.cp.Summary()
-
 }
 
 func (lcp *LazyContentProvider) Truncated() bool {
        lcp.init.Do()
        return lcp.cp.Truncated()
-
 }
 
 func (lcp *LazyContentProvider) FuzzyWordCount() int {
        lcp.init.Do()
        return lcp.cp.FuzzyWordCount()
-
 }
 
 func (lcp *LazyContentProvider) WordCount() int {
        lcp.init.Do()
        return lcp.cp.WordCount()
-
 }
 
 func (lcp *LazyContentProvider) ReadingTime() int {
        lcp.init.Do()
        return lcp.cp.ReadingTime()
-
 }
 
 func (lcp *LazyContentProvider) Len() int {
        lcp.init.Do()
        return lcp.cp.Len()
-
 }