mirror of
				https://github.com/TeaOSLab/EdgeNode.git
				synced 2025-11-04 16:00:25 +08:00 
			
		
		
		
	优化Partial Content缓存
This commit is contained in:
		@@ -88,6 +88,23 @@ func (this *PartialRanges) Contains(begin int64, end int64) bool {
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Nearest 查找最近的某个范围
 | 
				
			||||||
 | 
					func (this *PartialRanges) Nearest(begin int64, end int64) (r [2]int64, ok bool) {
 | 
				
			||||||
 | 
						if len(this.Ranges) == 0 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO 使用二分法查找改进性能
 | 
				
			||||||
 | 
						for _, r2 := range this.Ranges {
 | 
				
			||||||
 | 
							if r2[0] <= begin && r2[1] > begin {
 | 
				
			||||||
 | 
								r = [2]int64{begin, this.min(end, r2[1])}
 | 
				
			||||||
 | 
								ok = true
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AsJSON 转换为JSON
 | 
					// AsJSON 转换为JSON
 | 
				
			||||||
func (this *PartialRanges) AsJSON() ([]byte, error) {
 | 
					func (this *PartialRanges) AsJSON() ([]byte, error) {
 | 
				
			||||||
	return json.Marshal(this)
 | 
						return json.Marshal(this)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -97,6 +97,34 @@ func TestNewPartialRanges5(t *testing.T) {
 | 
				
			|||||||
	logs.PrintAsJSON(r.Ranges, t)
 | 
						logs.PrintAsJSON(r.Ranges, t)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNewPartialRanges_Nearest(t *testing.T) {
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// nearby
 | 
				
			||||||
 | 
							var r = caches.NewPartialRanges()
 | 
				
			||||||
 | 
							r.Add(301, 400)
 | 
				
			||||||
 | 
							r.Add(401, 500)
 | 
				
			||||||
 | 
							r.Add(501, 600)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Log(r.Nearest(100, 200))
 | 
				
			||||||
 | 
							t.Log(r.Nearest(300, 350))
 | 
				
			||||||
 | 
							t.Log(r.Nearest(302, 350))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// nearby
 | 
				
			||||||
 | 
							var r = caches.NewPartialRanges()
 | 
				
			||||||
 | 
							r.Add(301, 400)
 | 
				
			||||||
 | 
							r.Add(450, 500)
 | 
				
			||||||
 | 
							r.Add(550, 600)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Log(r.Nearest(100, 200))
 | 
				
			||||||
 | 
							t.Log(r.Nearest(300, 350))
 | 
				
			||||||
 | 
							t.Log(r.Nearest(302, 350))
 | 
				
			||||||
 | 
							t.Log(r.Nearest(302, 440))
 | 
				
			||||||
 | 
							t.Log(r.Nearest(302, 1000))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNewPartialRanges_AsJSON(t *testing.T) {
 | 
					func TestNewPartialRanges_AsJSON(t *testing.T) {
 | 
				
			||||||
	var r = caches.NewPartialRanges()
 | 
						var r = caches.NewPartialRanges()
 | 
				
			||||||
	for j := 0; j < 1000; j++ {
 | 
						for j := 0; j < 1000; j++ {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ type Reader interface {
 | 
				
			|||||||
	BodySize() int64
 | 
						BodySize() int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ContainsRange 是否包含某个区间内容
 | 
						// ContainsRange 是否包含某个区间内容
 | 
				
			||||||
	ContainsRange(r rangeutils.Range) bool
 | 
						ContainsRange(r rangeutils.Range) (r2 rangeutils.Range, ok bool)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Close 关闭
 | 
						// Close 关闭
 | 
				
			||||||
	Close() error
 | 
						Close() error
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -334,8 +334,8 @@ func (this *FileReader) ReadBodyRange(buf []byte, start int64, end int64, callba
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ContainsRange 是否包含某些区间内容
 | 
					// ContainsRange 是否包含某些区间内容
 | 
				
			||||||
func (this *FileReader) ContainsRange(r rangeutils.Range) bool {
 | 
					func (this *FileReader) ContainsRange(r rangeutils.Range) (r2 rangeutils.Range, ok bool) {
 | 
				
			||||||
	return true
 | 
						return r, true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *FileReader) Close() error {
 | 
					func (this *FileReader) Close() error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -199,8 +199,8 @@ func (this *MemoryReader) ReadBodyRange(buf []byte, start int64, end int64, call
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ContainsRange 是否包含某些区间内容
 | 
					// ContainsRange 是否包含某些区间内容
 | 
				
			||||||
func (this *MemoryReader) ContainsRange(r rangeutils.Range) bool {
 | 
					func (this *MemoryReader) ContainsRange(r rangeutils.Range) (r2 rangeutils.Range, ok bool) {
 | 
				
			||||||
	return true
 | 
						return r, true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *MemoryReader) Close() error {
 | 
					func (this *MemoryReader) Close() error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -113,8 +113,8 @@ func (this *PartialFileReader) InitAutoDiscard(autoDiscard bool) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ContainsRange 是否包含某些区间内容
 | 
					// ContainsRange 是否包含某些区间内容
 | 
				
			||||||
// 这里的 r 是已经经过格式化的
 | 
					// 这里的 r 是已经经过格式化的
 | 
				
			||||||
func (this *PartialFileReader) ContainsRange(r rangeutils.Range) bool {
 | 
					func (this *PartialFileReader) ContainsRange(r rangeutils.Range) (r2 rangeutils.Range, ok bool) {
 | 
				
			||||||
	return this.ranges.Contains(r.Start(), r.End())
 | 
						return this.ranges.Nearest(r.Start(), r.End())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// MaxLength 获取区间最大长度
 | 
					// MaxLength 获取区间最大长度
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -241,13 +241,15 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// 检查正常的文件
 | 
						// 检查正常的文件
 | 
				
			||||||
	var isPartialCache = false
 | 
						var isPartialCache = false
 | 
				
			||||||
 | 
						var partialRanges []rangeutils.Range
 | 
				
			||||||
	if reader == nil {
 | 
						if reader == nil {
 | 
				
			||||||
		reader, err = storage.OpenReader(key, useStale, false)
 | 
							reader, err = storage.OpenReader(key, useStale, false)
 | 
				
			||||||
		if err != nil && this.cacheRef.AllowPartialContent {
 | 
							if err != nil && this.cacheRef.AllowPartialContent {
 | 
				
			||||||
			pReader := this.tryPartialReader(storage, key, useStale, rangeHeader)
 | 
								pReader, ranges := this.tryPartialReader(storage, key, useStale, rangeHeader)
 | 
				
			||||||
			if pReader != nil {
 | 
								if pReader != nil {
 | 
				
			||||||
				isPartialCache = true
 | 
									isPartialCache = true
 | 
				
			||||||
				reader = pReader
 | 
									reader = pReader
 | 
				
			||||||
 | 
									partialRanges = ranges
 | 
				
			||||||
				err = nil
 | 
									err = nil
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -414,7 +416,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// 支持Range
 | 
							// 支持Range
 | 
				
			||||||
		var ranges = []rangeutils.Range{}
 | 
							var ranges = partialRanges
 | 
				
			||||||
		if supportRange {
 | 
							if supportRange {
 | 
				
			||||||
			if len(rangeHeader) > 0 {
 | 
								if len(rangeHeader) > 0 {
 | 
				
			||||||
				if fileSize == 0 {
 | 
									if fileSize == 0 {
 | 
				
			||||||
@@ -423,14 +425,15 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
 | 
				
			|||||||
					return true
 | 
										return true
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				set, ok := httpRequestParseRangeHeader(rangeHeader)
 | 
									if len(ranges) == 0 {
 | 
				
			||||||
				if !ok {
 | 
										ranges, ok = httpRequestParseRangeHeader(rangeHeader)
 | 
				
			||||||
					this.processResponseHeaders(http.StatusRequestedRangeNotSatisfiable)
 | 
										if !ok {
 | 
				
			||||||
					this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
 | 
											this.processResponseHeaders(http.StatusRequestedRangeNotSatisfiable)
 | 
				
			||||||
					return true
 | 
											this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
 | 
				
			||||||
 | 
											return true
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if len(set) > 0 {
 | 
									if len(ranges) > 0 {
 | 
				
			||||||
					ranges = set
 | 
					 | 
				
			||||||
					for k, r := range ranges {
 | 
										for k, r := range ranges {
 | 
				
			||||||
						r2, ok := r.Convert(fileSize)
 | 
											r2, ok := r.Convert(fileSize)
 | 
				
			||||||
						if !ok {
 | 
											if !ok {
 | 
				
			||||||
@@ -570,26 +573,26 @@ func (this *HTTPRequest) addExpiresHeader(expiresAt int64) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 尝试读取区间缓存
 | 
					// 尝试读取区间缓存
 | 
				
			||||||
func (this *HTTPRequest) tryPartialReader(storage caches.StorageInterface, key string, useStale bool, rangeHeader string) caches.Reader {
 | 
					func (this *HTTPRequest) tryPartialReader(storage caches.StorageInterface, key string, useStale bool, rangeHeader string) (caches.Reader, []rangeutils.Range) {
 | 
				
			||||||
	// 尝试读取Partial cache
 | 
						// 尝试读取Partial cache
 | 
				
			||||||
	if len(rangeHeader) == 0 {
 | 
						if len(rangeHeader) == 0 {
 | 
				
			||||||
		return nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ranges, ok := httpRequestParseRangeHeader(rangeHeader)
 | 
						ranges, ok := httpRequestParseRangeHeader(rangeHeader)
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		return nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pReader, pErr := storage.OpenReader(key+caches.SuffixPartial, useStale, true)
 | 
						pReader, pErr := storage.OpenReader(key+caches.SuffixPartial, useStale, true)
 | 
				
			||||||
	if pErr != nil {
 | 
						if pErr != nil {
 | 
				
			||||||
		return nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	partialReader, ok := pReader.(*caches.PartialFileReader)
 | 
						partialReader, ok := pReader.(*caches.PartialFileReader)
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		_ = pReader.Close()
 | 
							_ = pReader.Close()
 | 
				
			||||||
		return nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	var isOk = false
 | 
						var isOk = false
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
@@ -599,16 +602,18 @@ func (this *HTTPRequest) tryPartialReader(storage caches.StorageInterface, key s
 | 
				
			|||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 检查范围
 | 
						// 检查范围
 | 
				
			||||||
	for _, r := range ranges {
 | 
						for index, r := range ranges {
 | 
				
			||||||
		r1, ok := r.Convert(partialReader.MaxLength())
 | 
							r1, ok := r.Convert(partialReader.MaxLength())
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return nil
 | 
								return nil, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !partialReader.ContainsRange(r1) {
 | 
							r2, ok := partialReader.ContainsRange(r1)
 | 
				
			||||||
			return nil
 | 
							if !ok {
 | 
				
			||||||
 | 
								return nil, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							ranges[index] = r2
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	isOk = true
 | 
						isOk = true
 | 
				
			||||||
	return pReader
 | 
						return pReader, ranges
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,7 +65,8 @@ type HTTPWriter struct {
 | 
				
			|||||||
	isFinished bool // 是否已完成
 | 
						isFinished bool // 是否已完成
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Partial
 | 
						// Partial
 | 
				
			||||||
	isPartial bool
 | 
						isPartial        bool
 | 
				
			||||||
 | 
						partialFileIsNew bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// WebP
 | 
						// WebP
 | 
				
			||||||
	webpIsEncoding        bool
 | 
						webpIsEncoding        bool
 | 
				
			||||||
@@ -284,6 +285,10 @@ func (this *HTTPWriter) PrepareCache(resp *http.Response, size int64) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	this.cacheWriter = cacheWriter
 | 
						this.cacheWriter = cacheWriter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if this.isPartial {
 | 
				
			||||||
 | 
							this.partialFileIsNew = cacheWriter.(*caches.PartialFileWriter).IsNew()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 写入Header
 | 
						// 写入Header
 | 
				
			||||||
	for k, v := range this.Header() {
 | 
						for k, v := range this.Header() {
 | 
				
			||||||
		for _, v1 := range v {
 | 
							for _, v1 := range v {
 | 
				
			||||||
@@ -912,6 +917,28 @@ func (this *HTTPWriter) Close() {
 | 
				
			|||||||
			if this.isOk && this.cacheWriter != nil {
 | 
								if this.isOk && this.cacheWriter != nil {
 | 
				
			||||||
				err := this.cacheWriter.Close()
 | 
									err := this.cacheWriter.Close()
 | 
				
			||||||
				if err == nil {
 | 
									if err == nil {
 | 
				
			||||||
 | 
										if !this.isPartial || this.partialFileIsNew {
 | 
				
			||||||
 | 
											var expiredAt = this.cacheWriter.ExpiredAt()
 | 
				
			||||||
 | 
											this.cacheStorage.AddToList(&caches.Item{
 | 
				
			||||||
 | 
												Type:       this.cacheWriter.ItemType(),
 | 
				
			||||||
 | 
												Key:        this.cacheWriter.Key(),
 | 
				
			||||||
 | 
												ExpiredAt:  expiredAt,
 | 
				
			||||||
 | 
												StaleAt:    expiredAt + int64(this.calculateStaleLife()),
 | 
				
			||||||
 | 
												HeaderSize: this.cacheWriter.HeaderSize(),
 | 
				
			||||||
 | 
												BodySize:   this.cacheWriter.BodySize(),
 | 
				
			||||||
 | 
												Host:       this.req.ReqHost,
 | 
				
			||||||
 | 
												ServerId:   this.req.ReqServer.Id,
 | 
				
			||||||
 | 
											})
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if !this.isPartial || !this.cacheIsFinished {
 | 
				
			||||||
 | 
									_ = this.cacheWriter.Discard()
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									// Partial的文件内容不删除
 | 
				
			||||||
 | 
									err := this.cacheWriter.Close()
 | 
				
			||||||
 | 
									if err == nil && this.partialFileIsNew {
 | 
				
			||||||
					var expiredAt = this.cacheWriter.ExpiredAt()
 | 
										var expiredAt = this.cacheWriter.ExpiredAt()
 | 
				
			||||||
					this.cacheStorage.AddToList(&caches.Item{
 | 
										this.cacheStorage.AddToList(&caches.Item{
 | 
				
			||||||
						Type:       this.cacheWriter.ItemType(),
 | 
											Type:       this.cacheWriter.ItemType(),
 | 
				
			||||||
@@ -925,8 +952,6 @@ func (this *HTTPWriter) Close() {
 | 
				
			|||||||
					})
 | 
										})
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			_ = this.cacheWriter.Discard()
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user