|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916 |
- package cache
-
- import (
- "fmt"
- "io"
- "os"
- "path/filepath"
- "sync"
- "time"
-
- "gitlink.org.cn/cloudream/common/pkgs/logger"
- "gitlink.org.cn/cloudream/common/utils/io2"
- "gitlink.org.cn/cloudream/common/utils/lo2"
- "gitlink.org.cn/cloudream/common/utils/math2"
- "gitlink.org.cn/cloudream/common/utils/serder"
- "gitlink.org.cn/cloudream/jcs-pub/client/internal/mount/fuse"
- clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types"
- )
-
- type CacheLevel int
-
- const (
- // 未加载
- LevelNotLoaded CacheLevel = iota
- // 缓存数据都完整,但仅加载了一次元数据,只能读取,不能修改。
- LevelReadOnly
- // 缓存数据都完整存在,但仅加载了元数据,没有加载文件数据
- LevelMetaLoaded
- // 缓存数据都完整存在,且已加载到内存中
- LevelComplete
- )
-
- func (l CacheLevel) String() string {
- var levels = []string{"NotLoaded", "ReadOnly", "MetaLoaded", "Complete"}
- return levels[l]
- }
-
- type FileInfo struct {
- // 文件总大小。可能会超过对应的远端文件的大小。
- // 此大小可能与本地缓存文件大小也不同,需要定时将本地缓存文件大小修正到与这个值相同。
- Size int64
- // 文件数据的版本号。如果大于0,则代表有未提交的修改
- DataRevision int
- // 文件元数据的版本号
- MetaRevision int
- // 数据段列表,按照段开始位置从小到大排列
- Segments []*Range
- // 文件对应的对象ID,仅在文件是一个缓存文件时才有值
- // ObjectID cdssdk.ObjectID
- // 文件对应的对象大小,仅在文件是一个缓存文件时才有值。
- // 此值代表有多少数据应该从远端加载,所以可能会小于远端实际大小
- ObjectSize int64
- // 如果本文件完全是一个缓存文件,那么这个字段记录了其内容的哈希值,用于在下载缓存数据时,检查远端文件是否被修改过
- // Hash cdssdk.FileHash
- // 文件的最后修改时间
- ModTime time.Time
- // 文件的权限
- Perm os.FileMode
- }
-
- func (f *FileInfo) Clone() FileInfo {
- n := *f
- n.Segments = make([]*Range, len(f.Segments))
- for i, seg := range f.Segments {
- n.Segments[i] = &Range{
- Position: seg.Position,
- Length: seg.Length,
- }
- }
-
- return n
- }
-
- type Range struct {
- Position int64
- Length int64
- }
-
- func (r *Range) GetPosition() int64 {
- return r.Position
- }
-
- func (r *Range) SetPosition(pos int64) {
- r.Position = pos
- }
-
- func (r *Range) GetLength() int64 {
- return r.Length
- }
-
- func (r *Range) SetLength(length int64) {
- r.Length = length
- }
-
- func (r *Range) End() int64 {
- return r.Position + r.Length
- }
-
- // 所有读写过程共用同一个CacheFile对象。
- // 不应该将此结构体保存到对象中
- type CacheFile struct {
- cache *Cache
- pathComps []string
- info FileInfo
- remoteObj *clitypes.Object
- rwLock *sync.RWMutex
- readers []*CacheFileHandle
- writers []*CacheFileHandle
- saveMetaChan chan any
- saveMetaLock *sync.Mutex
- stopSaveMeta *bool
- isDeleted bool
-
- level CacheLevel
- refCount int
- freeTime time.Time
- changeLevelTime time.Time
-
- metaFile *os.File
- dataFile *os.File
- writeLock *sync.RWMutex
-
- // 缓存文件的状态,用于管理缓存文件的生命周期。不受rwLock保护,而是由Cache管理
- state cacheState
- }
-
- type cacheState struct {
- uploading *uploadingObject
- }
-
- func createNewCacheFile(cache *Cache, pathComps []string) (*CacheFile, error) {
- metaPath := cache.GetCacheMetaPath(pathComps...)
- dataPath := cache.GetCacheDataPath(pathComps...)
-
- info := FileInfo{
- DataRevision: 1,
- ModTime: time.Now(),
- Perm: 0755,
- }
-
- infoData, err := serder.ObjectToJSON(info)
- if err != nil {
- return nil, err
- }
-
- err = os.MkdirAll(filepath.Dir(metaPath), 0755)
- if err != nil {
- return nil, err
- }
-
- metaFile, err := os.OpenFile(metaPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
- if err != nil {
- return nil, fmt.Errorf("create cache meta file: %w", err)
- }
-
- err = io2.WriteAll(metaFile, infoData)
- if err != nil {
- metaFile.Close()
- return nil, fmt.Errorf("save cache meta file: %w", err)
- }
-
- dataFile, err := os.OpenFile(dataPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
- if err != nil {
- metaFile.Close()
- return nil, fmt.Errorf("create cache data file: %w", err)
- }
-
- ch := &CacheFile{
- cache: cache,
- pathComps: pathComps,
- info: info,
- rwLock: &sync.RWMutex{},
- saveMetaChan: make(chan any, 1),
- saveMetaLock: &sync.Mutex{},
- stopSaveMeta: new(bool),
- level: LevelComplete,
- metaFile: metaFile,
- dataFile: dataFile,
- writeLock: &sync.RWMutex{},
- state: cacheState{},
- }
-
- go ch.serving(ch.saveMetaChan, ch.stopSaveMeta)
-
- return ch, nil
- }
-
- func loadCacheFile(cache *Cache, pathComps []string) (*CacheFile, error) {
- metaPath := cache.GetCacheMetaPath(pathComps...)
- dataPath := cache.GetCacheDataPath(pathComps...)
-
- dataFile, err := os.OpenFile(dataPath, os.O_RDWR, 0644)
- if err != nil {
- // 不要包装这里的err
- return nil, err
- }
-
- info := &FileInfo{}
-
- metaFile, err := os.OpenFile(metaPath, os.O_RDWR, 0644)
- if err != nil {
- // 如果有数据文件,而没有元数据文件,则创建一个元数据文件
- if !os.IsNotExist(err) {
- dataFile.Close()
- return nil, err
- }
-
- stat, err := dataFile.Stat()
- if err != nil {
- dataFile.Close()
- return nil, err
- }
-
- err = os.MkdirAll(filepath.Dir(metaPath), 0755)
- if err != nil {
- dataFile.Close()
- return nil, err
- }
-
- metaFile, err = os.OpenFile(metaPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
- if err != nil {
- dataFile.Close()
- return nil, err
- }
-
- info.Size = stat.Size()
- info.ModTime = stat.ModTime()
- info.Perm = stat.Mode().Perm()
- info.Segments = []*Range{{Position: 0, Length: info.Size}}
- info.MetaRevision = 1 // 未同步的文件视为已修改
- info.DataRevision = 1
-
- } else {
- err = serder.JSONToObjectStream(metaFile, info)
- if err != nil {
- dataFile.Close()
- return nil, err
- }
- }
-
- ch := &CacheFile{
- cache: cache,
- pathComps: pathComps,
- info: *info,
- rwLock: &sync.RWMutex{},
- saveMetaChan: make(chan any, 1),
- saveMetaLock: &sync.Mutex{},
- stopSaveMeta: new(bool),
- level: LevelComplete,
- metaFile: metaFile,
- dataFile: dataFile,
- writeLock: &sync.RWMutex{},
- state: cacheState{},
- }
-
- go ch.serving(ch.saveMetaChan, ch.stopSaveMeta)
-
- return ch, nil
- }
-
- func newCacheFileFromObject(cache *Cache, pathComps []string, obj *clitypes.Object) (*CacheFile, error) {
- metaPath := cache.GetCacheMetaPath(pathComps...)
- dataPath := cache.GetCacheDataPath(pathComps...)
-
- info := FileInfo{
- Size: obj.Size,
- ObjectSize: obj.Size,
- ModTime: obj.UpdateTime,
- Perm: 0755,
- }
-
- infoData, err := serder.ObjectToJSON(info)
- if err != nil {
- return nil, err
- }
-
- err = os.MkdirAll(filepath.Dir(metaPath), 0755)
- if err != nil {
- return nil, err
- }
-
- metaFile, err := os.OpenFile(metaPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
- if err != nil {
- return nil, fmt.Errorf("create cache meta file: %w", err)
- }
-
- err = io2.WriteAll(metaFile, infoData)
- if err != nil {
- metaFile.Close()
- return nil, fmt.Errorf("save cache meta file: %w", err)
- }
-
- dataFile, err := os.OpenFile(dataPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
- if err != nil {
- metaFile.Close()
- return nil, fmt.Errorf("create cache file: %w", err)
- }
-
- ch := &CacheFile{
- cache: cache,
- pathComps: pathComps,
- info: info,
- remoteObj: obj,
- rwLock: &sync.RWMutex{},
- saveMetaChan: make(chan any, 1),
- saveMetaLock: &sync.Mutex{},
- stopSaveMeta: new(bool),
- level: LevelComplete,
- metaFile: metaFile,
- dataFile: dataFile,
- writeLock: &sync.RWMutex{},
- state: cacheState{},
- }
-
- go ch.serving(ch.saveMetaChan, ch.stopSaveMeta)
-
- return ch, nil
- }
-
- func loadCacheFileInfo(cache *Cache, pathComps []string, dataFileInfo os.FileInfo) (*CacheEntryInfo, error) {
- metaPath := cache.GetCacheMetaPath(pathComps...)
-
- metaData, err := os.ReadFile(metaPath)
- if err == nil {
- info := &FileInfo{}
- err = serder.JSONToObject(metaData, info)
- if err != nil {
- return nil, err
- }
-
- return &CacheEntryInfo{
- PathComps: pathComps,
- Size: info.Size,
- Perm: info.Perm,
- ModTime: info.ModTime,
- IsDir: false,
- }, nil
- }
-
- if !os.IsNotExist(err) {
- return nil, err
- }
-
- return &CacheEntryInfo{
- PathComps: pathComps,
- Size: dataFileInfo.Size(),
- Perm: dataFileInfo.Mode(),
- ModTime: dataFileInfo.ModTime(),
- IsDir: false,
- }, nil
- }
-
- // 增加一个引用计数。不应该被Cache之外的代码调用。
- func (f *CacheFile) IncRef() {
- f.rwLock.Lock()
- defer f.rwLock.Unlock()
-
- f.refCount++
- }
-
- // 减少一个引用计数
- func (f *CacheFile) Release() {
- f.rwLock.Lock()
- defer f.rwLock.Unlock()
-
- f.refCount--
- if f.refCount == 0 {
- f.freeTime = time.Now()
- }
- }
-
- func (f *CacheFile) LevelDown(level CacheLevel) bool {
- if level <= LevelReadOnly {
- // 如果降级到不需要保存元数据的级别,就要先暂停保存元数据的操作
- f.saveMetaLock.Lock()
- defer f.saveMetaLock.Unlock()
- }
-
- f.rwLock.Lock()
- defer f.rwLock.Unlock()
-
- if level >= f.level {
- return true
- }
-
- // 缓存正在被使用时,不能降级
- if f.refCount > 0 {
- return false
- }
-
- switch f.level {
- case LevelComplete:
- f.dataFile.Close()
-
- f.level = LevelMetaLoaded
- if level >= f.level {
- break
- }
- fallthrough
-
- case LevelMetaLoaded:
- if !f.isDeleted {
- // TODO 日志
- f.saveMeta(f.info)
- }
- f.saveMetaChan = nil
- // 由于已经获取了saveMetaLock,所以这里设置true之后调用metaFile.Close不会导致saveMeta线程的保存失败
- // 因为saveMeta线程会先检查stopSaveMete的值
- *f.stopSaveMeta = true
- f.stopSaveMeta = nil
- f.metaFile.Close()
-
- f.level = LevelReadOnly
- if level >= f.level {
- break
- }
- fallthrough
-
- case LevelReadOnly:
- f.level = LevelNotLoaded
- if level >= f.level {
- break
- }
- fallthrough
-
- case LevelNotLoaded:
- }
-
- f.changeLevelTime = time.Now()
-
- return true
- }
-
- func (f *CacheFile) LevelUp(level CacheLevel) bool {
- f.rwLock.Lock()
- defer f.rwLock.Unlock()
-
- if level <= f.level {
- return true
- }
-
- // 缓存正在使用时,可以升级
-
- switch f.level {
- case LevelNotLoaded:
- f.level = LevelReadOnly
- if level <= f.level {
- break
- }
- fallthrough
-
- case LevelReadOnly:
- metaPath := f.cache.GetCacheMetaPath(f.pathComps...)
- metaFile, err := os.OpenFile(metaPath, os.O_RDWR, 0644)
- if err != nil {
- logger.Warnf("open meta file %v: %v", metaPath, err)
- return false
- }
-
- f.saveMetaChan = make(chan any, 1)
- f.stopSaveMeta = new(bool)
- f.metaFile = metaFile
- f.level = LevelMetaLoaded
-
- go f.serving(f.saveMetaChan, f.stopSaveMeta)
-
- if level <= f.level {
- break
- }
- fallthrough
-
- case LevelMetaLoaded:
- dataPath := f.cache.GetCacheDataPath(f.pathComps...)
- dataFile, err := os.OpenFile(dataPath, os.O_RDWR|os.O_CREATE, 0644)
- if err != nil {
- logger.Warnf("open data file %v: %v", dataPath, err)
- return false
- }
-
- f.dataFile = dataFile
- f.level = LevelComplete
-
- if level <= f.level {
- break
- }
- fallthrough
-
- case LevelComplete:
- }
-
- f.changeLevelTime = time.Now()
-
- return true
- }
-
- func (f *CacheFile) RevisionUploaded(dataRev int, metaRev int) {
- f.rwLock.Lock()
- defer f.rwLock.Unlock()
-
- if dataRev != 0 && f.info.DataRevision == dataRev {
- f.info.DataRevision = 0
- }
-
- if metaRev != 0 && f.info.MetaRevision == metaRev {
- f.info.MetaRevision = 0
- }
-
- f.letSave()
- }
-
- func (f *CacheFile) Info() CacheEntryInfo {
- f.rwLock.RLock()
- defer f.rwLock.RUnlock()
-
- return CacheEntryInfo{
- PathComps: f.pathComps,
- Size: f.info.Size,
- Perm: f.info.Perm,
- ModTime: f.info.ModTime,
- IsDir: false,
- MetaRevision: f.info.MetaRevision,
- DataRevision: f.info.DataRevision,
- RefCount: f.refCount,
- FreeTime: f.freeTime,
- Level: f.level,
- ChangeLevelTime: f.changeLevelTime,
- }
- }
-
- func (f *CacheFile) Delete() {
- f.writeLock.Lock()
- defer f.writeLock.Unlock()
-
- f.rwLock.Lock()
- defer f.rwLock.Unlock()
-
- metaPath := f.cache.GetCacheMetaPath(f.pathComps...)
- dataPath := f.cache.GetCacheDataPath(f.pathComps...)
- os.Remove(metaPath)
- os.Remove(dataPath)
-
- // 不可能将isDeleted从true改为false,所以这里不需要使用stopSaveChan来等待saveMeta线程退出
- f.isDeleted = true
-
- if f.saveMetaChan != nil {
- f.letSave()
- }
- }
-
- func (f *CacheFile) Move(newPathComps []string) {
- f.writeLock.Lock()
- defer f.writeLock.Unlock()
-
- f.rwLock.Lock()
- defer f.rwLock.Unlock()
-
- f.pathComps = newPathComps
-
- if f.saveMetaChan != nil {
- f.letSave()
- }
- }
-
- // 打开一个写入句柄,同时支持读取
- func (f *CacheFile) Open(flags uint32) *CacheFileHandle {
- logger.Tracef("CacheFile.Open: %v, %#x", f.pathComps, flags)
-
- f.rwLock.Lock()
- defer f.rwLock.Unlock()
-
- f.refCount++
-
- h := &CacheFileHandle{
- file: f,
- remoteLock: &sync.Mutex{},
- revision: f.info.DataRevision,
- }
-
- if flags&uint32(os.O_RDWR) == uint32(os.O_RDWR) {
- h.readable = true
- h.writeable = true
- } else if flags&uint32(os.O_WRONLY) == uint32(os.O_WRONLY) {
- h.writeable = true
- } else if flags&uint32(os.O_RDONLY) == uint32(os.O_RDONLY) {
- h.readable = true
- }
-
- if f.remoteObj != nil {
- h.remote = newRemoteLoader(f)
- }
-
- if h.writeable {
- f.writers = append(f.writers, h)
- } else {
- f.readers = append(f.readers, h)
- }
-
- return h
- }
-
- // 打开一个读取句柄,用于同步本地文件到远端
- func (f *CacheFile) OpenReadWhenScanning() *CacheFileHandle {
- f.rwLock.Lock()
- defer f.rwLock.Unlock()
-
- f.refCount++
-
- h := &CacheFileHandle{
- file: f,
- remoteLock: &sync.Mutex{},
- revision: f.info.DataRevision,
- readable: true,
- }
-
- if f.remoteObj != nil {
- h.remote = newRemoteLoader(f)
- }
-
- f.readers = append(f.readers, h)
- return h
- }
-
- func (f *CacheFile) SetModTime(modTime time.Time) error {
- logger.Tracef("CacheFile.SetModTime: %v, %v", f.pathComps, modTime)
-
- f.rwLock.Lock()
- f.info.ModTime = modTime
- f.info.MetaRevision++
- f.rwLock.Unlock()
-
- f.letSave()
- return nil
- }
-
- func (f *CacheFile) Truncate(size int64) error {
- logger.Tracef("CacheFile.Truncate: %v, %v", f.pathComps, size)
-
- // 修改文件大小前不允许写入
- f.writeLock.Lock()
- defer f.writeLock.Unlock()
-
- err := f.dataFile.Truncate(size)
- if err != nil {
- return err
- }
-
- f.rwLock.Lock()
- defer f.rwLock.Unlock()
-
- // 调整能从远端下载的大小
- f.info.ObjectSize = math2.Min(f.info.ObjectSize, size)
-
- // 调整本地缓存文件里的有效数据大小
- if size < f.info.Size {
- f.info.Segments = TruncateRange(f.info.Segments, size)
- } else if size > f.info.Size {
- f.info.Segments = AddRange(f.info.Segments, &Range{Position: f.info.Size, Length: size - f.info.Size})
- }
- if f.info.Size != size {
- f.info.DataRevision++
- }
- f.info.Size = size
-
- f.letSave()
- return nil
- }
-
- func (f *CacheFile) serving(saveMetaChan chan any, stopSaveMeta *bool) {
- ticker := time.NewTicker(time.Second * 30)
- defer ticker.Stop()
-
- for {
- select {
- case _, ok := <-saveMetaChan:
- if !ok {
- return
- }
-
- case <-ticker.C:
- }
-
- f.saveMetaLock.Lock()
- if *stopSaveMeta {
- f.saveMetaLock.Unlock()
- break
- }
-
- f.rwLock.RLock()
- info := f.info.Clone()
- // 如果文件已被删除,则不能再保存元数据,防止覆盖掉新创建的同名文件
- if f.isDeleted {
- f.rwLock.RUnlock()
- f.saveMetaLock.Unlock()
- break
- }
-
- f.rwLock.RUnlock()
-
- // TODO 错误日志
- f.saveMeta(info)
- f.metaFile.Sync()
- f.saveMetaLock.Unlock()
- }
- }
-
- func (f *CacheFile) saveMeta(info FileInfo) error {
- jsonData, err := serder.ObjectToJSON(info)
- if err != nil {
- return err
- }
-
- err = f.metaFile.Truncate(0)
- if err != nil {
- return err
- }
-
- _, err = f.metaFile.Seek(0, io.SeekStart)
- if err != nil {
- return err
- }
-
- err = io2.WriteAll(f.metaFile, jsonData)
- if err != nil {
- return err
- }
-
- return nil
- }
-
- func (f *CacheFile) letSave() {
- select {
- case f.saveMetaChan <- nil:
- default:
- }
- }
-
- type CacheFileHandle struct {
- file *CacheFile
- readable bool
- writeable bool
- remote *RemoteLoader
- remoteLock *sync.Mutex
- revision int // 打开文件时,文件的版本号
- }
-
- func (h *CacheFileHandle) ReadAt(buf []byte, off int64) (int, error) {
- log := logger.WithField("F", "CacheFileHandle.ReadAt").
- WithField("Path", h.file.pathComps)
- log.Tracef("buf: %v, off: %v", len(buf), off)
-
- if !h.readable {
- return 0, fuse.ErrPermission
- }
-
- // 读取数据必须读满整个buf,否则就会被认为是文件已经结束了
- totalReadLen := 0
- for totalReadLen < len(buf) {
- curBuf := buf[totalReadLen:]
- curOff := off + int64(totalReadLen)
-
- h.file.rwLock.RLock()
-
- if curOff >= h.file.info.Size {
- h.file.rwLock.RUnlock()
- break
- }
-
- /// 1. 先尝试从本地缓存文件里读取
- rngIdx := FirstContainsIndex(h.file.info.Segments, curOff)
- if rngIdx >= 0 && h.file.info.Segments[rngIdx].End() > curOff {
- readLen := math2.Min(int64(len(curBuf)), h.file.info.Segments[rngIdx].End()-curOff)
- realReadLen, err := h.file.dataFile.ReadAt(curBuf[:readLen], curOff)
- totalReadLen += realReadLen
- h.file.rwLock.RUnlock()
-
- if err != nil {
- log.Tracef("read from local cache: %v", err)
- return totalReadLen, err
- }
- continue
- }
-
- // 否则从远端下载,计算一下要加载的长度
- loadLen := math2.Min(int64(len(curBuf)), h.file.info.ObjectSize-curOff)
- if rngIdx+1 < len(h.file.info.Segments) {
- // 最多加载到下一个段的开头
- loadLen = math2.Min(loadLen, h.file.info.Segments[rngIdx+1].Position-curOff)
- }
-
- h.file.rwLock.RUnlock()
-
- /// 2. 开始从远端下载数据
-
- if h.remote == nil {
- log.Warnf("no remote file")
- return totalReadLen, fmt.Errorf("no remote file")
- }
-
- // 由于RemoteLoader的Load方法没有加锁,所以这里要加锁,防止并发Seek导致的问题
- // 可以考虑在RemoteLoader里加锁,这样可以实现跨Writer共用Loader
- h.remoteLock.Lock()
- realLoadLen, err := h.remote.Load(curBuf[:loadLen], curOff)
- totalReadLen += realLoadLen
- if err != nil {
- h.remoteLock.Unlock()
- return totalReadLen, err
- }
- h.remoteLock.Unlock()
- log.Tracef("load from remote: %v", realLoadLen)
-
- /// 3. 数据加载完毕,写入到本地文件
-
- // 在写入到本地之前,先停止其他的写入,防止冲突
- h.file.writeLock.Lock()
-
- // 停止其他写入后,就可以计算一下实际要写回的长度。
- h.file.rwLock.RLock()
- loadRng := &Range{Position: curOff, Length: int64(realLoadLen)}
- DifferentRange(loadRng, h.file.info.Segments)
- h.file.rwLock.RUnlock()
-
- if loadRng.Length == 0 {
- h.file.writeLock.Unlock()
- continue
- }
-
- // 写入到本地缓存文件
- writeStart := loadRng.Position - curOff
- _, err = h.file.dataFile.WriteAt(curBuf[writeStart:writeStart+loadRng.Length], curOff)
- if err != nil {
- h.file.writeLock.Unlock()
-
- log.Warnf("save to local file: %v", err)
- return totalReadLen, err
- }
-
- log.Tracef("save to local: %v", loadRng.Length)
-
- h.file.writeLock.Unlock()
-
- // 提交到段列表里
- h.file.rwLock.Lock()
- h.file.info.Segments = AddRange(h.file.info.Segments, loadRng)
- h.file.rwLock.Unlock()
- h.file.letSave()
- }
-
- return totalReadLen, nil
- }
-
- func (h *CacheFileHandle) WriteAt(buf []byte, off int64) (int, error) {
- log := logger.WithField("F", "CacheFileHandle.WriteAt").WithField("Path", h.file.pathComps)
- log.Tracef("buf: %v, off: %v", len(buf), off)
-
- if !h.writeable {
- return 0, fuse.ErrPermission
- }
-
- // 允许多线程并行写入,但在数据加载期间不能写入
- h.file.writeLock.RLock()
- defer h.file.writeLock.RUnlock()
-
- // 写入到本地缓存文件
- writeLen, err := h.file.dataFile.WriteAt(buf, off)
- if err != nil {
- log.Tracef("save to local file: %v", err)
- return writeLen, err
- }
-
- // 提交到段列表里
- h.file.rwLock.Lock()
- defer h.file.rwLock.Unlock()
-
- h.file.info.Segments = AddRange(h.file.info.Segments, &Range{Position: off, Length: int64(writeLen)})
- h.file.info.Size = math2.Max(h.file.info.Size, off+int64(writeLen))
- h.file.info.DataRevision++
-
- h.file.letSave()
-
- return writeLen, nil
- }
-
- func (f *CacheFileHandle) Sync() error {
- log := logger.WithField("Path", f.file.pathComps)
-
- err := f.file.dataFile.Sync()
- if err != nil {
- log.Tracef("sync local file: %v", err)
- return err
- }
-
- return nil
- }
-
- func (f *CacheFileHandle) Close() error {
- f.Sync()
-
- if f.remote != nil {
- f.remote.Close()
- }
-
- f.file.rwLock.Lock()
- defer f.file.rwLock.Unlock()
-
- f.file.refCount--
- if f.file.refCount == 0 {
- f.file.freeTime = time.Now()
- }
-
- if f.writeable {
- f.file.writers = lo2.Remove(f.file.writers, f)
- } else if f.readable {
- f.file.readers = lo2.Remove(f.file.readers, f)
- }
- return nil
- }
|