1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 15:39:42 +00:00

fix(analyze): Fix race condition in currentPath

This commit is contained in:
Jack Phallen
2026-01-11 23:44:55 -05:00
parent 91fcbb925b
commit 47ce1cb75b
4 changed files with 19 additions and 16 deletions

View File

@@ -45,9 +45,10 @@ func TestScanPathConcurrentBasic(t *testing.T) {
}
var filesScanned, dirsScanned, bytesScanned int64
current := ""
current := &atomic.Value{}
current.Store("")
result, err := scanPathConcurrent(root, &filesScanned, &dirsScanned, &bytesScanned, &current)
result, err := scanPathConcurrent(root, &filesScanned, &dirsScanned, &bytesScanned, current)
if err != nil {
t.Fatalf("scanPathConcurrent returned error: %v", err)
}
@@ -361,10 +362,11 @@ func TestScanPathPermissionError(t *testing.T) {
}()
var files, dirs, bytes int64
current := ""
current := &atomic.Value{}
current.Store("")
// Scanning the locked dir itself should fail.
_, err := scanPathConcurrent(lockedDir, &files, &dirs, &bytes, &current)
_, err := scanPathConcurrent(lockedDir, &files, &dirs, &bytes, current)
if err == nil {
t.Fatalf("expected error scanning locked directory, got nil")
}

View File

@@ -97,7 +97,7 @@ type model struct {
filesScanned *int64
dirsScanned *int64
bytesScanned *int64
currentPath *string
currentPath *atomic.Value
showLargeFiles bool
isOverview bool
deleteConfirm bool
@@ -162,7 +162,8 @@ func main() {
func newModel(path string, isOverview bool) model {
var filesScanned, dirsScanned, bytesScanned int64
currentPath := ""
currentPath := &atomic.Value{}
currentPath.Store("")
var overviewFilesScanned, overviewDirsScanned, overviewBytesScanned int64
overviewCurrentPath := ""
@@ -174,7 +175,7 @@ func newModel(path string, isOverview bool) model {
filesScanned: &filesScanned,
dirsScanned: &dirsScanned,
bytesScanned: &bytesScanned,
currentPath: &currentPath,
currentPath: currentPath,
showLargeFiles: false,
isOverview: isOverview,
cache: make(map[string]historyEntry),
@@ -434,7 +435,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
atomic.StoreInt64(m.dirsScanned, 0)
atomic.StoreInt64(m.bytesScanned, 0)
if m.currentPath != nil {
*m.currentPath = ""
m.currentPath.Store("")
}
return m, tea.Batch(m.scanCmd(m.path), tickCmd())
}
@@ -712,7 +713,7 @@ func (m model) updateKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
atomic.StoreInt64(m.dirsScanned, 0)
atomic.StoreInt64(m.bytesScanned, 0)
if m.currentPath != nil {
*m.currentPath = ""
m.currentPath.Store("")
}
return m, tea.Batch(m.scanCmd(m.path), tickCmd())
case "t", "T":
@@ -984,7 +985,7 @@ func (m model) enterSelectedDir() (tea.Model, tea.Cmd) {
atomic.StoreInt64(m.dirsScanned, 0)
atomic.StoreInt64(m.bytesScanned, 0)
if m.currentPath != nil {
*m.currentPath = ""
m.currentPath.Store("")
}
if cached, ok := m.cache[m.path]; ok && !cached.Dirty {

View File

@@ -23,7 +23,7 @@ import (
var scanGroup singleflight.Group
func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *int64, currentPath *string) (scanResult, error) {
func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *int64, currentPath *atomic.Value) (scanResult, error) {
children, err := os.ReadDir(root)
if err != nil {
return scanResult{}, err
@@ -293,7 +293,7 @@ func shouldSkipFileForLargeTracking(path string) bool {
}
// calculateDirSizeFast performs concurrent dir sizing using os.ReadDir.
func calculateDirSizeFast(root string, filesScanned, dirsScanned, bytesScanned *int64, currentPath *string) int64 {
func calculateDirSizeFast(root string, filesScanned, dirsScanned, bytesScanned *int64, currentPath *atomic.Value) int64 {
var total int64
var wg sync.WaitGroup
@@ -312,7 +312,7 @@ func calculateDirSizeFast(root string, filesScanned, dirsScanned, bytesScanned *
}
if currentPath != nil && atomic.LoadInt64(filesScanned)%int64(batchUpdateSize) == 0 {
*currentPath = dirPath
currentPath.Store(dirPath)
}
entries, err := os.ReadDir(dirPath)
@@ -429,7 +429,7 @@ func isInFoldedDir(path string) bool {
return false
}
func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, duSem chan struct{}, filesScanned, dirsScanned, bytesScanned *int64, currentPath *string) int64 {
func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, duSem chan struct{}, filesScanned, dirsScanned, bytesScanned *int64, currentPath *atomic.Value) int64 {
children, err := os.ReadDir(root)
if err != nil {
return 0
@@ -507,7 +507,7 @@ func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, duS
// Update current path occasionally to prevent UI jitter.
if currentPath != nil && atomic.LoadInt64(filesScanned)%int64(batchUpdateSize) == 0 {
*currentPath = fullPath
currentPath.Store(fullPath)
}
}

View File

@@ -99,7 +99,7 @@ func (m model) View() string {
colorGreen, humanizeBytes(bytesScanned), colorReset)
if m.currentPath != nil {
currentPath := *m.currentPath
currentPath := m.currentPath.Load().(string)
if currentPath != "" {
shortPath := displayPath(currentPath)
shortPath = truncateMiddle(shortPath, 50)