1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 16:49:41 +00:00

perf: optimize scanner timer usage and app protection matching

- Replace time.After() with reusable timer to reduce GC pressure
- Use pre-compiled regex for app bundle matching (O(1) vs O(N))
- Fix Bash 3.2 compatibility (remove local -n usage)
This commit is contained in:
tw93
2026-01-30 15:37:13 +08:00
parent 89dcb0c3b5
commit e81be16031
2 changed files with 120 additions and 25 deletions

View File

@@ -119,6 +119,16 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
size := getActualFileSize(fullPath, info)
atomic.AddInt64(&total, size)
// Reuse timer to reduce GC pressure
timer := time.NewTimer(0)
// Ensure timer is drained immediately since we start with 0
if !timer.Stop() {
select {
case <-timer.C:
default:
}
}
select {
case entryChan <- dirEntry{
Name: child.Name() + " →",
@@ -127,10 +137,26 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
IsDir: isDir,
LastAccess: getLastAccessTimeFromInfo(info),
}:
case <-time.After(100 * time.Millisecond):
// Skip if channel is blocked
default:
// If channel is full, use timer to wait with timeout
timer.Reset(100 * time.Millisecond)
select {
case entryChan <- dirEntry{
Name: child.Name() + " →",
Path: fullPath,
Size: size,
IsDir: isDir,
LastAccess: getLastAccessTimeFromInfo(info),
}:
if !timer.Stop() {
<-timer.C
}
case <-timer.C:
// Skip if channel is blocked
}
}
continue
}
if child.IsDir() {
@@ -162,6 +188,7 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
atomic.AddInt64(&total, size)
atomic.AddInt64(dirsScanned, 1)
timer := time.NewTimer(100 * time.Millisecond)
select {
case entryChan <- dirEntry{
Name: name,
@@ -170,7 +197,10 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
IsDir: true,
LastAccess: time.Time{},
}:
case <-time.After(100 * time.Millisecond):
if !timer.Stop() {
<-timer.C
}
case <-timer.C:
}
}(child.Name(), fullPath)
continue
@@ -195,6 +225,7 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
atomic.AddInt64(&total, size)
atomic.AddInt64(dirsScanned, 1)
timer := time.NewTimer(100 * time.Millisecond)
select {
case entryChan <- dirEntry{
Name: name,
@@ -203,7 +234,10 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
IsDir: true,
LastAccess: time.Time{},
}:
case <-time.After(100 * time.Millisecond):
if !timer.Stop() {
<-timer.C
}
case <-timer.C:
}
}(child.Name(), fullPath)
continue
@@ -219,6 +253,7 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
atomic.AddInt64(&total, size)
atomic.AddInt64(dirsScanned, 1)
timer := time.NewTimer(100 * time.Millisecond)
select {
case entryChan <- dirEntry{
Name: name,
@@ -227,7 +262,10 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
IsDir: true,
LastAccess: time.Time{},
}:
case <-time.After(100 * time.Millisecond):
if !timer.Stop() {
<-timer.C
}
case <-timer.C:
}
}(child.Name(), fullPath)
continue
@@ -243,6 +281,9 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
atomic.AddInt64(filesScanned, 1)
atomic.AddInt64(bytesScanned, size)
// Single-use timer for main loop (less pressure than tight loop above)
// But let's be consistent and optimized
timer := time.NewTimer(100 * time.Millisecond)
select {
case entryChan <- dirEntry{
Name: child.Name(),
@@ -251,16 +292,23 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
IsDir: false,
LastAccess: getLastAccessTimeFromInfo(info),
}:
case <-time.After(100 * time.Millisecond):
if !timer.Stop() {
<-timer.C
}
case <-timer.C:
}
// Track large files only.
if !shouldSkipFileForLargeTracking(fullPath) {
minSize := atomic.LoadInt64(&largeFileMinSize)
if size >= minSize {
timer.Reset(100 * time.Millisecond)
select {
case largeFileChan <- fileEntry{Name: child.Name(), Path: fullPath, Size: size}:
case <-time.After(100 * time.Millisecond):
if !timer.Stop() {
<-timer.C
}
case <-timer.C:
}
}
}
@@ -471,6 +519,15 @@ func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, lar
maxConcurrent := min(runtime.NumCPU()*2, maxDirWorkers)
sem := make(chan struct{}, maxConcurrent)
// Reuse timer for large file sends
timer := time.NewTimer(0)
if !timer.Stop() {
select {
case <-timer.C:
default:
}
}
for _, child := range children {
fullPath := filepath.Join(root, child.Name())
@@ -536,9 +593,13 @@ func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, lar
if !shouldSkipFileForLargeTracking(fullPath) && largeFileMinSize != nil {
minSize := atomic.LoadInt64(largeFileMinSize)
if size >= minSize {
timer.Reset(100 * time.Millisecond)
select {
case largeFileChan <- fileEntry{Name: child.Name(), Path: fullPath, Size: size}:
case <-time.After(100 * time.Millisecond):
if !timer.Stop() {
<-timer.C
}
case <-timer.C:
}
}
}