mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-02 14:00:25 +08:00
193 lines
4.1 KiB
Go
193 lines
4.1 KiB
Go
package caches
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
"sync/atomic"
|
|
|
|
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
|
"github.com/cespare/xxhash/v2"
|
|
"github.com/iwind/TeaGo/types"
|
|
)
|
|
|
|
type MemoryWriter struct {
|
|
storage *MemoryStorage
|
|
|
|
key string
|
|
expiredAt int64
|
|
headerSize int64
|
|
bodySize int64
|
|
status int
|
|
isDirty bool
|
|
|
|
expectedBodySize int64
|
|
maxSize int64
|
|
|
|
hash uint64
|
|
item *MemoryItem
|
|
endFunc func(valueItem *MemoryItem)
|
|
once sync.Once
|
|
}
|
|
|
|
func NewMemoryWriter(memoryStorage *MemoryStorage, key string, expiredAt int64, status int, isDirty bool, expectedBodySize int64, maxSize int64, endFunc func(valueItem *MemoryItem)) *MemoryWriter {
|
|
var valueItem = &MemoryItem{
|
|
ExpiresAt: expiredAt,
|
|
ModifiedAt: fasttime.Now().Unix(),
|
|
Status: status,
|
|
}
|
|
|
|
if expectedBodySize > 0 {
|
|
valueItem.BodyValue = make([]byte, 0, expectedBodySize)
|
|
}
|
|
|
|
var w = &MemoryWriter{
|
|
storage: memoryStorage,
|
|
key: key,
|
|
expiredAt: expiredAt,
|
|
item: valueItem,
|
|
status: status,
|
|
isDirty: isDirty,
|
|
expectedBodySize: expectedBodySize,
|
|
maxSize: maxSize,
|
|
endFunc: endFunc,
|
|
}
|
|
|
|
w.hash = w.calculateHash(key)
|
|
|
|
return w
|
|
}
|
|
|
|
// WriteHeader 写入数据
|
|
func (this *MemoryWriter) WriteHeader(data []byte) (n int, err error) {
|
|
this.headerSize += int64(len(data))
|
|
this.item.HeaderValue = append(this.item.HeaderValue, data...)
|
|
return len(data), nil
|
|
}
|
|
|
|
// Write 写入数据
|
|
func (this *MemoryWriter) Write(data []byte) (n int, err error) {
|
|
var l = len(data)
|
|
if l == 0 {
|
|
return
|
|
}
|
|
|
|
if this.item.IsPrepared {
|
|
if this.item.WriteOffset+int64(l) > this.expectedBodySize {
|
|
err = ErrWritingUnavailable
|
|
return
|
|
}
|
|
copy(this.item.BodyValue[this.item.WriteOffset:], data)
|
|
this.item.WriteOffset += int64(l)
|
|
} else {
|
|
this.item.BodyValue = append(this.item.BodyValue, data...)
|
|
}
|
|
|
|
this.bodySize += int64(l)
|
|
|
|
// 检查尺寸
|
|
if this.maxSize > 0 && this.bodySize > this.maxSize {
|
|
err = ErrEntityTooLarge
|
|
this.storage.IgnoreKey(this.key, this.maxSize)
|
|
return l, err
|
|
}
|
|
|
|
return l, nil
|
|
}
|
|
|
|
// WriteAt 在指定位置写入数据
|
|
func (this *MemoryWriter) WriteAt(offset int64, b []byte) error {
|
|
_ = b
|
|
_ = offset
|
|
return errors.New("not supported")
|
|
}
|
|
|
|
// HeaderSize 数据尺寸
|
|
func (this *MemoryWriter) HeaderSize() int64 {
|
|
return this.headerSize
|
|
}
|
|
|
|
// BodySize 主体内容尺寸
|
|
func (this *MemoryWriter) BodySize() int64 {
|
|
return this.bodySize
|
|
}
|
|
|
|
// Close 关闭
|
|
func (this *MemoryWriter) Close() error {
|
|
// 需要在Locker之外
|
|
defer this.once.Do(func() {
|
|
this.endFunc(this.item)
|
|
})
|
|
|
|
if this.item == nil {
|
|
return nil
|
|
}
|
|
|
|
// check content length
|
|
if this.expectedBodySize > 0 && this.bodySize != this.expectedBodySize {
|
|
this.storage.locker.Lock()
|
|
delete(this.storage.valuesMap, this.hash)
|
|
this.storage.locker.Unlock()
|
|
return ErrUnexpectedContentLength
|
|
}
|
|
|
|
this.storage.locker.Lock()
|
|
this.item.IsDone = true
|
|
var err error
|
|
if this.isDirty {
|
|
if this.storage.parentStorage != nil {
|
|
this.storage.valuesMap[this.hash] = this.item
|
|
|
|
select {
|
|
case this.storage.dirtyChan <- types.String(this.bodySize) + "@" + this.key:
|
|
atomic.AddInt64(&this.storage.totalDirtySize, this.bodySize)
|
|
default:
|
|
// remove from values map
|
|
delete(this.storage.valuesMap, this.hash)
|
|
|
|
err = ErrWritingQueueFull
|
|
}
|
|
} else {
|
|
this.storage.valuesMap[this.hash] = this.item
|
|
}
|
|
} else {
|
|
this.storage.valuesMap[this.hash] = this.item
|
|
}
|
|
|
|
this.storage.locker.Unlock()
|
|
|
|
return err
|
|
}
|
|
|
|
// Discard 丢弃
|
|
func (this *MemoryWriter) Discard() error {
|
|
// 需要在Locker之外
|
|
defer this.once.Do(func() {
|
|
this.endFunc(this.item)
|
|
})
|
|
|
|
this.storage.locker.Lock()
|
|
delete(this.storage.valuesMap, this.hash)
|
|
this.storage.locker.Unlock()
|
|
return nil
|
|
}
|
|
|
|
// Key 获取Key
|
|
func (this *MemoryWriter) Key() string {
|
|
return this.key
|
|
}
|
|
|
|
// ExpiredAt 过期时间
|
|
func (this *MemoryWriter) ExpiredAt() int64 {
|
|
return this.expiredAt
|
|
}
|
|
|
|
// ItemType 内容类型
|
|
func (this *MemoryWriter) ItemType() ItemType {
|
|
return ItemTypeMemory
|
|
}
|
|
|
|
// 计算Key Hash
|
|
func (this *MemoryWriter) calculateHash(key string) uint64 {
|
|
return xxhash.Sum64String(key)
|
|
}
|