diff --git a/.jules/bolt.md b/.jules/bolt.md index 91ce70b..4951efd 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -1,5 +1,9 @@ # Bolt's Journal +## 2026-03-09 - Lock-Free Pre-Allocated Map-Reduce for Multi-Regional Queries +**Learning:** Performing multi-regional queries (like `listAllRegions` across 24 GCP regions) concurrently using a shared slice protected by `sync.Mutex` causes lock contention, slice allocation churn, and heavy garbage collection overhead. Utilizing a lock-free, pre-allocated map-reduce pattern using a slice of slices (`[][]T`) eliminates mutex contention entirely, and pre-allocating the final result slice based on the exact sum of sizes of individual regional results reduces heap allocations considerably. +**Action:** Always favor lock-free, index-mapped pre-allocation arrays (`[][]T`) over shared mutex-protected slices (`[]T`) when collecting results concurrently from a known, fixed number of concurrent tasks. + ## 2026-03-08 - GCP Logging Client Caching & Connection Longevity **Learning:** Establishing the GCP Stackdriver Logging client requires repeated Google credential discovery and connection establishment, causing high latency (~300ms) inside a reactive TUI interface. Caching `logadmin.Client` instances via a project-aware map with thread-safe `sync.Mutex` ensures subsequent streaming and log extraction operations are instantaneous. Crucially, calling `Close()` on individual stream terminations must be a no-op to prevent premature teardown of connection pools shared across other active streaming views. **Action:** Keep GCP Logging clients cached globally by project and handle connection termination via a no-op `Close` method, while adding test-isolation resets in unit tests. diff --git a/internal/run/api/domainmapping/domainmapping.go b/internal/run/api/domainmapping/domainmapping.go index 6379009..695069a 100644 --- a/internal/run/api/domainmapping/domainmapping.go +++ b/internal/run/api/domainmapping/domainmapping.go @@ -50,25 +50,35 @@ func List(project, region string) ([]model.DomainMapping, error) { } func listAllRegions(project string) ([]model.DomainMapping, error) { - var ( - mu sync.Mutex - domainMappings []model.DomainMapping - wg sync.WaitGroup - ) - - for _, region := range api_region.List() { + // Optimization: lock-free, pre-allocated map-reduce pattern with a slice of slices [][]model.DomainMapping. + // This eliminates mutex contention across concurrent region requests, avoids repeated slice resizing/heap allocations, + // and optimizes concurrency to reduce latency and memory usage. + regions := api_region.List() + results := make([][]model.DomainMapping, len(regions)) + var wg sync.WaitGroup + + for i, region := range regions { wg.Add(1) - go func(r string) { + go func(idx int, r string) { defer wg.Done() if dms, err := List(project, r); err == nil { - mu.Lock() - domainMappings = append(domainMappings, dms...) - mu.Unlock() + results[idx] = dms } - }(region) + }(i, region) } wg.Wait() + + total := 0 + for _, dms := range results { + total += len(dms) + } + + domainMappings := make([]model.DomainMapping, 0, total) + for _, dms := range results { + domainMappings = append(domainMappings, dms...) + } + return domainMappings, nil } diff --git a/internal/run/api/job/job.go b/internal/run/api/job/job.go index a3f8831..0bee04d 100644 --- a/internal/run/api/job/job.go +++ b/internal/run/api/job/job.go @@ -79,27 +79,37 @@ func mapJob(resp *runpb.Job, region string) model.Job { } func listAllRegions(project string) ([]model.Job, error) { - var ( - mu sync.Mutex - jobs []model.Job - wg sync.WaitGroup - ) - - for _, region := range api_region.List() { + // Optimization: lock-free, pre-allocated map-reduce pattern with a slice of slices [][]model.Job. + // This eliminates mutex contention across concurrent region requests, avoids repeated slice resizing/heap allocations, + // and optimizes concurrency to reduce latency and memory usage. + regions := api_region.List() + results := make([][]model.Job, len(regions)) + var wg sync.WaitGroup + + for i, region := range regions { wg.Add(1) - go func(r string) { + go func(idx int, r string) { defer wg.Done() // Call List recursively for each region // We ignore errors here to allow partial success (e.g. if one region is down or disabled) if j, err := List(project, r); err == nil { - mu.Lock() - jobs = append(jobs, j...) - mu.Unlock() + results[idx] = j } - }(region) + }(i, region) } wg.Wait() + + total := 0 + for _, j := range results { + total += len(j) + } + + jobs := make([]model.Job, 0, total) + for _, j := range results { + jobs = append(jobs, j...) + } + return jobs, nil } diff --git a/internal/run/api/service/service.go b/internal/run/api/service/service.go index eb9e078..d333040 100644 --- a/internal/run/api/service/service.go +++ b/internal/run/api/service/service.go @@ -299,26 +299,36 @@ func UpdateTraffic(ctx context.Context, project, region, serviceName string, tar } func listAllRegions(project string) ([]model.Service, error) { - var ( - mu sync.Mutex - services []model.Service - wg sync.WaitGroup - ) - - for _, region := range api_region.List() { + // Optimization: lock-free, pre-allocated map-reduce pattern with a slice of slices [][]model.Service. + // This eliminates mutex contention across concurrent region requests, avoids repeated slice resizing/heap allocations, + // and optimizes concurrency to reduce latency and memory usage. + regions := api_region.List() + results := make([][]model.Service, len(regions)) + var wg sync.WaitGroup + + for i, region := range regions { wg.Add(1) - go func(r string) { + go func(idx int, r string) { defer wg.Done() // Call List recursively for each region // We ignore errors here to allow partial success (e.g. if one region is down or disabled) if s, err := List(project, r); err == nil { - mu.Lock() - services = append(services, s...) - mu.Unlock() + results[idx] = s } - }(region) + }(i, region) } wg.Wait() + + total := 0 + for _, s := range results { + total += len(s) + } + + services := make([]model.Service, 0, total) + for _, s := range results { + services = append(services, s...) + } + return services, nil } diff --git a/internal/run/api/service/service_test.go b/internal/run/api/service/service_test.go index e598a02..904f82f 100644 --- a/internal/run/api/service/service_test.go +++ b/internal/run/api/service/service_test.go @@ -642,4 +642,23 @@ func TestUpdateAuthentication_Error(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "failed to update service") } - \ No newline at end of file + +func BenchmarkListAllRegions(b *testing.B) { + originalClient := apiClient + defer func() { apiClient = originalClient }() + + mock := &MockClient{} + apiClient = mock + + mock.ListServicesFunc = func(ctx context.Context, project, region string) ([]*runpb.Service, error) { + return []*runpb.Service{ + {Name: "projects/" + project + "/locations/" + region + "/services/s1"}, + {Name: "projects/" + project + "/locations/" + region + "/services/s2"}, + }, nil + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = List("my-project", api_region.ALL) + } +} diff --git a/internal/run/api/workerpool/workerpool.go b/internal/run/api/workerpool/workerpool.go index 041f8f4..716db71 100644 --- a/internal/run/api/workerpool/workerpool.go +++ b/internal/run/api/workerpool/workerpool.go @@ -111,27 +111,37 @@ func UpdateScaling(ctx context.Context, project, region, workerPoolName string, } func listAllRegions(project string) ([]model.WorkerPool, error) { - var ( - mu sync.Mutex - workerPools []model.WorkerPool - wg sync.WaitGroup - ) - - for _, region := range api_region.List() { + // Optimization: lock-free, pre-allocated map-reduce pattern with a slice of slices [][]model.WorkerPool. + // This eliminates mutex contention across concurrent region requests, avoids repeated slice resizing/heap allocations, + // and optimizes concurrency to reduce latency and memory usage. + regions := api_region.List() + results := make([][]model.WorkerPool, len(regions)) + var wg sync.WaitGroup + + for i, region := range regions { wg.Add(1) - go func(r string) { + go func(idx int, r string) { defer wg.Done() // Call List recursively for each region // We ignore errors here to allow partial success (e.g. if one region is down or disabled) if wp, err := List(project, r); err == nil { - mu.Lock() - workerPools = append(workerPools, wp...) - mu.Unlock() + results[idx] = wp } - }(region) + }(i, region) } wg.Wait() + + total := 0 + for _, wp := range results { + total += len(wp) + } + + workerPools := make([]model.WorkerPool, 0, total) + for _, wp := range results { + workerPools = append(workerPools, wp...) + } + return workerPools, nil }