mirror of
				https://github.com/TeaOSLab/EdgeNode.git
				synced 2025-11-04 16:00:25 +08:00 
			
		
		
		
	内容压缩增加繁忙(busy)检测
This commit is contained in:
		
							
								
								
									
										14
									
								
								internal/compressions/errors.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								internal/compressions/errors.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package compressions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var ErrIsBusy = errors.New("the system is busy for compression")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func CanIgnore(err error) bool {
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return errors.Is(err, ErrIsBusy)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -3,40 +3,58 @@
 | 
				
			|||||||
package compressions
 | 
					package compressions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeNode/internal/goman"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const maxWriterHits = 1 << 20
 | 
					const maxWriterHits = 1 << 20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var isBusy = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						if !teaconst.IsMain {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						goman.New(func() {
 | 
				
			||||||
 | 
							var ticker = time.NewTicker(100 * time.Millisecond)
 | 
				
			||||||
 | 
							for range ticker.C {
 | 
				
			||||||
 | 
								if isBusy {
 | 
				
			||||||
 | 
									isBusy = false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func IsBusy() bool {
 | 
				
			||||||
 | 
						return isBusy
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type WriterPool struct {
 | 
					type WriterPool struct {
 | 
				
			||||||
	m       map[int]chan Writer // level => chan Writer
 | 
						c       chan Writer // level => chan Writer
 | 
				
			||||||
	newFunc func(writer io.Writer, level int) (Writer, error)
 | 
						newFunc func(writer io.Writer, level int) (Writer, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewWriterPool(maxSize int, maxLevel int, newFunc func(writer io.Writer, level int) (Writer, error)) *WriterPool {
 | 
					func NewWriterPool(maxSize int, newFunc func(writer io.Writer, level int) (Writer, error)) *WriterPool {
 | 
				
			||||||
	if maxSize <= 0 {
 | 
						if maxSize <= 0 {
 | 
				
			||||||
		maxSize = 1024
 | 
							maxSize = 1024
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var m = map[int]chan Writer{}
 | 
					 | 
				
			||||||
	for i := 0; i <= maxLevel; i++ {
 | 
					 | 
				
			||||||
		m[i] = make(chan Writer, maxSize)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return &WriterPool{
 | 
						return &WriterPool{
 | 
				
			||||||
		m:       m,
 | 
							c:       make(chan Writer, maxSize),
 | 
				
			||||||
		newFunc: newFunc,
 | 
							newFunc: newFunc,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *WriterPool) Get(parentWriter io.Writer, level int) (Writer, error) {
 | 
					func (this *WriterPool) Get(parentWriter io.Writer, level int) (Writer, error) {
 | 
				
			||||||
	c, ok := this.m[level]
 | 
						if isBusy {
 | 
				
			||||||
	if !ok {
 | 
							return nil, ErrIsBusy
 | 
				
			||||||
		c = this.m[0]
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	select {
 | 
						select {
 | 
				
			||||||
	case writer := <-c:
 | 
						case writer := <-this.c:
 | 
				
			||||||
		writer.Reset(parentWriter)
 | 
							writer.Reset(parentWriter)
 | 
				
			||||||
		writer.ResetFinish()
 | 
							writer.ResetFinish()
 | 
				
			||||||
		return writer, nil
 | 
							return writer, nil
 | 
				
			||||||
@@ -56,13 +74,9 @@ func (this *WriterPool) Put(writer Writer) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var level = writer.Level()
 | 
					 | 
				
			||||||
	c, ok := this.m[level]
 | 
					 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		c = this.m[0]
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	select {
 | 
						select {
 | 
				
			||||||
	case c <- writer:
 | 
						case this.c <- writer:
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
 | 
							isBusy = true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,6 @@ package compressions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
 | 
						teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
 | 
				
			||||||
	"github.com/andybalholm/brotli"
 | 
					 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -15,7 +14,7 @@ func init() {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sharedBrotliWriterPool = NewWriterPool(CalculatePoolSize(), brotli.BestCompression, func(writer io.Writer, level int) (Writer, error) {
 | 
						sharedBrotliWriterPool = NewWriterPool(CalculatePoolSize(), func(writer io.Writer, level int) (Writer, error) {
 | 
				
			||||||
		return newBrotliWriter(writer)
 | 
							return newBrotliWriter(writer)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@
 | 
				
			|||||||
package compressions
 | 
					package compressions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"compress/flate"
 | 
					 | 
				
			||||||
	teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
 | 
						teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -15,7 +14,7 @@ func init() {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sharedDeflateWriterPool = NewWriterPool(CalculatePoolSize(), flate.BestCompression, func(writer io.Writer, level int) (Writer, error) {
 | 
						sharedDeflateWriterPool = NewWriterPool(CalculatePoolSize(), func(writer io.Writer, level int) (Writer, error) {
 | 
				
			||||||
		return newDeflateWriter(writer)
 | 
							return newDeflateWriter(writer)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@
 | 
				
			|||||||
package compressions
 | 
					package compressions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"compress/gzip"
 | 
					 | 
				
			||||||
	teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
 | 
						teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -15,8 +14,7 @@ func init() {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sharedGzipWriterPool = NewWriterPool(CalculatePoolSize(), func(writer io.Writer, level int) (Writer, error) {
 | 
				
			||||||
	sharedGzipWriterPool = NewWriterPool(CalculatePoolSize(), gzip.BestCompression, func(writer io.Writer, level int) (Writer, error) {
 | 
					 | 
				
			||||||
		return newGzipWriter(writer)
 | 
							return newGzipWriter(writer)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,6 @@ package compressions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
 | 
						teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
 | 
				
			||||||
	"github.com/klauspost/compress/zstd"
 | 
					 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -15,7 +14,7 @@ func init() {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sharedZSTDWriterPool = NewWriterPool(CalculatePoolSize(), int(zstd.SpeedBestCompression), func(writer io.Writer, level int) (Writer, error) {
 | 
						sharedZSTDWriterPool = NewWriterPool(CalculatePoolSize(), func(writer io.Writer, level int) (Writer, error) {
 | 
				
			||||||
		return newZSTDWriter(writer)
 | 
							return newZSTDWriter(writer)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -614,6 +614,11 @@ func (this *HTTPWriter) PrepareCompression(resp *http.Response, size int64) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 检查是否正繁忙
 | 
				
			||||||
 | 
						if compressions.IsBusy() {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 分区内容不压缩,防止读取失败
 | 
						// 分区内容不压缩,防止读取失败
 | 
				
			||||||
	if !this.compressionConfig.EnablePartialContent && this.StatusCode() == http.StatusPartialContent {
 | 
						if !this.compressionConfig.EnablePartialContent && this.StatusCode() == http.StatusPartialContent {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -733,7 +738,9 @@ func (this *HTTPWriter) PrepareCompression(resp *http.Response, size int64) {
 | 
				
			|||||||
	// compression writer
 | 
						// compression writer
 | 
				
			||||||
	compressionWriter, err := compressions.NewWriter(this.writer, compressionType, int(this.compressionConfig.Level))
 | 
						compressionWriter, err := compressions.NewWriter(this.writer, compressionType, int(this.compressionConfig.Level))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		remotelogs.Error("HTTP_WRITER", err.Error())
 | 
							if !compressions.CanIgnore(err) {
 | 
				
			||||||
 | 
								remotelogs.Error("HTTP_WRITER", "open compress writer failed: "+err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		header.Del("Content-Encoding")
 | 
							header.Del("Content-Encoding")
 | 
				
			||||||
		if this.compressionCacheWriter != nil {
 | 
							if this.compressionCacheWriter != nil {
 | 
				
			||||||
			_ = this.compressionCacheWriter.Discard()
 | 
								_ = this.compressionCacheWriter.Discard()
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user