mirror of
https://github.com/tw93/Mole.git
synced 2026-02-04 15:04:42 +00:00
fix(analyze): Fix race condition in currentPath
This commit is contained in:
@@ -45,9 +45,10 @@ func TestScanPathConcurrentBasic(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var filesScanned, dirsScanned, bytesScanned int64
|
var filesScanned, dirsScanned, bytesScanned int64
|
||||||
current := ""
|
current := &atomic.Value{}
|
||||||
|
current.Store("")
|
||||||
|
|
||||||
result, err := scanPathConcurrent(root, &filesScanned, &dirsScanned, &bytesScanned, ¤t)
|
result, err := scanPathConcurrent(root, &filesScanned, &dirsScanned, &bytesScanned, current)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("scanPathConcurrent returned error: %v", err)
|
t.Fatalf("scanPathConcurrent returned error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -361,10 +362,11 @@ func TestScanPathPermissionError(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
var files, dirs, bytes int64
|
var files, dirs, bytes int64
|
||||||
current := ""
|
current := &atomic.Value{}
|
||||||
|
current.Store("")
|
||||||
|
|
||||||
// Scanning the locked dir itself should fail.
|
// Scanning the locked dir itself should fail.
|
||||||
_, err := scanPathConcurrent(lockedDir, &files, &dirs, &bytes, ¤t)
|
_, err := scanPathConcurrent(lockedDir, &files, &dirs, &bytes, current)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected error scanning locked directory, got nil")
|
t.Fatalf("expected error scanning locked directory, got nil")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ type model struct {
|
|||||||
filesScanned *int64
|
filesScanned *int64
|
||||||
dirsScanned *int64
|
dirsScanned *int64
|
||||||
bytesScanned *int64
|
bytesScanned *int64
|
||||||
currentPath *string
|
currentPath *atomic.Value
|
||||||
showLargeFiles bool
|
showLargeFiles bool
|
||||||
isOverview bool
|
isOverview bool
|
||||||
deleteConfirm bool
|
deleteConfirm bool
|
||||||
@@ -162,7 +162,8 @@ func main() {
|
|||||||
|
|
||||||
func newModel(path string, isOverview bool) model {
|
func newModel(path string, isOverview bool) model {
|
||||||
var filesScanned, dirsScanned, bytesScanned int64
|
var filesScanned, dirsScanned, bytesScanned int64
|
||||||
currentPath := ""
|
currentPath := &atomic.Value{}
|
||||||
|
currentPath.Store("")
|
||||||
var overviewFilesScanned, overviewDirsScanned, overviewBytesScanned int64
|
var overviewFilesScanned, overviewDirsScanned, overviewBytesScanned int64
|
||||||
overviewCurrentPath := ""
|
overviewCurrentPath := ""
|
||||||
|
|
||||||
@@ -174,7 +175,7 @@ func newModel(path string, isOverview bool) model {
|
|||||||
filesScanned: &filesScanned,
|
filesScanned: &filesScanned,
|
||||||
dirsScanned: &dirsScanned,
|
dirsScanned: &dirsScanned,
|
||||||
bytesScanned: &bytesScanned,
|
bytesScanned: &bytesScanned,
|
||||||
currentPath: ¤tPath,
|
currentPath: currentPath,
|
||||||
showLargeFiles: false,
|
showLargeFiles: false,
|
||||||
isOverview: isOverview,
|
isOverview: isOverview,
|
||||||
cache: make(map[string]historyEntry),
|
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.dirsScanned, 0)
|
||||||
atomic.StoreInt64(m.bytesScanned, 0)
|
atomic.StoreInt64(m.bytesScanned, 0)
|
||||||
if m.currentPath != nil {
|
if m.currentPath != nil {
|
||||||
*m.currentPath = ""
|
m.currentPath.Store("")
|
||||||
}
|
}
|
||||||
return m, tea.Batch(m.scanCmd(m.path), tickCmd())
|
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.dirsScanned, 0)
|
||||||
atomic.StoreInt64(m.bytesScanned, 0)
|
atomic.StoreInt64(m.bytesScanned, 0)
|
||||||
if m.currentPath != nil {
|
if m.currentPath != nil {
|
||||||
*m.currentPath = ""
|
m.currentPath.Store("")
|
||||||
}
|
}
|
||||||
return m, tea.Batch(m.scanCmd(m.path), tickCmd())
|
return m, tea.Batch(m.scanCmd(m.path), tickCmd())
|
||||||
case "t", "T":
|
case "t", "T":
|
||||||
@@ -984,7 +985,7 @@ func (m model) enterSelectedDir() (tea.Model, tea.Cmd) {
|
|||||||
atomic.StoreInt64(m.dirsScanned, 0)
|
atomic.StoreInt64(m.dirsScanned, 0)
|
||||||
atomic.StoreInt64(m.bytesScanned, 0)
|
atomic.StoreInt64(m.bytesScanned, 0)
|
||||||
if m.currentPath != nil {
|
if m.currentPath != nil {
|
||||||
*m.currentPath = ""
|
m.currentPath.Store("")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cached, ok := m.cache[m.path]; ok && !cached.Dirty {
|
if cached, ok := m.cache[m.path]; ok && !cached.Dirty {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
|
|
||||||
var scanGroup singleflight.Group
|
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)
|
children, err := os.ReadDir(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanResult{}, err
|
return scanResult{}, err
|
||||||
@@ -293,7 +293,7 @@ func shouldSkipFileForLargeTracking(path string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// calculateDirSizeFast performs concurrent dir sizing using os.ReadDir.
|
// 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 total int64
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
@@ -312,7 +312,7 @@ func calculateDirSizeFast(root string, filesScanned, dirsScanned, bytesScanned *
|
|||||||
}
|
}
|
||||||
|
|
||||||
if currentPath != nil && atomic.LoadInt64(filesScanned)%int64(batchUpdateSize) == 0 {
|
if currentPath != nil && atomic.LoadInt64(filesScanned)%int64(batchUpdateSize) == 0 {
|
||||||
*currentPath = dirPath
|
currentPath.Store(dirPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
entries, err := os.ReadDir(dirPath)
|
entries, err := os.ReadDir(dirPath)
|
||||||
@@ -429,7 +429,7 @@ func isInFoldedDir(path string) bool {
|
|||||||
return false
|
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)
|
children, err := os.ReadDir(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0
|
return 0
|
||||||
@@ -507,7 +507,7 @@ func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, duS
|
|||||||
|
|
||||||
// Update current path occasionally to prevent UI jitter.
|
// Update current path occasionally to prevent UI jitter.
|
||||||
if currentPath != nil && atomic.LoadInt64(filesScanned)%int64(batchUpdateSize) == 0 {
|
if currentPath != nil && atomic.LoadInt64(filesScanned)%int64(batchUpdateSize) == 0 {
|
||||||
*currentPath = fullPath
|
currentPath.Store(fullPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ func (m model) View() string {
|
|||||||
colorGreen, humanizeBytes(bytesScanned), colorReset)
|
colorGreen, humanizeBytes(bytesScanned), colorReset)
|
||||||
|
|
||||||
if m.currentPath != nil {
|
if m.currentPath != nil {
|
||||||
currentPath := *m.currentPath
|
currentPath := m.currentPath.Load().(string)
|
||||||
if currentPath != "" {
|
if currentPath != "" {
|
||||||
shortPath := displayPath(currentPath)
|
shortPath := displayPath(currentPath)
|
||||||
shortPath = truncateMiddle(shortPath, 50)
|
shortPath = truncateMiddle(shortPath, 50)
|
||||||
|
|||||||
Reference in New Issue
Block a user