chore: build with Go 1.26; use Go 1.25 features (#10570)

WaitGroup.Go and built-in gomaxprocs handling.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
Jakob Borg
2026-02-11 10:41:38 +00:00
committed by GitHub
parent 478d8a007d
commit dc2a77ab8e
44 changed files with 175 additions and 289 deletions
-15
View File
@@ -1,15 +0,0 @@
// Copyright (C) 2024 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package automaxprocs
import (
"go.uber.org/automaxprocs/maxprocs"
)
func init() {
maxprocs.Set()
}
+3 -5
View File
@@ -329,12 +329,10 @@ func (w *wrapper) replaceLocked(to Configuration) (Waiter, error) {
func (w *wrapper) notifyListeners(from, to Configuration) Waiter {
wg := new(sync.WaitGroup)
wg.Add(len(w.subs))
for _, sub := range w.subs {
go func(committer Committer) {
w.notifyListener(committer, from, to)
wg.Done()
}(sub)
wg.Go(func() {
w.notifyListener(sub, from, to)
})
}
return wg
}
+4 -7
View File
@@ -337,23 +337,20 @@ func BenchmarkConnections(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var wg sync.WaitGroup
wg.Add(2)
errC := make(chan error, 2)
go func() {
wg.Go(func() {
if _, err := client.Write(data); err != nil {
errC <- err
return
}
wg.Done()
}()
go func() {
})
wg.Go(func() {
if _, err := io.ReadFull(server, data); err != nil {
errC <- err
return
}
total += sz
wg.Done()
}()
})
wg.Wait()
close(errC)
err := <-errC
+6 -12
View File
@@ -605,15 +605,13 @@ func (s *service) dialDevices(ctx context.Context, now time.Time, cfg config.Con
dialWG.Wait()
dialCancel()
}()
for i := range queue {
for _, entry := range queue {
select {
case <-dialCtx.Done():
return
default:
}
dialWG.Add(1)
go func(entry dialQueueEntry) {
defer dialWG.Done()
dialWG.Go(func() {
conn, ok := s.dialParallel(dialCtx, entry.id, entry.targets, dialSemaphore)
if !ok {
return
@@ -630,7 +628,7 @@ func (s *service) dialDevices(ctx context.Context, now time.Time, cfg config.Con
}
}
numConnsMut.Unlock()
}(queue[i])
})
}
}
@@ -1118,12 +1116,8 @@ func (s *service) dialParallel(ctx context.Context, deviceID protocol.DeviceID,
wg := sync.WaitGroup{}
for _, tgt := range tgts {
sema.Take(1)
wg.Add(1)
go func(tgt dialTarget) {
defer func() {
wg.Done()
sema.Give(1)
}()
wg.Go(func() {
defer sema.Give(1)
conn, err := tgt.Dial(ctx)
if err == nil {
// Closes the connection on error
@@ -1136,7 +1130,7 @@ func (s *service) dialParallel(ctx context.Context, deviceID protocol.DeviceID,
l.Debugln("dialing", deviceID, tgt.uri, "success:", conn)
res <- conn
}
}(tgt)
})
}
// Spawn a routine which will unblock main routine in case we fail
+4 -10
View File
@@ -378,11 +378,8 @@ func TestUnsubscribeContention(t *testing.T) {
stopListeners := make(chan struct{})
var listenerWg sync.WaitGroup
listenerWg.Add(listeners)
for i := 0; i < listeners; i++ {
go func() {
defer listenerWg.Done()
listenerWg.Go(func() {
s := l.Subscribe(AllEvents)
defer s.Unsubscribe()
@@ -394,7 +391,7 @@ func TestUnsubscribeContention(t *testing.T) {
return
}
}
}()
})
}
// Start senders. These send pointless events until the stop channel is
@@ -403,11 +400,8 @@ func TestUnsubscribeContention(t *testing.T) {
stopSenders := make(chan struct{})
defer close(stopSenders)
var senderWg sync.WaitGroup
senderWg.Add(senders)
for i := 0; i < senders; i++ {
go func() {
defer senderWg.Done()
senderWg.Go(func() {
t := time.NewTicker(time.Millisecond)
for {
@@ -419,7 +413,7 @@ func TestUnsubscribeContention(t *testing.T) {
return
}
}
}()
})
}
// Give everything time to start up.
+10 -22
View File
@@ -256,36 +256,28 @@ func (f *sendReceiveFolder) pullerIteration(ctx context.Context, scanChan chan<-
f.sl.DebugContext(ctx, "Starting puller iteration", "copiers", f.Copiers, "pullerPendingKiB", f.PullerMaxPendingKiB)
updateWg.Add(1)
var changed int // only read after updateWg closes
go func() {
updateWg.Go(func() {
// dbUpdaterRoutine finishes when dbUpdateChan is closed
changed = f.dbUpdaterRoutine(dbUpdateChan)
updateWg.Done()
}()
})
for range f.Copiers {
copyWg.Add(1)
go func() {
copyWg.Go(func() {
// copierRoutine finishes when copyChan is closed
f.copierRoutine(ctx, copyChan, pullChan, finisherChan)
copyWg.Done()
}()
})
}
pullWg.Add(1)
go func() {
pullWg.Go(func() {
// pullerRoutine finishes when pullChan is closed
f.pullerRoutine(ctx, pullChan, finisherChan)
pullWg.Done()
}()
})
doneWg.Add(1)
// finisherRoutine finishes when finisherChan is closed
go func() {
doneWg.Go(func() {
f.finisherRoutine(ctx, finisherChan, dbUpdateChan, scanChan)
doneWg.Done()
}()
})
fileDeletions, dirDeletions, err := f.processNeeded(ctx, dbUpdateChan, copyChan, scanChan)
@@ -1534,14 +1526,10 @@ func (f *sendReceiveFolder) pullerRoutine(ctx context.Context, in <-chan pullBlo
continue
}
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
defer requestLimiter.Give(bytes)
f.pullBlock(ctx, state, out)
}()
})
}
wg.Wait()
}
+4 -8
View File
@@ -463,11 +463,9 @@ func TestDeregisterOnFailInPull(t *testing.T) {
copyChan, copyWg := startCopier(t.Context(), f, pullChan, finisherBufferChan)
var pullWg sync.WaitGroup
pullWg.Add(1)
go func() {
pullWg.Go(func() {
f.pullerRoutine(t.Context(), pullChan, finisherBufferChan)
pullWg.Done()
}()
})
go f.finisherRoutine(t.Context(), finisherChan, dbUpdateChan, make(chan string))
defer func() {
// Unblock copier and puller
@@ -1246,10 +1244,8 @@ func cleanupSharedPullerState(s *sharedPullerState) {
func startCopier(ctx context.Context, f *sendReceiveFolder, pullChan chan<- pullBlockState, finisherChan chan<- *sharedPullerState) (chan copyBlocksState, *sync.WaitGroup) {
copyChan := make(chan copyBlocksState)
wg := new(sync.WaitGroup)
wg.Add(1)
go func() {
wg.Go(func() {
f.copierRoutine(ctx, copyChan, pullChan, finisherChan)
wg.Done()
}()
})
return copyChan, wg
}
+3 -7
View File
@@ -993,15 +993,13 @@ func TestIssue5063(t *testing.T) {
if fcfg, ok := m.cfg.Folder(id); !ok || !fcfg.SharedWith(device1) {
t.Error("expected shared", id)
}
wg.Done()
}
reps := 10
ids := make([]string, reps)
for i := 0; i < reps; i++ {
wg.Add(1)
ids[i] = srand.String(8)
go addAndVerify(ids[i])
wg.Go(func() { addAndVerify(ids[i]) })
}
finished := make(chan struct{})
@@ -2945,16 +2943,14 @@ func TestFolderRestartZombies(t *testing.T) {
// for the commit to complete, but there are many of them.
var wg sync.WaitGroup
for i := 0; i < 25; i++ {
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
t0 := time.Now()
for time.Since(t0) < time.Second {
fcfg := folderCfg.Copy()
fcfg.MaxConflicts = mrand.Int() // safe change that should cause a folder restart
setFolder(t, wrapper, fcfg)
}
}()
})
}
// Wait for the above to complete and check how many folders we have
+2 -4
View File
@@ -82,9 +82,7 @@ func TestStressBufferPool(t *testing.T) {
var wg sync.WaitGroup
fail := make(chan struct{}, routines)
for i := 0; i < routines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
for time.Since(t0) < runtime {
blocks := make([][]byte, 10)
for i := range blocks {
@@ -102,7 +100,7 @@ func TestStressBufferPool(t *testing.T) {
bp.Put(blocks[i])
}
}
}()
})
}
wg.Wait()
+6 -12
View File
@@ -110,24 +110,18 @@ func TestCloseOnBlockingSend(t *testing.T) {
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
wg.Go(func() {
c.ClusterConfig(&ClusterConfig{}, nil)
wg.Done()
}()
})
wg.Add(1)
go func() {
wg.Go(func() {
c.Close(errManual)
wg.Done()
}()
})
// This simulates an error from ping timeout
wg.Add(1)
go func() {
wg.Go(func() {
c.internalClose(ErrTimeout)
wg.Done()
}()
})
done := make(chan struct{})
go func() {
+2 -4
View File
@@ -198,10 +198,8 @@ func TryMigrateDatabase(ctx context.Context, deleteRetention time.Duration) erro
fis := make(chan protocol.FileInfo, 50)
var writeErr error
var wg sync.WaitGroup
wg.Add(1)
writerDone := make(chan struct{})
go func() {
defer wg.Done()
wg.Go(func() { //nolint:contextcheck
defer close(writerDone)
var batch []protocol.FileInfo
files, blocks := 0, 0
@@ -238,7 +236,7 @@ func TryMigrateDatabase(ctx context.Context, deleteRetention time.Duration) erro
slog.Info("Migrated folder", "folder", folder, "files", files, "blocks", blocks, "duration", d.Truncate(time.Second), "filesrate", float64(files)/d.Seconds())
totFiles += files
totBlocks += blocks
}()
})
// Iterate the existing files
fs, err := olddb.NewFileSet(folder, ll)
+2 -5
View File
@@ -48,16 +48,13 @@ func TestTimeoutCond(t *testing.T) {
var results [routines][2]int
var wg sync.WaitGroup
for i := 0; i < routines; i++ {
i := i
wg.Add(1)
go func() {
wg.Go(func() {
d := time.Duration(i) * timeMult * time.Millisecond
t.Logf("Routine %d waits for %v\n", i, d)
succ, fail := runLocks(t, iterations, c, d)
results[i][0] = succ
results[i][1] = fail
wg.Done()
}()
})
}
wg.Wait()
+6 -8
View File
@@ -123,28 +123,26 @@ func Discover(ctx context.Context, _, timeout time.Duration) []nat.Device {
continue
}
wg.Add(1)
// Discovery is done sequentially per interface because we discovered that
// FritzBox routers return a broken result sometimes if the IPv4 and IPv6
// request arrive at the same time.
go func(iface net.Interface) {
defer wg.Done()
hasGUA, err := interfaceHasGUAIPv6(iface)
wg.Go(func() {
hasGUA, err := interfaceHasGUAIPv6(intf)
if err != nil {
l.Debugf("Couldn't check for IPv6 GUAs on %s: %s", iface.Name, err)
l.Debugf("Couldn't check for IPv6 GUAs on %s: %s", intf.Name, err) //nolint:contextcheck
} else if hasGUA {
// Discover IPv6 gateways on interface. Only discover IGDv2, since IGDv1
// + IPv6 is not standardized and will lead to duplicates on routers.
// Only do this when a non-link-local IPv6 is available. if we can't
// enumerate the interface, the IPv6 code will not work anyway
discover(ctx, &iface, urnIgdV2, timeout, resultChan, true)
discover(ctx, &intf, urnIgdV2, timeout, resultChan, true)
}
// Discover IPv4 gateways on interface.
for _, deviceType := range []string{urnIgdV2, urnIgdV1} {
discover(ctx, &iface, deviceType, timeout, resultChan, false)
discover(ctx, &intf, deviceType, timeout, resultChan, false)
}
}(intf)
})
}
go func() {