Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package rqlite for openSUSE:Factory checked 
in at 2026-06-25 10:52:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rqlite (Old)
 and      /work/SRC/openSUSE:Factory/.rqlite.new.2088 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rqlite"

Thu Jun 25 10:52:13 2026 rev:51 rq:1361486 version:10.2.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/rqlite/rqlite.changes    2026-05-30 
22:58:25.484985549 +0200
+++ /work/SRC/openSUSE:Factory/.rqlite.new.2088/rqlite.changes  2026-06-25 
10:56:23.427685899 +0200
@@ -1,0 +2,11 @@
+Tue Jun 23 18:39:20 UTC 2026 - Andreas Stieger <[email protected]>
+
+- Update to version 10.2.4:
+  * Fix some non-AWS S3-compatible stores
+- includes changes from 10.2.3
+  * Check snapshot store integrity before first actual use
+  * Disable HTTP timeout for boot and restore operations via the shell
+  * HTTP layer ignores ErrNoWALToSnapshot when snapshotting
+  * Close Snapshot Streamer ASAP when restoring to local node
+
+-------------------------------------------------------------------

Old:
----
  rqlite-10.2.0.tar.xz

New:
----
  rqlite-10.2.4.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rqlite.spec ++++++
--- /var/tmp/diff_new_pack.e2c0B0/_old  2026-06-25 10:56:24.427720384 +0200
+++ /var/tmp/diff_new_pack.e2c0B0/_new  2026-06-25 10:56:24.431720523 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           rqlite
-Version:        10.2.0
+Version:        10.2.4
 Release:        0
 Summary:        Distributed relational database built on SQLite
 License:        MIT

++++++ _service ++++++
--- /var/tmp/diff_new_pack.e2c0B0/_old  2026-06-25 10:56:24.475722040 +0200
+++ /var/tmp/diff_new_pack.e2c0B0/_new  2026-06-25 10:56:24.479722178 +0200
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/rqlite/rqlite.git</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">v10.2.0</param>
+    <param name="revision">v10.2.4</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="changesgenerate">enable</param>
     <param name="versionrewrite-pattern">v(.*)</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.e2c0B0/_old  2026-06-25 10:56:24.503723005 +0200
+++ /var/tmp/diff_new_pack.e2c0B0/_new  2026-06-25 10:56:24.507723143 +0200
@@ -1,7 +1,7 @@
 <servicedata>
   <service name="tar_scm">
     <param name="url">https://github.com/rqlite/rqlite.git</param>
-    <param 
name="changesrevision">6809aa3b6f373b86aa4e1265b9c47bf5d09e1819</param>
+    <param 
name="changesrevision">d950fea281016fdf4006da72afa93ec04671f99a</param>
   </service>
 </servicedata>
 (No newline at EOF)

