diff --git a/Server.go b/Server.go index 477b8e8..6744860 100644 --- a/Server.go +++ b/Server.go @@ -8,7 +8,6 @@ import ( "os" "regexp" "strings" - "sync" "time" "github.com/boltdb/bolt" @@ -17,6 +16,8 @@ import ( var SERVER_HEADER string = `contented/0.0.0-dev` +const DEFAULT_MAX_CONCURRENT_THUMBS = 16 + type ServerPublicProperties struct { AppTitle string MaxUploadBytes int64 @@ -30,6 +31,7 @@ type ServerOptions struct { BandwidthLimit int64 TrustXForwardedFor bool EnableHomepage bool + MaxConcurrentThumbs int ServerPublicProperties } @@ -45,7 +47,7 @@ type Server struct { opts ServerOptions db *bolt.DB startTime time.Time - thumbnailSem sync.Mutex + thumbnailSem chan struct{} metadataBucket []byte } @@ -56,6 +58,17 @@ func NewServer(opts *ServerOptions) (*Server, error) { startTime: time.Now(), } + if s.opts.MaxConcurrentThumbs <= 0 { + s.opts.MaxConcurrentThumbs = DEFAULT_MAX_CONCURRENT_THUMBS // default + log.Printf("Allowing %d concurrent thumbnails", s.opts.MaxConcurrentThumbs) + } + + // "fill" the thumbnailer semaphore + s.thumbnailSem = make(chan struct{}, s.opts.MaxConcurrentThumbs) + for i := 0; i < s.opts.MaxConcurrentThumbs; i += 1 { + s.thumbnailSem <- struct{}{} + } + b, err := bolt.Open(opts.DBPath, 0644, bolt.DefaultOptions) if err != nil { return nil, err diff --git a/cmd/contented/main.go b/cmd/contented/main.go index d62c47c..9fdf4d6 100644 --- a/cmd/contented/main.go +++ b/cmd/contented/main.go @@ -21,6 +21,7 @@ func main() { trustXForwardedFor := flag.Bool("trustXForwardedFor", false, "Trust X-Forwarded-For reverse proxy headers") enableHomepage := flag.Bool("enableHomepage", true, "Enable homepage (disable for embedded use only)") diskFilesWorldReadable := flag.Bool("diskFilesWorldReadable", false, "Save files as 0644 instead of 0600") + maxConcurrentThumbs := flag.Int("concurrentthumbs", contented.DEFAULT_MAX_CONCURRENT_THUMBS, "Simultaneous thumbnail generation") flag.Parse() @@ -31,6 +32,7 @@ func main() { TrustXForwardedFor: *trustXForwardedFor, EnableHomepage: *enableHomepage, DiskFilesWorldReadable: *diskFilesWorldReadable, + MaxConcurrentThumbs: *maxConcurrentThumbs, ServerPublicProperties: contented.ServerPublicProperties{ AppTitle: *appTitle, MaxUploadBytes: int64(*maxUploadMb) * 1024 * 1024, diff --git a/thumb.go b/thumb.go index 556a208..b1bd24c 100644 --- a/thumb.go +++ b/thumb.go @@ -61,9 +61,9 @@ func (this *Server) handleThumb(w http.ResponseWriter, r *http.Request, thumbnai return } - // Only calculate one thumbnail at a time - this.thumbnailSem.Lock() - defer this.thumbnailSem.Unlock() + // Only a limited number of thumbnails can be generated concurrently + <-this.thumbnailSem + defer func() { this.thumbnailSem <- struct{}{} }() if ctx.Err() != nil { // The request was already cancelled