Release 3.8.2.5: cheaper idle UI poll and tighter hot paths.
Delta getState by rev, pause when hidden, cancellable background loops, hostCache bounds, unlock PollUI around engine status, corebin singleflight, PingAll worker pool. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,11 +3,14 @@ package corebin
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
cache = map[string]string{}
|
||||
group singleflight.Group
|
||||
)
|
||||
|
||||
// CacheKey identifies a resolved core binary for a binDir + protocol.
|
||||
@@ -48,15 +51,26 @@ func Invalidate() {
|
||||
// Resolve caches the result of fn under key.
|
||||
// Hot-path polls trust the cache until Invalidate (no per-poll os.Stat).
|
||||
// Embedded/virtual paths never touch the filesystem.
|
||||
// Concurrent cold misses for the same key share one fn call (singleflight).
|
||||
func Resolve(key string, fn func() (string, error)) (string, error) {
|
||||
if path, ok := Get(key); ok {
|
||||
return path, nil
|
||||
}
|
||||
path, err := fn()
|
||||
v, err, _ := group.Do(key, func() (any, error) {
|
||||
if path, ok := Get(key); ok {
|
||||
return path, nil
|
||||
}
|
||||
path, err := fn()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
Set(key, path)
|
||||
return path, nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
Set(key, path)
|
||||
path, _ := v.(string)
|
||||
return path, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@ package corebin
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestResolveTrustsCacheWithoutStat(t *testing.T) {
|
||||
@@ -35,6 +38,36 @@ func TestResolveTrustsCacheWithoutStat(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveSingleflight(t *testing.T) {
|
||||
Invalidate()
|
||||
key := CacheKey(t.TempDir(), "naive")
|
||||
var calls atomic.Int32
|
||||
var started sync.WaitGroup
|
||||
started.Add(1)
|
||||
fn := func() (string, error) {
|
||||
calls.Add(1)
|
||||
started.Wait()
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
return "embedded-test-core", nil
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 8; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if _, err := Resolve(key, fn); err != nil {
|
||||
t.Errorf("resolve: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
started.Done()
|
||||
wg.Wait()
|
||||
if calls.Load() != 1 {
|
||||
t.Fatalf("expected 1 cold resolve, got %d", calls.Load())
|
||||
}
|
||||
}
|
||||
|
||||
func TestVirtualEmbeddedAWG(t *testing.T) {
|
||||
Invalidate()
|
||||
key := CacheKey("/bin", "awg")
|
||||
|
||||
Reference in New Issue
Block a user