++++++ rqlite-10.2.0.tar.xz -> rqlite-10.2.4.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/CHANGELOG.md 
new/rqlite-10.2.4/CHANGELOG.md
--- old/rqlite-10.2.0/CHANGELOG.md      2026-05-29 15:30:17.000000000 +0200
+++ new/rqlite-10.2.4/CHANGELOG.md      2026-06-21 21:25:37.000000000 +0200
@@ -1,3 +1,26 @@
+## v10.2.4 (June 21st 2026)
+### Implementation changes and bug fixes
+- [PR #2700](https://github.com/rqlite/rqlite/pull/2700): Unit test Snapshot 
Store `Verify`.
+- [PR #2701](https://github.com/rqlite/rqlite/pull/2701): Set 
RequestChecksumCalculationWhenRequired for S3-compatible stores. Fixes issue 
[#2699](https://github.com/rqlite/rqlite/issues/2699). Thanks @NerdyShawn
+
+## v10.2.3 (June 20th 2026)
+### Implementation changes and bug fixes
+- [PR #2695](https://github.com/rqlite/rqlite/pull/2695): Check snapshot store 
integrity before first actual use.  Triggered by 
[#2687](https://github.com/rqlite/rqlite/issues/2687).
+- [PR #2696](https://github.com/rqlite/rqlite/pull/2696): Disable HTTP timeout 
for boot and restore operations via the shell.
+- [PR #2697](https://github.com/rqlite/rqlite/pull/2697): HTTP layer ignores 
`ErrNoWALToSnapshot` when snapshotting.
+- [PR #2698](https://github.com/rqlite/rqlite/pull/2698): Close Snapshot 
Streamer ASAP when restoring to local node.
+
+## v10.2.2 (June 19th 2026)
+### Implementation changes and bug fixes
+- [PR #2694](https://github.com/rqlite/rqlite/pull/2694): Force-close 
in-flight node-to-node connections during shutdown, so a stalled Raft snapshot 
transfer cannot block a node from shutting down. Triggered by 
[#2687](https://github.com/rqlite/rqlite/issues/2687).
+- [PR #2693](https://github.com/rqlite/rqlite/pull/2693): Export `Check` 
method on Snapshot Store.
+
+## v10.2.1 (June 17th 2026)
+### Implementation changes and bug fixes
+- [PR #2686](https://github.com/rqlite/rqlite/pull/2686): Limit number of 
connections to cluster service. Fixes issue 
[#2617](https://github.com/rqlite/rqlite/issues/2617). Thanks @shrtyk
+- [PR #2688](https://github.com/rqlite/rqlite/pull/2688): Upgrade dependencies 
via `go get`.
+- [PR #2689](https://github.com/rqlite/rqlite/pull/2689): Upgrade to SQLite 
3.35.2.
+
 ## v10.2.0 (May 29th 2026)
 ### New features
 - [PR #2661](https://github.com/rqlite/rqlite/pull/2661), [PR 
#2679](https://github.com/rqlite/rqlite/pull/2679), [PR 
#2683](https://github.com/rqlite/rqlite/pull/2683), [PR 
#2685](https://github.com/rqlite/rqlite/pull/2685): Support verifying mTLS peer 
Common Name. Thanks @hifi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/auto/aws/s3.go 
new/rqlite-10.2.4/auto/aws/s3.go
--- old/rqlite-10.2.0/auto/aws/s3.go    2026-05-29 15:30:17.000000000 +0200
+++ new/rqlite-10.2.4/auto/aws/s3.go    2026-06-21 21:25:37.000000000 +0200
@@ -58,6 +58,7 @@
        // Load the default config
        cfg, err := config.LoadDefaultConfig(context.Background(),
                config.WithRegion(region),
+               
config.WithRequestChecksumCalculation(aws.RequestChecksumCalculationWhenRequired),
        )
        if err != nil {
                return nil, fmt.Errorf("unable to load SDK config, %v", err)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/cluster/service.go 
new/rqlite-10.2.4/cluster/service.go
--- old/rqlite-10.2.0/cluster/service.go        2026-05-29 15:30:17.000000000 
+0200
+++ new/rqlite-10.2.4/cluster/service.go        2026-06-21 21:25:37.000000000 
+0200
@@ -5,6 +5,7 @@
        "compress/gzip"
        "context"
        "encoding/binary"
+       "errors"
        "expvar"
        "fmt"
        "io"
@@ -19,11 +20,17 @@
        "github.com/rqlite/rqlite/v10/auth"
        "github.com/rqlite/rqlite/v10/cluster/proto"
        command "github.com/rqlite/rqlite/v10/command/proto"
+       "github.com/rqlite/rqlite/v10/internal/rsync"
        pb "google.golang.org/protobuf/proto"
 )
 
-// stats captures stats for the Cluster service.
-var stats *expvar.Map
+var (
+       // stats captures stats for the Cluster service.
+       stats *expvar.Map
+
+       // ErrServiceOpen is returned when the service is already open.
+       ErrServiceOpen = errors.New("service already open")
+)
 
 const (
        numGetNodeAPIRequest   = "num_get_node_api_req"
@@ -39,6 +46,7 @@
        numStepdownRequest     = "num_stepdown_req"
        numBroadcastHWMRequest = "num_broadcast_hwm_req"
        numHWMUpdateDropped    = "num_hwm_update_dropped"
+       numConnRejected        = "num_conn_rejected"
 
        numClientRetries            = "num_client_retries"
        numGetNodeAPIRequestRetries = "num_get_node_api_req_retries"
@@ -66,6 +74,10 @@
        // connection is closed, preventing stalled clients from holding
        // goroutines indefinitely.
        connReadTimeout = 30 * time.Second
+
+       // maxConcurrentConns bounds the number of connections the service 
handles
+       // concurrently, preventing connection floods from spawning unbounded 
goroutines.
+       maxConcurrentConns = 512
 )
 
 func init() {
@@ -97,6 +109,7 @@
        stats.Add(numClientReadTimeouts, 0)
        stats.Add(numClientWriteTimeouts, 0)
        stats.Add(numClientForceNewConn, 0)
+       stats.Add(numConnRejected, 0)
 }
 
 // Dialer is the interface dialers must implement.
@@ -165,14 +178,21 @@
        credentialStore CredentialStore
 
        mu      sync.RWMutex
-       https   bool   // Serving HTTPS?
-       apiAddr string // host:port this node serves the HTTP API.
-       version string // Version of software this node is running.
+       https   bool              // Serving HTTPS?
+       apiAddr string            // host:port this node serves the HTTP API.
+       version string            // Version of software this node is running.
+       open    *rsync.AtomicBool // Tracks whether the service is currently 
open.
 
        // connTimeout is the maximum time to wait for data on a
        // connection. Must be set before Open is called.
        connTimeout time.Duration
 
+       // connLimit is the maximum number of concurrent service connections.
+       connLimit int
+
+       // connLimiterCh limits the number of in-service connections.
+       connLimiterCh chan struct{}
+
        hwmMu      sync.RWMutex
        hwmUpdateC chan<- uint64 // Channel for HWM updates
 
@@ -189,11 +209,20 @@
                logger:          log.New(os.Stderr, "[cluster] ", 
log.LstdFlags),
                credentialStore: credentialStore,
                connTimeout:     connReadTimeout,
+               connLimit:       maxConcurrentConns,
+               open:            rsync.NewAtomicBool(),
        }
 }
 
 // Open opens the Service.
 func (s *Service) Open() error {
+       if s.open.Is() {
+               return ErrServiceOpen
+       }
+
+       s.connLimiterCh = make(chan struct{}, s.connLimit)
+       s.open.Set()
+
        go s.serve()
        s.logger.Println("service listening on", s.addr)
        return nil
@@ -201,8 +230,11 @@
 
 // Close closes the service.
 func (s *Service) Close() error {
-       s.ln.Close()
-       return nil
+       err := s.ln.Close()
+       if err == nil {
+               s.open.Unset()
+       }
+       return err
 }
 
 // RegisterHWMUpdate registers a channel to receive highwater mark update 
requests.
@@ -275,6 +307,21 @@
        return st, nil
 }
 
+// SetConnectionLimit sets the maximum number of concurrent service 
connections.
+// It must be called before Open. Non-positive values use the default limit.
+func (s *Service) SetConnectionLimit(n int) error {
+       if s.open.Is() {
+               return ErrServiceOpen
+       }
+
+       if n <= 0 {
+               n = maxConcurrentConns
+       }
+
+       s.connLimit = n
+       return nil
+}
+
 func (s *Service) serve() error {
        for {
                conn, err := s.ln.Accept()
@@ -282,7 +329,16 @@
                        return err
                }
 
-               go s.handleConn(conn)
+               select {
+               case s.connLimiterCh <- struct{}{}:
+                       go func() {
+                               defer func() { <-s.connLimiterCh }()
+                               s.handleConn(conn)
+                       }()
+               default:
+                       _ = conn.Close()
+                       stats.Add(numConnRejected, 1)
+               }
        }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/cluster/service_test.go 
new/rqlite-10.2.4/cluster/service_test.go
--- old/rqlite-10.2.0/cluster/service_test.go   2026-05-29 15:30:17.000000000 
+0200
+++ new/rqlite-10.2.4/cluster/service_test.go   2026-06-21 21:25:37.000000000 
+0200
@@ -3,6 +3,7 @@
 import (
        "context"
        "crypto/tls"
+       "errors"
        "fmt"
        "io"
        "net"
@@ -539,6 +540,100 @@
        }
 }
 
+func Test_ServiceSetConnectionLimitOpen(t *testing.T) {
+       ml := mustNewMockTransport()
+       s := New(ml, mustNewMockDatabase(), mustNewMockManager(), 
mustNewMockCredentialStore())
+
+       if err := s.Open(); err != nil {
+               t.Fatalf("failed to open cluster service")
+       }
+       defer s.Close()
+
+       if err := s.SetConnectionLimit(1); !errors.Is(err, ErrServiceOpen) {
+               t.Fatalf("expected ErrServiceOpen, got: %v", err)
+       }
+}
+
+func Test_ServiceConnLimiterRejectAndRelease(t *testing.T) {
+       ml := mustNewMockTransport()
+       s := New(ml, mustNewMockDatabase(), mustNewMockManager(), 
mustNewMockCredentialStore())
+       if err := s.SetConnectionLimit(1); err != nil {
+               t.Fatalf("failed to set connection limit: %s", err)
+       }
+
+       if err := s.Open(); err != nil {
+               t.Fatalf("failed to open cluster service")
+       }
+       defer s.Close()
+
+       md := &mockDialer{Dialer: ml}
+       t.Cleanup(md.CloseAll)
+
+       c1 := NewClient(md, 30*time.Second)
+       _, err := c1.GetNodeMeta(context.Background(), s.Addr(), noRetries, 
5*time.Second)
+       if err != nil {
+               t.Fatalf("failed to get node metadata on first connection: %s", 
err)
+       }
+
+       // The first client's pooled connection remains open and holds the 
limiter slot.
+       c2 := NewClient(md, 30*time.Second)
+       _, err = c2.GetNodeMeta(context.Background(), s.Addr(), noRetries, 
500*time.Millisecond)
+       if err == nil {
+               t.Fatalf("expected request on rejected connection to fail")
+       }
+       if netErr, ok := errors.AsType[net.Error](err); ok && netErr.Timeout() {
+               t.Fatalf("expected connection to be rejected without timing 
out, got: %v", err)
+       }
+
+       // Releasing the idle connection should free its limiter slot.
+       if err := md.CloseConn(0); err != nil {
+               t.Fatalf("failed to close first connection: %s", err)
+       }
+
+       // A new client request should be accepted once capacity is available 
again.
+       c3 := NewClient(md, 30*time.Second)
+       _, err = c3.GetNodeMeta(context.Background(), s.Addr(), noRetries, 
500*time.Millisecond)
+       if err != nil {
+               t.Fatalf("failed to get node metadata after release: %s", err)
+       }
+}
+
+type mockDialer struct {
+       Dialer
+       mu    sync.Mutex
+       conns []net.Conn
+}
+
+func (d *mockDialer) Dial(address string, timeout time.Duration) (net.Conn, 
error) {
+       conn, err := d.Dialer.Dial(address, timeout)
+       if err != nil {
+               return nil, err
+       }
+
+       d.mu.Lock()
+       d.conns = append(d.conns, conn)
+       d.mu.Unlock()
+
+       return conn, nil
+}
+
+func (d *mockDialer) CloseConn(index int) error {
+       d.mu.Lock()
+       defer d.mu.Unlock()
+       if index < 0 || index >= len(d.conns) {
+               return fmt.Errorf("connection %d not tracked", index)
+       }
+       return d.conns[index].Close()
+}
+
+func (d *mockDialer) CloseAll() {
+       d.mu.Lock()
+       defer d.mu.Unlock()
+       for _, conn := range d.conns {
+               _ = conn.Close()
+       }
+}
+
 type mockTransport struct {
        tn              net.Listener
        remoteEncrypted bool
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/cmd/rqlite/backup.go 
new/rqlite-10.2.4/cmd/rqlite/backup.go
--- old/rqlite-10.2.0/cmd/rqlite/backup.go      2026-05-29 15:30:17.000000000 
+0200
+++ new/rqlite-10.2.4/cmd/rqlite/backup.go      2026-06-21 21:25:37.000000000 
+0200
@@ -137,9 +137,12 @@
                contentType = "application/octet-stream"
        }
 
+       // Restoring uploads the whole file and waits for the node to load it, 
which
+       // can take far longer than a normal request, so use a client without an
+       // overall request timeout to avoid aborting the upload mid-transfer.
        u := fmt.Sprintf("%sdb/load", client.Prefix)
        headers := http.Header{"Content-Type": {contentType}}
-       resp, err := client.PostWithHeaders(u, bytes.NewReader(restoreFile), 
headers)
+       resp, err := client.WithoutTimeout().PostWithHeaders(u, 
bytes.NewReader(restoreFile), headers)
        if err != nil {
                return err
        }
@@ -192,8 +195,12 @@
        }
        defer fd.Close()
 
+       // Booting streams a potentially large SQLite file, and the node must 
finish
+       // loading it before responding, so this can take far longer than a 
normal
+       // request. Use a client without an overall request timeout to avoid 
aborting
+       // the upload mid-transfer.
        u := fmt.Sprintf("%sboot", client.Prefix)
-       resp, err := client.Post(u, fd)
+       resp, err := client.WithoutTimeout().Post(u, fd)
        if err != nil {
                return err
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/cmd/rqlite/http/client.go 
new/rqlite-10.2.4/cmd/rqlite/http/client.go
--- old/rqlite-10.2.0/cmd/rqlite/http/client.go 2026-05-29 15:30:17.000000000 
+0200
+++ new/rqlite-10.2.4/cmd/rqlite/http/client.go 2026-06-21 21:25:37.000000000 
+0200
@@ -103,6 +103,21 @@
        }
 }
 
+// WithoutTimeout returns a shallow copy of the Client whose underlying
+// http.Client has no overall request timeout, while sharing the same 
Transport,
+// hosts, credentials, and configuration as the receiver. It is intended for
+// long-running streaming uploads (e.g. boot and restore) where a fixed
+// whole-request deadline is inappropriate; liveness is instead governed by the
+// Transport's connection-level timeouts. The receiver is left unmodified.
+func (c *Client) WithoutTimeout() *Client {
+       httpClient := *c.Client
+       httpClient.Timeout = 0
+
+       clientCopy := *c
+       clientCopy.Client = &httpClient
+       return &clientCopy
+}
+
 // GetDirect sends a GET request to the exact URL provided, with authentication
 // but without host override or failover. Use this when you need to target a
 // specific node rather than any node in the cluster.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/cmd/rqlite/main.go 
new/rqlite-10.2.4/cmd/rqlite/main.go
--- old/rqlite-10.2.0/cmd/rqlite/main.go        2026-05-29 15:30:17.000000000 
+0200
+++ new/rqlite-10.2.4/cmd/rqlite/main.go        2026-06-21 21:25:37.000000000 
+0200
@@ -877,7 +877,14 @@
 func createHostList(argv *argT) []string {
        var hosts = make([]string, 0)
        hosts = append(hosts, address6(argv))
-       hosts = append(hosts, strings.Split(argv.Alternatives, ",")...)
+       // Alternatives is a comma-separated list. Skip empty entries so a 
blank or
+       // trailing-comma value doesn't add a bogus "" host to the failover list
+       // (strings.Split("", ",") returns [""]).
+       for _, a := range strings.Split(argv.Alternatives, ",") {
+               if a = strings.TrimSpace(a); a != "" {
+                       hosts = append(hosts, a)
+               }
+       }
        return hosts
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/cmd/rqlited/main.go 
new/rqlite-10.2.4/cmd/rqlited/main.go
--- old/rqlite-10.2.0/cmd/rqlited/main.go       2026-05-29 15:30:17.000000000 
+0200
+++ new/rqlite-10.2.4/cmd/rqlited/main.go       2026-06-21 21:25:37.000000000 
+0200
@@ -270,7 +270,15 @@
                str.Stepdown(true, "")
        }
        muxLn.Close()
-       defer mux.Close()
+
+       // Close the mux, which force-closes any in-flight node-to-node 
connections
+       // (e.g. a Raft snapshot transfer from a peer that is itself shutting 
down).
+       // Such internode reads have no deadline, so this must happen before
+       // str.Close below, otherwise the pre-close snapshot and Raft shutdown 
could
+       // block indefinitely on the Raft run goroutine.
+       if err := mux.Close(); err != nil {
+               log.Printf("failed to close mux during shutdown: %s", 
err.Error())
+       }
 
        if err := str.Close(true); err != nil {
                log.Printf("failed to close store: %s", err.Error())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/go.mod new/rqlite-10.2.4/go.mod
--- old/rqlite-10.2.0/go.mod    2026-05-29 15:30:17.000000000 +0200
+++ new/rqlite-10.2.4/go.mod    2026-06-21 21:25:37.000000000 +0200
@@ -3,15 +3,15 @@
 go 1.26
 
 require (
-       github.com/aws/aws-sdk-go-v2 v1.41.7
-       github.com/aws/aws-sdk-go-v2/config v1.32.17
-       github.com/aws/aws-sdk-go-v2/credentials v1.19.16
-       github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.18
-       github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0
+       github.com/aws/aws-sdk-go-v2 v1.42.0
+       github.com/aws/aws-sdk-go-v2/config v1.32.25
+       github.com/aws/aws-sdk-go-v2/credentials v1.19.24
+       github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.28
+       github.com/aws/aws-sdk-go-v2/service/s3 v1.104.0
        github.com/hashicorp/go-hclog v1.6.3
        github.com/hashicorp/raft v1.7.3
        github.com/klauspost/compress v1.18.6
-       github.com/mattn/go-sqlite3 v1.14.44
+       github.com/mattn/go-sqlite3 v1.14.45
        github.com/mkideal/cli v0.2.7
        github.com/mkideal/pkg v0.1.3
        github.com/peterh/liner v1.2.2
@@ -19,26 +19,26 @@
        github.com/rqlite/rqlite-disco-clients 
v0.0.0-20250205044118-8ada2b350099
        github.com/rqlite/sql v0.0.0-20260224021119-1b2524a41372
        go.etcd.io/bbolt v1.4.3
-       golang.org/x/net v0.55.0
+       golang.org/x/net v0.56.0
        google.golang.org/protobuf v1.36.11
 )
 
 require (
        github.com/armon/go-metrics v0.5.4 // indirect
-       github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10 // 
indirect
-       github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 // indirect
-       github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect
-       github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 // indirect
-       github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect
-       github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 
// indirect
-       github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.15 // 
indirect
-       github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // 
indirect
-       github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.23 // 
indirect
-       github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect
-       github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect
-       github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 // indirect
-       github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect
-       github.com/aws/smithy-go v1.25.1 // indirect
+       github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.13 // 
indirect
+       github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29 // indirect
+       github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29 // indirect
+       github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29 // indirect
+       github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30 // indirect
+       github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12 
// indirect
+       github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.22 // 
indirect
+       github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29 // 
indirect
+       github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.29 // 
indirect
+       github.com/aws/aws-sdk-go-v2/service/signin v1.2.0 // indirect
+       github.com/aws/aws-sdk-go-v2/service/sso v1.31.3 // indirect
+       github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6 // indirect
+       github.com/aws/aws-sdk-go-v2/service/sts v1.43.3 // indirect
+       github.com/aws/smithy-go v1.27.2 // indirect
        github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
        github.com/coreos/go-semver v0.3.1 // indirect
        github.com/coreos/go-systemd/v22 v22.7.0 // indirect
@@ -47,7 +47,7 @@
        github.com/gogo/protobuf v1.3.2 // indirect
        github.com/golang/protobuf v1.5.4 // indirect
        github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
-       github.com/hashicorp/consul/api v1.34.2 // indirect
+       github.com/hashicorp/consul/api v1.34.3 // indirect
        github.com/hashicorp/errwrap v1.1.0 // indirect
        github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
        github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
@@ -59,27 +59,27 @@
        github.com/hashicorp/golang-lru v1.0.2 // indirect
        github.com/hashicorp/serf v0.10.2 // indirect
        github.com/labstack/gommon v0.5.0 // indirect
-       github.com/mattn/go-colorable v0.1.14 // indirect
+       github.com/mattn/go-colorable v0.1.15 // indirect
        github.com/mattn/go-isatty v0.0.22 // indirect
-       github.com/mattn/go-runewidth v0.0.23 // indirect
+       github.com/mattn/go-runewidth v0.0.24 // indirect
        github.com/mitchellh/go-homedir v1.1.0 // indirect
        github.com/mkideal/expr v0.1.0 // indirect
-       go.etcd.io/etcd/api/v3 v3.6.11 // indirect
-       go.etcd.io/etcd/client/pkg/v3 v3.6.11 // indirect
-       go.etcd.io/etcd/client/v3 v3.6.11 // indirect
+       go.etcd.io/etcd/api/v3 v3.6.12 // indirect
+       go.etcd.io/etcd/client/pkg/v3 v3.6.12 // indirect
+       go.etcd.io/etcd/client/v3 v3.6.12 // indirect
        go.uber.org/multierr v1.11.0 // indirect
        go.uber.org/zap v1.28.0 // indirect
-       golang.org/x/crypto v0.51.0 // indirect
-       golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect
-       golang.org/x/sys v0.45.0 // indirect
-       golang.org/x/term v0.43.0 // indirect
-       golang.org/x/text v0.37.0 // indirect
-       google.golang.org/genproto/googleapis/api 
v0.0.0-20260504160031-60b97b32f348 // indirect
-       google.golang.org/genproto/googleapis/rpc 
v0.0.0-20260504160031-60b97b32f348 // indirect
-       google.golang.org/grpc v1.81.0 // indirect
+       golang.org/x/crypto v0.53.0 // indirect
+       golang.org/x/exp v0.0.0-20260611194520-c48552f49976 // indirect
+       golang.org/x/sys v0.46.0 // indirect
+       golang.org/x/term v0.44.0 // indirect
+       golang.org/x/text v0.38.0 // indirect
+       google.golang.org/genproto/googleapis/api 
v0.0.0-20260615183401-62b3387ff324 // indirect
+       google.golang.org/genproto/googleapis/rpc 
v0.0.0-20260615183401-62b3387ff324 // indirect
+       google.golang.org/grpc v1.81.1 // indirect
 )
 
 replace (
        github.com/armon/go-metrics => github.com/hashicorp/go-metrics v0.5.1
-       github.com/mattn/go-sqlite3 => github.com/rqlite/go-sqlite3 v1.47.0
+       github.com/mattn/go-sqlite3 => github.com/rqlite/go-sqlite3 v1.48.0
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/go.sum new/rqlite-10.2.4/go.sum
--- old/rqlite-10.2.0/go.sum    2026-05-29 15:30:17.000000000 +0200
+++ new/rqlite-10.2.4/go.sum    2026-06-21 21:25:37.000000000 +0200
@@ -5,44 +5,44 @@
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod 
h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod 
h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod 
h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aws/aws-sdk-go-v2 v1.41.7 
h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6tLY8=
-github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod 
h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10 
h1:gx1AwW1Iyk9Z9dD9F4akX5gnN3QZwUB20GGKH/I+Rho=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10/go.mod 
h1:qqY157uZoqm5OXq/amuaBJyC9hgBCBQnsaWnPe905GY=
-github.com/aws/aws-sdk-go-v2/config v1.32.17 
h1:FpL4/758/diKwqbytU0prpuiu60fgXKUWCpDJtApclU=
-github.com/aws/aws-sdk-go-v2/config v1.32.17/go.mod 
h1:OXqUMzgXytfoF9JaKkhrOYsyh72t9G+MJH8mMRaexOE=
-github.com/aws/aws-sdk-go-v2/credentials v1.19.16 
h1:r3RJBuU7X9ibt8RHbMjWE6y60QbKBiII6wSrXnapxSU=
-github.com/aws/aws-sdk-go-v2/credentials v1.19.16/go.mod 
h1:6cx7zqDENJDbBIIWX6P8s0h6hqHC8Avbjh9Dseo27ug=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 
h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod 
h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.18 
h1:9XFUd2lkr7VrbE4Qtrhm7AtNhGgZeGFI5QLZtQIflj8=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.18/go.mod 
h1:trImuKdWelQIJALvyGj6sKolJ1W8t628JOoTdDGVL9Q=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 
h1:GpT/TrnBYuE5gan2cZbTtvP+JlHsutdmlV2YfEyNde0=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23/go.mod 
h1:xYWD6BS9ywC5bS3sz9Xh04whO/hzK2plt2Zkyrp4JuA=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 
h1:bpd8vxhlQi2r1hiueOw02f/duEPTMK59Q4QMAoTTtTo=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23/go.mod 
h1:15DfR2nw+CRHIk0tqNyifu3G1YdAOy68RftkhMDDwYk=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 
h1:OQqn11BtaYv1WLUowvcA30MpzIu8Ti4pcLPIIyoKZrA=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24/go.mod 
h1:X5ZJyfwVrWA96GzPmUCWFQaEARPR7gCrpq2E92PJwAE=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 
h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod 
h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.15 
h1:ieLCO1JxUWuxTZ1cRd0GAaeX7O6cIxnwk7tc1LsQhC4=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.15/go.mod 
h1:e3IzZvQ3kAWNykvE0Tr0RDZCMFInMvhku3qNpcIQXhM=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 
h1:pbrxO/kuIwgEsOPLkaHu0O+m4fNgLU8B3vxQ+72jTPw=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23/go.mod 
h1:/CMNUqoj46HpS3MNRDEDIwcgEnrtZlKRaHNaHxIFpNA=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.23 
h1:03xatSQO4+AM1lTAbnRg5OK528EUg744nW7F73U8DKw=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.23/go.mod 
h1:M8l3mwgx5ToK7wot2sBBce/ojzgnPzZXUV445gTSyE8=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0 
h1:etqBTKY581iwLL/H/S2sVgk3C9lAsTJFeXWFDsDcWOU=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0/go.mod 
h1:L2dcoOgS2VSgbPLvpak2NyUPsO1TBN7M45Z4H7DlRc4=
-github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 
h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc=
-github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod 
h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI=
-github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 
h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE=
-github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod 
h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 
h1:+1Kl1zx6bWi4X7cKi3VYh29h8BvsCoHQEQ6ST9X8w7w=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21/go.mod 
h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg=
-github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 
h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk=
-github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod 
h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio=
-github.com/aws/smithy-go v1.25.1 
h1:J8ERsGSU7d+aCmdQur5Txg6bVoYelvQJgtZehD12GkI=
-github.com/aws/smithy-go v1.25.1/go.mod 
h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
+github.com/aws/aws-sdk-go-v2 v1.42.0 
h1:XvXMJTkFQtpBKIWZnmr9ZEOc2InWM2yldjXEJ/bymhA=
+github.com/aws/aws-sdk-go-v2 v1.42.0/go.mod 
h1:27+ACypSLljLAEKsCYOmrjKh83vuTRkuAe9Uv/3A4bg=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.13 
h1:p1BBrg/Hhp6uK7zpejeI8QFXHJeC/mynzi04Sl03k9g=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.13/go.mod 
h1:8cIfkE9MDhkRZGpQ22aV6/lkYeYSozpz16Smrs5x4Ls=
+github.com/aws/aws-sdk-go-v2/config v1.32.25 
h1:ACCejvStYoilgwrfegSt5ZntCbPrk52qfwyNcnl3omM=
+github.com/aws/aws-sdk-go-v2/config v1.32.25/go.mod 
h1:LJyU8sDRbXUxFn8xMJIGP+v9QYYwveNLI8a/giAOiAs=
+github.com/aws/aws-sdk-go-v2/credentials v1.19.24 
h1:2hQqYCV9yqyePQ9o6dCrZc/zO8U3TwPr9mIKlZnPu/I=
+github.com/aws/aws-sdk-go-v2/credentials v1.19.24/go.mod 
h1:IDwpACtwqHLISdzfwUUNq4P9DsB/h5BLg4FwJPNfqFY=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29 
h1:r6qZHbT+wxgWO/e9vYNUEtg7lv5+UN3pRqKhLXvnArg=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29/go.mod 
h1:QRnaRcTVGKPGRy8w78HMQtKUGRYcnMZAANATkeVA6Mo=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.28 
h1:ez4y5o7sa0uaRI8BquYOXtZpioUPhbQEh7Igm88oV9U=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.28/go.mod 
h1:TpmZOrQA12XKEpVypgBGZSQBsm1WUTndCiSnbDsbvug=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29 
h1:f3vKqSo13fhTYb+JEcXwXefZQE26I1FB5eTSniU67ko=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29/go.mod 
h1:MzoLFUArKGpGD+ukmPiTPG1X5x4o6M2kq4v2dr1FiEc=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29 
h1:RdwIf/CuUsvJX3RgJagbOyotl/cxoLY4xviKuE7p2GY=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29/go.mod 
h1:71wt8W2EgswdZy9Mf9KNnzxZ3TiZlv4caKghPktDOkA=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30 
h1:VTGy885W5DKBxWRUJbym9hytNaYzsyaPkCHGRRMAOhU=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30/go.mod 
h1:AS0HycUvJRFvTt613AYDOgO2jzw+00cVSMny8XB3yMY=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12 
h1:ZD2+BSw9vFsNlKYIasSNt3uDbjqqXIBcM13UJv/Lx2k=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12/go.mod 
h1:Ms4zlcVBbXbiP7EVLhl+lgjvA/a7YphqQ3Ih3174EmI=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.22 
h1:V51LGlOq/1VsDsHUdoklAQi7rMmx4qQubvFYAlP2254=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.22/go.mod 
h1:4Pzhyz8hJOm2bepgl+NjvRx8vlUFAIIvJnZ/MkcNPpU=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29 
h1:DRebniUGZ2MqiiIVmQJ04vIXr918hubdHMnarSLEWyU=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29/go.mod 
h1:LfRkPCD8YHDM2E5eTkos2UpwYeZnBcVarTa8L59bJHA=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.29 
h1:hiME6pBzC7OTl9LMtlyTWBuEl1f4QBcUmFDKC7MLXtc=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.29/go.mod 
h1:G7RP+uhagpKtKhd1BM9N6JQqjCcGEU47K5lBVZQyRQw=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.104.0 
h1:ta8csKy5vN91F3i5gGR85lFV0srBqySEji7Jroes6rE=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.104.0/go.mod 
h1:77ZAgynvx1txMvDG8gGWoWkO1augYDxkp9JElWFgjQU=
+github.com/aws/aws-sdk-go-v2/service/signin v1.2.0 
h1:3nXpRcFwRCW8n7HgO2QGy0Dc20eQNfBuUemGQhpF8m8=
+github.com/aws/aws-sdk-go-v2/service/signin v1.2.0/go.mod 
h1:LxYujSTLPRlp2vTtcUO/+1ilrew8ytt6SvQyOgejzFQ=
+github.com/aws/aws-sdk-go-v2/service/sso v1.31.3 
h1:ey1XLTYXb9PcLt4535632o5kCGXNXEhNb620Dqwuylo=
+github.com/aws/aws-sdk-go-v2/service/sso v1.31.3/go.mod 
h1:Lk7PlmoTYryQmyBG0EXqj5BcUbj3whXdU2s3yGI3EAc=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6 
h1:yLr03zQE/5Eu5l3QU0Si+xMbLMbSDF2YXsigqXngs6g=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6/go.mod 
h1:Q5N6icH+KJZDLh+ESNwzdv6cZ6vLFF/egy3IOxWhmz4=
+github.com/aws/aws-sdk-go-v2/service/sts v1.43.3 
h1:VrIhKRCSK1umelSgB9RghvA9RTUYeQffyAS5ApXehNI=
+github.com/aws/aws-sdk-go-v2/service/sts v1.43.3/go.mod 
h1:r8wkDOuLaaMFqFiYAb8dGY2A3gJCOujMc6CFOVC4Zhc=
+github.com/aws/smithy-go v1.27.2 
h1:y9NPmSE6am6LjEFPfqHqG/jJk7AauQvhCJONKh7kpzk=
+github.com/aws/smithy-go v1.27.2/go.mod 
h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod 
h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod 
h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1/go.mod 
h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
@@ -109,8 +109,8 @@
 github.com/google/uuid v1.6.0/go.mod 
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 
h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod 
h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
-github.com/hashicorp/consul/api v1.34.2 
h1:B5jqSSKwWyY8U8WiGS5vmPEPkkF0bAvrECykdZkDR80=
-github.com/hashicorp/consul/api v1.34.2/go.mod 
h1:+gAdHQa2zvgYX3ZfcgITtnYCSj6AgS/cgotvCKaE+b8=
+github.com/hashicorp/consul/api v1.34.3 
h1:OiZaQnwkS6uvutie3CF6NFXj8uScNezDlsU9MEqKT0s=
+github.com/hashicorp/consul/api v1.34.3/go.mod 
h1:A4wKd7yw7Wz4zn07p74+o0bLBi5dXsSDMMcMCEinY40=
 github.com/hashicorp/consul/sdk v0.18.1 
h1:RDTeBvAeOveI2xI86sV+8WkaN7OkP4zz+cG3fOobDCM=
 github.com/hashicorp/consul/sdk v0.18.1/go.mod 
h1:XdP2tEJmAvlK4jgoKTTtohGkRJlS4mU44mv9/sjU21s=
 github.com/hashicorp/errwrap v1.0.0/go.mod 
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -181,8 +181,8 @@
 github.com/mattn/go-colorable v0.1.7/go.mod 
h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.9/go.mod 
h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.12/go.mod 
h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-colorable v0.1.14 
h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
-github.com/mattn/go-colorable v0.1.14/go.mod 
h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
+github.com/mattn/go-colorable v0.1.15 
h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
+github.com/mattn/go-colorable v0.1.15/go.mod 
h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
 github.com/mattn/go-isatty v0.0.8/go.mod 
h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.9/go.mod 
h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
 github.com/mattn/go-isatty v0.0.12/go.mod 
h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
@@ -190,8 +190,8 @@
 github.com/mattn/go-isatty v0.0.22 
h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
 github.com/mattn/go-isatty v0.0.22/go.mod 
h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
 github.com/mattn/go-runewidth v0.0.3/go.mod 
h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.23 
h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
-github.com/mattn/go-runewidth v0.0.23/go.mod 
h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/mattn/go-runewidth v0.0.24 
h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
+github.com/mattn/go-runewidth v0.0.24/go.mod 
h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod 
h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
 github.com/miekg/dns v1.1.56/go.mod 
h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
@@ -237,8 +237,8 @@
 github.com/prometheus/procfs v0.0.8/go.mod 
h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
 github.com/prometheus/procfs v0.1.3/go.mod 
h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.6.0/go.mod 
h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
-github.com/rqlite/go-sqlite3 v1.47.0 
h1:doFNzjRdGAmxuHsH1LoLPX6IBaaht4uNoMag9IHK5Qo=
-github.com/rqlite/go-sqlite3 v1.47.0/go.mod 
h1:X4XrrRWGScIJdfec2Tj0/M8C8RhUUN8Ysn+AcOovZwM=
+github.com/rqlite/go-sqlite3 v1.48.0 
h1:3z/QU1WEFrywWvhjhLvZ+SBkaoIQZtkNcHgpCaxE1eg=
+github.com/rqlite/go-sqlite3 v1.48.0/go.mod 
h1:XIq9SQymduohsJwPy++jWepF9QJ5gT/S3SkUivYSVZ0=
 github.com/rqlite/raft-boltdb/v2 v2.0.0-20230523104317-c08e70f4de48 
h1:NZ62M+kT0JqhyFUMc8I4SMmfmD4NGJxhb2ePJQXjryc=
 github.com/rqlite/raft-boltdb/v2 v2.0.0-20230523104317-c08e70f4de48/go.mod 
h1:CRnsxgy5G8fAf5J+AM0yrsSdxXHKkIYOaq2sm+Q4DYc=
 github.com/rqlite/rqlite-disco-clients v0.0.0-20250205044118-8ada2b350099 
h1:5cqkVLdl6sGJSY3kiF2dqaA3bD+8OS5FUdZqO0BxXLU=
@@ -268,12 +268,12 @@
 go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
 go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
 go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
-go.etcd.io/etcd/api/v3 v3.6.11 h1:XFGTgrJ8nak3kB4NgMG8t7NT+lEeuuvKQAqUHKVgkWQ=
-go.etcd.io/etcd/api/v3 v3.6.11/go.mod 
h1:HYfTh0jyh+uFgp6gMbxJteIDYY97yMuYz85Rnw6Gy9o=
-go.etcd.io/etcd/client/pkg/v3 v3.6.11 
h1:e41mp315Yn3QMGPmEzCyLsMINgJXTY/dX8kM++1csxU=
-go.etcd.io/etcd/client/pkg/v3 v3.6.11/go.mod 
h1:DysuMe/inqRyC/1tjRR6hReH/VV9Lufs27YKSKBWWJg=
-go.etcd.io/etcd/client/v3 v3.6.11 
h1:LAByD96VmmeuairkvdAcE0RZnrmGz/q3ceeWePo9bwc=
-go.etcd.io/etcd/client/v3 v3.6.11/go.mod 
h1:vOTDMCo+fGPEClJqcFEFSqZ+8e7WKV7AyqJjX//HR2w=
+go.etcd.io/etcd/api/v3 v3.6.12 h1:OLOZUKEuAA36TR48F0cIaa8FdzrWygjyfrJxXg4iDgs=
+go.etcd.io/etcd/api/v3 v3.6.12/go.mod 
h1:p14EIQXHbuOQbVvL/WEes5uqKnxP9AgKJgpjbMVvzvE=
+go.etcd.io/etcd/client/pkg/v3 v3.6.12 
h1:36zzB+pQOdHbhN+kH2iJz/K8bJn0ZLtLfPPO7jozTDo=
+go.etcd.io/etcd/client/pkg/v3 v3.6.12/go.mod 
h1:hh2+ZXtfLzs3o6mn92ntgNPBrTJJOvXqICM5g3L3DMY=
+go.etcd.io/etcd/client/v3 v3.6.12 
h1:kMSP6JcPZMqSJiX+TXdUIBU/4eXEZWBAaui4VihMbIc=
+go.etcd.io/etcd/client/v3 v3.6.12/go.mod 
h1:CMs6fJWYiZQk4ytFjd4lE1diOvvRMmtbbn/alZXd3dQ=
 go.opentelemetry.io/auto/sdk v1.2.1 
h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
 go.opentelemetry.io/auto/sdk v1.2.1/go.mod 
h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
 go.opentelemetry.io/otel v1.43.0 
h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
@@ -299,14 +299,14 @@
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod 
h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod 
h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
-golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
-golang.org/x/crypto v0.51.0/go.mod 
h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
-golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a 
h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw=
-golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod 
h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw=
+golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
+golang.org/x/crypto v0.53.0/go.mod 
h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
+golang.org/x/exp v0.0.0-20260611194520-c48552f49976 
h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M=
+golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod 
h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
-golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
+golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -318,8 +318,8 @@
 golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod 
h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod 
h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod 
h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
-golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod 
h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -327,8 +327,8 @@
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
-golang.org/x/sync v0.20.0/go.mod 
h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod 
h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -352,23 +352,23 @@
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
-golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod 
h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
-golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
-golang.org/x/term v0.43.0/go.mod 
h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
+golang.org/x/term v0.44.0/go.mod 
h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
-golang.org/x/text v0.37.0/go.mod 
h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
+golang.org/x/text v0.38.0/go.mod 
h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod 
h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod 
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod 
h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod 
h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
-golang.org/x/tools v0.45.0/go.mod 
h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
+golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk=
+golang.org/x/tools v0.46.0/go.mod 
h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -376,12 +376,12 @@
 gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
 gonum.org/v1/gonum v0.17.0/go.mod 
h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
 google.golang.org/appengine v1.4.0/go.mod 
h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348 
h1:U8orV30l6KpDsi9dxU0CoJZGbjS8EEpw+6ba+XwGPQA=
-google.golang.org/genproto/googleapis/api 
v0.0.0-20260504160031-60b97b32f348/go.mod 
h1:Yzdzr5OOZFgSsEV2D/Xi9NL3bszpXFAg0hFJiRohcD8=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 
h1:pfIbyB44sWzHiCpRqIen67ZQnVXSfIxWrqUMk1qwODE=
-google.golang.org/genproto/googleapis/rpc 
v0.0.0-20260504160031-60b97b32f348/go.mod 
h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
-google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw=
-google.golang.org/grpc v1.81.0/go.mod 
h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
+google.golang.org/genproto/googleapis/api v0.0.0-20260615183401-62b3387ff324 
h1:g0RAkxK/smSu/iRwC/KIX1mwUoVJtk2OjbgaeS4DmUM=
+google.golang.org/genproto/googleapis/api 
v0.0.0-20260615183401-62b3387ff324/go.mod 
h1:Z4WJ5pJOYWFWcHEQUelD5QaZDknIQkpIL/+fyJOT9+A=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260615183401-62b3387ff324 
h1:9HZDLIdYBJXAnaFOr9WHrKVycfpY+75s9HGadC0305A=
+google.golang.org/genproto/googleapis/rpc 
v0.0.0-20260615183401-62b3387ff324/go.mod 
h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
+google.golang.org/grpc v1.81.1/go.mod 
h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod 
h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod 
h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod 
h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/http/service.go 
new/rqlite-10.2.4/http/service.go
--- old/rqlite-10.2.0/http/service.go   2026-05-29 15:30:17.000000000 +0200
+++ new/rqlite-10.2.4/http/service.go   2026-06-21 21:25:37.000000000 +0200
@@ -826,7 +826,7 @@
 
        err := s.store.Snapshot(uint64(qp.TrailingLogs(0)))
        if err != nil {
-               if err == store.ErrNothingNewToSnapshot {
+               if errors.Is(err, store.ErrNothingNewToSnapshot) || 
errors.Is(err, store.ErrNoWALToSnapshot) {
                        w.WriteHeader(http.StatusNoContent)
                        return
                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/snapshot/store.go 
new/rqlite-10.2.4/snapshot/store.go
--- old/rqlite-10.2.0/snapshot/store.go 2026-05-29 15:30:17.000000000 +0200
+++ new/rqlite-10.2.4/snapshot/store.go 2026-06-21 21:25:37.000000000 +0200
@@ -196,6 +196,19 @@
 
        catalog *SnapshotCatalog
 
+       // verifyOnce ensures the CRC32 integrity check of all snapshot files 
runs at
+       // most once over the lifetime of the Store, the first time snapshot 
data is
+       // about to be used. verifyErr caches the result so a corruption 
verdict is
+       // sticky and a successful check is never recomputed.
+       verifyOnce sync.Once
+       verifyErr  error
+
+       // fatalFn is invoked when snapshot data is found to be corrupt during
+       // verification. By default it terminates the process, since continuing 
risks
+       // using corrupt data (the cluster is expected to provide fault 
tolerance).
+       // Tests set it to nil so the error propagates and can be asserted on 
instead.
+       fatalFn func(error)
+
        // Multi-reader single-writer lock for the Store, which must be held
        // if snapshots are deleted i.e. reaped. Simply creating or reading
        // a snapshot requires only a read lock.
@@ -225,6 +238,7 @@
                return nil, err
        }
 
+       logger := log.New(os.Stderr, "[snapshot-store] ", log.LstdFlags)
        str := &Store{
                dir:            dir,
                fullNeededPath: filepath.Join(dir, fullNeededFile),
@@ -238,19 +252,16 @@
                reapCh:         make(chan struct{}, 1),
                reapDoneCh:     make(chan struct{}),
                observers:      newObserverSet(),
-               logger:         log.New(os.Stderr, "[snapshot-store] ", 
log.LstdFlags),
+               logger:         logger,
+               fatalFn: func(err error) {
+                       logger.Fatalf("fatal snapshot integrity error, exiting 
process: %s", err)
+               },
        }
        str.logger.Printf("store initialized using %s", dir)
 
-       emp, err := fsutil.DirIsEmpty(dir)
-       if err != nil {
+       if err := str.check(); err != nil {
                return nil, err
        }
-       if !emp {
-               if err := str.check(); err != nil {
-                       return nil, fmt.Errorf("check failed: %s", err)
-               }
-       }
 
        // Kick off the reaper goroutine.
        str.wg.Go(str.reapLoop)
@@ -380,6 +391,14 @@
                }
        }()
 
+       // The data files are about to be read, so verify their integrity first
+       // (runs at most once over the Store's lifetime). On corruption this 
hard
+       // exits in production via fatalFn; with fatalFn disabled (tests) the 
error
+       // is returned.
+       if err := s.ensureVerified(); err != nil {
+               return nil, nil, err
+       }
+
        snapSet, err := s.getSnapshots()
        if err != nil {
                return nil, nil, fmt.Errorf("scanning snapshots: %w", err)
@@ -506,6 +525,16 @@
                        return 0, 0, fmt.Errorf("reading reap plan: %w", err)
                }
                return s.executeReapPlan(p, s.reapPlanPath)
+       } else {
+               // A reap reads and rewrites the data files, so verify their 
integrity
+               // first (runs at most once over the Store's lifetime). We only 
do this if
+               // a reap wasn't previously interrupted (by a crash most 
likely), as an
+               // interrupted reap leaves data in an undefined state. On 
corruption this
+               // hard exits in production via fatalFn; with fatalFn disabled 
(tests) the
+               // error is returned.
+               if err := s.ensureVerified(); err != nil {
+                       return 0, 0, err
+               }
        }
 
        // Scan store.
@@ -768,31 +797,30 @@
        }
 }
 
-// check checks the Store for any inconsistencies, and repairs
-// any inconsistencies it finds. Inconsistencies can happen
-// if the system crashes during snapshotting or reaping.
+// check repairs any structural inconsistencies in the Store left behind by a
+// crash during snapshotting or reaping: it discards an incomplete reap plan,
+// resumes an interrupted reap, and removes leftover temporary directories.
+//
+// Check does NOT verify file checksums. That is done lazily, exactly once, the
+// first time snapshot data is about to be used -- see Verify, Open, and Reap.
+//
+// Check must be called on an idle Store or the results are undefined.
+// If called on a empty Store, then it returns without an error.
 func (s *Store) check() error {
+       emp, err := fsutil.DirIsEmpty(s.dir)
+       if err != nil {
+               return err
+       }
+       if emp {
+               return nil
+       }
+
        // Remove any incomplete plan file from an interrupted plan write.
        os.Remove(tmpName(s.reapPlanPath))
 
-       reapPlanFound := fsutil.FileExists(s.reapPlanPath)
-
-       // If no reap was interrupted, verify the CRC32 of every data file
-       // in every snapshot directory. If a reap was interrupted, the files
-       // may be in an inconsistent state and the CRC32 validation may fail,
-       // so we skip it in that case and just resume the reap to fix any
-       // inconsistencies.
-       if !reapPlanFound {
-               if err := s.checkCRCs(); err != nil {
-                       return err
-               }
-       }
-
-       // Resume an interrupted reap if such a plan file exists. Only then 
should
-       // we remove any leftover temporary directories, since they may be 
needed
-       // for the reap to complete. If a reap plan was found, skip CRC 
validation
-       // since files may have been left in an inconsistent state by the crash.
-       if reapPlanFound {
+       // Resume an interrupted reap if a plan file exists, before any 
temporary
+       // directories are removed below, since the reap may still need them.
+       if fsutil.FileExists(s.reapPlanPath) {
                s.logger.Printf("found interrupted reap plan at %s, resuming", 
s.reapPlanPath)
                p, err := plan.ReadFromFile(s.reapPlanPath)
                if err != nil {
@@ -850,6 +878,35 @@
        return nil
 }
 
+// ensureVerified runs the CRC32 integrity check of every snapshot data file
+// exactly once over the lifetime of the Store, the first time snapshot data is
+// about to be used. The result is cached: a corruption verdict is returned to
+// every subsequent caller, and a successful check is never recomputed.
+//
+// If the check fails, fatalFn is invoked. In production this terminates the
+// process and ensureVerified never returns; tests set fatalFn to nil so the
+// error is returned and can be asserted on instead.
+//
+// The check reads every data file, so the caller must hold the Store read or
+// write lock so it does not run concurrently with a reap.
+func (s *Store) ensureVerified() error {
+       s.verifyOnce.Do(func() {
+               err := s.checkCRCs()
+               if err != nil && s.fatalFn != nil {
+                       s.fatalFn(err) // terminates the process in production; 
never returns
+               }
+               s.verifyErr = err // reached only when fatalFn is nil (tests)
+       })
+       return s.verifyErr
+}
+
+// Verify runs the CRC32 integrity check.
+func (s *Store) Verify() error {
+       s.mrsw.BeginReadBlocking()
+       defer s.mrsw.EndRead()
+       return s.checkCRCs()
+}
+
 // getSnapshots returns the set of snapshots in the Store.
 func (s *Store) getSnapshots() (SnapshotSet, error) {
        return s.catalog.Scan(s.dir)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/snapshot/store_test.go 
new/rqlite-10.2.4/snapshot/store_test.go
--- old/rqlite-10.2.0/snapshot/store_test.go    2026-05-29 15:30:17.000000000 
+0200
+++ new/rqlite-10.2.4/snapshot/store_test.go    2026-06-21 21:25:37.000000000 
+0200
@@ -331,6 +331,57 @@
        }
 }
 
+func Test_Store_Verify(t *testing.T) {
+       dir := t.TempDir()
+       store, err := NewStore(dir)
+       if err != nil {
+               t.Fatalf("Failed to create new store: %v", err)
+       }
+       defer store.Close()
+
+       // Create a full snapshot, then an incremental.
+       createSnapshotInStore(t, store, "2-1017-1704807719996", 1017, 2, 1, 
"testdata/db-and-wals/backup.db")
+       createSnapshotInStore(t, store, "2-1131-1704807720976", 1131, 2, 1, "", 
"testdata/db-and-wals/wal-00")
+
+       // The default fatalFn would terminate the process on corruption; 
disable it
+       // so the integrity failure surfaces as a returned error we can assert 
on.
+       store.fatalFn = nil
+
+       // Ensure Verify passes.
+       if err := store.Verify(); err != nil {
+               t.Fatalf("verify of store failed: %s", err)
+       }
+
+       // Corrupt the full snapshot's DB file by flipping the last bit.
+       dbPath := filepath.Join(store.Dir(), "2-1017-1704807719996", dbfileName)
+       fd, err := os.OpenFile(dbPath, os.O_RDWR, 0)
+       if err != nil {
+               t.Fatalf("failed to open file: %s", err)
+       }
+       defer fd.Close()
+       if _, err := fd.Seek(-1, io.SeekEnd); err != nil {
+               t.Fatalf("failed to seek: %s", err)
+       }
+       var b [1]byte
+       if _, err := fd.Read(b[:]); err != nil {
+               t.Fatalf("failed to read: %s", err)
+       }
+       b[0] ^= 0x01
+
+       // Read advanced the offset; step back before writing.
+       if _, err := fd.Seek(-1, io.SeekCurrent); err != nil {
+               t.Fatalf("failed to seek: %s", err)
+       }
+       if _, err := fd.Write(b[:]); err != nil {
+               t.Fatalf("failed to write: %s", err)
+       }
+
+       // Ensure Verify fails.
+       if err := store.Verify(); err == nil {
+               t.Fatalf("verify of store should have failed")
+       }
+}
+
 // Test_Store_EndToEndCycle tests an end-to-end cycle of creating a Store,
 // creating sinks, and writing various types of snapshots to other Stores.
 func Test_Store_EndToEndCycle(t *testing.T) {
@@ -945,6 +996,10 @@
        createSnapshotInStore(t, store, "2-1017-1704807719996", 1017, 2, 1, 
"testdata/db-and-wals/backup.db")
        createSnapshotInStore(t, store, "2-1131-1704807720976", 1131, 2, 1, "", 
"testdata/db-and-wals/wal-00")
 
+       // The default fatalFn would terminate the process on corruption; 
disable it
+       // so the integrity failure surfaces as a returned error we can assert 
on.
+       store.fatalFn = nil
+
        // Corrupt the full snapshot's DB file.
        dbPath := filepath.Join(store.Dir(), "2-1017-1704807719996", dbfileName)
        if err := os.WriteFile(dbPath, []byte("corrupted"), 0644); err != nil {
@@ -970,6 +1025,10 @@
        createSnapshotInStore(t, store, "2-1017-1704807719996", 1017, 2, 1, 
"testdata/db-and-wals/backup.db")
        createSnapshotInStore(t, store, "2-1131-1704807720976", 1131, 2, 1, "", 
"testdata/db-and-wals/wal-00")
 
+       // The default fatalFn would terminate the process on corruption; 
disable it
+       // so the integrity failure surfaces as a returned error we can assert 
on.
+       store.fatalFn = nil
+
        // Find and corrupt the WAL file in the incremental snapshot.
        walPattern := filepath.Join(store.Dir(), "2-1131-1704807720976", 
"*.wal")
        matches, err := filepath.Glob(walPattern)
@@ -1033,7 +1092,7 @@
                t.Fatalf("Failed to write file in tmp dir: %v", err)
        }
 
-       // Re-open the store — check() should clean up the .tmp directory.
+       // Re-open the store — Check() should clean up the .tmp directory.
        store2, err := NewStore(dir)
        if err != nil {
                t.Fatalf("Failed to re-open store: %v", err)
@@ -1110,6 +1169,10 @@
        }
        p.AddCheckpoint(filepath.Join(fullPath, dbfileName), walMatches)
        p.NCheckpointed = len(walMatches)
+       // Mirror Reap()'s plan: refresh the data.db CRC32 sidecar after the
+       // checkpoint rewrites the file, otherwise the consolidated snapshot 
would
+       // fail integrity verification when it is later opened.
+       p.AddCalcCRC32(filepath.Join(fullPath, dbfileName), 
filepath.Join(fullPath, dbfileName)+crcSuffix)
        p.AddRemoveAll(incPath)
        p.NReaped = 1
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/store/store.go 
new/rqlite-10.2.4/store/store.go
--- old/rqlite-10.2.0/store/store.go    2026-05-29 15:30:17.000000000 +0200
+++ new/rqlite-10.2.4/store/store.go    2026-06-21 21:25:37.000000000 +0200
@@ -810,6 +810,18 @@
                }
        }
 
+       // If Raft will restore from a snapshot on start, verify the snapshot's
+       // integrity now, so the cost and any corruption are surfaced 
explicitly at
+       // startup before Raft reads it. If we won't restore on start (e.g. the 
clean
+       // snapshot fast path), this is skipped: the check then runs lazily the 
first
+       // time snapshot data is actually used -- a reap, a snapshot transfer 
to a
+       // peer, or a later restore.
+       if !raftConfig.NoSnapshotRestoreOnStart {
+               if err := snapshotStore.Verify(); err != nil {
+                       return fmt.Errorf("snapshot integrity check failed: 
%s", err)
+               }
+       }
+
        // Instantiate the Raft system.
        ra, err := raft.NewRaft(raftConfig, NewFSM(s), s.raftLog, s.raftStable, 
s.snapshotStore, s.raftTn)
        if err != nil {
@@ -1966,7 +1978,7 @@
 
        cw := progress.NewCountingWriter(f)
        cm := progress.StartCountingMonitor(func(n int64) {
-               s.logger.Printf("boot process installed %d bytes", n)
+               s.logger.Printf("boot process installed %d bytes (%s)", n, 
humanize.Bytes(uint64(n)))
        }, cw)
        n, err := func() (int64, error) {
                defer cm.StopAndWait()
@@ -2768,9 +2780,17 @@
        defer os.Remove(tmpPath)
 
        if _, err := snapshot.Restore(rc, tmpPath); err != nil {
+               rc.Close()
                return fmt.Errorf("error restoring database from snapshot: %v", 
err)
        }
 
+       // The snapshot stream is now fully drained into tmpPath, so close the 
reader
+       // immediately. Do this so we're not holding onto the underlying 
LockingStreamer
+       // while we calculate fingerprint (which can take measurable time for 
large databases).
+       if err := rc.Close(); err != nil {
+               s.logger.Printf("error closing snapshot reader after restore: 
%s", err)
+       }
+
        // Any existing SQLite file is about to be invalid, so mark that we 
can't
        // fast-restart with it.
        if err := fsutil.RemoveFile(s.cleanSnapshotPath); err != nil {
@@ -2810,7 +2830,6 @@
 
        stats.Add(numRestores, 1)
        s.logger.Printf("node restored in %s", time.Since(startT))
-       rc.Close()
        return nil
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/tcp/mux.go new/rqlite-10.2.4/tcp/mux.go
--- old/rqlite-10.2.0/tcp/mux.go        2026-05-29 15:30:17.000000000 +0200
+++ new/rqlite-10.2.4/tcp/mux.go        2026-06-21 21:25:37.000000000 +0200
@@ -78,6 +78,12 @@
 
        wg sync.WaitGroup
 
+       // conns tracks every demultiplexed connection currently handed off to a
+       // listener, so that they can be force-closed during shutdown. Each
+       // connection deregisters itself when closed.
+       connsMu sync.Mutex
+       conns   map[*trackedConn]struct{}
+
        // The amount of time to wait for the first header byte.
        Timeout time.Duration
 
@@ -100,6 +106,7 @@
                ln:      ln,
                addr:    addr,
                m:       make(map[byte]*listener),
+               conns:   make(map[*trackedConn]struct{}),
                Timeout: DefaultTimeout,
                Logger:  log.New(os.Stderr, "[mux] ", log.LstdFlags),
        }, nil
@@ -178,9 +185,15 @@
                        return err
                }
 
+               // Track the connection so it can be force-closed during 
shutdown, even
+               // if it stalls before sending a header byte. It deregisters 
itself when
+               // closed.
+               tc := &trackedConn{Conn: conn, mux: mux}
+               mux.registerConn(tc)
+
                // Demux in a goroutine to
                mux.wg.Add(1)
-               go mux.handleConn(conn)
+               go mux.handleConn(tc)
        }
 }
 
@@ -220,10 +233,67 @@
 }
 
 // Close closes the mux. It does not close any listeners created by the mux, 
nor
-// does it close the listener it was passed at creation time. It cleans up
-// other resources however.
+// does it close the listener it was passed at creation time. It force-closes
+// any demultiplexed connections still in flight.
 func (mux *Mux) Close() error {
-       return nil
+       return mux.CloseConns()
+}
+
+// CloseConns force-closes every demultiplexed connection currently handed off
+// to a listener. It is used during shutdown to unblock any consumer (such as
+// Raft) that is parked in a deadline-less read on a connection whose peer has
+// stopped sending -- for example a node receiving a snapshot from a peer that
+// is itself shutting down. Without this such a read has no upper bound and can
+// block shutdown indefinitely.
+func (mux *Mux) CloseConns() error {
+       mux.connsMu.Lock()
+       conns := make([]*trackedConn, 0, len(mux.conns))
+       for c := range mux.conns {
+               conns = append(conns, c)
+       }
+       mux.connsMu.Unlock()
+
+       var lastErr error
+       for _, c := range conns {
+               if err := c.Close(); err != nil {
+                       lastErr = err
+               }
+       }
+       return lastErr
+}
+
+// registerConn adds a connection to the set of tracked connections.
+func (mux *Mux) registerConn(c *trackedConn) {
+       mux.connsMu.Lock()
+       defer mux.connsMu.Unlock()
+       mux.conns[c] = struct{}{}
+}
+
+// removeConn removes a connection from the set of tracked connections.
+func (mux *Mux) removeConn(c *trackedConn) {
+       mux.connsMu.Lock()
+       defer mux.connsMu.Unlock()
+       delete(mux.conns, c)
+}
+
+// trackedConn wraps an accepted connection so the Mux can force-close it 
during
+// shutdown. It deregisters itself from the Mux on Close so the tracking set 
does
+// not grow without bound over the lifetime of the node.
+type trackedConn struct {
+       net.Conn
+       mux  *Mux
+       once sync.Once
+}
+
+// Close removes the connection from the Mux's tracking set and closes the
+// underlying connection. It is safe to call multiple times.
+func (c *trackedConn) Close() error {
+       c.mux.removeConn(c)
+       var err error
+       c.once.Do(func() {
+               err = c.Conn.Close()
+       })
+       return err
 }
 
 func (mux *Mux) handleConn(conn net.Conn) {
@@ -260,7 +330,8 @@
                return
        }
 
-       // Send connection to handler.  The handler is responsible for closing 
the connection.
+       // Send connection to handler. The handler is responsible for closing 
the
+       // connection.
        handler.c <- conn
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rqlite-10.2.0/tcp/mux_test.go 
new/rqlite-10.2.4/tcp/mux_test.go
--- old/rqlite-10.2.0/tcp/mux_test.go   2026-05-29 15:30:17.000000000 +0200
+++ new/rqlite-10.2.4/tcp/mux_test.go   2026-06-21 21:25:37.000000000 +0200
@@ -392,6 +392,117 @@
        return m.Addr
 }
 
+// Test_MuxCloseConns verifies that CloseConns actually closes the underlying
+// socket of a tracked connection (not merely drops it from the tracking set),
+// so a peer parked in a read on it is unblocked. This is the property that 
lets
+// a node shut down while parked reading a Raft snapshot body from a peer that
+// has gone silent. See https://github.com/rqlite/rqlite/issues/2687.
+func Test_MuxCloseConns(t *testing.T) {
+       tcpListener := mustTCPListener("127.0.0.1:0")
+       defer tcpListener.Close()
+
+       mux, err := NewMux(tcpListener, nil)
+       if err != nil {
+               t.Fatalf("failed to create mux: %s", err.Error())
+       }
+       if !testing.Verbose() {
+               mux.Logger = log.New(io.Discard, "", 0)
+       }
+       go mux.Serve()
+
+       // Connecting is enough for the Mux to accept and track the connection.
+       client, err := net.Dial("tcp", tcpListener.Addr().String())
+       if err != nil {
+               t.Fatalf("failed to dial mux: %s", err.Error())
+       }
+       defer client.Close()
+       if !waitForTrackedConns(mux, 1, 5*time.Second) {
+               t.Fatalf("connection was not tracked, got %d", 
numTrackedConns(mux))
+       }
+
+       // Park a read on the connection; nothing is ever sent on it.
+       readReturned := make(chan error, 1)
+       go func() {
+               var b [1]byte
+               _, err := client.Read(b[:])
+               readReturned <- err
+       }()
+
+       // Force-close all connections; the parked read must return promptly.
+       if err := mux.CloseConns(); err != nil {
+               t.Fatalf("CloseConns returned error: %s", err.Error())
+       }
+       select {
+       case err := <-readReturned:
+               if err == nil {
+                       t.Fatal("expected blocked read to return an error after 
CloseConns")
+               }
+       case <-time.After(5 * time.Second):
+               t.Fatal("blocked read did not return after CloseConns")
+       }
+
+       // The tracking set must be empty again, so it does not grow without 
bound.
+       if got := numTrackedConns(mux); got != 0 {
+               t.Fatalf("expected 0 tracked connections after close, got %d", 
got)
+       }
+}
+
+// Test_MuxConnDeregisterOnClose verifies that an accepted connection 
deregisters
+// itself from the Mux's tracking set when closed, so the set does not leak 
over
+// the lifetime of the node. Connecting is enough for the Mux to track the
+// connection; no header byte is required.
+func Test_MuxConnDeregisterOnClose(t *testing.T) {
+       tcpListener := mustTCPListener("127.0.0.1:0")
+       defer tcpListener.Close()
+
+       mux, err := NewMux(tcpListener, nil)
+       if err != nil {
+               t.Fatalf("failed to create mux: %s", err.Error())
+       }
+       if !testing.Verbose() {
+               mux.Logger = log.New(io.Discard, "", 0)
+       }
+       go mux.Serve()
+
+       // Connecting is enough for the Mux to accept and track the connection.
+       client, err := net.Dial("tcp", tcpListener.Addr().String())
+       if err != nil {
+               t.Fatalf("failed to dial mux: %s", err.Error())
+       }
+       if !waitForTrackedConns(mux, 1, 5*time.Second) {
+               t.Fatalf("connection was not tracked after connecting, got %d", 
numTrackedConns(mux))
+       }
+
+       // Closing the connection must deregister it from the tracking set.
+       client.Close()
+       if !waitForTrackedConns(mux, 0, 5*time.Second) {
+               t.Fatalf("connection was not deregistered after close, got %d", 
numTrackedConns(mux))
+       }
+}
+
+// numTrackedConns returns the number of connections currently tracked by the
+// Mux for force-close on shutdown.
+func numTrackedConns(mux *Mux) int {
+       mux.connsMu.Lock()
+       defer mux.connsMu.Unlock()
+       return len(mux.conns)
+}
+
+// waitForTrackedConns waits up to timeout for the Mux to be tracking exactly n
+// connections, returning true if that count is reached.
+func waitForTrackedConns(mux *Mux, n int, timeout time.Duration) bool {
+       deadline := time.Now().Add(timeout)
+       for {
+               if numTrackedConns(mux) == n {
+                       return true
+               }
+               if time.Now().After(deadline) {
+                       return false
+               }
+               time.Sleep(time.Millisecond)
+       }
+}
+
 // mustTCPListener returns a listener on bind, or panics.
 func mustTCPListener(bind string) net.Listener {
        l, err := net.Listen("tcp", bind)

++++++ vendor.tar.xz ++++++
++++ 34673 lines of diff (skipped)

Reply via email to