package cache import ( "gitlink.org.cn/cloudream/common/utils/lo2" "gitlink.org.cn/cloudream/common/utils/math2" ) type SegmentType int const ( // 数据段刚被初始化 SegmentInit = iota // 数据来自本地文件 SegmentLocal // 数据来自远端文件,还未写入到本地文件 SegmentRemote // 数据由用户写入,还未写入到本地文件 SegmentDirty ) type FileSegment struct { Position int64 // 有效数据的长度。不一定等于Buffer的长度 Length int64 Type SegmentType // 文件数据缓冲区。不可对此缓冲区进行append操作! Buffer []byte // 当前段是否正在被保存到本地文件中 IsSaving bool // 引用计数。当引用计数为0时,可以安全地删除此段 RefCount int } func (s *FileSegment) GetPosition() int64 { return s.Position } func (s *FileSegment) GetLength() int64 { return s.Length } func (s *FileSegment) SubSliceAbs(pos int64, len int64) []byte { start := pos - s.Position return s.Buffer[start : start+len] } // 将当前段拆分为两个段。当前段将持有第一个段,返回值持有第二个段 func (s *FileSegment) SplitAbs(pos int64) *FileSegment { s2 := s.Buffer[pos-s.Position:] s2Len := math2.Max(s.Position+s.Length-pos, 0) s.Buffer = s.Buffer[:pos-s.Position] s.Length = math2.Min(int64(len(s.Buffer)), s.Length) return &FileSegment{ Position: pos, Length: s2Len, Type: s.Type, Buffer: s2, } } func (s *FileSegment) AvailableEnd() int64 { return s.Position + s.Length } func (s *FileSegment) BufferEnd() int64 { return s.Position + int64(len(s.Buffer)) } func (s *FileSegment) EnlargeTo(pos int64) { if pos > s.Position+s.Length { s.Length = pos - s.Position } } type SegmentBuffer struct { // 正在使用的文件段缓冲区 buzys []*FileSegment } func (s *SegmentBuffer) BuzyCount() int { return len(s.buzys) } func (s *SegmentBuffer) Segment(idx int) *FileSegment { return s.buzys[idx] } func (s *SegmentBuffer) FirstContains(pos int64) int { return FirstContains(s.buzys, pos) } // 将指定段插入到段缓存的恰当位置 func (s *SegmentBuffer) Insert(seg *FileSegment) { index := s.FirstContains(seg.Position) if index == -1 { s.buzys = append([]*FileSegment{seg}, s.buzys...) } else { // index是最后一个小于Position的位置,所以要加1 s.buzys = lo2.Insert(s.buzys, index+1, seg) } } // 插入一个段到指定索引位置。不会检查插入后Segments是否依然保持有序。 func (s *SegmentBuffer) InsertAt(index int, seg *FileSegment) { s.buzys = lo2.Insert(s.buzys, index, seg) } func (s *SegmentBuffer) RemoveAt(index int) { s.buzys = lo2.RemoveAt(s.buzys, index) } func (s *SegmentBuffer) Remove(seg *FileSegment) { s.buzys = lo2.Remove(s.buzys, seg) }