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:
@@ -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:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user