gallery: try to avoid OOM while thumbnailing

This commit is contained in:
Přemysl Eric Janouch 2024-01-20 19:58:42 +01:00
parent de0dc58b99
commit d37e9e821a
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 27 additions and 3 deletions

30
main.go
View File

@ -41,6 +41,9 @@ import (
"golang.org/x/image/webp" "golang.org/x/image/webp"
) )
// #include <unistd.h>
import "C"
var ( var (
db *sql.DB // sqlite database db *sql.DB // sqlite database
galleryDirectory string // gallery directory galleryDirectory string // gallery directory
@ -2176,6 +2179,11 @@ func makeThumbnail(load bool, pathImage, pathThumb string) (
return 0, 0, err return 0, 0, err
} }
// This is still too much, but it will be effective enough.
memoryLimit := strconv.FormatInt(
int64(C.sysconf(C._SC_PHYS_PAGES)*C.sysconf(C._SC_PAGE_SIZE))/
int64(len(taskSemaphore)), 10)
// Create a normalized thumbnail. Since we don't particularly need // Create a normalized thumbnail. Since we don't particularly need
// any complex processing, such as surrounding metadata, // any complex processing, such as surrounding metadata,
// simply push it through ImageMagick. // simply push it through ImageMagick.
@ -2189,8 +2197,17 @@ func makeThumbnail(load bool, pathImage, pathThumb string) (
// //
// TODO: See if we can optimize resulting WebP animations. // TODO: See if we can optimize resulting WebP animations.
// (Do -layers optimize* apply to this format at all?) // (Do -layers optimize* apply to this format at all?)
cmd := exec.Command("magick", "-limit", "thread", "1", pathImage, cmd := exec.Command("magick", "-limit", "thread", "1",
"-coalesce", "-colorspace", "RGB", "-auto-orient", "-strip",
// Do not invite the OOM killer, a particularly unpleasant guest.
"-limit", "memory", memoryLimit,
// ImageMagick creates files in /tmp, but that tends to be a tmpfs,
// which is backed by memory. The path could also be moved elsewhere:
// -define registry:temporary-path=/var/tmp
"-limit", "map", "0", "-limit", "disk", "0",
pathImage, "-coalesce", "-colorspace", "RGB", "-auto-orient", "-strip",
"-resize", "256x128>", "-colorspace", "sRGB", "-resize", "256x128>", "-colorspace", "sRGB",
"-format", "%w %h", "+write", pathThumb, "-delete", "1--1", "info:") "-format", "%w %h", "+write", pathThumb, "-delete", "1--1", "info:")
@ -2478,6 +2495,8 @@ func usage() {
} }
func main() { func main() {
threads := flag.Int("threads", -1, "level of parallelization")
// This implements the -h switch for us by default. // This implements the -h switch for us by default.
// The rest of the handling here closely follows what flag does internally. // The rest of the handling here closely follows what flag does internally.
flag.Usage = usage flag.Usage = usage
@ -2503,7 +2522,12 @@ func main() {
fs.PrintDefaults() fs.PrintDefaults()
} }
taskSemaphore = newSemaphore(runtime.NumCPU()) if *threads > 0 {
taskSemaphore = newSemaphore(*threads)
} else {
taskSemaphore = newSemaphore(runtime.NumCPU())
}
err := cmd.handler(fs, flag.Args()[1:]) err := cmd.handler(fs, flag.Args()[1:])
// Note that the database object has a closing finalizer, // Note that the database object has a closing finalizer,