mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
Misc resource fixes/improvements
* Add --pprof flag to server to enable profile debugging. * Don't cache the resource content, it seem to eat memory on bigger sites. * Keep --printMemoryUsag running in server Fixes #11974
This commit is contained in:
parent
d0788b96ae
commit
2873324898
7 changed files with 58 additions and 65 deletions
|
@ -22,6 +22,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
@ -341,8 +342,12 @@ func (r *rootCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args
|
||||||
if r.buildWatch {
|
if r.buildWatch {
|
||||||
defer r.timeTrack(time.Now(), "Built")
|
defer r.timeTrack(time.Now(), "Built")
|
||||||
}
|
}
|
||||||
err := b.build()
|
close, err := b.build()
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
close()
|
||||||
|
return nil
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -411,6 +416,7 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
|
||||||
MaxEntries: 1,
|
MaxEntries: 1,
|
||||||
OnEvict: func(key int32, value *hugolib.HugoSites) {
|
OnEvict: func(key int32, value *hugolib.HugoSites) {
|
||||||
value.Close()
|
value.Close()
|
||||||
|
runtime.GC()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -361,34 +361,32 @@ func (c *hugoBuilder) newWatcher(pollIntervalStr string, dirList ...string) (*wa
|
||||||
return watcher, nil
|
return watcher, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *hugoBuilder) build() error {
|
func (c *hugoBuilder) build() (func(), error) {
|
||||||
stopProfiling, err := c.initProfiling()
|
stopProfiling, err := c.initProfiling()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if stopProfiling != nil {
|
|
||||||
stopProfiling()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := c.fullBuild(false); err != nil {
|
if err := c.fullBuild(false); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.r.quiet {
|
if !c.r.quiet {
|
||||||
c.r.Println()
|
c.r.Println()
|
||||||
h, err := c.hugo()
|
h, err := c.hugo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
h.PrintProcessingStats(os.Stdout)
|
h.PrintProcessingStats(os.Stdout)
|
||||||
c.r.Println()
|
c.r.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return func() {
|
||||||
|
if stopProfiling != nil {
|
||||||
|
stopProfiling()
|
||||||
|
}
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *hugoBuilder) buildSites(noBuildLock bool) (err error) {
|
func (c *hugoBuilder) buildSites(noBuildLock bool) (err error) {
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
_ "net/http/pprof"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
@ -451,6 +452,7 @@ type serverCommand struct {
|
||||||
tlsCertFile string
|
tlsCertFile string
|
||||||
tlsKeyFile string
|
tlsKeyFile string
|
||||||
tlsAuto bool
|
tlsAuto bool
|
||||||
|
pprof bool
|
||||||
serverPort int
|
serverPort int
|
||||||
liveReloadPort int
|
liveReloadPort int
|
||||||
serverWatch bool
|
serverWatch bool
|
||||||
|
@ -465,6 +467,11 @@ func (c *serverCommand) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *serverCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args []string) error {
|
func (c *serverCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args []string) error {
|
||||||
|
if c.pprof {
|
||||||
|
go func() {
|
||||||
|
http.ListenAndServe("localhost:8080", nil)
|
||||||
|
}()
|
||||||
|
}
|
||||||
// Watch runs its own server as part of the routine
|
// Watch runs its own server as part of the routine
|
||||||
if c.serverWatch {
|
if c.serverWatch {
|
||||||
|
|
||||||
|
@ -487,15 +494,19 @@ func (c *serverCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var close func()
|
||||||
err := func() error {
|
err := func() error {
|
||||||
defer c.r.timeTrack(time.Now(), "Built")
|
defer c.r.timeTrack(time.Now(), "Built")
|
||||||
err := c.build()
|
var err error
|
||||||
|
close, err = c.build()
|
||||||
return err
|
return err
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer close()
|
||||||
|
|
||||||
return c.serve()
|
return c.serve()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,6 +531,7 @@ of a second, you will be able to save and see your changes nearly instantly.`
|
||||||
cmd.Flags().StringVarP(&c.tlsCertFile, "tlsCertFile", "", "", "path to TLS certificate file")
|
cmd.Flags().StringVarP(&c.tlsCertFile, "tlsCertFile", "", "", "path to TLS certificate file")
|
||||||
cmd.Flags().StringVarP(&c.tlsKeyFile, "tlsKeyFile", "", "", "path to TLS key file")
|
cmd.Flags().StringVarP(&c.tlsKeyFile, "tlsKeyFile", "", "", "path to TLS key file")
|
||||||
cmd.Flags().BoolVar(&c.tlsAuto, "tlsAuto", false, "generate and use locally-trusted certificates.")
|
cmd.Flags().BoolVar(&c.tlsAuto, "tlsAuto", false, "generate and use locally-trusted certificates.")
|
||||||
|
cmd.Flags().BoolVar(&c.pprof, "pprof", false, "enable the pprof server (port 8080)")
|
||||||
cmd.Flags().BoolVarP(&c.serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
|
cmd.Flags().BoolVarP(&c.serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
|
||||||
cmd.Flags().BoolVar(&c.noHTTPCache, "noHTTPCache", false, "prevent HTTP caching")
|
cmd.Flags().BoolVar(&c.noHTTPCache, "noHTTPCache", false, "prevent HTTP caching")
|
||||||
cmd.Flags().BoolVarP(&c.serverAppend, "appendPort", "", true, "append port to baseURL")
|
cmd.Flags().BoolVarP(&c.serverAppend, "appendPort", "", true, "append port to baseURL")
|
||||||
|
|
|
@ -720,9 +720,11 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
|
||||||
h.pageTrees.treeTaxonomyEntries.DeletePrefix("")
|
h.pageTrees.treeTaxonomyEntries.DeletePrefix("")
|
||||||
|
|
||||||
if delete {
|
if delete {
|
||||||
|
|
||||||
_, ok := h.pageTrees.treePages.LongestPrefixAll(pathInfo.Base())
|
_, ok := h.pageTrees.treePages.LongestPrefixAll(pathInfo.Base())
|
||||||
if ok {
|
if ok {
|
||||||
h.pageTrees.treePages.DeleteAll(pathInfo.Base())
|
h.pageTrees.treePages.DeleteAll(pathInfo.Base())
|
||||||
|
h.pageTrees.resourceTrees.DeleteAll(pathInfo.Base())
|
||||||
if pathInfo.IsBundle() {
|
if pathInfo.IsBundle() {
|
||||||
// Assume directory removed.
|
// Assume directory removed.
|
||||||
h.pageTrees.treePages.DeletePrefixAll(pathInfo.Base() + "/")
|
h.pageTrees.treePages.DeletePrefixAll(pathInfo.Base() + "/")
|
||||||
|
|
|
@ -101,10 +101,10 @@ func TestRebuildEditTextFileInBranchBundle(t *testing.T) {
|
||||||
|
|
||||||
func TestRebuildRenameTextFileInLeafBundle(t *testing.T) {
|
func TestRebuildRenameTextFileInLeafBundle(t *testing.T) {
|
||||||
b := TestRunning(t, rebuildFilesSimple)
|
b := TestRunning(t, rebuildFilesSimple)
|
||||||
b.AssertFileContent("public/mysection/mysectionbundle/index.html", "My Section Bundle Text 2 Content.")
|
b.AssertFileContent("public/mysection/mysectionbundle/index.html", "My Section Bundle Text 2 Content.", "Len Resources: 2|")
|
||||||
|
|
||||||
b.RenameFile("content/mysection/mysectionbundle/mysectionbundletext.txt", "content/mysection/mysectionbundle/mysectionbundletext2.txt").Build()
|
b.RenameFile("content/mysection/mysectionbundle/mysectionbundletext.txt", "content/mysection/mysectionbundle/mysectionbundletext2.txt").Build()
|
||||||
b.AssertFileContent("public/mysection/mysectionbundle/index.html", "mysectionbundletext2", "My Section Bundle Text 2 Content.")
|
b.AssertFileContent("public/mysection/mysectionbundle/index.html", "mysectionbundletext2", "My Section Bundle Text 2 Content.", "Len Resources: 2|")
|
||||||
b.AssertRenderCountPage(3)
|
b.AssertRenderCountPage(3)
|
||||||
b.AssertRenderCountContent(3)
|
b.AssertRenderCountContent(3)
|
||||||
}
|
}
|
||||||
|
|
|
@ -343,7 +343,7 @@ func GetTestInfoForResource(r resource.Resource) GenericResourceTestInfo {
|
||||||
|
|
||||||
// genericResource represents a generic linkable resource.
|
// genericResource represents a generic linkable resource.
|
||||||
type genericResource struct {
|
type genericResource struct {
|
||||||
*resourceContent
|
publishInit *sync.Once
|
||||||
|
|
||||||
sd ResourceSourceDescriptor
|
sd ResourceSourceDescriptor
|
||||||
paths internal.ResourcePaths
|
paths internal.ResourcePaths
|
||||||
|
@ -412,11 +412,18 @@ func (l *genericResource) cloneTo(targetPath string) resource.Resource {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *genericResource) Content(context.Context) (any, error) {
|
func (l *genericResource) Content(context.Context) (any, error) {
|
||||||
if err := l.initContent(); err != nil {
|
r, err := l.ReadSeekCloser()
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
return l.content, nil
|
var b []byte
|
||||||
|
b, err = io.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *genericResource) Err() resource.ResourceError {
|
func (r *genericResource) Err() resource.ResourceError {
|
||||||
|
@ -527,28 +534,6 @@ func (l *genericResource) Title() string {
|
||||||
return l.title
|
return l.title
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *genericResource) initContent() error {
|
|
||||||
var err error
|
|
||||||
l.contentInit.Do(func() {
|
|
||||||
var r hugio.ReadSeekCloser
|
|
||||||
r, err = l.ReadSeekCloser()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer r.Close()
|
|
||||||
|
|
||||||
var b []byte
|
|
||||||
b, err = io.ReadAll(r)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
l.content = string(b)
|
|
||||||
})
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *genericResource) getSpec() *Spec {
|
func (l *genericResource) getSpec() *Spec {
|
||||||
return l.spec
|
return l.spec
|
||||||
}
|
}
|
||||||
|
@ -588,12 +573,9 @@ func (rc *genericResource) cloneWithUpdates(u *transformationUpdate) (baseResour
|
||||||
r := rc.clone()
|
r := rc.clone()
|
||||||
|
|
||||||
if u.content != nil {
|
if u.content != nil {
|
||||||
r.contentInit.Do(func() {
|
|
||||||
r.content = *u.content
|
|
||||||
r.sd.OpenReadSeekCloser = func() (hugio.ReadSeekCloser, error) {
|
r.sd.OpenReadSeekCloser = func() (hugio.ReadSeekCloser, error) {
|
||||||
return hugio.NewReadSeekerNoOpCloserFromString(r.content), nil
|
return hugio.NewReadSeekerNoOpCloserFromString(*u.content), nil
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r.sd.MediaType = u.mediaType
|
r.sd.MediaType = u.mediaType
|
||||||
|
@ -620,7 +602,7 @@ func (rc *genericResource) cloneWithUpdates(u *transformationUpdate) (baseResour
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l genericResource) clone() *genericResource {
|
func (l genericResource) clone() *genericResource {
|
||||||
l.resourceContent = &resourceContent{}
|
l.publishInit = &sync.Once{}
|
||||||
return &l
|
return &l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,13 +615,6 @@ type targetPather interface {
|
||||||
TargetPath() string
|
TargetPath() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type resourceContent struct {
|
|
||||||
content string
|
|
||||||
contentInit sync.Once
|
|
||||||
|
|
||||||
publishInit sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
type resourceHash struct {
|
type resourceHash struct {
|
||||||
value string
|
value string
|
||||||
size int64
|
size int64
|
||||||
|
|
|
@ -165,13 +165,13 @@ func (r *Spec) NewResource(rd ResourceSourceDescriptor) (resource.Resource, erro
|
||||||
gr := &genericResource{
|
gr := &genericResource{
|
||||||
Staler: &AtomicStaler{},
|
Staler: &AtomicStaler{},
|
||||||
h: &resourceHash{},
|
h: &resourceHash{},
|
||||||
|
publishInit: &sync.Once{},
|
||||||
paths: rp,
|
paths: rp,
|
||||||
spec: r,
|
spec: r,
|
||||||
sd: rd,
|
sd: rd,
|
||||||
params: make(map[string]any),
|
params: make(map[string]any),
|
||||||
name: rd.Name,
|
name: rd.Name,
|
||||||
title: rd.Name,
|
title: rd.Name,
|
||||||
resourceContent: &resourceContent{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if rd.MediaType.MainType == "image" {
|
if rd.MediaType.MainType == "image" {
|
||||||
|
|
Loading…
Reference in a new issue