From d35e0e0d0ba2b9c8e9dbc3061462c6c321dae3ce Mon Sep 17 00:00:00 2001 From: Nova Kwok Date: Fri, 29 Dec 2023 19:38:05 +0800 Subject: [PATCH] Lock on convert (#307) * Lock on convert * Fix typo * Should use debug for convert lock * Bump to 0.10.5 --- config/config.go | 3 ++- encoder/encoder.go | 26 ++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/config/config.go b/config/config.go index 4157da374..50c875c6c 100644 --- a/config/config.go +++ b/config/config.go @@ -46,8 +46,9 @@ var ( ProxyMode bool Prefetch bool Config = NewWebPConfig() - Version = "0.10.4" + Version = "0.10.5" WriteLock = cache.New(5*time.Minute, 10*time.Minute) + ConvertLock = cache.New(5*time.Minute, 10*time.Minute) RemoteRaw = "./remote-raw" Metadata = "./metadata" LocalHostAlias = "local" diff --git a/encoder/encoder.go b/encoder/encoder.go index 7e20cf992..c4b77b301 100644 --- a/encoder/encoder.go +++ b/encoder/encoder.go @@ -6,6 +6,7 @@ import ( "runtime" "strings" "sync" + "time" "webp_server_go/config" "webp_server_go/helper" @@ -33,7 +34,24 @@ func init() { } func ConvertFilter(rawPath, avifPath, webpPath string, extraParams config.ExtraParams, c chan int) { - // all absolute paths + // Wait for the conversion to complete and return the converted image + retryDelay := 100 * time.Millisecond // Initial retry delay + + for { + if _, found := config.ConvertLock.Get(rawPath); found { + log.Debugf("file %s is locked under conversion, retrying in %s", rawPath, retryDelay) + time.Sleep(retryDelay) + } else { + // The lock is released, indicating that the conversion is complete + break + } + } + + // If there is a lock here, it means that another thread is converting the same image + // Lock rawPath to prevent concurrent conversion + config.ConvertLock.Set(rawPath, true, -1) + defer config.ConvertLock.Delete(rawPath) + var wg sync.WaitGroup wg.Add(2) if !helper.ImageExists(avifPath) && config.Config.EnableAVIF { @@ -77,9 +95,9 @@ func convertImage(rawPath, optimizedPath, imageType string, extraParams config.E var convertedRaw, converted = ConvertRawToJPG(rawPath, optimizedPath) // If converted, use converted file as raw if converted { - // Use converted file(JPG) as raw input for further convertion + // Use converted file(JPG) as raw input for further conversion rawPath = convertedRaw - // Remove converted file after convertion + // Remove converted file after conversion defer func() { log.Infoln("Removing intermediate conversion file:", convertedRaw) err := os.Remove(convertedRaw) @@ -105,6 +123,7 @@ func convertImage(rawPath, optimizedPath, imageType string, extraParams config.E case "avif": err = avifEncoder(img, rawPath, optimizedPath, extraParams) } + return err } @@ -179,7 +198,6 @@ func webpEncoder(img *vips.ImageRef, rawPath string, optimizedPath string, extra } } buf, _, err = img.ExportWebp(&ep) - } if err != nil {