// Copyright (C) 2022 Marius Schellenberger package fs import ( "os" "sync" "sync/atomic" "time" ) func now() int64 { return time.Now().UTC().Unix() } type MetadataMap map[string]*Metadata type Metadata struct { mu sync.RWMutex `json:"-"` fs *FS `json:"-"` f *os.File `json:"-"` name string `json:"-"` Size int64 `json:"s"` Atime int64 `json:"a"` Chunks Chunks `json:"c"` } func (md *Metadata) Delete() error { md.mu.Lock() defer md.mu.Unlock() md.Chunks = Chunks{} md.f.Close() md.f = nil atomic.StoreInt64(&md.Atime, now()) return md.fs.RemoveDst(md.name) } func (md *Metadata) HasChunk(off int64, n int) bool { md.mu.RLock() defer md.mu.RUnlock() return md.Chunks.Exists(off, n, md.Size) } func (md *Metadata) AddChunk(off int64, n int) { md.mu.Lock() defer md.mu.Unlock() md.Chunks.Add(off, n) } func (md *Metadata) ReadAt(p []byte, pos int64) (int, error) { if md.f == nil { err := md.openCacheFile() if err != nil { return 0, err } } atomic.StoreInt64(&md.Atime, now()) return md.f.ReadAt(p, pos) } func (md *Metadata) WriteAt(data []byte, pos int64) (int, error) { if md.f == nil { err := md.openCacheFile() if err != nil { return 0, err } } atomic.StoreInt64(&md.Atime, now()) md.fs.q.Add(len(data)) return md.f.WriteAt(data, pos) } func (md *Metadata) openCacheFile() error { md.mu.Lock() defer md.mu.Unlock() if md.f != nil { return nil } f, err := md.fs.openCacheFile(md.name, md.Size) md.f = f return err } func (md *Metadata) Stat() (os.FileInfo, error) { if md.f == nil { err := md.openCacheFile() if err != nil { return nil, err } } return md.f.Stat() }