package cache import ( "io" "time" ) type RemoteLoader struct { file *CacheFile loaders []*OpenLoader } type OpenLoader struct { reader io.ReadCloser pos int64 lastUsedTime time.Time } func newRemoteLoader(file *CacheFile) *RemoteLoader { return &RemoteLoader{ file: file, loaders: make([]*OpenLoader, 2), } } func (r *RemoteLoader) Load(p []byte, pos int64) (n int, err error) { replaceIdx := -1 for i := 0; i < len(r.loaders); i++ { loader := r.loaders[i] if loader == nil { replaceIdx = i continue } // 找到一个position刚好等于off的loader if loader.pos == pos { loader.lastUsedTime = time.Now() n, err = io.ReadFull(loader.reader, p) loader.pos += int64(n) if err != nil { loader.reader.Close() r.loaders[i] = nil } return } if replaceIdx == -1 || r.loaders[replaceIdx] != nil && r.loaders[replaceIdx].lastUsedTime.After(loader.lastUsedTime) { replaceIdx = i } } if r.loaders[replaceIdx] != nil { r.loaders[replaceIdx].reader.Close() r.loaders[replaceIdx] = nil } loader, err := r.newLoader(pos) if err != nil { return 0, err } loader.lastUsedTime = time.Now() r.loaders[replaceIdx] = loader n, err = io.ReadFull(loader.reader, p) loader.pos += int64(n) if err != nil { loader.reader.Close() r.loaders[replaceIdx] = nil } return } func (r *RemoteLoader) Close() { for i := 0; i < len(r.loaders); i++ { if r.loaders[i] != nil { r.loaders[i].reader.Close() } } } func (r *RemoteLoader) newLoader(pos int64) (*OpenLoader, error) { detail, err := r.file.cache.db.Object().GetDetail(r.file.cache.db.DefCtx(), r.file.remoteObj.ObjectID) if err != nil { return nil, err } down, err := r.file.cache.downloader.DownloadObjectByDetail(detail, pos, -1) if err != nil { return nil, err } return &OpenLoader{ reader: down.File, pos: pos, }, nil }