vfs/cache: Fix promoteToFast race with WriteCloser Close
promoteToFast read FileInfo.Size from Stat after the VFS lock was released, while WriteCloser.Close updated Size on the same live object. Concurrent Create/Open on overlapping keys tripped the race detector. Stat now returns a FileInfo snapshot, and promotion uses the ReadAll length for the fast-tier Create size. Promotion stays best-effort. #21
This commit is contained in:
@@ -27,6 +27,17 @@ func NewFileInfo(key string, size int64) *FileInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// Clone returns a snapshot copy of fi. Stat returns Clone() so callers can
|
||||
// read Size and other fields without racing Close/Open mutations of the
|
||||
// in-map FileInfo.
|
||||
func (fi *FileInfo) Clone() *FileInfo {
|
||||
if fi == nil {
|
||||
return nil
|
||||
}
|
||||
cp := *fi
|
||||
return &cp
|
||||
}
|
||||
|
||||
// NewFileInfoFromOS creates a FileInfo from os.FileInfo
|
||||
func NewFileInfoFromOS(info os.FileInfo, key string) *FileInfo {
|
||||
return &FileInfo{
|
||||
|
||||
@@ -16,6 +16,34 @@ func TestNewFileInfo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileInfoClone(t *testing.T) {
|
||||
t.Parallel()
|
||||
fi := NewFileInfo("k", 42)
|
||||
fi.AccessCount = 7
|
||||
cp := fi.Clone()
|
||||
if cp == fi {
|
||||
t.Fatal("Clone returned the same pointer")
|
||||
}
|
||||
if cp.Key != fi.Key || cp.Size != fi.Size || cp.AccessCount != fi.AccessCount {
|
||||
t.Errorf("Clone mismatch: %+v vs %+v", cp, fi)
|
||||
}
|
||||
if !cp.ATime.Equal(fi.ATime) || !cp.CTime.Equal(fi.CTime) {
|
||||
t.Error("Clone timestamps mismatch")
|
||||
}
|
||||
cp.Size = 99
|
||||
cp.AccessCount = 1
|
||||
if fi.Size != 42 || fi.AccessCount != 7 {
|
||||
t.Error("mutating Clone affected original")
|
||||
}
|
||||
if NewFileInfo("x", 1).Clone() == nil {
|
||||
t.Error("Clone of non-nil was nil")
|
||||
}
|
||||
var none *FileInfo
|
||||
if none.Clone() != nil {
|
||||
t.Error("Clone of nil was non-nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateAccess(t *testing.T) {
|
||||
t.Parallel()
|
||||
fi := NewFileInfo("k", 1)
|
||||
|
||||
Reference in New Issue
Block a user