From 1219ce3c4a3b965107a887a44bbe2f7d67ea282e Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Mon, 20 Feb 2023 09:26:20 +0100 Subject: [PATCH 1/4] Move to Go 1.19 atomics This change moves to Go 1.19 atomics in favor of the version we had in the `sync2` package. The version in that package predates the availability of the new atomics, but for the future we want to use the Go provided ones. On top of that, we can also use the semaphore from `x/sync` instead of a custom one in `sync2`. This cleans up a bunch of additional code from `sync2`. Signed-off-by: Dirkjan Bussink --- go.mod | 1 + go/mysql/conn.go | 10 +- go/mysql/handshake_test.go | 2 +- go/mysql/server.go | 17 +- go/mysql/server_flaky_test.go | 14 +- go/pools/resource_pool.go | 84 +++---- go/pools/resource_pool_test.go | 201 +++++++++-------- go/stats/counter.go | 25 ++- go/stats/duration.go | 17 +- go/stats/histogram.go | 21 +- go/stats/timings.go | 17 +- go/sync2/atomic.go | 212 ------------------ go/sync2/atomic_test.go | 128 ----------- go/sync2/batcher.go | 13 +- go/sync2/batcher_test.go | 11 +- go/sync2/doc.go | 18 -- go/sync2/norace.go | 7 - go/sync2/race.go | 7 - go/sync2/semaphore.go | 97 -------- go/sync2/semaphore_test.go | 79 ------- .../vtgate/reservedconn/get_lock_test.go | 15 +- go/timer/timer.go | 15 +- go/timer/timer_flaky_test.go | 25 +-- go/vt/binlog/binlogplayer/binlog_player.go | 12 +- go/vt/binlog/updatestreamctl.go | 12 +- go/vt/discovery/tablet_health_check.go | 9 +- go/vt/mysqlctl/builtinbackupengine.go | 14 +- go/vt/mysqlctl/fakemysqldaemon.go | 14 +- go/vt/schemamanager/tablet_executor.go | 5 +- go/vt/srvtopo/resilient_server_test.go | 7 +- go/vt/throttler/max_rate_module.go | 14 +- go/vt/throttler/max_replication_lag_module.go | 33 +-- go/vt/throttler/thread_throttler.go | 13 +- go/vt/topo/zk2topo/zk_conn.go | 13 +- go/vt/vtctl/grpcvtctldserver/server.go | 12 +- go/vt/vtctl/schematools/reload.go | 16 +- go/vt/vtctl/schematools/reload_test.go | 4 +- go/vt/vtgate/autocommit_test.go | 2 +- go/vt/vtgate/buffer/buffer.go | 9 +- go/vt/vtgate/buffer/buffer_helper_test.go | 2 +- go/vt/vtgate/buffer/shard_buffer.go | 4 +- go/vt/vtgate/executor.go | 10 +- go/vt/vtgate/executor_dml_test.go | 2 +- go/vt/vtgate/executor_framework_test.go | 2 +- go/vt/vtgate/executor_select_test.go | 20 +- go/vt/vtgate/executor_set_test.go | 2 +- go/vt/vtgate/executor_test.go | 118 +++++----- go/vt/vtgate/executor_vschema_ddl_test.go | 12 +- go/vt/vtgate/legacy_scatter_conn_test.go | 16 +- go/vt/vtgate/plugin_mysql_server.go | 4 +- go/vt/vtgate/scatter_conn_test.go | 30 +-- go/vt/vtgate/schema/tracker_test.go | 2 +- go/vt/vtgate/tx_conn_test.go | 204 ++++++++--------- go/vt/vtgate/vstream_manager_test.go | 18 +- go/vt/vtgate/vtgate_test.go | 28 +-- go/vt/vtgr/controller/diagnose.go | 10 +- go/vt/vtgr/controller/refresh.go | 8 +- go/vt/vtgr/controller/repair.go | 2 +- go/vt/vtgr/vtgr.go | 10 +- go/vt/vtgr/vtgr_test.go | 12 +- go/vt/vttablet/endtoend/config_test.go | 4 +- go/vt/vttablet/grpctmclient/cached_client.go | 18 +- .../grpctmclient/cached_client_flaky_test.go | 7 +- go/vt/vttablet/sandboxconn/sandboxconn.go | 38 ++-- go/vt/vttablet/tabletmanager/rpc_server.go | 12 +- go/vt/vttablet/tabletmanager/tm_init.go | 6 +- go/vt/vttablet/tabletmanager/tm_init_test.go | 5 +- go/vt/vttablet/tabletmanager/vdiff/engine.go | 5 +- .../tabletmanager/vreplication/controller.go | 11 +- .../vreplication/controller_test.go | 15 +- .../tabletmanager/vreplication/engine.go | 10 +- .../tabletmanager/vreplication/engine_test.go | 38 ++-- .../tabletmanager/vreplication/fuzz.go | 4 +- .../tabletmanager/vreplication/stats.go | 23 +- .../tabletmanager/vreplication/stats_test.go | 8 +- .../tabletmanager/vreplication/vcopier.go | 2 +- .../tabletmanager/vreplication/vplayer.go | 6 +- .../tabletmanager/vreplication/vreplicator.go | 2 +- .../vttablet/tabletserver/connpool/dbconn.go | 21 +- go/vt/vttablet/tabletserver/connpool/pool.go | 10 +- .../tabletserver/connpool/pool_test.go | 2 +- .../vttablet/tabletserver/health_streamer.go | 19 +- .../tabletserver/health_streamer_test.go | 11 +- .../vttablet/tabletserver/messager/engine.go | 7 +- .../tabletserver/messager/message_manager.go | 29 ++- .../messager/message_manager_test.go | 57 +++-- go/vt/vttablet/tabletserver/query_engine.go | 26 +-- go/vt/vttablet/tabletserver/query_executor.go | 18 +- go/vt/vttablet/tabletserver/state_manager.go | 48 ++-- .../tabletserver/state_manager_test.go | 44 ++-- .../tabletserver/stateful_connection_pool.go | 27 +-- .../stateful_connection_pool_test.go | 2 +- go/vt/vttablet/tabletserver/status.go | 16 +- go/vt/vttablet/tabletserver/tabletserver.go | 64 +++--- .../tabletserver/tabletserver_test.go | 8 +- .../throttle/config/mysql_config.go | 24 +- .../tabletserver/throttle/throttler.go | 19 +- go/vt/vttablet/tabletserver/tx_engine_test.go | 2 +- .../tabletserver/vstreamer/vstreamer.go | 11 - go/vt/wrangler/fake_tablet_test.go | 2 +- .../testlib/external_reparent_test.go | 2 +- go/vt/wrangler/testlib/fake_tablet.go | 2 +- go/vt/wrangler/traffic_switcher_env_test.go | 14 +- go/vt/wrangler/workflow.go | 4 +- go/vt/wrangler/wrangler.go | 5 +- 105 files changed, 961 insertions(+), 1488 deletions(-) delete mode 100644 go/sync2/atomic.go delete mode 100644 go/sync2/atomic_test.go delete mode 100644 go/sync2/doc.go delete mode 100644 go/sync2/norace.go delete mode 100644 go/sync2/race.go delete mode 100644 go/sync2/semaphore.go delete mode 100644 go/sync2/semaphore_test.go diff --git a/go.mod b/go.mod index df53d214477..9b485caec07 100644 --- a/go.mod +++ b/go.mod @@ -113,6 +113,7 @@ require ( github.com/kr/text v0.2.0 github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 + golang.org/x/sync v0.1.0 modernc.org/sqlite v1.20.3 ) diff --git a/go/mysql/conn.go b/go/mysql/conn.go index 485b0a3def3..74c70da7728 100644 --- a/go/mysql/conn.go +++ b/go/mysql/conn.go @@ -26,6 +26,7 @@ import ( "net" "strings" "sync" + "sync/atomic" "time" "vitess.io/vitess/go/mysql/collations" @@ -34,7 +35,6 @@ import ( "vitess.io/vitess/go/bucketpool" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/log" querypb "vitess.io/vitess/go/vt/proto/query" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" @@ -161,7 +161,7 @@ type Conn struct { Capabilities uint32 // closed is set to true when Close() is called on the connection. - closed sync2.AtomicBool + closed atomic.Bool // ConnectionID is set: // - at Connect() time for clients, with the value returned by @@ -236,7 +236,6 @@ var readersPool = sync.Pool{New: func() any { return bufio.NewReaderSize(nil, co func newConn(conn net.Conn) *Conn { return &Conn{ conn: conn, - closed: sync2.NewAtomicBool(false), bufferedReader: bufio.NewReaderSize(conn, connBufferSize), } } @@ -250,7 +249,6 @@ func newServerConn(conn net.Conn, listener *Listener) *Conn { c := &Conn{ conn: conn, listener: listener, - closed: sync2.NewAtomicBool(false), PrepareData: make(map[uint32]*PrepareData), } @@ -717,7 +715,7 @@ func (c *Conn) Close() { // Close() method. Note if the other side closes the connection, but // Close() wasn't called, this will return false. func (c *Conn) IsClosed() bool { - return c.closed.Get() + return c.closed.Load() } // @@ -1294,7 +1292,7 @@ func (c *Conn) handleComSetOption(data []byte) bool { func (c *Conn) handleComPing() bool { c.recycleReadPacket() // Return error if listener was shut down and OK otherwise - if c.listener.isShutdown() { + if c.listener.shutdown.Load() { if !c.writeErrorAndLog(ERServerShutdown, SSNetError, "Server shutdown in progress") { return false } diff --git a/go/mysql/handshake_test.go b/go/mysql/handshake_test.go index 57435284cba..b6532f830b3 100644 --- a/go/mysql/handshake_test.go +++ b/go/mysql/handshake_test.go @@ -71,7 +71,7 @@ func TestClearTextClientAuth(t *testing.T) { } // Change server side to allow clear text without auth. - l.AllowClearTextWithoutTLS.Set(true) + l.AllowClearTextWithoutTLS.Store(true) conn, err := Connect(ctx, params) require.NoError(t, err, "unexpected connection error: %v", err) diff --git a/go/mysql/server.go b/go/mysql/server.go index 4d65ce93a81..e17bd82ef90 100644 --- a/go/mysql/server.go +++ b/go/mysql/server.go @@ -35,7 +35,6 @@ import ( "vitess.io/vitess/go/netutil" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/tb" "vitess.io/vitess/go/vt/log" querypb "vitess.io/vitess/go/vt/proto/query" @@ -175,11 +174,11 @@ type Listener struct { // AllowClearTextWithoutTLS needs to be set for the // mysql_clear_password authentication method to be accepted // by the server when TLS is not in use. - AllowClearTextWithoutTLS sync2.AtomicBool + AllowClearTextWithoutTLS atomic.Bool // SlowConnectWarnThreshold if non-zero specifies an amount of time // beyond which a warning is logged to identify the slow connection - SlowConnectWarnThreshold sync2.AtomicDuration + SlowConnectWarnThreshold atomic.Int64 // The following parameters are changed by the Accept routine. @@ -198,7 +197,7 @@ type Listener struct { connBufferPooling bool // shutdown indicates that Shutdown method was called. - shutdown sync2.AtomicBool + shutdown atomic.Bool // RequireSecureTransport configures the server to reject connections from insecure clients RequireSecureTransport bool @@ -454,7 +453,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti return } - if !l.AllowClearTextWithoutTLS.Get() && !c.TLSEnabled() && !negotiatedAuthMethod.AllowClearTextWithoutTLS() { + if !l.AllowClearTextWithoutTLS.Load() && !c.TLSEnabled() && !negotiatedAuthMethod.AllowClearTextWithoutTLS() { c.writeErrorPacket(CRServerHandshakeErr, SSUnknownSQLState, "Cannot use clear text authentication over non-SSL connections.") return } @@ -514,8 +513,8 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti timings.Record(connectTimingKey, acceptTime) // Log a warning if it took too long to connect - connectTime := time.Since(acceptTime) - if threshold := l.SlowConnectWarnThreshold.Get(); threshold != 0 && connectTime > threshold { + connectTime := time.Since(acceptTime).Nanoseconds() + if threshold := l.SlowConnectWarnThreshold.Load(); threshold != 0 && connectTime > threshold { connSlow.Add(1) log.Warningf("Slow connection from %s: %v", c, connectTime) } @@ -545,10 +544,6 @@ func (l *Listener) Shutdown() { } } -func (l *Listener) isShutdown() bool { - return l.shutdown.Get() -} - // writeHandshakeV10 writes the Initial Handshake Packet, server side. // It returns the salt data. func (c *Conn) writeHandshakeV10(serverVersion string, authServer AuthServer, enableTLS bool) ([]byte, error) { diff --git a/go/mysql/server_flaky_test.go b/go/mysql/server_flaky_test.go index d1c749882db..7225f29a816 100644 --- a/go/mysql/server_flaky_test.go +++ b/go/mysql/server_flaky_test.go @@ -530,7 +530,7 @@ func TestServer(t *testing.T) { defer authServer.close() l, err := NewListener("tcp", "127.0.0.1:", authServer, th, 0, 0, false, false) require.NoError(t, err) - l.SlowConnectWarnThreshold.Set(time.Nanosecond * 1) + l.SlowConnectWarnThreshold.Store(time.Nanosecond.Nanoseconds()) defer l.Close() go l.Accept() @@ -630,7 +630,7 @@ func TestServerStats(t *testing.T) { defer authServer.close() l, err := NewListener("tcp", "127.0.0.1:", authServer, th, 0, 0, false, false) require.NoError(t, err) - l.SlowConnectWarnThreshold.Set(time.Nanosecond * 1) + l.SlowConnectWarnThreshold.Store(time.Nanosecond.Nanoseconds()) defer l.Close() go l.Accept() @@ -675,7 +675,7 @@ func TestServerStats(t *testing.T) { } // Set the slow connect threshold to something high that we don't expect to trigger - l.SlowConnectWarnThreshold.Set(time.Second * 1) + l.SlowConnectWarnThreshold.Store(time.Second.Nanoseconds()) // Run a 'panic' command, other side should panic, recover and // close the connection. @@ -723,7 +723,7 @@ func TestClearTextServer(t *testing.T) { // Run a 'select rows' command with results. This should fail // as clear text is not enabled by default on the client // (except MariaDB). - l.AllowClearTextWithoutTLS.Set(true) + l.AllowClearTextWithoutTLS.Store(true) sql := "select rows" output, ok := runMysql(t, params, sql) if ok { @@ -741,7 +741,7 @@ func TestClearTextServer(t *testing.T) { } // Now enable clear text plugin in client, but server requires SSL. - l.AllowClearTextWithoutTLS.Set(false) + l.AllowClearTextWithoutTLS.Store(false) if !isMariaDB { sql = enableCleartextPluginPrefix + sql } @@ -750,7 +750,7 @@ func TestClearTextServer(t *testing.T) { assert.Contains(t, output, "Cannot use clear text authentication over non-SSL connections", "Unexpected output for 'select rows': %v", output) // Now enable clear text plugin, it should now work. - l.AllowClearTextWithoutTLS.Set(true) + l.AllowClearTextWithoutTLS.Store(true) output, ok = runMysql(t, params, sql) require.True(t, ok, "mysql failed: %v", output) @@ -777,7 +777,7 @@ func TestDialogServer(t *testing.T) { defer authServer.close() l, err := NewListener("tcp", "127.0.0.1:", authServer, th, 0, 0, false, false) require.NoError(t, err) - l.AllowClearTextWithoutTLS.Set(true) + l.AllowClearTextWithoutTLS.Store(true) defer l.Close() go l.Accept() diff --git a/go/pools/resource_pool.go b/go/pools/resource_pool.go index 37ffc189e09..940a2b2026c 100644 --- a/go/pools/resource_pool.go +++ b/go/pools/resource_pool.go @@ -24,9 +24,9 @@ import ( "fmt" "math/rand" "sync" + "sync/atomic" "time" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/vterrors" @@ -88,19 +88,18 @@ type ( // ResourcePool allows you to use a pool of resources. ResourcePool struct { - // stats. Atomic fields must remain at the top in order to prevent panics on certain architectures. - available sync2.AtomicInt64 - active sync2.AtomicInt64 - inUse sync2.AtomicInt64 - waitCount sync2.AtomicInt64 - waitTime sync2.AtomicDuration - idleClosed sync2.AtomicInt64 - maxLifetimeClosed sync2.AtomicInt64 - exhausted sync2.AtomicInt64 - - capacity sync2.AtomicInt64 - idleTimeout sync2.AtomicDuration - maxLifetime sync2.AtomicDuration + available atomic.Int64 + active atomic.Int64 + inUse atomic.Int64 + waitCount atomic.Int64 + waitTime atomic.Int64 + idleClosed atomic.Int64 + maxLifetimeClosed atomic.Int64 + exhausted atomic.Int64 + + capacity atomic.Int64 + idleTimeout atomic.Int64 + maxLifetime atomic.Int64 resources chan resourceWrapper factory Factory @@ -108,10 +107,10 @@ type ( logWait func(time.Time) settingResources chan resourceWrapper - getCount sync2.AtomicInt64 - getSettingCount sync2.AtomicInt64 - diffSettingCount sync2.AtomicInt64 - resetSettingCount sync2.AtomicInt64 + getCount atomic.Int64 + getSettingCount atomic.Int64 + diffSettingCount atomic.Int64 + resetSettingCount atomic.Int64 reopenMutex sync.Mutex refresh *poolRefresh @@ -166,12 +165,13 @@ func NewResourcePool(factory Factory, capacity, maxCap int, idleTimeout time.Dur resources: make(chan resourceWrapper, maxCap), settingResources: make(chan resourceWrapper, maxCap), factory: factory, - available: sync2.NewAtomicInt64(int64(capacity)), - capacity: sync2.NewAtomicInt64(int64(capacity)), - idleTimeout: sync2.NewAtomicDuration(idleTimeout), - maxLifetime: sync2.NewAtomicDuration(maxLifetime), logWait: logWait, } + rp.available.Store(int64(capacity)) + rp.capacity.Store(int64(capacity)) + rp.idleTimeout.Store(idleTimeout.Nanoseconds()) + rp.maxLifetime.Store(maxLifetime.Nanoseconds()) + for i := 0; i < capacity; i++ { rp.resources <- resourceWrapper{} } @@ -244,7 +244,7 @@ func (rp *ResourcePool) returnResource(wrapper *resourceWrapper, origPool bool, func (rp *ResourcePool) reopen() { rp.reopenMutex.Lock() // Avoid race, since we can refresh asynchronously defer rp.reopenMutex.Unlock() - capacity := int(rp.capacity.Get()) + capacity := int(rp.capacity.Load()) log.Infof("Draining and reopening resource pool with capacity %d by request", capacity) rp.Close() _ = rp.SetCapacity(capacity) @@ -462,7 +462,7 @@ func (rp *ResourcePool) SetCapacity(capacity int) error { // Atomically swap new capacity with old var oldcap int for { - oldcap = int(rp.capacity.Get()) + oldcap = int(rp.capacity.Load()) if oldcap == 0 && capacity > 0 { // Closed this before, re-open the channel rp.resources = make(chan resourceWrapper, cap(rp.resources)) @@ -509,7 +509,7 @@ func (rp *ResourcePool) SetCapacity(capacity int) error { func (rp *ResourcePool) recordWait(start time.Time) { rp.waitCount.Add(1) - rp.waitTime.Add(time.Since(start)) + rp.waitTime.Add(time.Since(start).Nanoseconds()) if rp.logWait != nil { rp.logWait(start) } @@ -522,7 +522,7 @@ func (rp *ResourcePool) SetIdleTimeout(idleTimeout time.Duration) { panic("SetIdleTimeout called when timer not initialized") } - rp.idleTimeout.Set(idleTimeout) + rp.idleTimeout.Store(idleTimeout.Nanoseconds()) rp.idleTimer.SetInterval(idleTimeout / 10) } @@ -545,23 +545,23 @@ func (rp *ResourcePool) StatsJSON() string { // Capacity returns the capacity. func (rp *ResourcePool) Capacity() int64 { - return rp.capacity.Get() + return rp.capacity.Load() } // Available returns the number of currently unused and available resources. func (rp *ResourcePool) Available() int64 { - return rp.available.Get() + return rp.available.Load() } // Active returns the number of active (i.e. non-nil) resources either in the // pool or claimed for use func (rp *ResourcePool) Active() int64 { - return rp.active.Get() + return rp.active.Load() } // InUse returns the number of claimed resources from the pool func (rp *ResourcePool) InUse() int64 { - return rp.inUse.Get() + return rp.inUse.Load() } // MaxCap returns the max capacity. @@ -571,59 +571,59 @@ func (rp *ResourcePool) MaxCap() int64 { // WaitCount returns the total number of waits. func (rp *ResourcePool) WaitCount() int64 { - return rp.waitCount.Get() + return rp.waitCount.Load() } // WaitTime returns the total wait time. func (rp *ResourcePool) WaitTime() time.Duration { - return rp.waitTime.Get() + return time.Duration(rp.waitTime.Load()) } // IdleTimeout returns the resource idle timeout. func (rp *ResourcePool) IdleTimeout() time.Duration { - return rp.idleTimeout.Get() + return time.Duration(rp.idleTimeout.Load()) } // IdleClosed returns the count of resources closed due to idle timeout. func (rp *ResourcePool) IdleClosed() int64 { - return rp.idleClosed.Get() + return rp.idleClosed.Load() } // extendedLifetimeTimeout returns random duration within range [maxLifetime, 2*maxLifetime) func (rp *ResourcePool) extendedMaxLifetime() time.Duration { - maxLifetime := rp.maxLifetime.Get() + maxLifetime := rp.maxLifetime.Load() if maxLifetime == 0 { return 0 } - return maxLifetime + time.Duration(rand.Int63n(maxLifetime.Nanoseconds())) + return time.Duration(maxLifetime + rand.Int63n(maxLifetime)) } // MaxLifetimeClosed returns the count of resources closed due to refresh timeout. func (rp *ResourcePool) MaxLifetimeClosed() int64 { - return rp.maxLifetimeClosed.Get() + return rp.maxLifetimeClosed.Load() } // Exhausted returns the number of times Available dropped below 1 func (rp *ResourcePool) Exhausted() int64 { - return rp.exhausted.Get() + return rp.exhausted.Load() } // GetCount returns the number of times get was called func (rp *ResourcePool) GetCount() int64 { - return rp.getCount.Get() + return rp.getCount.Load() } // GetSettingCount returns the number of times getWithSettings was called func (rp *ResourcePool) GetSettingCount() int64 { - return rp.getSettingCount.Get() + return rp.getSettingCount.Load() } // DiffSettingCount returns the number of times different setting were applied on the resource. func (rp *ResourcePool) DiffSettingCount() int64 { - return rp.diffSettingCount.Get() + return rp.diffSettingCount.Load() } // ResetSettingCount returns the number of times setting were reset on the resource. func (rp *ResourcePool) ResetSettingCount() int64 { - return rp.resetSettingCount.Get() + return rp.resetSettingCount.Load() } diff --git a/go/pools/resource_pool_test.go b/go/pools/resource_pool_test.go index 8ec812b4603..886fab34751 100644 --- a/go/pools/resource_pool_test.go +++ b/go/pools/resource_pool_test.go @@ -20,17 +20,16 @@ import ( "context" "errors" "fmt" + "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "vitess.io/vitess/go/sync2" ) var ( - lastID, count, closeCount, resetCount sync2.AtomicInt64 + lastID, count, closeCount, resetCount atomic.Int64 waitStarts []time.Time @@ -108,8 +107,8 @@ func DisallowSettingsFactory(context.Context) (Resource, error) { func TestOpen(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) waitStarts = waitStarts[:0] p := NewResourcePool(PoolFactory, 6, 6, time.Second, 0, logWait, nil, 0) @@ -131,8 +130,8 @@ func TestOpen(t *testing.T) { assert.Zero(t, p.WaitCount()) assert.Zero(t, len(waitStarts)) assert.Zero(t, p.WaitTime()) - assert.EqualValues(t, i+1, lastID.Get()) - assert.EqualValues(t, i+1, count.Get()) + assert.EqualValues(t, i+1, lastID.Load()) + assert.EqualValues(t, i+1, count.Load()) } // Test that Get waits @@ -167,15 +166,15 @@ func TestOpen(t *testing.T) { } } assert.NotZero(t, p.WaitTime()) - assert.EqualValues(t, 5, lastID.Get()) + assert.EqualValues(t, 5, lastID.Load()) // Test Close resource r, err = p.Get(ctx, nil) require.NoError(t, err) r.Close() // A nil Put should cause the resource to be reopened. p.Put(nil) - assert.EqualValues(t, 5, count.Get()) - assert.EqualValues(t, 6, lastID.Get()) + assert.EqualValues(t, 5, count.Load()) + assert.EqualValues(t, 6, lastID.Load()) for i := 0; i < 5; i++ { if i%2 == 0 { @@ -189,13 +188,13 @@ func TestOpen(t *testing.T) { for i := 0; i < 5; i++ { p.Put(resources[i]) } - assert.EqualValues(t, 5, count.Get()) - assert.EqualValues(t, 6, lastID.Get()) + assert.EqualValues(t, 5, count.Load()) + assert.EqualValues(t, 6, lastID.Load()) // SetCapacity p.SetCapacity(3) - assert.EqualValues(t, 3, count.Get()) - assert.EqualValues(t, 6, lastID.Get()) + assert.EqualValues(t, 3, count.Load()) + assert.EqualValues(t, 6, lastID.Load()) assert.EqualValues(t, 3, p.Capacity()) assert.EqualValues(t, 3, p.Available()) @@ -215,20 +214,20 @@ func TestOpen(t *testing.T) { for i := 0; i < 6; i++ { p.Put(resources[i]) } - assert.EqualValues(t, 6, count.Get()) - assert.EqualValues(t, 9, lastID.Get()) + assert.EqualValues(t, 6, count.Load()) + assert.EqualValues(t, 9, lastID.Load()) // Close p.Close() assert.EqualValues(t, 0, p.Capacity()) assert.EqualValues(t, 0, p.Available()) - assert.EqualValues(t, 0, count.Get()) + assert.EqualValues(t, 0, count.Load()) } func TestShrinking(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) waitStarts = waitStarts[:0] p := NewResourcePool(PoolFactory, 5, 5, time.Second, 0, logWait, nil, 0) @@ -271,7 +270,7 @@ func TestShrinking(t *testing.T) { stats := p.StatsJSON() expected = `{"Capacity": 3, "Available": 3, "Active": 3, "InUse": 0, "MaxCapacity": 5, "WaitCount": 0, "WaitTime": 0, "IdleTimeout": 1000000000, "IdleClosed": 0, "MaxLifetimeClosed": 0, "Exhausted": 0}` assert.Equal(t, expected, stats) - assert.EqualValues(t, 3, count.Get()) + assert.EqualValues(t, 3, count.Load()) // Ensure no deadlock if SetCapacity is called after we start // waiting for a resource @@ -311,7 +310,7 @@ func TestShrinking(t *testing.T) { assert.EqualValues(t, 2, p.Available()) assert.EqualValues(t, 1, p.WaitCount()) assert.EqualValues(t, p.WaitCount(), len(waitStarts)) - assert.EqualValues(t, 2, count.Get()) + assert.EqualValues(t, 2, count.Load()) // Test race condition of SetCapacity with itself p.SetCapacity(3) @@ -362,8 +361,8 @@ func TestShrinking(t *testing.T) { func TestClosing(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p := NewResourcePool(PoolFactory, 5, 5, time.Second, 0, logWait, nil, 0) var resources [10]Resource for i := 0; i < 5; i++ { @@ -400,14 +399,14 @@ func TestClosing(t *testing.T) { stats = p.StatsJSON() expected = `{"Capacity": 0, "Available": 0, "Active": 0, "InUse": 0, "MaxCapacity": 5, "WaitCount": 0, "WaitTime": 0, "IdleTimeout": 1000000000, "IdleClosed": 0, "MaxLifetimeClosed": 0, "Exhausted": 1}` assert.Equal(t, expected, stats) - assert.EqualValues(t, 5, lastID.Get()) - assert.EqualValues(t, 0, count.Get()) + assert.EqualValues(t, 5, lastID.Load()) + assert.EqualValues(t, 0, count.Load()) } func TestReopen(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) refreshCheck := func() (bool, error) { return true, nil } @@ -438,49 +437,49 @@ func TestReopen(t *testing.T) { stats = p.StatsJSON() expected = `{"Capacity": 5, "Available": 5, "Active": 0, "InUse": 0, "MaxCapacity": 5, "WaitCount": 0, "WaitTime": 0, "IdleTimeout": 1000000000, "IdleClosed": 0, "MaxLifetimeClosed": 0, "Exhausted": 1}` assert.Equal(t, expected, stats) - assert.EqualValues(t, 5, lastID.Get()) - assert.EqualValues(t, 0, count.Get()) + assert.EqualValues(t, 5, lastID.Load()) + assert.EqualValues(t, 0, count.Load()) } func TestIdleTimeout(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p := NewResourcePool(PoolFactory, 1, 1, 10*time.Millisecond, 0, logWait, nil, 0) defer p.Close() r, err := p.Get(ctx, nil) require.NoError(t, err) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 0, p.IdleClosed()) p.Put(r) - assert.EqualValues(t, 1, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 0, p.IdleClosed()) time.Sleep(15 * time.Millisecond) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.IdleClosed()) r, err = p.Get(ctx, nil) require.NoError(t, err) - assert.EqualValues(t, 2, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 2, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.IdleClosed()) // sleep to let the idle closer run while all resources are in use // then make sure things are still as we expect time.Sleep(15 * time.Millisecond) - assert.EqualValues(t, 2, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 2, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.IdleClosed()) p.Put(r) r, err = p.Get(ctx, nil) require.NoError(t, err) - assert.EqualValues(t, 2, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 2, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.IdleClosed()) // the idle close thread wakes up every 1/100 of the idle time, so ensure @@ -489,8 +488,8 @@ func TestIdleTimeout(t *testing.T) { p.Put(r) time.Sleep(15 * time.Millisecond) - assert.EqualValues(t, 2, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 2, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.IdleClosed()) // Get and Put to refresh timeUsed @@ -499,50 +498,50 @@ func TestIdleTimeout(t *testing.T) { p.Put(r) p.SetIdleTimeout(10 * time.Millisecond) time.Sleep(15 * time.Millisecond) - assert.EqualValues(t, 3, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 3, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 2, p.IdleClosed()) } func TestIdleTimeoutWithSettings(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p := NewResourcePool(PoolFactory, 1, 1, 10*time.Millisecond, 0, logWait, nil, 0) defer p.Close() r, err := p.Get(ctx, sFooBar) require.NoError(t, err) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 0, p.IdleClosed()) p.Put(r) - assert.EqualValues(t, 1, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 0, p.IdleClosed()) time.Sleep(15 * time.Millisecond) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.IdleClosed()) r, err = p.Get(ctx, sFooBar) require.NoError(t, err) - assert.EqualValues(t, 2, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 2, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.IdleClosed()) // sleep to let the idle closer run while all resources are in use // then make sure things are still as we expect time.Sleep(15 * time.Millisecond) - assert.EqualValues(t, 2, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 2, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.IdleClosed()) p.Put(r) r, err = p.Get(ctx, sFooBar) require.NoError(t, err) - assert.EqualValues(t, 2, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 2, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.IdleClosed()) // the idle close thread wakes up every 1/100 of the idle time, so ensure @@ -551,8 +550,8 @@ func TestIdleTimeoutWithSettings(t *testing.T) { p.Put(r) time.Sleep(15 * time.Millisecond) - assert.EqualValues(t, 2, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 2, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.IdleClosed()) // Get and Put to refresh timeUsed @@ -561,15 +560,15 @@ func TestIdleTimeoutWithSettings(t *testing.T) { p.Put(r) p.SetIdleTimeout(10 * time.Millisecond) time.Sleep(15 * time.Millisecond) - assert.EqualValues(t, 3, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 3, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 2, p.IdleClosed()) } func TestIdleTimeoutCreateFail(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p := NewResourcePool(PoolFactory, 1, 1, 10*time.Millisecond, 0, logWait, nil, 0) defer p.Close() for _, setting := range []*Setting{nil, sFoo} { @@ -596,54 +595,54 @@ func TestIdleTimeoutCreateFail(t *testing.T) { func TestMaxLifetime(t *testing.T) { // maxLifetime 0 ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p := NewResourcePool(PoolFactory, 1, 1, 10*time.Second, 0, logWait, nil, 0) defer p.Close() r, err := p.Get(ctx, nil) require.NoError(t, err) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 0, p.MaxLifetimeClosed()) time.Sleep(10 * time.Millisecond) p.Put(r) - assert.EqualValues(t, 1, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 0, p.MaxLifetimeClosed()) // maxLifetime > 0 ctx = context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p = NewResourcePool(PoolFactory, 1, 1, 10*time.Second, 10*time.Millisecond, logWait, nil, 0) defer p.Close() r, err = p.Get(ctx, nil) require.NoError(t, err) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 0, p.MaxLifetimeClosed()) time.Sleep(5 * time.Millisecond) p.Put(r) - assert.EqualValues(t, 1, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 0, p.MaxLifetimeClosed()) r, err = p.Get(ctx, nil) require.NoError(t, err) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 0, p.MaxLifetimeClosed()) time.Sleep(10 * time.Millisecond * 2) p.Put(r) - assert.EqualValues(t, 2, lastID.Get()) - assert.EqualValues(t, 1, count.Get()) + assert.EqualValues(t, 2, lastID.Load()) + assert.EqualValues(t, 1, count.Load()) assert.EqualValues(t, 1, p.MaxLifetimeClosed()) } @@ -665,8 +664,8 @@ func TestExtendedLifetimeTimeout(t *testing.T) { func TestCreateFail(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p := NewResourcePool(FailFactory, 5, 5, time.Second, 0, logWait, nil, 0) defer p.Close() @@ -682,8 +681,8 @@ func TestCreateFail(t *testing.T) { func TestCreateFailOnPut(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p := NewResourcePool(PoolFactory, 5, 5, time.Second, 0, logWait, nil, 0) defer p.Close() @@ -703,8 +702,8 @@ func TestCreateFailOnPut(t *testing.T) { func TestSlowCreateFail(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p := NewResourcePool(SlowFailFactory, 2, 2, time.Second, 0, logWait, nil, 0) defer p.Close() ch := make(chan bool) @@ -725,8 +724,8 @@ func TestSlowCreateFail(t *testing.T) { func TestTimeout(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p := NewResourcePool(PoolFactory, 1, 1, time.Second, 0, logWait, nil, 0) defer p.Close() @@ -748,8 +747,8 @@ func TestTimeout(t *testing.T) { } func TestExpired(t *testing.T) { - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) p := NewResourcePool(PoolFactory, 1, 1, time.Second, 0, logWait, nil, 0) defer p.Close() @@ -764,8 +763,8 @@ func TestExpired(t *testing.T) { func TestMultiSettings(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) + lastID.Store(0) + count.Store(0) waitStarts = waitStarts[:0] p := NewResourcePool(PoolFactory, 5, 5, time.Second, 0, logWait, nil, 0) @@ -784,8 +783,8 @@ func TestMultiSettings(t *testing.T) { assert.Zero(t, p.WaitCount()) assert.Zero(t, len(waitStarts)) assert.Zero(t, p.WaitTime()) - assert.EqualValues(t, i+1, lastID.Get()) - assert.EqualValues(t, i+1, count.Get()) + assert.EqualValues(t, i+1, lastID.Load()) + assert.EqualValues(t, i+1, count.Load()) } // Test that Get waits @@ -816,20 +815,20 @@ func TestMultiSettings(t *testing.T) { } } assert.NotZero(t, p.WaitTime()) - assert.EqualValues(t, 5, lastID.Get()) + assert.EqualValues(t, 5, lastID.Load()) // Close p.Close() assert.EqualValues(t, 0, p.Capacity()) assert.EqualValues(t, 0, p.Available()) - assert.EqualValues(t, 0, count.Get()) + assert.EqualValues(t, 0, count.Load()) } func TestMultiSettingsWithReset(t *testing.T) { ctx := context.Background() - lastID.Set(0) - count.Set(0) - resetCount.Set(0) + lastID.Store(0) + count.Store(0) + resetCount.Store(0) p := NewResourcePool(PoolFactory, 5, 5, time.Second, 0, logWait, nil, 0) var resources [10]Resource @@ -844,8 +843,8 @@ func TestMultiSettingsWithReset(t *testing.T) { require.NoError(t, err) resources[i] = r assert.EqualValues(t, 5-i-1, p.Available()) - assert.EqualValues(t, i+1, lastID.Get()) - assert.EqualValues(t, i+1, count.Get()) + assert.EqualValues(t, i+1, lastID.Load()) + assert.EqualValues(t, i+1, count.Load()) } // Put all of them back @@ -859,16 +858,16 @@ func TestMultiSettingsWithReset(t *testing.T) { require.NoError(t, err) p.Put(r) } - assert.EqualValues(t, 2, resetCount.Get()) // when setting was {bar} and getting for {foo} + assert.EqualValues(t, 2, resetCount.Load()) // when setting was {bar} and getting for {foo} assert.EqualValues(t, 5, p.Available()) - assert.EqualValues(t, 5, lastID.Get()) - assert.EqualValues(t, 5, count.Get()) + assert.EqualValues(t, 5, lastID.Load()) + assert.EqualValues(t, 5, count.Load()) // Close p.Close() assert.EqualValues(t, 0, p.Capacity()) assert.EqualValues(t, 0, p.Available()) - assert.EqualValues(t, 0, count.Get()) + assert.EqualValues(t, 0, count.Load()) } func TestApplySettingsFailure(t *testing.T) { diff --git a/go/stats/counter.go b/go/stats/counter.go index bca3a07768b..406ab5843bc 100644 --- a/go/stats/counter.go +++ b/go/stats/counter.go @@ -17,10 +17,11 @@ limitations under the License. package stats import ( + "math" "strconv" + "sync/atomic" "time" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/logutil" ) @@ -31,7 +32,7 @@ var logCounterNegative = logutil.NewThrottledLogger("StatsCounterNegative", 1*ti // For a one-dimensional or multi-dimensional counter, please use // CountersWithSingleLabel or CountersWithMultiLabels instead. type Counter struct { - i sync2.AtomicInt64 + i atomic.Int64 help string } @@ -57,22 +58,22 @@ func (v *Counter) Add(delta int64) { // only when we are certain that the underlying value we are setting // is increment only func (v *Counter) Set(value int64) { - v.i.Set(value) + v.i.Store(value) } // Reset resets the counter value to 0. func (v *Counter) Reset() { - v.i.Set(int64(0)) + v.i.Store(0) } // Get returns the value. func (v *Counter) Get() int64 { - return v.i.Get() + return v.i.Load() } // String implements the expvar.Var interface. func (v *Counter) String() string { - return strconv.FormatInt(v.i.Get(), 10) + return strconv.FormatInt(v.Get(), 10) } // Help returns the help string. @@ -137,7 +138,7 @@ func NewGauge(name string, help string) *Gauge { // Set overwrites the current value. func (v *Gauge) Set(value int64) { - v.Counter.i.Set(value) + v.Counter.i.Store(value) } // Add adds the provided value to the Gauge. @@ -172,7 +173,7 @@ func NewGaugeFunc(name string, help string, f func() int64) *GaugeFunc { // For a one-dimensional or multi-dimensional counter, please use // CountersWithSingleLabel or CountersWithMultiLabels instead. type GaugeFloat64 struct { - i sync2.AtomicFloat64 + i atomic.Uint64 help string } @@ -190,22 +191,22 @@ func NewGaugeFloat64(name string, help string) *GaugeFloat64 { // only when we are certain that the underlying value we are setting // is increment only func (v *GaugeFloat64) Set(value float64) { - v.i.Set(value) + v.i.Store(math.Float64bits(value)) } // Reset resets the counter value to 0. func (v *GaugeFloat64) Reset() { - v.i.Set(float64(0)) + v.i.Store(0) } // Get returns the value. func (v *GaugeFloat64) Get() float64 { - return v.i.Get() + return math.Float64frombits(v.i.Load()) } // String implements the expvar.Var interface. func (v *GaugeFloat64) String() string { - return strconv.FormatFloat(v.i.Get(), 'f', -1, 64) + return strconv.FormatFloat(v.Get(), 'f', -1, 64) } // Help returns the help string. diff --git a/go/stats/duration.go b/go/stats/duration.go index 297192fbe9c..9bfb39e7c1d 100644 --- a/go/stats/duration.go +++ b/go/stats/duration.go @@ -18,14 +18,13 @@ package stats import ( "strconv" + "sync/atomic" "time" - - "vitess.io/vitess/go/sync2" ) // CounterDuration exports a time.Duration as counter. type CounterDuration struct { - i sync2.AtomicDuration + i atomic.Int64 help string } @@ -39,23 +38,23 @@ func NewCounterDuration(name, help string) *CounterDuration { } // Help implements the Variable interface. -func (cd CounterDuration) Help() string { +func (cd *CounterDuration) Help() string { return cd.help } // String is the implementation of expvar.var. -func (cd CounterDuration) String() string { - return strconv.FormatInt(int64(cd.i.Get()), 10) +func (cd *CounterDuration) String() string { + return strconv.FormatInt(cd.i.Load(), 10) } // Add adds the provided value to the CounterDuration. func (cd *CounterDuration) Add(delta time.Duration) { - cd.i.Add(delta) + cd.i.Add(delta.Nanoseconds()) } // Get returns the value. func (cd *CounterDuration) Get() time.Duration { - return cd.i.Get() + return time.Duration(cd.i.Load()) } // GaugeDuration exports a time.Duration as gauge. @@ -78,7 +77,7 @@ func NewGaugeDuration(name, help string) *GaugeDuration { // Set sets the value. func (gd *GaugeDuration) Set(value time.Duration) { - gd.i.Set(value) + gd.i.Store(value.Nanoseconds()) } // CounterDurationFunc allows to provide the value via a custom function. diff --git a/go/stats/histogram.go b/go/stats/histogram.go index 3fe3562cade..833c09b86bb 100644 --- a/go/stats/histogram.go +++ b/go/stats/histogram.go @@ -19,8 +19,7 @@ package stats import ( "bytes" "fmt" - - "vitess.io/vitess/go/sync2" + "sync/atomic" ) // Histogram tracks counts and totals while @@ -35,8 +34,8 @@ type Histogram struct { totalLabel string hook func(int64) - buckets []sync2.AtomicInt64 - total sync2.AtomicInt64 + buckets []atomic.Int64 + total atomic.Int64 } // NewHistogram creates a histogram with auto-generated labels @@ -67,7 +66,7 @@ func NewGenericHistogram(name, help string, cutoffs []int64, labels []string, co labels: labels, countLabel: countLabel, totalLabel: totalLabel, - buckets: make([]sync2.AtomicInt64, len(labels)), + buckets: make([]atomic.Int64, len(labels)), } if name != "" { publish(name, h) @@ -108,12 +107,12 @@ func (h *Histogram) MarshalJSON() ([]byte, error) { fmt.Fprintf(b, "{") totalCount := int64(0) for i, label := range h.labels { - count := h.buckets[i].Get() + count := h.buckets[i].Load() totalCount += count fmt.Fprintf(b, "\"%v\": %v, ", label, count) } fmt.Fprintf(b, "\"%s\": %v, ", h.countLabel, totalCount) - fmt.Fprintf(b, "\"%s\": %v", h.totalLabel, h.total.Get()) + fmt.Fprintf(b, "\"%s\": %v", h.totalLabel, h.total.Load()) fmt.Fprintf(b, "}") return b.Bytes(), nil } @@ -122,7 +121,7 @@ func (h *Histogram) MarshalJSON() ([]byte, error) { func (h *Histogram) Counts() map[string]int64 { counts := make(map[string]int64, len(h.labels)) for i, label := range h.labels { - counts[label] = h.buckets[i].Get() + counts[label] = h.buckets[i].Load() } return counts } @@ -135,7 +134,7 @@ func (h *Histogram) CountLabel() string { // Count returns the number of times Add has been called. func (h *Histogram) Count() (count int64) { for i := range h.buckets { - count += h.buckets[i].Get() + count += h.buckets[i].Load() } return } @@ -147,7 +146,7 @@ func (h *Histogram) TotalLabel() string { // Total returns the sum of all values that have been added to this Histogram. func (h *Histogram) Total() (total int64) { - return h.total.Get() + return h.total.Load() } // Labels returns the labels that were set when this Histogram was created. @@ -164,7 +163,7 @@ func (h *Histogram) Cutoffs() []int64 { func (h *Histogram) Buckets() []int64 { buckets := make([]int64, len(h.buckets)) for i := range h.buckets { - buckets[i] = h.buckets[i].Get() + buckets[i] = h.buckets[i].Load() } return buckets } diff --git a/go/stats/timings.go b/go/stats/timings.go index 9048bedee11..fe12ccd0604 100644 --- a/go/stats/timings.go +++ b/go/stats/timings.go @@ -20,16 +20,15 @@ import ( "encoding/json" "fmt" "sync" + "sync/atomic" "time" - - "vitess.io/vitess/go/sync2" ) // Timings is meant to tracks timing data // by named categories as well as histograms. type Timings struct { - totalCount sync2.AtomicInt64 - totalTime sync2.AtomicInt64 + totalCount atomic.Int64 + totalTime atomic.Int64 mu sync.RWMutex histograms map[string]*Histogram @@ -118,8 +117,8 @@ func (t *Timings) String() string { TotalTime int64 Histograms map[string]*Histogram }{ - t.totalCount.Get(), - t.totalTime.Get(), + t.totalCount.Load(), + t.totalTime.Load(), t.histograms, } @@ -143,12 +142,12 @@ func (t *Timings) Histograms() (h map[string]*Histogram) { // Count returns the total count for all values. func (t *Timings) Count() int64 { - return t.totalCount.Get() + return t.totalCount.Load() } // Time returns the total time elapsed for all values. func (t *Timings) Time() int64 { - return t.totalTime.Get() + return t.totalTime.Load() } // Counts returns the total count for each value. @@ -160,7 +159,7 @@ func (t *Timings) Counts() map[string]int64 { for k, v := range t.histograms { counts[k] = v.Count() } - counts["All"] = t.totalCount.Get() + counts["All"] = t.totalCount.Load() return counts } diff --git a/go/sync2/atomic.go b/go/sync2/atomic.go deleted file mode 100644 index e974eae3960..00000000000 --- a/go/sync2/atomic.go +++ /dev/null @@ -1,212 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sync2 - -import ( - "math" - "sync" - "sync/atomic" - "time" -) - -// AtomicInt32 is a wrapper with a simpler interface around atomic.(Add|Store|Load|CompareAndSwap)Int32 functions. -type AtomicInt32 struct { - int32 -} - -// NewAtomicInt32 initializes a new AtomicInt32 with a given value. -func NewAtomicInt32(n int32) AtomicInt32 { - return AtomicInt32{n} -} - -// Add atomically adds n to the value. -func (i *AtomicInt32) Add(n int32) int32 { - return atomic.AddInt32(&i.int32, n) -} - -// Set atomically sets n as new value. -func (i *AtomicInt32) Set(n int32) { - atomic.StoreInt32(&i.int32, n) -} - -// Get atomically returns the current value. -func (i *AtomicInt32) Get() int32 { - return atomic.LoadInt32(&i.int32) -} - -// CompareAndSwap automatically swaps the old with the new value. -func (i *AtomicInt32) CompareAndSwap(oldval, newval int32) (swapped bool) { - return atomic.CompareAndSwapInt32(&i.int32, oldval, newval) -} - -// AtomicInt64 is a wrapper with a simpler interface around atomic.(Add|Store|Load|CompareAndSwap)Int64 functions. -type AtomicInt64 struct { - int64 -} - -// NewAtomicInt64 initializes a new AtomicInt64 with a given value. -func NewAtomicInt64(n int64) AtomicInt64 { - return AtomicInt64{n} -} - -// Add atomically adds n to the value. -func (i *AtomicInt64) Add(n int64) int64 { - return atomic.AddInt64(&i.int64, n) -} - -// Set atomically sets n as new value. -func (i *AtomicInt64) Set(n int64) { - atomic.StoreInt64(&i.int64, n) -} - -// Get atomically returns the current value. -func (i *AtomicInt64) Get() int64 { - return atomic.LoadInt64(&i.int64) -} - -// CompareAndSwap automatically swaps the old with the new value. -func (i *AtomicInt64) CompareAndSwap(oldval, newval int64) (swapped bool) { - return atomic.CompareAndSwapInt64(&i.int64, oldval, newval) -} - -// AtomicFloat64 is a wrapper with a simpler interface around atomic.(Add|Store|Load|CompareAndSwap)Flat64 functions. -type AtomicFloat64 struct { - uint64 -} - -// NewAtomicFloat64 initializes a new AtomicFloat64 with a given value. -func NewAtomicFloat64(n float64) AtomicFloat64 { - return AtomicFloat64{math.Float64bits(n)} -} - -// Set atomically sets n as new value. -func (f *AtomicFloat64) Set(n float64) { - atomic.StoreUint64(&f.uint64, math.Float64bits(n)) -} - -// Get atomically returns the current value. -func (f *AtomicFloat64) Get() float64 { - return math.Float64frombits(atomic.LoadUint64(&f.uint64)) -} - -// CompareAndSwap automatically swaps the old with the new value. -func (f *AtomicFloat64) CompareAndSwap(oldval, newval float64) (swapped bool) { - return atomic.CompareAndSwapUint64(&f.uint64, math.Float64bits(oldval), math.Float64bits(newval)) -} - -// AtomicDuration is a wrapper with a simpler interface around atomic.(Add|Store|Load|CompareAndSwap)Int64 functions. -type AtomicDuration struct { - int64 -} - -// NewAtomicDuration initializes a new AtomicDuration with a given value. -func NewAtomicDuration(duration time.Duration) AtomicDuration { - return AtomicDuration{int64(duration)} -} - -// Add atomically adds duration to the value. -func (d *AtomicDuration) Add(duration time.Duration) time.Duration { - return time.Duration(atomic.AddInt64(&d.int64, int64(duration))) -} - -// Set atomically sets duration as new value. -func (d *AtomicDuration) Set(duration time.Duration) { - atomic.StoreInt64(&d.int64, int64(duration)) -} - -// Get atomically returns the current value. -func (d *AtomicDuration) Get() time.Duration { - return time.Duration(atomic.LoadInt64(&d.int64)) -} - -// CompareAndSwap automatically swaps the old with the new value. -func (d *AtomicDuration) CompareAndSwap(oldval, newval time.Duration) (swapped bool) { - return atomic.CompareAndSwapInt64(&d.int64, int64(oldval), int64(newval)) -} - -// AtomicBool gives an atomic boolean variable. -type AtomicBool struct { - int32 -} - -// NewAtomicBool initializes a new AtomicBool with a given value. -func NewAtomicBool(n bool) AtomicBool { - if n { - return AtomicBool{1} - } - return AtomicBool{0} -} - -// Set atomically sets n as new value. -func (i *AtomicBool) Set(n bool) { - if n { - atomic.StoreInt32(&i.int32, 1) - } else { - atomic.StoreInt32(&i.int32, 0) - } -} - -// Get atomically returns the current value. -func (i *AtomicBool) Get() bool { - return atomic.LoadInt32(&i.int32) != 0 -} - -// CompareAndSwap automatically swaps the old with the new value. -func (i *AtomicBool) CompareAndSwap(o, n bool) bool { - var old, new int32 - if o { - old = 1 - } - if n { - new = 1 - } - return atomic.CompareAndSwapInt32(&i.int32, old, new) -} - -// AtomicString gives you atomic-style APIs for string, but -// it's only a convenience wrapper that uses a mutex. So, it's -// not as efficient as the rest of the atomic types. -type AtomicString struct { - mu sync.Mutex - str string -} - -// Set atomically sets str as new value. -func (s *AtomicString) Set(str string) { - s.mu.Lock() - s.str = str - s.mu.Unlock() -} - -// Get atomically returns the current value. -func (s *AtomicString) Get() string { - s.mu.Lock() - str := s.str - s.mu.Unlock() - return str -} - -// CompareAndSwap automatically swaps the old with the new value. -func (s *AtomicString) CompareAndSwap(oldval, newval string) (swqpped bool) { - s.mu.Lock() - defer s.mu.Unlock() - if s.str == oldval { - s.str = newval - return true - } - return false -} diff --git a/go/sync2/atomic_test.go b/go/sync2/atomic_test.go deleted file mode 100644 index 2754c7bef85..00000000000 --- a/go/sync2/atomic_test.go +++ /dev/null @@ -1,128 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sync2 - -import ( - "testing" - "time" - - "gotest.tools/assert" -) - -func TestAtomicInt32(t *testing.T) { - i := NewAtomicInt32(1) - assert.Equal(t, int32(1), i.Get()) - - i.Set(2) - assert.Equal(t, int32(2), i.Get()) - - i.Add(1) - assert.Equal(t, int32(3), i.Get()) - - i.CompareAndSwap(3, 4) - assert.Equal(t, int32(4), i.Get()) - - i.CompareAndSwap(3, 5) - assert.Equal(t, int32(4), i.Get()) -} - -func TestAtomicInt64(t *testing.T) { - i := NewAtomicInt64(1) - assert.Equal(t, int64(1), i.Get()) - - i.Set(2) - assert.Equal(t, int64(2), i.Get()) - - i.Add(1) - assert.Equal(t, int64(3), i.Get()) - - i.CompareAndSwap(3, 4) - assert.Equal(t, int64(4), i.Get()) - - i.CompareAndSwap(3, 5) - assert.Equal(t, int64(4), i.Get()) -} - -func TestAtomicFloat64(t *testing.T) { - i := NewAtomicFloat64(1.0) - assert.Equal(t, float64(1.0), i.Get()) - - i.Set(2.0) - assert.Equal(t, float64(2.0), i.Get()) - { - swapped := i.CompareAndSwap(2.0, 4.0) - assert.Equal(t, float64(4), i.Get()) - assert.Equal(t, true, swapped) - } - { - swapped := i.CompareAndSwap(2.0, 5.0) - assert.Equal(t, float64(4), i.Get()) - assert.Equal(t, false, swapped) - } -} - -func TestAtomicDuration(t *testing.T) { - d := NewAtomicDuration(time.Second) - assert.Equal(t, time.Second, d.Get()) - - d.Set(time.Second * 2) - assert.Equal(t, time.Second*2, d.Get()) - - d.Add(time.Second) - assert.Equal(t, time.Second*3, d.Get()) - - d.CompareAndSwap(time.Second*3, time.Second*4) - assert.Equal(t, time.Second*4, d.Get()) - - d.CompareAndSwap(time.Second*3, time.Second*5) - assert.Equal(t, time.Second*4, d.Get()) -} - -func TestAtomicString(t *testing.T) { - var s AtomicString - assert.Equal(t, "", s.Get()) - - s.Set("a") - assert.Equal(t, "a", s.Get()) - - assert.Equal(t, false, s.CompareAndSwap("b", "c")) - assert.Equal(t, "a", s.Get()) - - assert.Equal(t, true, s.CompareAndSwap("a", "c")) - assert.Equal(t, "c", s.Get()) -} - -func TestAtomicBool(t *testing.T) { - b := NewAtomicBool(true) - assert.Equal(t, true, b.Get()) - - b.Set(false) - assert.Equal(t, false, b.Get()) - - b.Set(true) - assert.Equal(t, true, b.Get()) - - assert.Equal(t, false, b.CompareAndSwap(false, true)) - - assert.Equal(t, true, b.CompareAndSwap(true, false)) - - assert.Equal(t, true, b.CompareAndSwap(false, false)) - - assert.Equal(t, true, b.CompareAndSwap(false, true)) - - assert.Equal(t, true, b.CompareAndSwap(true, true)) -} diff --git a/go/sync2/batcher.go b/go/sync2/batcher.go index 8d8254d5712..bb53294eb31 100644 --- a/go/sync2/batcher.go +++ b/go/sync2/batcher.go @@ -17,6 +17,7 @@ limitations under the License. package sync2 import ( + "sync/atomic" "time" ) @@ -30,8 +31,8 @@ import ( type Batcher struct { interval time.Duration queue chan int - waiters AtomicInt32 - nextID AtomicInt32 + waiters atomic.Int32 + nextID atomic.Int32 after func(time.Duration) <-chan time.Time } @@ -40,8 +41,6 @@ func NewBatcher(interval time.Duration) *Batcher { return &Batcher{ interval: interval, queue: make(chan int), - waiters: NewAtomicInt32(0), - nextID: NewAtomicInt32(0), after: time.After, } } @@ -52,8 +51,6 @@ func newBatcherForTest(interval time.Duration, after func(time.Duration) <-chan return &Batcher{ interval: interval, queue: make(chan int), - waiters: NewAtomicInt32(0), - nextID: NewAtomicInt32(0), after: after, } } @@ -77,9 +74,9 @@ func (b *Batcher) newBatch() { // Make sure to atomically reset the number of waiters to make // sure that all incoming requests either make it into the // current batch or the next one. - waiters := b.waiters.Get() + waiters := b.waiters.Load() for !b.waiters.CompareAndSwap(waiters, 0) { - waiters = b.waiters.Get() + waiters = b.waiters.Load() } for i := int32(0); i < waiters; i++ { diff --git a/go/sync2/batcher_test.go b/go/sync2/batcher_test.go index e3172ceae2b..2b8f13fd444 100644 --- a/go/sync2/batcher_test.go +++ b/go/sync2/batcher_test.go @@ -17,6 +17,7 @@ limitations under the License. package sync2 import ( + "sync/atomic" "testing" "time" ) @@ -46,7 +47,7 @@ func TestBatcher(t *testing.T) { afterFn, releaseBatch := makeAfterFnWithLatch(t) b := newBatcherForTest(interval, afterFn) - waitersFinished := NewAtomicInt32(0) + var waitersFinished atomic.Int32 startWaiter := func(testcase string, want int) { go func() { @@ -58,8 +59,8 @@ func TestBatcher(t *testing.T) { }() } - awaitVal := func(name string, val *AtomicInt32, expected int32) { - for count := 0; val.Get() != expected; count++ { + awaitVal := func(name string, val *atomic.Int32, expected int32) { + for count := 0; val.Load() != expected; count++ { time.Sleep(50 * time.Millisecond) if count > 5 { t.Errorf("Timed out waiting for %s to be %v", name, expected) @@ -72,14 +73,14 @@ func TestBatcher(t *testing.T) { // Wait for all the waiters to register awaitVal("Batcher.waiters for "+name, &b.waiters, n) // Release the batch and wait for the batcher to catch up. - if waitersFinished.Get() != 0 { + if waitersFinished.Load() != 0 { t.Errorf("Waiters finished before being released") } releaseBatch() awaitVal("Batcher.waiters for "+name, &b.waiters, 0) // Make sure the waiters actually run so they can verify their batch number. awaitVal("waitersFinshed for "+name, &waitersFinished, n) - waitersFinished.Set(0) + waitersFinished.Store(0) } // test single waiter diff --git a/go/sync2/doc.go b/go/sync2/doc.go deleted file mode 100644 index 4fc32a7e53b..00000000000 --- a/go/sync2/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package sync2 provides extra functionality along the same lines as sync. -package sync2 diff --git a/go/sync2/norace.go b/go/sync2/norace.go deleted file mode 100644 index a2ce9fd058c..00000000000 --- a/go/sync2/norace.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build !race -// +build !race - -package sync2 - -// Race reports if the race detector is enabled. -const Race = false diff --git a/go/sync2/race.go b/go/sync2/race.go deleted file mode 100644 index 0efd57c3d8f..00000000000 --- a/go/sync2/race.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build race -// +build race - -package sync2 - -// Race reports if the race detector is enabled. -const Race = true diff --git a/go/sync2/semaphore.go b/go/sync2/semaphore.go deleted file mode 100644 index c0d1fd2ce48..00000000000 --- a/go/sync2/semaphore.go +++ /dev/null @@ -1,97 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sync2 - -// What's in a name? Channels have all you need to emulate a counting -// semaphore with a boatload of extra functionality. However, in some -// cases, you just want a familiar API. - -import ( - "context" - "time" -) - -// Semaphore is a counting semaphore with the option to -// specify a timeout. -type Semaphore struct { - slots chan struct{} - timeout time.Duration -} - -// NewSemaphore creates a Semaphore. The count parameter must be a positive -// number. A timeout of zero means that there is no timeout. -func NewSemaphore(count int, timeout time.Duration) *Semaphore { - sem := &Semaphore{ - slots: make(chan struct{}, count), - timeout: timeout, - } - for i := 0; i < count; i++ { - sem.slots <- struct{}{} - } - return sem -} - -// Acquire returns true on successful acquisition, and -// false on a timeout. -func (sem *Semaphore) Acquire() bool { - if sem.timeout == 0 { - <-sem.slots - return true - } - tm := time.NewTimer(sem.timeout) - defer tm.Stop() - select { - case <-sem.slots: - return true - case <-tm.C: - return false - } -} - -// AcquireContext returns true on successful acquisition, and -// false on context expiry. Timeout is ignored. -func (sem *Semaphore) AcquireContext(ctx context.Context) bool { - select { - case <-sem.slots: - return true - case <-ctx.Done(): - return false - } -} - -// TryAcquire acquires a semaphore if it's immediately available. -// It returns false otherwise. -func (sem *Semaphore) TryAcquire() bool { - select { - case <-sem.slots: - return true - default: - return false - } -} - -// Release releases the acquired semaphore. You must -// not release more than the number of semaphores you've -// acquired. -func (sem *Semaphore) Release() { - sem.slots <- struct{}{} -} - -// Size returns the current number of available slots. -func (sem *Semaphore) Size() int { - return len(sem.slots) -} diff --git a/go/sync2/semaphore_test.go b/go/sync2/semaphore_test.go deleted file mode 100644 index aa4f6f5cee1..00000000000 --- a/go/sync2/semaphore_test.go +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sync2 - -import ( - "context" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestSemaNoTimeout(t *testing.T) { - s := NewSemaphore(1, 0) - s.Acquire() - released := false - go func() { - released = true - s.Release() - }() - s.Acquire() - assert.True(t, released) -} - -func TestSemaTimeout(t *testing.T) { - s := NewSemaphore(1, 1*time.Millisecond) - s.Acquire() - release := make(chan struct{}) - released := make(chan struct{}) - go func() { - <-release - s.Release() - released <- struct{}{} - }() - assert.False(t, s.Acquire()) - release <- struct{}{} - <-released - assert.True(t, s.Acquire()) -} - -func TestSemaAcquireContext(t *testing.T) { - s := NewSemaphore(1, 0) - s.Acquire() - release := make(chan struct{}) - released := make(chan struct{}) - go func() { - <-release - s.Release() - released <- struct{}{} - }() - ctx, cancel := context.WithCancel(context.Background()) - cancel() - assert.False(t, s.AcquireContext(ctx)) - release <- struct{}{} - <-released - assert.True(t, s.AcquireContext(context.Background())) -} - -func TestSemaTryAcquire(t *testing.T) { - s := NewSemaphore(1, 0) - assert.True(t, s.TryAcquire()) - assert.False(t, s.TryAcquire()) - s.Release() - assert.True(t, s.TryAcquire()) -} diff --git a/go/test/endtoend/vtgate/reservedconn/get_lock_test.go b/go/test/endtoend/vtgate/reservedconn/get_lock_test.go index 9e193557424..380ad2ec7c0 100644 --- a/go/test/endtoend/vtgate/reservedconn/get_lock_test.go +++ b/go/test/endtoend/vtgate/reservedconn/get_lock_test.go @@ -19,13 +19,12 @@ package reservedconn import ( "context" "fmt" + "sync/atomic" "testing" "time" "vitess.io/vitess/go/test/endtoend/utils" - "vitess.io/vitess/go/sync2" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -118,7 +117,7 @@ func TestLocksBlockEachOther(t *testing.T) { // in the first connection, grab a lock utils.AssertMatches(t, conn1, `select get_lock('lock', 2)`, `[[INT64(1)]]`) - released := sync2.NewAtomicBool(false) + var released atomic.Bool go func() { conn2, err := mysql.Connect(context.Background(), &vtParams) @@ -127,13 +126,13 @@ func TestLocksBlockEachOther(t *testing.T) { // in the second connection, we try to grab a lock, and should get blocked utils.AssertMatches(t, conn2, `select get_lock('lock', 2)`, `[[INT64(1)]]`) - assert.True(t, released.Get(), "was not blocked by get_lock") + assert.True(t, released.Load(), "was not blocked by get_lock") utils.AssertMatches(t, conn2, `select release_lock('lock')`, `[[INT64(1)]]`) }() time.Sleep(1 * time.Second) - released.Set(true) + released.Store(true) utils.AssertMatches(t, conn1, `select release_lock('lock')`, `[[INT64(1)]]`) } @@ -148,7 +147,7 @@ func TestLocksBlocksWithTx(t *testing.T) { utils.Exec(t, conn1, "insert into test(id, val1) values(1,'1')") // -80 utils.Exec(t, conn1, "commit") - released := sync2.NewAtomicBool(false) + var released atomic.Bool go func() { conn2, err := mysql.Connect(context.Background(), &vtParams) @@ -157,13 +156,13 @@ func TestLocksBlocksWithTx(t *testing.T) { // in the second connection, we try to grab a lock, and should get blocked utils.AssertMatches(t, conn2, `select get_lock('lock', 2)`, `[[INT64(1)]]`) - assert.True(t, released.Get(), "was not blocked by get_lock") + assert.True(t, released.Load(), "was not blocked by get_lock") utils.AssertMatches(t, conn2, `select release_lock('lock')`, `[[INT64(1)]]`) }() time.Sleep(1 * time.Second) - released.Set(true) + released.Store(true) utils.AssertMatches(t, conn1, `select release_lock('lock')`, `[[INT64(1)]]`) utils.Exec(t, conn1, "delete from test") } diff --git a/go/timer/timer.go b/go/timer/timer.go index 7f64e6fa3cb..5a28820274f 100644 --- a/go/timer/timer.go +++ b/go/timer/timer.go @@ -19,9 +19,8 @@ package timer import ( "sync" + "sync/atomic" "time" - - "vitess.io/vitess/go/sync2" ) // Out-of-band messages @@ -56,7 +55,7 @@ A zero value interval will cause the timer to wait indefinitely, and it will react only to an explicit Trigger or Stop. */ type Timer struct { - interval sync2.AtomicDuration + interval atomic.Int64 // state management mu sync.Mutex @@ -71,7 +70,7 @@ func NewTimer(interval time.Duration) *Timer { tm := &Timer{ msg: make(chan typeAction), } - tm.interval.Set(interval) + tm.interval.Store(interval.Nanoseconds()) return tm } @@ -90,9 +89,9 @@ func (tm *Timer) run(keephouse func()) { var timer *time.Timer for { var ch <-chan time.Time - interval := tm.interval.Get() + interval := tm.interval.Load() if interval > 0 { - timer = time.NewTimer(interval) + timer = time.NewTimer(time.Duration(interval)) ch = timer.C } select { @@ -116,7 +115,7 @@ func (tm *Timer) run(keephouse func()) { // SetInterval changes the wait interval. // It will cause the timer to restart the wait. func (tm *Timer) SetInterval(ns time.Duration) { - tm.interval.Set(ns) + tm.interval.Store(ns.Nanoseconds()) tm.mu.Lock() defer tm.mu.Unlock() if tm.running { @@ -155,7 +154,7 @@ func (tm *Timer) Stop() { // Interval returns the current interval. func (tm *Timer) Interval() time.Duration { - return tm.interval.Get() + return time.Duration(tm.interval.Load()) } func (tm *Timer) Running() bool { diff --git a/go/timer/timer_flaky_test.go b/go/timer/timer_flaky_test.go index 4453d92fa07..c504a7d0eb2 100644 --- a/go/timer/timer_flaky_test.go +++ b/go/timer/timer_flaky_test.go @@ -17,12 +17,11 @@ limitations under the License. package timer import ( + "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" - - "vitess.io/vitess/go/sync2" ) const ( @@ -31,47 +30,47 @@ const ( tenth = 10 * time.Millisecond ) -var numcalls sync2.AtomicInt64 +var numcalls atomic.Int64 func f() { numcalls.Add(1) } func TestWait(t *testing.T) { - numcalls.Set(0) + numcalls.Store(0) timer := NewTimer(quarter) assert.False(t, timer.Running()) timer.Start(f) defer timer.Stop() assert.True(t, timer.Running()) time.Sleep(tenth) - assert.Equal(t, int64(0), numcalls.Get()) + assert.Equal(t, int64(0), numcalls.Load()) time.Sleep(quarter) - assert.Equal(t, int64(1), numcalls.Get()) + assert.Equal(t, int64(1), numcalls.Load()) time.Sleep(quarter) - assert.Equal(t, int64(2), numcalls.Get()) + assert.Equal(t, int64(2), numcalls.Load()) } func TestReset(t *testing.T) { - numcalls.Set(0) + numcalls.Store(0) timer := NewTimer(half) timer.Start(f) defer timer.Stop() timer.SetInterval(quarter) time.Sleep(tenth) - assert.Equal(t, int64(0), numcalls.Get()) + assert.Equal(t, int64(0), numcalls.Load()) time.Sleep(quarter) - assert.Equal(t, int64(1), numcalls.Get()) + assert.Equal(t, int64(1), numcalls.Load()) } func TestIndefinite(t *testing.T) { - numcalls.Set(0) + numcalls.Store(0) timer := NewTimer(0) timer.Start(f) defer timer.Stop() timer.TriggerAfter(quarter) time.Sleep(tenth) - assert.Equal(t, int64(0), numcalls.Get()) + assert.Equal(t, int64(0), numcalls.Load()) time.Sleep(quarter) - assert.Equal(t, int64(1), numcalls.Get()) + assert.Equal(t, int64(1), numcalls.Load()) } diff --git a/go/vt/binlog/binlogplayer/binlog_player.go b/go/vt/binlog/binlogplayer/binlog_player.go index 1f7bb9905c4..cfefc275269 100644 --- a/go/vt/binlog/binlogplayer/binlog_player.go +++ b/go/vt/binlog/binlogplayer/binlog_player.go @@ -30,6 +30,7 @@ import ( "math" "os" "sync" + "sync/atomic" "time" "github.com/spf13/pflag" @@ -40,7 +41,6 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/log" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -86,10 +86,10 @@ type Stats struct { heartbeatMutex sync.Mutex heartbeat int64 - ReplicationLagSeconds sync2.AtomicInt64 + ReplicationLagSeconds atomic.Int64 History *history.History - State sync2.AtomicString + State atomic.Value PhaseTimings *stats.Timings QueryTimings *stats.Timings @@ -152,7 +152,7 @@ func NewStats() *Stats { bps.Timings = stats.NewTimings("", "", "") bps.Rates = stats.NewRates("", bps.Timings, 15*60/5, 5*time.Second) bps.History = history.New(3) - bps.ReplicationLagSeconds.Set(math.MaxInt64) + bps.ReplicationLagSeconds.Store(math.MaxInt64) bps.PhaseTimings = stats.NewTimings("", "", "Phase") bps.QueryTimings = stats.NewTimings("", "", "Phase") bps.QueryCount = stats.NewCountersWithSingleLabel("", "", "Phase", "") @@ -503,7 +503,7 @@ func (blp *BinlogPlayer) writeRecoveryPosition(tx *binlogdatapb.BinlogTransactio blp.position = position blp.blplStats.SetLastPosition(blp.position) if tx.EventToken.Timestamp != 0 { - blp.blplStats.ReplicationLagSeconds.Set(now - tx.EventToken.Timestamp) + blp.blplStats.ReplicationLagSeconds.Store(now - tx.EventToken.Timestamp) } return nil } @@ -515,7 +515,7 @@ func (blp *BinlogPlayer) setVReplicationState(state, message string) error { Message: message, }) } - blp.blplStats.State.Set(state) + blp.blplStats.State.Store(state) query := fmt.Sprintf("update _vt.vreplication set state='%v', message=%v where id=%v", state, encodeString(MessageTruncate(message)), blp.uid) if _, err := blp.dbClient.ExecuteFetch(query, 1); err != nil { return fmt.Errorf("could not set state: %v: %v", query, err) diff --git a/go/vt/binlog/updatestreamctl.go b/go/vt/binlog/updatestreamctl.go index c49c372101b..7ece45cda9c 100644 --- a/go/vt/binlog/updatestreamctl.go +++ b/go/vt/binlog/updatestreamctl.go @@ -19,12 +19,12 @@ package binlog import ( "fmt" "sync" + "sync/atomic" "context" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/tb" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" @@ -124,7 +124,7 @@ type UpdateStreamImpl struct { // actionLock protects the following variables actionLock sync.Mutex - state sync2.AtomicInt64 + state atomic.Int64 stateWaitGroup sync.WaitGroup streams StreamList } @@ -199,7 +199,7 @@ func (updateStream *UpdateStreamImpl) InitDBConfig(dbcfgs *dbconfigs.DBConfigs) func (updateStream *UpdateStreamImpl) RegisterService() { // publish the stats stats.Publish("UpdateStreamState", stats.StringFunc(func() string { - return usStateNames[updateStream.state.Get()] + return usStateNames[updateStream.state.Load()] })) // and register all the RPC protocols @@ -223,7 +223,7 @@ func (updateStream *UpdateStreamImpl) Enable() { return } - updateStream.state.Set(usEnabled) + updateStream.state.Store(usEnabled) updateStream.streams.Init() log.Infof("Enabling update stream, dbname: %s", updateStream.cp.DBName()) } @@ -237,7 +237,7 @@ func (updateStream *UpdateStreamImpl) Disable() { return } - updateStream.state.Set(usDisabled) + updateStream.state.Store(usDisabled) updateStream.streams.Stop() updateStream.stateWaitGroup.Wait() log.Infof("Update Stream Disabled") @@ -245,7 +245,7 @@ func (updateStream *UpdateStreamImpl) Disable() { // IsEnabled returns true if UpdateStreamImpl is enabled func (updateStream *UpdateStreamImpl) IsEnabled() bool { - return updateStream.state.Get() == usEnabled + return updateStream.state.Load() == usEnabled } // StreamKeyRange is part of the UpdateStream interface diff --git a/go/vt/discovery/tablet_health_check.go b/go/vt/discovery/tablet_health_check.go index f0ad9b0a2ac..b3cc06e2d10 100644 --- a/go/vt/discovery/tablet_health_check.go +++ b/go/vt/discovery/tablet_health_check.go @@ -21,10 +21,9 @@ import ( "fmt" "strings" "sync" + "sync/atomic" "time" - "vitess.io/vitess/go/sync2" - "vitess.io/vitess/go/vt/grpcclient" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/proto/vtrpc" @@ -255,14 +254,14 @@ func (thc *tabletHealthCheck) checkConn(hc *HealthCheckImpl) { // timedout is accessed atomically because there could be a race // between the goroutine that sets it and the check for its value // later. - timedout := sync2.NewAtomicBool(false) + var timedout atomic.Bool go func() { for { select { case <-servingStatus: continue case <-time.After(hc.healthCheckTimeout): - timedout.Set(true) + timedout.Store(true) streamCancel() return case <-streamCtx.Done(): @@ -306,7 +305,7 @@ func (thc *tabletHealthCheck) checkConn(hc *HealthCheckImpl) { // If there was a timeout send an error. We do this after stream has returned. // This will ensure that this update prevails over any previous message that // stream could have sent. - if timedout.Get() { + if timedout.Load() { thc.LastError = fmt.Errorf("healthcheck timed out (latest %v)", thc.lastResponseTimestamp) thc.setServingState(false, thc.LastError.Error()) hcErrorCounters.Add([]string{thc.Target.Keyspace, thc.Target.Shard, topoproto.TabletTypeLString(thc.Target.TabletType)}, 1) diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index e6e60786c22..68625ede3ef 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -33,10 +33,10 @@ import ( "time" "github.com/spf13/pflag" + "golang.org/x/sync/semaphore" "vitess.io/vitess/go/ioutil" "vitess.io/vitess/go/mysql" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" @@ -491,7 +491,7 @@ func (be *BuiltinBackupEngine) backupFiles( params.Logger.Infof("found %v files to backup", len(fes)) // Backup with the provided concurrency. - sema := sync2.NewSemaphore(params.Concurrency, 0) + sema := semaphore.NewWeighted(int64(params.Concurrency)) wg := sync.WaitGroup{} for i := range fes { wg.Add(1) @@ -500,8 +500,8 @@ func (be *BuiltinBackupEngine) backupFiles( // Wait until we are ready to go, skip if we already // encountered an error. - sema.Acquire() - defer sema.Release() + sema.Acquire(ctx, 1) + defer sema.Release(1) if bh.HasErrors() { return } @@ -862,7 +862,7 @@ func (be *BuiltinBackupEngine) restoreFiles(ctx context.Context, params RestoreP } } fes := bm.FileEntries - sema := sync2.NewSemaphore(params.Concurrency, 0) + sema := semaphore.NewWeighted(int64(params.Concurrency)) rec := concurrency.AllErrorRecorder{} wg := sync.WaitGroup{} for i := range fes { @@ -872,8 +872,8 @@ func (be *BuiltinBackupEngine) restoreFiles(ctx context.Context, params RestoreP // Wait until we are ready to go, skip if we already // encountered an error. - sema.Acquire() - defer sema.Release() + sema.Acquire(ctx, 1) + defer sema.Release(1) if rec.HasErrors() { return } diff --git a/go/vt/mysqlctl/fakemysqldaemon.go b/go/vt/mysqlctl/fakemysqldaemon.go index e73fa86b87e..25b4f328de4 100644 --- a/go/vt/mysqlctl/fakemysqldaemon.go +++ b/go/vt/mysqlctl/fakemysqldaemon.go @@ -22,12 +22,12 @@ import ( "reflect" "strings" "sync" + "sync/atomic" "time" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/fakesqldb" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/dbconnpool" "vitess.io/vitess/go/vt/mysqlctl/tmutils" @@ -58,7 +58,7 @@ type FakeMysqlDaemon struct { // MysqlPort will be returned by GetMysqlPort(). Set to -1 to // return an error. - MysqlPort sync2.AtomicInt32 + MysqlPort atomic.Int32 // Replicating is updated when calling StartReplication / StopReplication // (it is not used at all when calling ReplicationStatus, it is the @@ -159,7 +159,7 @@ type FakeMysqlDaemon struct { FetchSuperQueryMap map[string]*sqltypes.Result // BinlogPlayerEnabled is used by {Enable,Disable}BinlogPlayer - BinlogPlayerEnabled sync2.AtomicBool + BinlogPlayerEnabled atomic.Bool // SemiSyncPrimaryEnabled represents the state of rpl_semi_sync_master_enabled. SemiSyncPrimaryEnabled bool @@ -245,10 +245,10 @@ func (fmd *FakeMysqlDaemon) Wait(ctx context.Context, cnf *Mycnf) error { // GetMysqlPort is part of the MysqlDaemon interface func (fmd *FakeMysqlDaemon) GetMysqlPort() (int32, error) { - if fmd.MysqlPort.Get() == -1 { + if fmd.MysqlPort.Load() == -1 { return 0, fmt.Errorf("FakeMysqlDaemon.GetMysqlPort returns an error") } - return fmd.MysqlPort.Get(), nil + return fmd.MysqlPort.Load(), nil } // GetServerID is part of the MysqlDaemon interface @@ -536,13 +536,13 @@ func (fmd *FakeMysqlDaemon) FetchSuperQuery(ctx context.Context, query string) ( // EnableBinlogPlayback is part of the MysqlDaemon interface func (fmd *FakeMysqlDaemon) EnableBinlogPlayback() error { - fmd.BinlogPlayerEnabled.Set(true) + fmd.BinlogPlayerEnabled.Store(true) return nil } // DisableBinlogPlayback disable playback of binlog events func (fmd *FakeMysqlDaemon) DisableBinlogPlayback() error { - fmd.BinlogPlayerEnabled.Set(false) + fmd.BinlogPlayerEnabled.Store(false) return nil } diff --git a/go/vt/schemamanager/tablet_executor.go b/go/vt/schemamanager/tablet_executor.go index 59fb7255bfa..9609adeedb2 100644 --- a/go/vt/schemamanager/tablet_executor.go +++ b/go/vt/schemamanager/tablet_executor.go @@ -22,7 +22,8 @@ import ( "sync" "time" - "vitess.io/vitess/go/sync2" + "golang.org/x/sync/semaphore" + "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/schema" @@ -385,7 +386,7 @@ func (exec *TabletExecutor) Execute(ctx context.Context, sqls []string) *Execute // If all shards succeeded, wait (up to waitReplicasTimeout) for replicas to // execute the schema change via replication. This is best-effort, meaning // we still return overall success if the timeout expires. - concurrency := sync2.NewSemaphore(10, 0) + concurrency := semaphore.NewWeighted(10) reloadCtx, cancel := context.WithTimeout(ctx, exec.waitReplicasTimeout) defer cancel() for _, result := range uniqueShards { diff --git a/go/vt/srvtopo/resilient_server_test.go b/go/vt/srvtopo/resilient_server_test.go index a57af927e5d..47ff6df81e2 100644 --- a/go/vt/srvtopo/resilient_server_test.go +++ b/go/vt/srvtopo/resilient_server_test.go @@ -23,13 +23,12 @@ import ( "html/template" "reflect" "sync" + "sync/atomic" "testing" "time" "vitess.io/vitess/go/vt/key" - "vitess.io/vitess/go/sync2" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" @@ -805,7 +804,7 @@ func TestSrvKeyspaceListener(t *testing.T) { rs := NewResilientServer(ts, "TestGetSrvKeyspaceWatcher") ctx, cancel := context.WithCancel(context.Background()) - var callbackCount sync2.AtomicInt32 + var callbackCount atomic.Int32 // adding listener will perform callback. rs.WatchSrvKeyspace(context.Background(), "test_cell", "test_ks", func(srvKs *topodatapb.SrvKeyspace, err error) bool { @@ -835,5 +834,5 @@ func TestSrvKeyspaceListener(t *testing.T) { } // only 3 times the callback called for the listener - assert.EqualValues(t, 3, callbackCount.Get()) + assert.EqualValues(t, 3, callbackCount.Load()) } diff --git a/go/vt/throttler/max_rate_module.go b/go/vt/throttler/max_rate_module.go index 2b2cb246212..a90f57306f1 100644 --- a/go/vt/throttler/max_rate_module.go +++ b/go/vt/throttler/max_rate_module.go @@ -17,22 +17,22 @@ limitations under the License. package throttler import ( - "vitess.io/vitess/go/sync2" + "sync/atomic" ) // MaxRateModule allows to set and retrieve a maximum rate limit. // It implements the Module interface. type MaxRateModule struct { - maxRate sync2.AtomicInt64 + maxRate atomic.Int64 rateUpdateChan chan<- struct{} } // NewMaxRateModule will create a new module instance and set the initial // rate limit to maxRate. func NewMaxRateModule(maxRate int64) *MaxRateModule { - return &MaxRateModule{ - maxRate: sync2.NewAtomicInt64(maxRate), - } + mx := &MaxRateModule{} + mx.maxRate.Store(maxRate) + return mx } // Start currently does nothing. It implements the Module interface. @@ -45,12 +45,12 @@ func (m *MaxRateModule) Stop() {} // MaxRate returns the current maximum allowed rate. func (m *MaxRateModule) MaxRate() int64 { - return m.maxRate.Get() + return m.maxRate.Load() } // SetMaxRate sets the current max rate and notifies the throttler about the // rate update. func (m *MaxRateModule) SetMaxRate(rate int64) { - m.maxRate.Set(rate) + m.maxRate.Store(rate) m.rateUpdateChan <- struct{}{} } diff --git a/go/vt/throttler/max_replication_lag_module.go b/go/vt/throttler/max_replication_lag_module.go index f8037f7f975..bd4666ec92f 100644 --- a/go/vt/throttler/max_replication_lag_module.go +++ b/go/vt/throttler/max_replication_lag_module.go @@ -20,11 +20,11 @@ import ( "fmt" "math" "sync" + "sync/atomic" "time" "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/topo/topoproto" @@ -95,7 +95,7 @@ type MaxReplicationLagModule struct { applyMutableConfig bool // rate is the rate calculated for the throttler. - rate sync2.AtomicInt64 + rate atomic.Int64 currentState state // lastRateChange is the time when rate was adjusted last. lastRateChange time.Time @@ -139,13 +139,10 @@ func NewMaxReplicationLagModule(config MaxReplicationLagModuleConfig, actualRate // Register "config" for a future config update. mutableConfig: config, applyMutableConfig: true, - // Always start off with a non-zero rate because zero means all requests - // get throttled. - rate: sync2.NewAtomicInt64(rate), - currentState: stateIncreaseRate, - lastRateChange: nowFunc(), - memory: newMemory(memoryGranularity, config.AgeBadRateAfter(), config.BadRateIncrease), - lagRecords: make(chan replicationLagRecord, 10), + currentState: stateIncreaseRate, + lastRateChange: nowFunc(), + memory: newMemory(memoryGranularity, config.AgeBadRateAfter(), config.BadRateIncrease), + lagRecords: make(chan replicationLagRecord, 10), // Prevent an immediate increase of the initial rate. nextAllowedChangeAfterInit: nowFunc().Add(config.MaxDurationBetweenIncreases()), actualRatesHistory: actualRatesHistory, @@ -154,6 +151,10 @@ func NewMaxReplicationLagModule(config MaxReplicationLagModuleConfig, actualRate results: newResultRing(1000), } + // Always start off with a non-zero rate because zero means all requests + // get throttled. + m.rate.Store(rate) + // Enforce a config update. m.applyLatestConfig() @@ -178,7 +179,7 @@ func (m *MaxReplicationLagModule) Stop() { // MaxRate returns the current maximum allowed rate. // It implements the Module interface. func (m *MaxReplicationLagModule) MaxRate() int64 { - return m.rate.Get() + return m.rate.Load() } // applyLatestConfig checks if "mutableConfig" should be applied as the new @@ -312,8 +313,8 @@ func (m *MaxReplicationLagModule) recalculateRate(lagRecordNow replicationLagRec lastRateChange: m.lastRateChange, OldState: m.currentState, NewState: m.currentState, - OldRate: m.rate.Get(), - NewRate: m.rate.Get(), + OldRate: m.rate.Load(), + NewRate: m.rate.Load(), LagRecordNow: lagRecordNow, } if lagNow <= m.config.TargetReplicationLagSec { @@ -469,7 +470,7 @@ func (m *MaxReplicationLagModule) isReplicaUnderTest(r *result, now time.Time, t func (m *MaxReplicationLagModule) increaseRate(r *result, now time.Time, lagRecordNow replicationLagRecord) { m.markCurrentRateAsBadOrGood(r, now, stateIncreaseRate, unknown) - oldRate := m.rate.Get() + oldRate := m.rate.Load() actualRate := m.actualRatesHistory.average(m.lastRateChange, now) // Do not increase the rate if we didn't see an actual rate that approached the current max rate. // actualRate will be NaN if there were no observations in the history. @@ -678,7 +679,7 @@ func (m *MaxReplicationLagModule) emergency(r *result, now time.Time, lagRecordN } func (m *MaxReplicationLagModule) decreaseRateByPercentage(r *result, now time.Time, lagRecordNow replicationLagRecord, newState state, decrease float64, decreaseReason string) { - oldRate := m.rate.Get() + oldRate := m.rate.Load() rate := int64(float64(oldRate) - float64(oldRate)*decrease) if rate == 0 { // Never fully stop throttling. @@ -690,7 +691,7 @@ func (m *MaxReplicationLagModule) decreaseRateByPercentage(r *result, now time.T } func (m *MaxReplicationLagModule) updateRate(r *result, newState state, rate int64, reason string, now time.Time, lagRecordNow replicationLagRecord, testDuration time.Duration) { - oldRate := m.rate.Get() + oldRate := m.rate.Load() m.currentState = newState @@ -710,7 +711,7 @@ func (m *MaxReplicationLagModule) updateRate(r *result, newState state, rate int if rate == oldRate { return } - m.rate.Set(int64(rate)) + m.rate.Store(rate) // Notify the throttler that we updated our max rate. m.rateUpdateChan <- struct{}{} } diff --git a/go/vt/throttler/thread_throttler.go b/go/vt/throttler/thread_throttler.go index 957f726fe48..314b68372e2 100644 --- a/go/vt/throttler/thread_throttler.go +++ b/go/vt/throttler/thread_throttler.go @@ -18,10 +18,9 @@ package throttler import ( "fmt" + "sync/atomic" "time" - "vitess.io/vitess/go/sync2" - "golang.org/x/time/rate" ) @@ -39,7 +38,7 @@ type threadThrottler struct { // maxRate holds the last rate set by setMaxRate. It will be set // in the limiter object in the next call to throttle(). - maxRate sync2.AtomicInt64 + maxRate atomic.Int64 limiter *rate.Limiter actualRateHistory *aggregatedIntervalHistory } @@ -74,7 +73,7 @@ func (t *threadThrottler) throttle(now time.Time) time.Duration { // Pass the limit set by the last call to setMaxRate. Limiter.SetLimitAt // is idempotent, so we can call it with the same value more than once without // issues. - t.limiter.SetLimitAt(now, rate.Limit(t.maxRate.Get())) + t.limiter.SetLimitAt(now, rate.Limit(t.maxRate.Load())) // Initialize or advance the current second interval when necessary. nowSecond := now.Truncate(time.Second) @@ -101,7 +100,7 @@ func (t *threadThrottler) throttle(now time.Time) time.Duration { reservation := t.limiter.ReserveN(now, 1) if !reservation.OK() { panic(fmt.Sprintf("BUG: limiter was unable to reserve an event. "+ - "threadThrottler: %v, reservation:%v", *t, *reservation)) + "threadThrottler: %+v, reservation:%v", t, *reservation)) } waitDuration := reservation.DelayFrom(now) if waitDuration <= 0 { @@ -115,11 +114,11 @@ func (t *threadThrottler) throttle(now time.Time) time.Duration { // setMaxRate sets the maximum rate for the next time throttle() is called. // setMaxRate() can be called concurrently with other methods of this object. func (t *threadThrottler) setMaxRate(newRate int64) { - t.maxRate.Set(newRate) + t.maxRate.Store(newRate) } // maxRate returns the rate set by the last call to setMaxRate(). // If setMaxRate() was not called, this method returns 0. func (t *threadThrottler) getMaxRate() int64 { - return t.maxRate.Get() + return t.maxRate.Load() } diff --git a/go/vt/topo/zk2topo/zk_conn.go b/go/vt/topo/zk2topo/zk_conn.go index 7c4ba066caf..a0eec8b4340 100644 --- a/go/vt/topo/zk2topo/zk_conn.go +++ b/go/vt/topo/zk2topo/zk_conn.go @@ -30,8 +30,8 @@ import ( "github.com/spf13/pflag" "github.com/z-division/go-zookeeper/zk" + "golang.org/x/sync/semaphore" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/servenv" ) @@ -94,7 +94,7 @@ type ZkConn struct { addr string // sem protects concurrent calls to Zookeeper. - sem *sync2.Semaphore + sem *semaphore.Weighted // mu protects the following fields. mu sync.Mutex @@ -107,7 +107,7 @@ type ZkConn struct { func Connect(addr string) *ZkConn { return &ZkConn{ addr: addr, - sem: sync2.NewSemaphore(maxConcurrency, 0), + sem: semaphore.NewWeighted(int64(maxConcurrency)), } } @@ -241,8 +241,11 @@ func (c *ZkConn) Close() error { func (c *ZkConn) withRetry(ctx context.Context, action func(conn *zk.Conn) error) (err error) { // Handle concurrent access to a Zookeeper server here. - c.sem.Acquire() - defer c.sem.Release() + err = c.sem.Acquire(ctx, 1) + if err != nil { + return err + } + defer c.sem.Release(1) for i := 0; i < maxAttempts; i++ { if i > 0 { diff --git a/go/vt/vtctl/grpcvtctldserver/server.go b/go/vt/vtctl/grpcvtctldserver/server.go index c7a2197f751..2ab12ec8c9c 100644 --- a/go/vt/vtctl/grpcvtctldserver/server.go +++ b/go/vt/vtctl/grpcvtctldserver/server.go @@ -29,6 +29,7 @@ import ( "sync" "time" + "golang.org/x/sync/semaphore" "google.golang.org/grpc" "google.golang.org/protobuf/proto" @@ -37,7 +38,6 @@ import ( "vitess.io/vitess/go/protoutil" "vitess.io/vitess/go/sets" "vitess.io/vitess/go/sqlescape" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/trace" "vitess.io/vitess/go/vt/callerid" "vitess.io/vitess/go/vt/concurrency" @@ -2476,9 +2476,9 @@ func (s *VtctldServer) ReloadSchemaShard(ctx context.Context, req *vtctldatapb.R logger, getEvents := eventStreamLogger() - var sema *sync2.Semaphore + var sema *semaphore.Weighted if req.Concurrency > 0 { - sema = sync2.NewSemaphore(int(req.Concurrency), 0) + sema = semaphore.NewWeighted(int64(req.Concurrency)) } s.reloadSchemaShard(ctx, req, sema, logger) @@ -2488,7 +2488,7 @@ func (s *VtctldServer) ReloadSchemaShard(ctx context.Context, req *vtctldatapb.R }, nil } -func (s *VtctldServer) reloadSchemaShard(ctx context.Context, req *vtctldatapb.ReloadSchemaShardRequest, sema *sync2.Semaphore, logger logutil.Logger) { +func (s *VtctldServer) reloadSchemaShard(ctx context.Context, req *vtctldatapb.ReloadSchemaShardRequest, sema *semaphore.Weighted, logger logutil.Logger) { span, ctx := trace.NewSpan(ctx, "VtctldServer.ReloadSchemaShard") defer span.Finish() @@ -2526,12 +2526,12 @@ func (s *VtctldServer) ReloadSchemaKeyspace(ctx context.Context, req *vtctldatap var ( wg sync.WaitGroup - sema *sync2.Semaphore + sema *semaphore.Weighted logger, getEvents = eventStreamLogger() ) if req.Concurrency > 0 { - sema = sync2.NewSemaphore(int(req.Concurrency), 0) + sema = semaphore.NewWeighted(int64(req.Concurrency)) } for _, shard := range shards { diff --git a/go/vt/vtctl/schematools/reload.go b/go/vt/vtctl/schematools/reload.go index 12734b53452..daa9ae64960 100644 --- a/go/vt/vtctl/schematools/reload.go +++ b/go/vt/vtctl/schematools/reload.go @@ -20,7 +20,8 @@ import ( "context" "sync" - "vitess.io/vitess/go/sync2" + "golang.org/x/sync/semaphore" + "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" @@ -36,7 +37,7 @@ import ( // and the periodic schema reload makes them self-healing anyway. // So we do this on a best-effort basis, and log warnings for any tablets // that fail to reload within the context deadline. -func ReloadShard(ctx context.Context, ts *topo.Server, tmc tmclient.TabletManagerClient, logger logutil.Logger, keyspace, shard, replicationPos string, concurrency *sync2.Semaphore, includePrimary bool) (isPartial bool, ok bool) { +func ReloadShard(ctx context.Context, ts *topo.Server, tmc tmclient.TabletManagerClient, logger logutil.Logger, keyspace, shard, replicationPos string, concurrency *semaphore.Weighted, includePrimary bool) (isPartial bool, ok bool) { tablets, err := ts.GetTabletMapForShard(ctx, keyspace, shard) switch { case topo.IsErrType(err, topo.PartialResult): @@ -67,8 +68,15 @@ func ReloadShard(ctx context.Context, ts *topo.Server, tmc tmclient.TabletManage defer wg.Done() if concurrency != nil { - concurrency.Acquire() - defer concurrency.Release() + if concurrency.Acquire(ctx, 1) != nil { + // We timed out waiting for the semaphore. This is best-effort, so just log it and move on. + logger.Warningf( + "Failed to reload schema on replica tablet %v in %v/%v (use vtctl ReloadSchema to try again): timed out waiting for concurrency", + topoproto.TabletAliasString(tablet.Alias), keyspace, shard, + ) + return + } + defer concurrency.Release(1) } pos := replicationPos diff --git a/go/vt/vtctl/schematools/reload_test.go b/go/vt/vtctl/schematools/reload_test.go index 5c6b624cca0..6fbc7f152be 100644 --- a/go/vt/vtctl/schematools/reload_test.go +++ b/go/vt/vtctl/schematools/reload_test.go @@ -23,8 +23,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + "golang.org/x/sync/semaphore" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo/memorytopo" "vitess.io/vitess/go/vt/topo/topoproto" @@ -338,7 +338,7 @@ func TestReloadShard(t *testing.T) { results: tt.results, } - isPartial, ok := ReloadShard(ctx, ts, tmc, logutil.NewMemoryLogger(), tt.req.Keyspace, tt.req.Shard, tt.req.Position, sync2.NewSemaphore(1, 0), tt.req.IncludePrimary) + isPartial, ok := ReloadShard(ctx, ts, tmc, logutil.NewMemoryLogger(), tt.req.Keyspace, tt.req.Shard, tt.req.Position, semaphore.NewWeighted(1), tt.req.IncludePrimary) assert.Equal(t, tt.expected.IsPartial, isPartial, "incorrect value for isPartial") assert.Equal(t, tt.expected.Ok, ok, "incorrect value for ok") diff --git a/go/vt/vtgate/autocommit_test.go b/go/vt/vtgate/autocommit_test.go index 13d01d288bf..94f0ef9b4d3 100644 --- a/go/vt/vtgate/autocommit_test.go +++ b/go/vt/vtgate/autocommit_test.go @@ -389,7 +389,7 @@ func TestAutocommitTransactionStarted(t *testing.T) { testCommitCount(t, "sbc1", sbc1, 0) sbc1.Queries = nil - sbc1.CommitCount.Set(0) + sbc1.CommitCount.Store(0) // multi shard query - savepoint needed sql = "update `user` set a = 2 where id in (1, 4)" diff --git a/go/vt/vtgate/buffer/buffer.go b/go/vt/vtgate/buffer/buffer.go index 25fe4181a4a..f9618b6e0c7 100644 --- a/go/vt/vtgate/buffer/buffer.go +++ b/go/vt/vtgate/buffer/buffer.go @@ -31,7 +31,8 @@ import ( "fmt" "sync" - "vitess.io/vitess/go/sync2" + "golang.org/x/sync/semaphore" + "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/log" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -87,7 +88,8 @@ type Buffer struct { // bufferSizeSema limits how many requests can be buffered // ("-buffer_size") and is shared by all shardBuffer instances. - bufferSizeSema *sync2.Semaphore + bufferSizeSema *semaphore.Weighted + bufferSize int // mu guards all fields in this group. // In particular, it is used to serialize the following Go routines: @@ -108,7 +110,8 @@ type Buffer struct { func New(cfg *Config) *Buffer { return &Buffer{ config: cfg, - bufferSizeSema: sync2.NewSemaphore(cfg.Size, 0), + bufferSizeSema: semaphore.NewWeighted(int64(cfg.Size)), + bufferSize: cfg.Size, buffers: make(map[string]*shardBuffer), } } diff --git a/go/vt/vtgate/buffer/buffer_helper_test.go b/go/vt/vtgate/buffer/buffer_helper_test.go index 442e78d08f7..a6b7605d4da 100644 --- a/go/vt/vtgate/buffer/buffer_helper_test.go +++ b/go/vt/vtgate/buffer/buffer_helper_test.go @@ -121,7 +121,7 @@ func waitForState(b *Buffer, want bufferState) error { func waitForPoolSlots(b *Buffer, want int) error { start := time.Now() for { - got := b.bufferSizeSema.Size() + got := b.bufferSize if got == want { return nil } diff --git a/go/vt/vtgate/buffer/shard_buffer.go b/go/vt/vtgate/buffer/shard_buffer.go index b1f8c4538ec..1b829cb3ddd 100644 --- a/go/vt/vtgate/buffer/shard_buffer.go +++ b/go/vt/vtgate/buffer/shard_buffer.go @@ -307,7 +307,7 @@ func (sb *shardBuffer) logErrorIfStateNotLocked(state bufferState) { // give up their spot in the buffer. It also holds the "bufferCancel" function. // If buffering fails e.g. due to a full buffer, an error is returned. func (sb *shardBuffer) bufferRequestLocked(ctx context.Context) (*entry, error) { - if !sb.buf.bufferSizeSema.TryAcquire() { + if !sb.buf.bufferSizeSema.TryAcquire(1) { // Buffer is full. Evict the oldest entry and buffer this request instead. if len(sb.queue) == 0 { // Overall buffer is full, but this shard's queue is empty. That means @@ -384,7 +384,7 @@ func (sb *shardBuffer) waitForRequestFinish(e *entry, releaseSlot, async bool) { // the buffer full eviction or the timeout thread does not block on us. // This way, the request's slot can only be reused after the request finished. if releaseSlot { - sb.buf.bufferSizeSema.Release() + sb.buf.bufferSizeSema.Release(1) } } diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index 8558eed1ed5..6327b72acab 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -28,6 +28,7 @@ import ( "net/http" "strings" "sync" + "sync/atomic" "time" "github.com/spf13/pflag" @@ -38,7 +39,6 @@ import ( "vitess.io/vitess/go/mysql/collations" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/trace" "vitess.io/vitess/go/vt/callerid" "vitess.io/vitess/go/vt/key" @@ -256,7 +256,7 @@ func (e *Executor) StreamExecute( var err error resultHandler := func(ctx context.Context, plan *engine.Plan, vc *vcursorImpl, bindVars map[string]*querypb.BindVariable, execStart time.Time) error { - var seenResults sync2.AtomicBool + var seenResults atomic.Bool var resultMu sync.Mutex result := &sqltypes.Result{} if canReturnRows(plan.Type) { @@ -271,7 +271,7 @@ func (e *Executor) StreamExecute( if err := callback(qr.Metadata()); err != nil { return err } - seenResults.Set(true) + seenResults.Store(true) } for _, row := range qr.Rows { @@ -283,7 +283,7 @@ func (e *Executor) StreamExecute( if byteCount >= e.streamSize { err := callback(result) - seenResults.Set(true) + seenResults.Store(true) result = &sqltypes.Result{} byteCount = 0 if err != nil { @@ -313,7 +313,7 @@ func (e *Executor) StreamExecute( } // Send left-over rows if there is no error on execution. - if len(result.Rows) > 0 || !seenResults.Get() { + if len(result.Rows) > 0 || !seenResults.Load() { if err := callback(result); err != nil { return err } diff --git a/go/vt/vtgate/executor_dml_test.go b/go/vt/vtgate/executor_dml_test.go index b73cf1fab16..8a61c0e80d3 100644 --- a/go/vt/vtgate/executor_dml_test.go +++ b/go/vt/vtgate/executor_dml_test.go @@ -2582,7 +2582,7 @@ func TestStreamingDML(t *testing.T) { // match the query received on tablet assertQueries(t, sbc, tcase.expQuery) - assert.EqualValues(t, tcase.commitCount, sbc.CommitCount.Get()) + assert.EqualValues(t, tcase.commitCount, sbc.CommitCount.Load()) } } diff --git a/go/vt/vtgate/executor_framework_test.go b/go/vt/vtgate/executor_framework_test.go index fe26e20a4c4..7b87528afef 100644 --- a/go/vt/vtgate/executor_framework_test.go +++ b/go/vt/vtgate/executor_framework_test.go @@ -315,7 +315,7 @@ func assertQueriesWithSavepoint(t *testing.T, sbc *sandboxconn.SandboxConn, want func testCommitCount(t *testing.T, sbcName string, sbc *sandboxconn.SandboxConn, want int) { t.Helper() - if got, want := sbc.CommitCount.Get(), int64(want); got != want { + if got, want := sbc.CommitCount.Load(), int64(want); got != want { t.Errorf("%s.CommitCount: %d, want %d\n", sbcName, got, want) } } diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go index ff028bd892c..5c105e23e5a 100644 --- a/go/vt/vtgate/executor_select_test.go +++ b/go/vt/vtgate/executor_select_test.go @@ -65,8 +65,8 @@ func TestSelectNext(t *testing.T) { require.NoError(t, err) utils.MustMatch(t, wantQueries, sbclookup.Queries) - assert.Zero(t, sbclookup.BeginCount.Get()) - assert.Zero(t, sbclookup.ReserveCount.Get()) + assert.Zero(t, sbclookup.BeginCount.Load()) + assert.Zero(t, sbclookup.ReserveCount.Load()) sbclookup.Queries = nil // Txn @@ -76,8 +76,8 @@ func TestSelectNext(t *testing.T) { require.NoError(t, err) utils.MustMatch(t, wantQueries, sbclookup.Queries) - assert.Zero(t, sbclookup.BeginCount.Get()) - assert.Zero(t, sbclookup.ReserveCount.Get()) + assert.Zero(t, sbclookup.BeginCount.Load()) + assert.Zero(t, sbclookup.ReserveCount.Load()) sbclookup.Queries = nil // Reserve @@ -87,8 +87,8 @@ func TestSelectNext(t *testing.T) { require.NoError(t, err) utils.MustMatch(t, wantQueries, sbclookup.Queries) - assert.Zero(t, sbclookup.BeginCount.Get()) - assert.Zero(t, sbclookup.ReserveCount.Get()) + assert.Zero(t, sbclookup.BeginCount.Load()) + assert.Zero(t, sbclookup.ReserveCount.Load()) sbclookup.Queries = nil // Reserve and Txn @@ -99,8 +99,8 @@ func TestSelectNext(t *testing.T) { require.NoError(t, err) utils.MustMatch(t, wantQueries, sbclookup.Queries) - assert.Zero(t, sbclookup.BeginCount.Get()) - assert.Zero(t, sbclookup.ReserveCount.Get()) + assert.Zero(t, sbclookup.BeginCount.Load()) + assert.Zero(t, sbclookup.ReserveCount.Load()) } func TestSelectDBA(t *testing.T) { @@ -1178,7 +1178,7 @@ func TestSelectEqual(t *testing.T) { BindVariables: map[string]*querypb.BindVariable{}, }} utils.MustMatch(t, wantQueries, sbc2.Queries) - if execCount := sbc1.ExecCount.Get(); execCount != 1 { + if execCount := sbc1.ExecCount.Load(); execCount != 1 { t.Errorf("sbc1.ExecCount: %v, want 1\n", execCount) } if sbc1.Queries != nil { @@ -1193,7 +1193,7 @@ func TestSelectEqual(t *testing.T) { BindVariables: map[string]*querypb.BindVariable{}, }} utils.MustMatch(t, wantQueries, sbc2.Queries) - if execCount := sbc1.ExecCount.Get(); execCount != 1 { + if execCount := sbc1.ExecCount.Load(); execCount != 1 { t.Errorf("sbc1.ExecCount: %v, want 1\n", execCount) } if sbc1.Queries != nil { diff --git a/go/vt/vtgate/executor_set_test.go b/go/vt/vtgate/executor_set_test.go index c806d10dd5d..52f12354bc9 100644 --- a/go/vt/vtgate/executor_set_test.go +++ b/go/vt/vtgate/executor_set_test.go @@ -603,7 +603,7 @@ func TestExecutorSetAndSelect(t *testing.T) { session := NewAutocommitSession(&vtgatepb.Session{TargetString: KsTestUnsharded, EnableSystemSettings: true}) for _, tcase := range testcases { t.Run(fmt.Sprintf("%s-%s", tcase.sysVar, tcase.val), func(t *testing.T) { - sbc.ExecCount.Set(0) // reset the value + sbc.ExecCount.Store(0) // reset the value if tcase.val != "" { // check query result for `select from dual where @@transaction_isolation != diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index bf5bb68c673..388f84d8c91 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -130,7 +130,7 @@ func TestExecutorTransactionsNoAutoCommit(t *testing.T) { require.NoError(t, err) wantSession := &vtgatepb.Session{InTransaction: true, TargetString: "@primary", SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") - assert.EqualValues(t, 0, sbclookup.CommitCount.Get(), "commit count") + assert.EqualValues(t, 0, sbclookup.CommitCount.Load(), "commit count") logStats := testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) assert.EqualValues(t, 0, logStats.CommitTime, "logstats: expected zero CommitTime") assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") @@ -150,7 +150,7 @@ func TestExecutorTransactionsNoAutoCommit(t *testing.T) { if !proto.Equal(session.Session, wantSession) { t.Errorf("begin: %v, want %v", session.Session, wantSession) } - if commitCount := sbclookup.CommitCount.Get(); commitCount != 1 { + if commitCount := sbclookup.CommitCount.Load(); commitCount != 1 { t.Errorf("want 1, got %d", commitCount) } logStats = testQueryLog(t, logChan, "TestExecute", "COMMIT", "commit", 1) @@ -168,7 +168,7 @@ func TestExecutorTransactionsNoAutoCommit(t *testing.T) { require.NoError(t, err) wantSession = &vtgatepb.Session{TargetString: "@primary", SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") - assert.EqualValues(t, 1, sbclookup.RollbackCount.Get(), "rollback count") + assert.EqualValues(t, 1, sbclookup.RollbackCount.Load(), "rollback count") _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) _ = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) logStats = testQueryLog(t, logChan, "TestExecute", "ROLLBACK", "rollback", 1) @@ -222,7 +222,7 @@ func TestExecutorTransactionsAutoCommit(t *testing.T) { require.NoError(t, err) wantSession := &vtgatepb.Session{InTransaction: true, TargetString: "@primary", Autocommit: true, SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") - if commitCount := sbclookup.CommitCount.Get(); commitCount != 0 { + if commitCount := sbclookup.CommitCount.Load(); commitCount != 0 { t.Errorf("want 0, got %d", commitCount) } logStats := testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) @@ -235,7 +235,7 @@ func TestExecutorTransactionsAutoCommit(t *testing.T) { require.NoError(t, err) wantSession = &vtgatepb.Session{TargetString: "@primary", Autocommit: true, SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") - assert.EqualValues(t, 1, sbclookup.CommitCount.Get()) + assert.EqualValues(t, 1, sbclookup.CommitCount.Load()) logStats = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) assert.EqualValues(t, 0, logStats.CommitTime) @@ -253,7 +253,7 @@ func TestExecutorTransactionsAutoCommit(t *testing.T) { require.NoError(t, err) wantSession = &vtgatepb.Session{TargetString: "@primary", Autocommit: true, SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") - if rollbackCount := sbclookup.RollbackCount.Get(); rollbackCount != 1 { + if rollbackCount := sbclookup.RollbackCount.Load(); rollbackCount != 1 { t.Errorf("want 1, got %d", rollbackCount) } _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) @@ -295,7 +295,7 @@ func TestExecutorTransactionsAutoCommitStreaming(t *testing.T) { SessionUUID: "suuid", } utils.MustMatch(t, wantSession, session.Session, "session") - assert.Zero(t, sbclookup.CommitCount.Get()) + assert.Zero(t, sbclookup.CommitCount.Load()) logStats := testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") @@ -306,7 +306,7 @@ func TestExecutorTransactionsAutoCommitStreaming(t *testing.T) { require.NoError(t, err) wantSession = &vtgatepb.Session{TargetString: "@primary", Autocommit: true, Options: oltpOptions, SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") - assert.EqualValues(t, 1, sbclookup.CommitCount.Get()) + assert.EqualValues(t, 1, sbclookup.CommitCount.Load()) logStats = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) assert.EqualValues(t, 0, logStats.CommitTime) @@ -324,7 +324,7 @@ func TestExecutorTransactionsAutoCommitStreaming(t *testing.T) { require.NoError(t, err) wantSession = &vtgatepb.Session{TargetString: "@primary", Autocommit: true, Options: oltpOptions, SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") - assert.EqualValues(t, 1, sbclookup.RollbackCount.Get()) + assert.EqualValues(t, 1, sbclookup.RollbackCount.Load()) } func TestExecutorDeleteMetadata(t *testing.T) { @@ -367,7 +367,7 @@ func TestExecutorAutocommit(t *testing.T) { defer QueryLogger.Unsubscribe(logChan) // autocommit = 0 - startCount := sbclookup.CommitCount.Get() + startCount := sbclookup.CommitCount.Load() _, err := executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) require.NoError(t, err) wantSession := &vtgatepb.Session{TargetString: "@primary", InTransaction: true, FoundRows: 1, RowCount: -1} @@ -389,7 +389,7 @@ func TestExecutorAutocommit(t *testing.T) { _ = testQueryLog(t, logChan, "TestExecute", "SET", "set @@autocommit = 1", 0) // Setting autocommit=1 commits existing transaction. - if got, want := sbclookup.CommitCount.Get(), startCount+1; got != want { + if got, want := sbclookup.CommitCount.Load(), startCount+1; got != want { t.Errorf("Commit count: %d, want %d", got, want) } @@ -404,7 +404,7 @@ func TestExecutorAutocommit(t *testing.T) { // autocommit = 1, "begin" session.ResetTx() - startCount = sbclookup.CommitCount.Get() + startCount = sbclookup.CommitCount.Load() _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) require.NoError(t, err) _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) @@ -415,7 +415,7 @@ func TestExecutorAutocommit(t *testing.T) { testSession = proto.Clone(session.Session).(*vtgatepb.Session) testSession.ShardSessions = nil utils.MustMatch(t, wantSession, testSession, "session does not match for autocommit=1") - if got, want := sbclookup.CommitCount.Get(), startCount; got != want { + if got, want := sbclookup.CommitCount.Load(), startCount; got != want { t.Errorf("Commit count: %d, want %d", got, want) } @@ -433,19 +433,19 @@ func TestExecutorAutocommit(t *testing.T) { if !proto.Equal(session.Session, wantSession) { t.Errorf("autocommit=1: %v, want %v", session.Session, wantSession) } - if got, want := sbclookup.CommitCount.Get(), startCount+1; got != want { + if got, want := sbclookup.CommitCount.Load(), startCount+1; got != want { t.Errorf("Commit count: %d, want %d", got, want) } _ = testQueryLog(t, logChan, "TestExecute", "COMMIT", "commit", 1) // transition autocommit from 0 to 1 in the middle of a transaction. - startCount = sbclookup.CommitCount.Get() + startCount = sbclookup.CommitCount.Load() session = NewSafeSession(&vtgatepb.Session{TargetString: "@primary"}) _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) require.NoError(t, err) _, err = executor.Execute(ctx, "TestExecute", session, "update main1 set id=1", nil) require.NoError(t, err) - if got, want := sbclookup.CommitCount.Get(), startCount; got != want { + if got, want := sbclookup.CommitCount.Load(), startCount; got != want { t.Errorf("Commit count: %d, want %d", got, want) } _, err = executor.Execute(ctx, "TestExecute", session, "set autocommit=1", nil) @@ -454,7 +454,7 @@ func TestExecutorAutocommit(t *testing.T) { if !proto.Equal(session.Session, wantSession) { t.Errorf("autocommit=1: %v, want %v", session.Session, wantSession) } - if got, want := sbclookup.CommitCount.Get(), startCount+1; got != want { + if got, want := sbclookup.CommitCount.Load(), startCount+1; got != want { t.Errorf("Commit count: %d, want %d", got, want) } } @@ -1208,9 +1208,9 @@ func TestExecutorOther(t *testing.T) { for _, stmt := range stmts { for _, tc := range tcs { t.Run(fmt.Sprintf("%s-%s", stmt, tc.targetStr), func(t *testing.T) { - sbc1.ExecCount.Set(0) - sbc2.ExecCount.Set(0) - sbclookup.ExecCount.Set(0) + sbc1.ExecCount.Store(0) + sbc2.ExecCount.Store(0) + sbclookup.ExecCount.Store(0) _, err := executor.Execute(ctx, "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: tc.targetStr}), stmt, nil) if tc.hasNoKeyspaceErr { @@ -1222,9 +1222,9 @@ func TestExecutorOther(t *testing.T) { } utils.MustMatch(t, tc.wantCnts, cnts{ - Sbc1Cnt: sbc1.ExecCount.Get(), - Sbc2Cnt: sbc2.ExecCount.Get(), - SbcLookupCnt: sbclookup.ExecCount.Get(), + Sbc1Cnt: sbc1.ExecCount.Load(), + Sbc2Cnt: sbc2.ExecCount.Load(), + SbcLookupCnt: sbclookup.ExecCount.Load(), }) }) } @@ -1302,9 +1302,9 @@ func TestExecutorDDL(t *testing.T) { for _, stmt := range stmts { for _, tc := range tcs { - sbc1.ExecCount.Set(0) - sbc2.ExecCount.Set(0) - sbclookup.ExecCount.Set(0) + sbc1.ExecCount.Store(0) + sbc2.ExecCount.Store(0) + sbclookup.ExecCount.Store(0) stmtType := "DDL" _, err := executor.Execute(ctx, "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: tc.targetStr}), stmt, nil) if tc.hasNoKeyspaceErr { @@ -1315,9 +1315,9 @@ func TestExecutorDDL(t *testing.T) { } diff := cmp.Diff(tc.wantCnts, cnts{ - Sbc1Cnt: sbc1.ExecCount.Get(), - Sbc2Cnt: sbc2.ExecCount.Get(), - SbcLookupCnt: sbclookup.ExecCount.Get(), + Sbc1Cnt: sbc1.ExecCount.Load(), + Sbc2Cnt: sbc2.ExecCount.Load(), + SbcLookupCnt: sbclookup.ExecCount.Load(), }) if diff != "" { t.Errorf("stmt: %s\ntc: %+v\n-want,+got:\n%s", stmt, tc, diff) @@ -1341,9 +1341,9 @@ func TestExecutorDDL(t *testing.T) { } for _, stmt := range stmts2 { - sbc1.ExecCount.Set(0) - sbc2.ExecCount.Set(0) - sbclookup.ExecCount.Set(0) + sbc1.ExecCount.Store(0) + sbc2.ExecCount.Store(0) + sbclookup.ExecCount.Store(0) _, err := executor.Execute(ctx, "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: ""}), stmt.input, nil) if stmt.hasErr { require.EqualError(t, err, errNoKeyspace.Error(), "expect query to fail") @@ -1367,12 +1367,12 @@ func TestExecutorDDLFk(t *testing.T) { for _, stmt := range stmts { for _, fkMode := range []string{"allow", "disallow"} { t.Run(stmt+fkMode, func(t *testing.T) { - sbc.ExecCount.Set(0) + sbc.ExecCount.Store(0) foreignKeyMode = fkMode _, err := executor.Execute(ctx, mName, NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded}), stmt, nil) if fkMode == "allow" { require.NoError(t, err) - require.EqualValues(t, 1, sbc.ExecCount.Get()) + require.EqualValues(t, 1, sbc.ExecCount.Load()) } else { require.Error(t, err) require.Contains(t, err.Error(), "foreign key constraints are not allowed") @@ -1473,9 +1473,9 @@ func TestExecutorCreateVindexDDL(t *testing.T) { // No queries should have gone to any tablets wantCount := []int64{0, 0, 0} gotCount := []int64{ - sbc1.ExecCount.Get(), - sbc2.ExecCount.Get(), - sbclookup.ExecCount.Get(), + sbc1.ExecCount.Load(), + sbc2.ExecCount.Load(), + sbclookup.ExecCount.Load(), } require.Equal(t, wantCount, gotCount) } @@ -1525,9 +1525,9 @@ func TestExecutorAddDropVschemaTableDDL(t *testing.T) { // No queries should have gone to any tablets wantCount := []int64{0, 0, 0} gotCount := []int64{ - sbc1.ExecCount.Get(), - sbc2.ExecCount.Get(), - sbclookup.ExecCount.Get(), + sbc1.ExecCount.Load(), + sbc2.ExecCount.Load(), + sbclookup.ExecCount.Load(), } utils.MustMatch(t, wantCount, gotCount, "") } @@ -2080,9 +2080,9 @@ func TestExecutorOtherRead(t *testing.T) { for _, stmt := range stmts { for _, tc := range tcs { t.Run(stmt+tc.targetStr, func(t *testing.T) { - sbc1.ExecCount.Set(0) - sbc2.ExecCount.Set(0) - sbclookup.ExecCount.Set(0) + sbc1.ExecCount.Store(0) + sbc2.ExecCount.Store(0) + sbclookup.ExecCount.Store(0) _, err := executor.Execute(context.Background(), "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: tc.targetStr}), stmt, nil) if tc.hasNoKeyspaceErr { @@ -2094,9 +2094,9 @@ func TestExecutorOtherRead(t *testing.T) { } utils.MustMatch(t, tc.wantCnts, cnts{ - Sbc1Cnt: sbc1.ExecCount.Get(), - Sbc2Cnt: sbc2.ExecCount.Get(), - SbcLookupCnt: sbclookup.ExecCount.Get(), + Sbc1Cnt: sbc1.ExecCount.Load(), + Sbc2Cnt: sbc2.ExecCount.Load(), + SbcLookupCnt: sbclookup.ExecCount.Load(), }, "count did not match") }) } @@ -2172,9 +2172,9 @@ func TestExecutorOtherAdmin(t *testing.T) { for _, stmt := range stmts { for _, tc := range tcs { - sbc1.ExecCount.Set(0) - sbc2.ExecCount.Set(0) - sbclookup.ExecCount.Set(0) + sbc1.ExecCount.Store(0) + sbc2.ExecCount.Store(0) + sbclookup.ExecCount.Store(0) _, err := executor.Execute(context.Background(), "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: tc.targetStr}), stmt, nil) if tc.hasNoKeyspaceErr { @@ -2186,9 +2186,9 @@ func TestExecutorOtherAdmin(t *testing.T) { } diff := cmp.Diff(tc.wantCnts, cnts{ - Sbc1Cnt: sbc1.ExecCount.Get(), - Sbc2Cnt: sbc2.ExecCount.Get(), - SbcLookupCnt: sbclookup.ExecCount.Get(), + Sbc1Cnt: sbc1.ExecCount.Load(), + Sbc2Cnt: sbc2.ExecCount.Load(), + SbcLookupCnt: sbclookup.ExecCount.Load(), }) if diff != "" { t.Errorf("stmt: %s\ntc: %+v\n-want,+got:\n%s", stmt, tc, diff) @@ -2431,9 +2431,9 @@ func TestExecutorCallProc(t *testing.T) { for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { - sbc1.ExecCount.Set(0) - sbc2.ExecCount.Set(0) - sbcUnsharded.ExecCount.Set(0) + sbc1.ExecCount.Store(0) + sbc2.ExecCount.Store(0) + sbcUnsharded.ExecCount.Store(0) _, err := executor.Execute(context.Background(), "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: tc.targetStr}), "CALL proc()", nil) if tc.hasNoKeyspaceErr { @@ -2445,9 +2445,9 @@ func TestExecutorCallProc(t *testing.T) { } utils.MustMatch(t, tc.wantCnts, cnts{ - Sbc1Cnt: sbc1.ExecCount.Get(), - Sbc2Cnt: sbc2.ExecCount.Get(), - SbcUnsharded: sbcUnsharded.ExecCount.Get(), + Sbc1Cnt: sbc1.ExecCount.Load(), + Sbc2Cnt: sbc2.ExecCount.Load(), + SbcUnsharded: sbcUnsharded.ExecCount.Load(), }, "count did not match") }) } @@ -2461,7 +2461,7 @@ func TestExecutorTempTable(t *testing.T) { ctx := context.Background() _, err := executor.Execute(ctx, "TestExecutorTempTable", session, creatQuery, nil) require.NoError(t, err) - assert.EqualValues(t, 1, sbcUnsharded.ExecCount.Get()) + assert.EqualValues(t, 1, sbcUnsharded.ExecCount.Load()) assert.NotEmpty(t, session.Warnings) before := executor.plans.Len() diff --git a/go/vt/vtgate/executor_vschema_ddl_test.go b/go/vt/vtgate/executor_vschema_ddl_test.go index 8e3e6d9f84d..d5da6858c5a 100644 --- a/go/vt/vtgate/executor_vschema_ddl_test.go +++ b/go/vt/vtgate/executor_vschema_ddl_test.go @@ -318,9 +318,9 @@ func TestPlanExecutorAddDropVschemaTableDDL(t *testing.T) { // No queries should have gone to any tablets wantCount := []int64{0, 0, 0} gotCount := []int64{ - sbc1.ExecCount.Get(), - sbc2.ExecCount.Get(), - sbclookup.ExecCount.Get(), + sbc1.ExecCount.Load(), + sbc2.ExecCount.Load(), + sbclookup.ExecCount.Load(), } if !reflect.DeepEqual(gotCount, wantCount) { t.Errorf("Exec %s: %v, want %v", stmt, gotCount, wantCount) @@ -614,9 +614,9 @@ func TestExecutorAddDropVindexDDL(t *testing.T) { // no queries should have gone to any tablets wantCount := []int64{0, 0, 0} gotCount := []int64{ - sbc1.ExecCount.Get(), - sbc2.ExecCount.Get(), - sbclookup.ExecCount.Get(), + sbc1.ExecCount.Load(), + sbc2.ExecCount.Load(), + sbclookup.ExecCount.Load(), } utils.MustMatch(t, wantCount, gotCount) } diff --git a/go/vt/vtgate/legacy_scatter_conn_test.go b/go/vt/vtgate/legacy_scatter_conn_test.go index 7cbdab3af69..601b07f94c6 100644 --- a/go/vt/vtgate/legacy_scatter_conn_test.go +++ b/go/vt/vtgate/legacy_scatter_conn_test.go @@ -177,7 +177,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s t.Errorf("want %s, got %v", want, err) } // Ensure that we tried only once. - if execCount := sbc.ExecCount.Get(); execCount != 1 { + if execCount := sbc.ExecCount.Load(); execCount != 1 { t.Errorf("want 1, got %v", execCount) } @@ -194,10 +194,10 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s want = fmt.Sprintf("target: %v.0.replica: INVALID_ARGUMENT error\ntarget: %v.1.replica: INVALID_ARGUMENT error", name, name) verifyScatterConnError(t, err, want, vtrpcpb.Code_INVALID_ARGUMENT) // Ensure that we tried only once. - if execCount := sbc0.ExecCount.Get(); execCount != 1 { + if execCount := sbc0.ExecCount.Load(); execCount != 1 { t.Errorf("want 1, got %v", execCount) } - if execCount := sbc1.ExecCount.Get(); execCount != 1 { + if execCount := sbc1.ExecCount.Load(); execCount != 1 { t.Errorf("want 1, got %v", execCount) } @@ -215,10 +215,10 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s // We should only surface the higher priority error code verifyScatterConnError(t, err, want, vtrpcpb.Code_INVALID_ARGUMENT) // Ensure that we tried only once. - if execCount := sbc0.ExecCount.Get(); execCount != 1 { + if execCount := sbc0.ExecCount.Load(); execCount != 1 { t.Errorf("want 1, got %v", execCount) } - if execCount := sbc1.ExecCount.Get(); execCount != 1 { + if execCount := sbc1.ExecCount.Load(); execCount != 1 { t.Errorf("want 1, got %v", execCount) } @@ -229,7 +229,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s sbc = hc.AddTestTablet("aa", "0", 1, name, "0", topodatapb.TabletType_REPLICA, true, 1, nil) _, _ = f(sc, []string{"0", "0"}) // Ensure that we executed only once. - if execCount := sbc.ExecCount.Get(); execCount != 1 { + if execCount := sbc.ExecCount.Load(); execCount != 1 { t.Errorf("want 1, got %v", execCount) } @@ -243,10 +243,10 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s if err != nil { t.Fatalf("want nil, got %v", err) } - if execCount := sbc0.ExecCount.Get(); execCount != 1 { + if execCount := sbc0.ExecCount.Load(); execCount != 1 { t.Errorf("want 1, got %v", execCount) } - if execCount := sbc1.ExecCount.Get(); execCount != 1 { + if execCount := sbc1.ExecCount.Load(); execCount != 1 { t.Errorf("want 1, got %v", execCount) } if qr.RowsAffected != 0 { diff --git a/go/vt/vtgate/plugin_mysql_server.go b/go/vt/vtgate/plugin_mysql_server.go index 4a6f45ce629..1dbd9074485 100644 --- a/go/vt/vtgate/plugin_mysql_server.go +++ b/go/vt/vtgate/plugin_mysql_server.go @@ -484,11 +484,11 @@ func initMySQLProtocol() { _ = initTLSConfig(mysqlListener, mysqlSslCert, mysqlSslKey, mysqlSslCa, mysqlSslCrl, mysqlSslServerCA, mysqlServerRequireSecureTransport, tlsVersion) } - mysqlListener.AllowClearTextWithoutTLS.Set(mysqlAllowClearTextWithoutTLS) + mysqlListener.AllowClearTextWithoutTLS.Store(mysqlAllowClearTextWithoutTLS) // Check for the connection threshold if mysqlSlowConnectWarnThreshold != 0 { log.Infof("setting mysql slow connection threshold to %v", mysqlSlowConnectWarnThreshold) - mysqlListener.SlowConnectWarnThreshold.Set(mysqlSlowConnectWarnThreshold) + mysqlListener.SlowConnectWarnThreshold.Store(mysqlSlowConnectWarnThreshold.Nanoseconds()) } // Start listening for tcp go mysqlListener.Accept() diff --git a/go/vt/vtgate/scatter_conn_test.go b/go/vt/vtgate/scatter_conn_test.go index 5129079435a..7fe751c9a00 100644 --- a/go/vt/vtgate/scatter_conn_test.go +++ b/go/vt/vtgate/scatter_conn_test.go @@ -123,8 +123,8 @@ func TestReservedOnMultiReplica(t *testing.T) { destinations := []key.Destination{key.DestinationShard("0")} for i := 0; i < 10; i++ { executeOnShards(t, res, keyspace, sc, session, destinations) - assert.EqualValues(t, 1, sbc0_1.ReserveCount.Get()+sbc0_2.ReserveCount.Get(), "sbc0 reserve count") - assert.EqualValues(t, 0, sbc0_1.BeginCount.Get()+sbc0_2.BeginCount.Get(), "sbc0 begin count") + assert.EqualValues(t, 1, sbc0_1.ReserveCount.Load()+sbc0_2.ReserveCount.Load(), "sbc0 reserve count") + assert.EqualValues(t, 0, sbc0_1.BeginCount.Load()+sbc0_2.BeginCount.Load(), "sbc0 begin count") } } @@ -273,14 +273,14 @@ func TestReservedBeginTableDriven(t *testing.T) { destinations = append(destinations, key.DestinationShard(shard)) } executeOnShards(t, res, keyspace, sc, session, destinations) - assert.EqualValues(t, action.sbc0Reserve, sbc0.ReserveCount.Get(), "sbc0 reserve count") - assert.EqualValues(t, action.sbc0Begin, sbc0.BeginCount.Get(), "sbc0 begin count") - assert.EqualValues(t, action.sbc1Reserve, sbc1.ReserveCount.Get(), "sbc1 reserve count") - assert.EqualValues(t, action.sbc1Begin, sbc1.BeginCount.Get(), "sbc1 begin count") - sbc0.BeginCount.Set(0) - sbc0.ReserveCount.Set(0) - sbc1.BeginCount.Set(0) - sbc1.ReserveCount.Set(0) + assert.EqualValues(t, action.sbc0Reserve, sbc0.ReserveCount.Load(), "sbc0 reserve count") + assert.EqualValues(t, action.sbc0Begin, sbc0.BeginCount.Load(), "sbc0 begin count") + assert.EqualValues(t, action.sbc1Reserve, sbc1.ReserveCount.Load(), "sbc1 reserve count") + assert.EqualValues(t, action.sbc1Begin, sbc1.BeginCount.Load(), "sbc1 begin count") + sbc0.BeginCount.Store(0) + sbc0.ReserveCount.Store(0) + sbc1.BeginCount.Store(0) + sbc1.ReserveCount.Store(0) } }) } @@ -363,9 +363,9 @@ func TestReservedConnFail(t *testing.T) { sbc0Rep := hc.AddTestTablet("aa", "0", 2, keyspace, "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc0.Queries = nil - sbc0.ExecCount.Set(0) + sbc0.ExecCount.Store(0) _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) - assert.EqualValues(t, 1, sbc0.ExecCount.Get(), "first attempt should be made on original tablet") + assert.EqualValues(t, 1, sbc0.ExecCount.Load(), "first attempt should be made on original tablet") assert.EqualValues(t, 0, len(sbc0.Queries), "no query should be executed on it") assert.Equal(t, 1, len(sbc0Rep.Queries), "this attempt on new healthy tablet should pass") require.Equal(t, 1, len(session.ShardSessions)) @@ -390,12 +390,12 @@ func TestReservedConnFail(t *testing.T) { sbc0Rep.Tablet().Type = topodatapb.TabletType_SPARE sbc0Th.Serving = true sbc0.NotServing = false - sbc0.ExecCount.Set(0) + sbc0.ExecCount.Store(0) sbc0Rep.Queries = nil - sbc0Rep.ExecCount.Set(0) + sbc0Rep.ExecCount.Store(0) _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) - assert.EqualValues(t, 1, sbc0Rep.ExecCount.Get(), "first attempt should be made on the changed tablet type") + assert.EqualValues(t, 1, sbc0Rep.ExecCount.Load(), "first attempt should be made on the changed tablet type") assert.EqualValues(t, 0, len(sbc0Rep.Queries), "no query should be executed on it") assert.Equal(t, 1, len(sbc0.Queries), "this attempt should pass as it is on new healthy tablet and matches the target") require.Equal(t, 1, len(session.ShardSessions)) diff --git a/go/vt/vtgate/schema/tracker_test.go b/go/vt/vtgate/schema/tracker_test.go index 11cbaffab5b..b719c40a727 100644 --- a/go/vt/vtgate/schema/tracker_test.go +++ b/go/vt/vtgate/schema/tracker_test.go @@ -380,7 +380,7 @@ func TestViewsTracking(t *testing.T) { } require.False(t, waitTimeout(&wg, time.Second), "schema was updated but received no signal") - require.EqualValues(t, count+1, sbc.GetSchemaCount.Get()) + require.EqualValues(t, count+1, sbc.GetSchemaCount.Load()) _, keyspacePresent := tracker.tracked[target.Keyspace] require.Equal(t, true, keyspacePresent) diff --git a/go/vt/vtgate/tx_conn_test.go b/go/vt/vtgate/tx_conn_test.go index 4f86e266b8d..f7dff51accd 100644 --- a/go/vt/vtgate/tx_conn_test.go +++ b/go/vt/vtgate/tx_conn_test.go @@ -59,7 +59,7 @@ func TestTxConnBegin(t *testing.T) { require.NoError(t, sc.txConn.Begin(ctx, safeSession, nil)) utils.MustMatch(t, &wantSession, session, "Session") - assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc0.CommitCount.Load(), "sbc0.CommitCount") } func TestTxConnCommitFailure(t *testing.T) { @@ -115,8 +115,8 @@ func TestTxConnCommitFailure(t *testing.T) { require.ErrorContains(t, sc.txConn.Commit(ctx, session), expectErr.Error()) wantSession = vtgatepb.Session{} utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") - assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") + assert.EqualValues(t, 1, sbc0.CommitCount.Load(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Load(), "sbc1.CommitCount") } func TestTxConnCommitSuccess(t *testing.T) { @@ -166,8 +166,8 @@ func TestTxConnCommitSuccess(t *testing.T) { sc.txConn.Commit(ctx, session)) wantSession = vtgatepb.Session{} utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") - assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") + assert.EqualValues(t, 1, sbc0.CommitCount.Load(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Load(), "sbc1.CommitCount") } func TestTxConnReservedCommitSuccess(t *testing.T) { @@ -241,15 +241,15 @@ func TestTxConnReservedCommitSuccess(t *testing.T) { }}, } utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") - assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") + assert.EqualValues(t, 1, sbc0.CommitCount.Load(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Load(), "sbc1.CommitCount") require.NoError(t, sc.txConn.Release(ctx, session)) wantSession = vtgatepb.Session{InReservedConn: true} utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.ReleaseCount.Get(), "sbc0.ReleaseCount") - assert.EqualValues(t, 1, sbc1.ReleaseCount.Get(), "sbc1.ReleaseCount") + assert.EqualValues(t, 1, sbc0.ReleaseCount.Load(), "sbc0.ReleaseCount") + assert.EqualValues(t, 1, sbc1.ReleaseCount.Load(), "sbc1.ReleaseCount") } func TestTxConnReservedOn2ShardTxOn1ShardAndCommit(t *testing.T) { @@ -341,8 +341,8 @@ func TestTxConnReservedOn2ShardTxOn1ShardAndCommit(t *testing.T) { }}, } utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") - assert.EqualValues(t, 0, sbc1.CommitCount.Get(), "sbc1.CommitCount") + assert.EqualValues(t, 1, sbc0.CommitCount.Load(), "sbc0.CommitCount") + assert.EqualValues(t, 0, sbc1.CommitCount.Load(), "sbc1.CommitCount") } func TestTxConnReservedOn2ShardTxOn1ShardAndRollback(t *testing.T) { @@ -434,8 +434,8 @@ func TestTxConnReservedOn2ShardTxOn1ShardAndRollback(t *testing.T) { }}, } utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.RollbackCount.Get(), "sbc0.RollbackCount") - assert.EqualValues(t, 0, sbc1.RollbackCount.Get(), "sbc1.RollbackCount") + assert.EqualValues(t, 1, sbc0.RollbackCount.Load(), "sbc0.RollbackCount") + assert.EqualValues(t, 0, sbc1.RollbackCount.Load(), "sbc1.RollbackCount") } func TestTxConnCommitOrderFailure1(t *testing.T) { @@ -461,12 +461,12 @@ func TestTxConnCommitOrderFailure1(t *testing.T) { wantSession := vtgatepb.Session{} utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc0.CommitCount.Load(), "sbc0.CommitCount") // first commit failed so we don't try to commit the second shard - assert.EqualValues(t, 0, sbc1.CommitCount.Get(), "sbc1.CommitCount") + assert.EqualValues(t, 0, sbc1.CommitCount.Load(), "sbc1.CommitCount") // When the commit fails, we try to clean up by issuing a rollback - assert.EqualValues(t, 2, sbc0.ReleaseCount.Get(), "sbc0.ReleaseCount") - assert.EqualValues(t, 1, sbc1.ReleaseCount.Get(), "sbc1.ReleaseCount") + assert.EqualValues(t, 2, sbc0.ReleaseCount.Load(), "sbc0.ReleaseCount") + assert.EqualValues(t, 1, sbc1.ReleaseCount.Load(), "sbc1.ReleaseCount") } func TestTxConnCommitOrderFailure2(t *testing.T) { @@ -494,11 +494,11 @@ func TestTxConnCommitOrderFailure2(t *testing.T) { wantSession := vtgatepb.Session{} utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") - assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") + assert.EqualValues(t, 1, sbc0.CommitCount.Load(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Load(), "sbc1.CommitCount") // When the commit fails, we try to clean up by issuing a rollback - assert.EqualValues(t, 0, sbc0.ReleaseCount.Get(), "sbc0.ReleaseCount") - assert.EqualValues(t, 2, sbc1.ReleaseCount.Get(), "sbc1.ReleaseCount") + assert.EqualValues(t, 0, sbc0.ReleaseCount.Load(), "sbc0.ReleaseCount") + assert.EqualValues(t, 2, sbc1.ReleaseCount.Load(), "sbc1.ReleaseCount") } func TestTxConnCommitOrderFailure3(t *testing.T) { @@ -535,10 +535,10 @@ func TestTxConnCommitOrderFailure3(t *testing.T) { }}, } utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 2, sbc0.CommitCount.Get(), "sbc0.CommitCount") - assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") - assert.EqualValues(t, 0, sbc0.RollbackCount.Get(), "sbc0.RollbackCount") - assert.EqualValues(t, 0, sbc1.RollbackCount.Get(), "sbc1.RollbackCount") + assert.EqualValues(t, 2, sbc0.CommitCount.Load(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Load(), "sbc1.CommitCount") + assert.EqualValues(t, 0, sbc0.RollbackCount.Load(), "sbc0.RollbackCount") + assert.EqualValues(t, 0, sbc1.RollbackCount.Load(), "sbc1.RollbackCount") } func TestTxConnCommitOrderSuccess(t *testing.T) { @@ -633,8 +633,8 @@ func TestTxConnCommitOrderSuccess(t *testing.T) { sc.txConn.Commit(ctx, session)) wantSession = vtgatepb.Session{} utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 2, sbc0.CommitCount.Get(), "sbc0.CommitCount") - assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") + assert.EqualValues(t, 2, sbc0.CommitCount.Load(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Load(), "sbc1.CommitCount") } func TestTxConnReservedCommitOrderSuccess(t *testing.T) { @@ -767,15 +767,15 @@ func TestTxConnReservedCommitOrderSuccess(t *testing.T) { }}, } utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 2, sbc0.CommitCount.Get(), "sbc0.CommitCount") - assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") + assert.EqualValues(t, 2, sbc0.CommitCount.Load(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Load(), "sbc1.CommitCount") require.NoError(t, sc.txConn.Release(ctx, session)) wantSession = vtgatepb.Session{InReservedConn: true} utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 2, sbc0.ReleaseCount.Get(), "sbc0.ReleaseCount") - assert.EqualValues(t, 1, sbc1.ReleaseCount.Get(), "sbc1.ReleaseCount") + assert.EqualValues(t, 2, sbc0.ReleaseCount.Load(), "sbc0.ReleaseCount") + assert.EqualValues(t, 1, sbc1.ReleaseCount.Load(), "sbc1.ReleaseCount") } func TestTxConnCommit2PC(t *testing.T) { @@ -787,11 +787,11 @@ func TestTxConnCommit2PC(t *testing.T) { session.TransactionMode = vtgatepb.TransactionMode_TWOPC require.NoError(t, sc.txConn.Commit(ctx, session)) - assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") - assert.EqualValues(t, 1, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") - assert.EqualValues(t, 1, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") - assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Load(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc1.PrepareCount.Load(), "sbc1.PrepareCount") + assert.EqualValues(t, 1, sbc0.StartCommitCount.Load(), "sbc0.StartCommitCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnCommit2PCOneParticipant(t *testing.T) { @@ -801,7 +801,7 @@ func TestTxConnCommit2PCOneParticipant(t *testing.T) { session.TransactionMode = vtgatepb.TransactionMode_TWOPC require.NoError(t, sc.txConn.Commit(ctx, session)) - assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc0.CommitCount.Load(), "sbc0.CommitCount") } func TestTxConnCommit2PCCreateTransactionFail(t *testing.T) { @@ -817,13 +817,13 @@ func TestTxConnCommit2PCCreateTransactionFail(t *testing.T) { want := "error: err" require.Error(t, err) assert.Contains(t, err.Error(), want, "Commit") - assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") - assert.EqualValues(t, 1, sbc0.RollbackCount.Get(), "sbc0.RollbackCount") - assert.EqualValues(t, 1, sbc1.RollbackCount.Get(), "sbc1.RollbackCount") - assert.EqualValues(t, 0, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") - assert.EqualValues(t, 0, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") - assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Load(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc0.RollbackCount.Load(), "sbc0.RollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackCount.Load(), "sbc1.RollbackCount") + assert.EqualValues(t, 0, sbc1.PrepareCount.Load(), "sbc1.PrepareCount") + assert.EqualValues(t, 0, sbc0.StartCommitCount.Load(), "sbc0.StartCommitCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnCommit2PCPrepareFail(t *testing.T) { @@ -839,11 +839,11 @@ func TestTxConnCommit2PCPrepareFail(t *testing.T) { want := "error: err" require.Error(t, err) assert.Contains(t, err.Error(), want, "Commit") - assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") - assert.EqualValues(t, 1, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") - assert.EqualValues(t, 0, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") - assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Load(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc1.PrepareCount.Load(), "sbc1.PrepareCount") + assert.EqualValues(t, 0, sbc0.StartCommitCount.Load(), "sbc0.StartCommitCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnCommit2PCStartCommitFail(t *testing.T) { @@ -859,11 +859,11 @@ func TestTxConnCommit2PCStartCommitFail(t *testing.T) { want := "error: err" require.Error(t, err) assert.Contains(t, err.Error(), want, "Commit") - assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") - assert.EqualValues(t, 1, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") - assert.EqualValues(t, 1, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") - assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Load(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc1.PrepareCount.Load(), "sbc1.PrepareCount") + assert.EqualValues(t, 1, sbc0.StartCommitCount.Load(), "sbc0.StartCommitCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnCommit2PCCommitPreparedFail(t *testing.T) { @@ -879,11 +879,11 @@ func TestTxConnCommit2PCCommitPreparedFail(t *testing.T) { want := "error: err" require.Error(t, err) assert.Contains(t, err.Error(), want, "Commit") - assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") - assert.EqualValues(t, 1, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") - assert.EqualValues(t, 1, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") - assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Load(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc1.PrepareCount.Load(), "sbc1.PrepareCount") + assert.EqualValues(t, 1, sbc0.StartCommitCount.Load(), "sbc0.StartCommitCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnCommit2PCConcludeTransactionFail(t *testing.T) { @@ -899,11 +899,11 @@ func TestTxConnCommit2PCConcludeTransactionFail(t *testing.T) { want := "error: err" require.Error(t, err) assert.Contains(t, err.Error(), want, "Commit") - assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") - assert.EqualValues(t, 1, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") - assert.EqualValues(t, 1, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") - assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Load(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc1.PrepareCount.Load(), "sbc1.PrepareCount") + assert.EqualValues(t, 1, sbc0.StartCommitCount.Load(), "sbc0.StartCommitCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnRollback(t *testing.T) { @@ -916,8 +916,8 @@ func TestTxConnRollback(t *testing.T) { sc.txConn.Rollback(ctx, session)) wantSession := vtgatepb.Session{} utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.RollbackCount.Get(), "sbc0.RollbackCount") - assert.EqualValues(t, 1, sbc1.RollbackCount.Get(), "sbc1.RollbackCount") + assert.EqualValues(t, 1, sbc0.RollbackCount.Load(), "sbc0.RollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackCount.Load(), "sbc1.RollbackCount") } func TestTxConnReservedRollback(t *testing.T) { @@ -949,10 +949,10 @@ func TestTxConnReservedRollback(t *testing.T) { }}, } utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.RollbackCount.Get(), "sbc0.RollbackCount") - assert.EqualValues(t, 1, sbc1.RollbackCount.Get(), "sbc1.RollbackCount") - assert.EqualValues(t, 0, sbc0.ReleaseCount.Get(), "sbc0.ReleaseCount") - assert.EqualValues(t, 0, sbc1.ReleaseCount.Get(), "sbc1.ReleaseCount") + assert.EqualValues(t, 1, sbc0.RollbackCount.Load(), "sbc0.RollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackCount.Load(), "sbc1.RollbackCount") + assert.EqualValues(t, 0, sbc0.ReleaseCount.Load(), "sbc0.ReleaseCount") + assert.EqualValues(t, 0, sbc1.ReleaseCount.Load(), "sbc1.ReleaseCount") } func TestTxConnReservedRollbackFailure(t *testing.T) { @@ -978,10 +978,10 @@ func TestTxConnReservedRollbackFailure(t *testing.T) { }}, } utils.MustMatch(t, &wantSession, session.Session, "Session") - assert.EqualValues(t, 1, sbc0.RollbackCount.Get(), "sbc0.RollbackCount") - assert.EqualValues(t, 1, sbc1.RollbackCount.Get(), "sbc1.RollbackCount") - assert.EqualValues(t, 1, sbc0.ReleaseCount.Get(), "sbc0.ReleaseCount") - assert.EqualValues(t, 1, sbc1.ReleaseCount.Get(), "sbc1.ReleaseCount") + assert.EqualValues(t, 1, sbc0.RollbackCount.Load(), "sbc0.RollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackCount.Load(), "sbc1.RollbackCount") + assert.EqualValues(t, 1, sbc0.ReleaseCount.Load(), "sbc0.ReleaseCount") + assert.EqualValues(t, 1, sbc1.ReleaseCount.Load(), "sbc1.ReleaseCount") } func TestTxConnResolveOnPrepare(t *testing.T) { @@ -999,10 +999,10 @@ func TestTxConnResolveOnPrepare(t *testing.T) { }} err := sc.txConn.Resolve(ctx, dtid) require.NoError(t, err) - assert.EqualValues(t, 1, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") - assert.EqualValues(t, 1, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") - assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 1, sbc0.SetRollbackCount.Load(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackPreparedCount.Load(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveOnRollback(t *testing.T) { @@ -1020,10 +1020,10 @@ func TestTxConnResolveOnRollback(t *testing.T) { }} require.NoError(t, sc.txConn.Resolve(ctx, dtid)) - assert.EqualValues(t, 0, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") - assert.EqualValues(t, 1, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") - assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 0, sbc0.SetRollbackCount.Load(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackPreparedCount.Load(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveOnCommit(t *testing.T) { @@ -1041,10 +1041,10 @@ func TestTxConnResolveOnCommit(t *testing.T) { }} require.NoError(t, sc.txConn.Resolve(ctx, dtid)) - assert.EqualValues(t, 0, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") - assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") - assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 0, sbc0.SetRollbackCount.Load(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Load(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveInvalidDTID(t *testing.T) { @@ -1103,10 +1103,10 @@ func TestTxConnResolveSetRollbackFail(t *testing.T) { want := "error: err" require.Error(t, err) assert.Contains(t, err.Error(), want, "Resolve") - assert.EqualValues(t, 1, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") - assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") - assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 1, sbc0.SetRollbackCount.Load(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Load(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveRollbackPreparedFail(t *testing.T) { @@ -1127,10 +1127,10 @@ func TestTxConnResolveRollbackPreparedFail(t *testing.T) { want := "error: err" require.Error(t, err) assert.Contains(t, err.Error(), want, "Resolve") - assert.EqualValues(t, 0, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") - assert.EqualValues(t, 1, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") - assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 0, sbc0.SetRollbackCount.Load(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackPreparedCount.Load(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveCommitPreparedFail(t *testing.T) { @@ -1151,10 +1151,10 @@ func TestTxConnResolveCommitPreparedFail(t *testing.T) { want := "error: err" require.Error(t, err) assert.Contains(t, err.Error(), want, "Resolve") - assert.EqualValues(t, 0, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") - assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") - assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 0, sbc0.SetRollbackCount.Load(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Load(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveConcludeTransactionFail(t *testing.T) { @@ -1175,10 +1175,10 @@ func TestTxConnResolveConcludeTransactionFail(t *testing.T) { want := "error: err" require.Error(t, err) assert.Contains(t, err.Error(), want, "Resolve") - assert.EqualValues(t, 0, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") - assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") - assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") - assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") + assert.EqualValues(t, 0, sbc0.SetRollbackCount.Load(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Load(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Load(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Load(), "sbc0.ConcludeTransactionCount") } func TestTxConnMultiGoSessions(t *testing.T) { diff --git a/go/vt/vtgate/vstream_manager_test.go b/go/vt/vtgate/vstream_manager_test.go index d71008bc6ae..7136539510b 100644 --- a/go/vt/vtgate/vstream_manager_test.go +++ b/go/vt/vtgate/vstream_manager_test.go @@ -21,11 +21,10 @@ import ( "fmt" "strings" "sync" + "sync/atomic" "testing" "time" - "vitess.io/vitess/go/sync2" - "vitess.io/vitess/go/vt/topo" vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" @@ -226,9 +225,7 @@ func TestVStreamChunks(t *testing.T) { rowEncountered := false doneCounting := false - var rowCount, ddlCount sync2.AtomicInt32 - rowCount.Set(0) - ddlCount.Set(0) + var rowCount, ddlCount atomic.Int32 vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ Keyspace: ks, @@ -265,13 +262,13 @@ func TestVStreamChunks(t *testing.T) { t.Errorf("Unexpected event: %v", events[0]) return fmt.Errorf("unexpected event: %v", events[0]) } - if rowCount.Get() == int32(100) && ddlCount.Get() == int32(100) { + if rowCount.Load() == int32(100) && ddlCount.Load() == int32(100) { cancel() } return nil }) - assert.Equal(t, int32(100), rowCount.Get()) - assert.Equal(t, int32(100), ddlCount.Get()) + assert.Equal(t, int32(100), rowCount.Load()) + assert.Equal(t, int32(100), ddlCount.Load()) } func TestVStreamMulti(t *testing.T) { @@ -358,8 +355,7 @@ func TestVStreamRetry(t *testing.T) { sbc0.AddVStreamEvents(nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "bb")) sbc0.AddVStreamEvents(nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "cc")) sbc0.AddVStreamEvents(nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "final error")) - var count sync2.AtomicInt32 - count.Set(0) + var count atomic.Int32 vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ Keyspace: ks, @@ -376,7 +372,7 @@ func TestVStreamRetry(t *testing.T) { t.Errorf("vstream end: %v, must contain %v", err.Error(), wantErr) } time.Sleep(100 * time.Millisecond) // wait for goroutine within VStream to finish - assert.Equal(t, int32(2), count.Get()) + assert.Equal(t, int32(2), count.Load()) } func TestVStreamShouldNotSendSourceHeartbeats(t *testing.T) { diff --git a/go/vt/vtgate/vtgate_test.go b/go/vt/vtgate/vtgate_test.go index aaa739913d9..e24dd5df8e2 100644 --- a/go/vt/vtgate/vtgate_test.go +++ b/go/vt/vtgate/vtgate_test.go @@ -409,8 +409,8 @@ func TestErrorIssuesRollback(t *testing.T) { if err != nil { t.Fatalf("want nil, got %v", err) } - if sbc.RollbackCount.Get() != 0 { - t.Errorf("want 0, got %d", sbc.RollbackCount.Get()) + if sbc.RollbackCount.Load() != 0 { + t.Errorf("want 0, got %d", sbc.RollbackCount.Load()) } sbc.MustFailCodes[vtrpcpb.Code_ABORTED] = 20 _, _, err = rpcVTGate.Execute( @@ -422,10 +422,10 @@ func TestErrorIssuesRollback(t *testing.T) { if err == nil { t.Fatalf("want error but got nil") } - if sbc.RollbackCount.Get() != 1 { - t.Errorf("want 1, got %d", sbc.RollbackCount.Get()) + if sbc.RollbackCount.Load() != 1 { + t.Errorf("want 1, got %d", sbc.RollbackCount.Load()) } - sbc.RollbackCount.Set(0) + sbc.RollbackCount.Store(0) sbc.MustFailCodes[vtrpcpb.Code_ABORTED] = 0 // Start a transaction, send one statement. @@ -449,8 +449,8 @@ func TestErrorIssuesRollback(t *testing.T) { if err != nil { t.Fatalf("want nil, got %v", err) } - if sbc.RollbackCount.Get() != 0 { - t.Errorf("want 0, got %d", sbc.RollbackCount.Get()) + if sbc.RollbackCount.Load() != 0 { + t.Errorf("want 0, got %d", sbc.RollbackCount.Load()) } sbc.MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 20 _, _, err = rpcVTGate.Execute( @@ -462,10 +462,10 @@ func TestErrorIssuesRollback(t *testing.T) { if err == nil { t.Fatalf("want error but got nil") } - if sbc.RollbackCount.Get() != 1 { - t.Errorf("want 1, got %d", sbc.RollbackCount.Get()) + if sbc.RollbackCount.Load() != 1 { + t.Errorf("want 1, got %d", sbc.RollbackCount.Load()) } - sbc.RollbackCount.Set(0) + sbc.RollbackCount.Store(0) sbc.MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 0 // Start a transaction, send one statement. @@ -489,8 +489,8 @@ func TestErrorIssuesRollback(t *testing.T) { if err != nil { t.Fatalf("want nil, got %v", err) } - if sbc.RollbackCount.Get() != 0 { - t.Errorf("want 0, got %d", sbc.RollbackCount.Get()) + if sbc.RollbackCount.Load() != 0 { + t.Errorf("want 0, got %d", sbc.RollbackCount.Load()) } sbc.MustFailCodes[vtrpcpb.Code_ALREADY_EXISTS] = 20 _, _, err = rpcVTGate.Execute( @@ -502,8 +502,8 @@ func TestErrorIssuesRollback(t *testing.T) { if err == nil { t.Fatalf("want error but got nil") } - if sbc.RollbackCount.Get() != 0 { - t.Errorf("want 0, got %d", sbc.RollbackCount.Get()) + if sbc.RollbackCount.Load() != 0 { + t.Errorf("want 0, got %d", sbc.RollbackCount.Load()) } sbc.MustFailCodes[vtrpcpb.Code_ALREADY_EXISTS] = 0 } diff --git a/go/vt/vtgr/controller/diagnose.go b/go/vt/vtgr/controller/diagnose.go index 8307f354972..b0896f4555a 100644 --- a/go/vt/vtgr/controller/diagnose.go +++ b/go/vt/vtgr/controller/diagnose.go @@ -147,7 +147,7 @@ func (shard *GRShard) Diagnose(ctx context.Context) (DiagnoseType, error) { func (shard *GRShard) diagnoseLocked(ctx context.Context) (DiagnoseType, error) { // fast path only diagnose problem Vitess primary // which does not needed if the shard is inactive - if shard.localDbPort != 0 && shard.isActive.Get() { + if shard.localDbPort != 0 && shard.isActive.Load() { localView := shard.getLocalView() if localView != nil { fastDiagnose := shard.fastPathDiagnose(ctx, localView) @@ -202,7 +202,7 @@ func (shard *GRShard) diagnoseLocked(ctx context.Context) (DiagnoseType, error) // We only check Vitess primary iff shard is active. // Otherwise VTGR will only make sure there is a mysql group in the shard. - if shard.isActive.Get() { + if shard.isActive.Load() { // Secondly, we check if there is a primary tablet. // If there is a group but we cannot find a primary tablet // we should set it based on mysql group @@ -240,17 +240,17 @@ func (shard *GRShard) diagnoseLocked(ctx context.Context) (DiagnoseType, error) onlineMembers, isReadOnly := shard.getOnlineGroupInfo() // If we found a writable shard in the inactive shard // we should consider the shard as InsufficientGroupSize to set read only - if !isReadOnly && !shard.isActive.Get() { + if !isReadOnly && !shard.isActive.Load() { return DiagnoseTypeInsufficientGroupSize, nil } // Then we check if we satisfy the minimum replica requirement if shard.minNumReplicas > 0 { - if onlineMembers >= shard.minNumReplicas && isReadOnly && shard.isActive.Get() { + if onlineMembers >= shard.minNumReplicas && isReadOnly && shard.isActive.Load() { return DiagnoseTypeReadOnlyShard, nil } // If we disable readonly protection and still found we have a read only shard, // we should return DiagnoseTypeReadOnlyShard so that VTGR can turn off read only - if shard.disableReadOnlyProtection && isReadOnly && shard.isActive.Get() { + if shard.disableReadOnlyProtection && isReadOnly && shard.isActive.Load() { return DiagnoseTypeReadOnlyShard, nil } // We don't check isActive here since if it is inactive, VTGR should already return InsufficientGroupSize diff --git a/go/vt/vtgr/controller/refresh.go b/go/vt/vtgr/controller/refresh.go index 32524769558..d7e78ba5ff6 100644 --- a/go/vt/vtgr/controller/refresh.go +++ b/go/vt/vtgr/controller/refresh.go @@ -20,6 +20,7 @@ import ( "fmt" "strconv" "sync" + "sync/atomic" "time" "vitess.io/vitess/go/vt/topo/topoproto" @@ -27,7 +28,6 @@ import ( "golang.org/x/net/context" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/logutil" topodatapb "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/vt/topo" @@ -93,7 +93,7 @@ type GRShard struct { lastDiagnoseResult DiagnoseType lastDiagnoseSince time.Time - isActive sync2.AtomicBool + isActive atomic.Bool logger *log.Logger @@ -150,7 +150,7 @@ func NewGRShard( transientErrorWaitTime: time.Duration(config.BackoffErrorWaitTimeSeconds) * time.Second, bootstrapWaitTime: time.Duration(config.BootstrapWaitTimeSeconds) * time.Second, } - grShard.isActive.Set(isActive) + grShard.isActive.Store(isActive) return grShard } @@ -349,7 +349,7 @@ func (shard *GRShard) GetUnlock() func(*error) { // SetIsActive sets isActive for the shard func (shard *GRShard) SetIsActive(isActive bool) { shard.logger.Infof("Setting is active to %v", isActive) - shard.isActive.Set(isActive) + shard.isActive.Store(isActive) } func (collector *shardStatusCollector) isUnreachable(instance *grInstance) bool { diff --git a/go/vt/vtgr/controller/repair.go b/go/vt/vtgr/controller/repair.go index e4225a4ae5a..a7fa64d7c97 100644 --- a/go/vt/vtgr/controller/repair.go +++ b/go/vt/vtgr/controller/repair.go @@ -674,7 +674,7 @@ func (shard *GRShard) failoverLocked(ctx context.Context) error { return err } shard.logger.Infof("Successfully failover MySQL to %v for %v", candidate.instanceKey.Hostname, formatKeyspaceShard(shard.KeyspaceShard)) - if !shard.isActive.Get() { + if !shard.isActive.Load() { shard.logger.Infof("Skip vttablet failover on an inactive shard %v", formatKeyspaceShard(shard.KeyspaceShard)) return nil } diff --git a/go/vt/vtgr/vtgr.go b/go/vt/vtgr/vtgr.go index 97ddabd44bc..80a5f99fad9 100644 --- a/go/vt/vtgr/vtgr.go +++ b/go/vt/vtgr/vtgr.go @@ -23,12 +23,12 @@ import ( "os/signal" "strings" "sync" + "sync/atomic" "syscall" "time" "github.com/spf13/pflag" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/servenv" @@ -70,7 +70,7 @@ type VTGR struct { tmc tmclient.TabletManagerClient ctx context.Context - stopped sync2.AtomicBool + stopped atomic.Bool } func newVTGR(ctx context.Context, ts controller.GRTopo, tmc tmclient.TabletManagerClient) *VTGR { @@ -168,7 +168,7 @@ func (vtgr *VTGR) ScanAndRepair() { func() { ctx, cancel := context.WithTimeout(vtgr.ctx, scanAndRepairTimeout) defer cancel() - if !vtgr.stopped.Get() { + if !vtgr.stopped.Load() { log.Infof("Start scan and repair %v/%v", shard.KeyspaceShard.Keyspace, shard.KeyspaceShard.Shard) shard.ScanAndRepairShard(ctx) log.Infof("Finished scan and repair %v/%v", shard.KeyspaceShard.Keyspace, shard.KeyspaceShard.Shard) @@ -186,7 +186,7 @@ func (vtgr *VTGR) Diagnose(ctx context.Context, shard *controller.GRShard) (cont // Repair exposes the endpoint to repair a particular shard func (vtgr *VTGR) Repair(ctx context.Context, shard *controller.GRShard, diagnose controller.DiagnoseType) (controller.RepairResultCode, error) { - if vtgr.stopped.Get() { + if vtgr.stopped.Load() { return controller.Fail, errors.New("VTGR is stopped") } return shard.Repair(ctx, diagnose) @@ -224,7 +224,7 @@ func (vtgr *VTGR) handleSignal(action func(int)) { log.Infof("Handling SIGHUP") // Set stopped to true so that following repair call won't do anything // For the ongoing repairs, checkShardLocked will abort if needed - vtgr.stopped.Set(true) + vtgr.stopped.Store(true) for _, shard := range vtgr.Shards { shard.UnlockShard() } diff --git a/go/vt/vtgr/vtgr_test.go b/go/vt/vtgr/vtgr_test.go index 337426dbd76..3632e88427c 100644 --- a/go/vt/vtgr/vtgr_test.go +++ b/go/vt/vtgr/vtgr_test.go @@ -2,13 +2,13 @@ package vtgr import ( "context" + "sync/atomic" "syscall" "testing" "time" "github.com/stretchr/testify/assert" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/topo/memorytopo" "vitess.io/vitess/go/vt/vtgr/config" "vitess.io/vitess/go/vt/vtgr/controller" @@ -41,15 +41,15 @@ func TestSighupHandle(t *testing.T) { vtgr.Shards = shards shard := vtgr.Shards[0] shard.LockShard(ctx, "test") - res := sync2.NewAtomicInt32(0) + var res atomic.Bool vtgr.handleSignal(func(i int) { - res.Set(1) + res.Store(true) }) assert.NotNil(t, shard.GetUnlock()) - assert.False(t, vtgr.stopped.Get()) + assert.False(t, vtgr.stopped.Load()) syscall.Kill(syscall.Getpid(), syscall.SIGHUP) time.Sleep(100 * time.Millisecond) - assert.Equal(t, int32(1), res.Get()) + assert.True(t, res.Load()) assert.Nil(t, shard.GetUnlock()) - assert.True(t, vtgr.stopped.Get()) + assert.True(t, vtgr.stopped.Load()) } diff --git a/go/vt/vttablet/endtoend/config_test.go b/go/vt/vttablet/endtoend/config_test.go index 99f1bc8583e..759deb87ba2 100644 --- a/go/vt/vttablet/endtoend/config_test.go +++ b/go/vt/vttablet/endtoend/config_test.go @@ -253,8 +253,8 @@ func TestWarnResultSize(t *testing.T) { func TestQueryTimeout(t *testing.T) { vstart := framework.DebugVars() - defer framework.Server.QueryTimeout.Set(framework.Server.QueryTimeout.Get()) - framework.Server.QueryTimeout.Set(100 * time.Millisecond) + defer framework.Server.QueryTimeout.Store(framework.Server.QueryTimeout.Load()) + framework.Server.QueryTimeout.Store(100 * time.Millisecond.Nanoseconds()) client := framework.NewClient() err := client.Begin(false) diff --git a/go/vt/vttablet/grpctmclient/cached_client.go b/go/vt/vttablet/grpctmclient/cached_client.go index a1f387b1937..c0dd751ec30 100644 --- a/go/vt/vttablet/grpctmclient/cached_client.go +++ b/go/vt/vttablet/grpctmclient/cached_client.go @@ -24,11 +24,11 @@ import ( "time" "github.com/spf13/pflag" + "golang.org/x/sync/semaphore" "google.golang.org/grpc" "vitess.io/vitess/go/netutil" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/grpcclient" "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/vttablet/tmclient" @@ -77,7 +77,7 @@ type cachedConnDialer struct { conns map[string]*cachedConn evict []*cachedConn evictSorted bool - connWaitSema *sync2.Semaphore + connWaitSema *semaphore.Weighted capacity int } @@ -99,7 +99,7 @@ func NewCachedConnClient(capacity int) *Client { dialer := &cachedConnDialer{ conns: make(map[string]*cachedConn, capacity), evict: make([]*cachedConn, 0, capacity), - connWaitSema: sync2.NewSemaphore(capacity, 0), + connWaitSema: semaphore.NewWeighted(int64(capacity)), capacity: capacity, } return &Client{dialer} @@ -129,7 +129,7 @@ func (dialer *cachedConnDialer) dial(ctx context.Context, tablet *topodatapb.Tab return client, closer, err } - if dialer.connWaitSema.TryAcquire() { + if dialer.connWaitSema.TryAcquire(1) { defer func() { dialerStats.DialTimings.Add("sema_fast", time.Since(start)) }() @@ -140,7 +140,7 @@ func (dialer *cachedConnDialer) dial(ctx context.Context, tablet *topodatapb.Tab // are able to use the cache, allowing another goroutine to dial a new // conn instead. if client, closer, found, err := dialer.tryFromCache(addr, &dialer.m); found { - dialer.connWaitSema.Release() + dialer.connWaitSema.Release(1) return client, closer, err } return dialer.newdial(ctx, addr) @@ -239,13 +239,13 @@ func (dialer *cachedConnDialer) pollOnce(ctx context.Context, addr string) (clie func (dialer *cachedConnDialer) newdial(ctx context.Context, addr string) (tabletmanagerservicepb.TabletManagerClient, io.Closer, error) { opt, err := grpcclient.SecureDialOption(cert, key, ca, crl, name) if err != nil { - dialer.connWaitSema.Release() + dialer.connWaitSema.Release(1) return nil, nil, err } cc, err := grpcclient.DialContext(ctx, addr, grpcclient.FailFast(false), opt) if err != nil { - dialer.connWaitSema.Release() + dialer.connWaitSema.Release(1) return nil, nil, err } @@ -258,7 +258,7 @@ func (dialer *cachedConnDialer) newdial(ctx context.Context, addr string) (table // close this connection and reuse the existing one. by doing this, we can keep // the actual Dial out of the global lock and significantly increase throughput cc.Close() - dialer.connWaitSema.Release() + dialer.connWaitSema.Release(1) return dialer.redialLocked(conn) } @@ -328,7 +328,7 @@ func (dialer *cachedConnDialer) Close() { for _, conn := range dialer.evict { conn.cc.Close() delete(dialer.conns, conn.addr) - dialer.connWaitSema.Release() + dialer.connWaitSema.Release(1) } dialer.evict = make([]*cachedConn, 0, dialer.capacity) } diff --git a/go/vt/vttablet/grpctmclient/cached_client_flaky_test.go b/go/vt/vttablet/grpctmclient/cached_client_flaky_test.go index 096e0278150..c5346a99aa4 100644 --- a/go/vt/vttablet/grpctmclient/cached_client_flaky_test.go +++ b/go/vt/vttablet/grpctmclient/cached_client_flaky_test.go @@ -24,6 +24,7 @@ import ( "net" "runtime" "sync" + "sync/atomic" "testing" "time" @@ -32,7 +33,6 @@ import ( "golang.org/x/net/nettest" "google.golang.org/grpc" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/vttablet/grpctmserver" "vitess.io/vitess/go/vt/vttablet/tabletmanager" "vitess.io/vitess/go/vt/vttablet/tmrpctest" @@ -320,8 +320,7 @@ func TestCachedConnClient(t *testing.T) { client := NewCachedConnClient(poolSize) defer client.Close() - dialAttempts := sync2.NewAtomicInt64(0) - dialErrors := sync2.NewAtomicInt64(0) + var dialAttempts, dialErrors atomic.Int64 longestDials := make(chan time.Duration, numGoroutines) @@ -375,7 +374,7 @@ func TestCachedConnClient(t *testing.T) { } } - attempts, errors := dialAttempts.Get(), dialErrors.Get() + attempts, errors := dialAttempts.Load(), dialErrors.Load() assert.Less(t, float64(errors)/float64(attempts), 0.001, fmt.Sprintf("fewer than 0.1%% of dial attempts should fail (attempts = %d, errors = %d, max running procs = %d)", attempts, errors, procs)) assert.Less(t, errors, int64(1), "at least one dial attempt failed (attempts = %d, errors = %d)", attempts, errors) assert.Less(t, longestDial.Milliseconds(), int64(50)) diff --git a/go/vt/vttablet/sandboxconn/sandboxconn.go b/go/vt/vttablet/sandboxconn/sandboxconn.go index 822f6774fe9..8b9e31a2f96 100644 --- a/go/vt/vttablet/sandboxconn/sandboxconn.go +++ b/go/vt/vttablet/sandboxconn/sandboxconn.go @@ -22,13 +22,13 @@ import ( "context" "fmt" "sync" + "sync/atomic" "time" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/queryservice" @@ -61,22 +61,22 @@ type SandboxConn struct { // These Count vars report how often the corresponding // functions were called. - ExecCount sync2.AtomicInt64 - BeginCount sync2.AtomicInt64 - CommitCount sync2.AtomicInt64 - RollbackCount sync2.AtomicInt64 - AsTransactionCount sync2.AtomicInt64 - PrepareCount sync2.AtomicInt64 - CommitPreparedCount sync2.AtomicInt64 - RollbackPreparedCount sync2.AtomicInt64 - CreateTransactionCount sync2.AtomicInt64 - StartCommitCount sync2.AtomicInt64 - SetRollbackCount sync2.AtomicInt64 - ConcludeTransactionCount sync2.AtomicInt64 - ReadTransactionCount sync2.AtomicInt64 - ReserveCount sync2.AtomicInt64 - ReleaseCount sync2.AtomicInt64 - GetSchemaCount sync2.AtomicInt64 + ExecCount atomic.Int64 + BeginCount atomic.Int64 + CommitCount atomic.Int64 + RollbackCount atomic.Int64 + AsTransactionCount atomic.Int64 + PrepareCount atomic.Int64 + CommitPreparedCount atomic.Int64 + RollbackPreparedCount atomic.Int64 + CreateTransactionCount atomic.Int64 + StartCommitCount atomic.Int64 + SetRollbackCount atomic.Int64 + ConcludeTransactionCount atomic.Int64 + ReadTransactionCount atomic.Int64 + ReserveCount atomic.Int64 + ReleaseCount atomic.Int64 + GetSchemaCount atomic.Int64 // Queries stores the non-batch requests received. Queries []*querypb.BoundQuery @@ -105,10 +105,10 @@ type SandboxConn struct { VStreamCh chan *binlogdatapb.VEvent // transaction id generator - TransactionID sync2.AtomicInt64 + TransactionID atomic.Int64 // reserve id generator - ReserveID sync2.AtomicInt64 + ReserveID atomic.Int64 mapMu sync.Mutex //protects the map txIDToRID txIDToRID map[int64]int64 diff --git a/go/vt/vttablet/tabletmanager/rpc_server.go b/go/vt/vttablet/tabletmanager/rpc_server.go index ffd30d299a4..da4d4e0b042 100644 --- a/go/vt/vttablet/tabletmanager/rpc_server.go +++ b/go/vt/vttablet/tabletmanager/rpc_server.go @@ -38,20 +38,12 @@ import ( // lock is used at the beginning of an RPC call, to acquire the // action semaphore. It returns ctx.Err() if the context expires. func (tm *TabletManager) lock(ctx context.Context) error { - if tm.actionSema.AcquireContext(ctx) { - return nil - } - return ctx.Err() -} - -// tryLock will return immediately, true on success and false on failure. -func (tm *TabletManager) tryLock() bool { - return tm.actionSema.TryAcquire() + return tm.actionSema.Acquire(ctx, 1) } // unlock is the symmetrical action to lock. func (tm *TabletManager) unlock() { - tm.actionSema.Release() + tm.actionSema.Release(1) } // HandleRPCPanic is part of the RPCTM interface. diff --git a/go/vt/vttablet/tabletmanager/tm_init.go b/go/vt/vttablet/tabletmanager/tm_init.go index 2eb87578291..171da67fa46 100644 --- a/go/vt/vttablet/tabletmanager/tm_init.go +++ b/go/vt/vttablet/tabletmanager/tm_init.go @@ -44,13 +44,13 @@ import ( "time" "github.com/spf13/pflag" + "golang.org/x/sync/semaphore" "vitess.io/vitess/go/flagutil" "vitess.io/vitess/go/mysql/collations" "vitess.io/vitess/go/netutil" "vitess.io/vitess/go/sets" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/binlog" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/dbconnpool" @@ -165,7 +165,7 @@ type TabletManager struct { // This semaphore can be held for long periods of time (hours), // like in the case of a restore. This semaphore must be obtained // first before other mutexes. - actionSema *sync2.Semaphore + actionSema *semaphore.Weighted // mutex protects all the following fields (that start with '_'), // only hold the mutex to update the fields, nothing else. @@ -343,7 +343,7 @@ func (tm *TabletManager) Start(tablet *topodatapb.Tablet, healthCheckInterval ti tm.DBConfigs.DBName = topoproto.TabletDbName(tablet) tm.tabletAlias = tablet.Alias tm.tmState = newTMState(tm, tablet) - tm.actionSema = sync2.NewSemaphore(1, 0) + tm.actionSema = semaphore.NewWeighted(1) tm.baseTabletType = tablet.Type diff --git a/go/vt/vttablet/tabletmanager/tm_init_test.go b/go/vt/vttablet/tabletmanager/tm_init_test.go index 36e6e175531..71ed915c2c4 100644 --- a/go/vt/vttablet/tabletmanager/tm_init_test.go +++ b/go/vt/vttablet/tabletmanager/tm_init_test.go @@ -29,7 +29,6 @@ import ( "vitess.io/vitess/go/mysql/collations" "vitess.io/vitess/go/mysql/fakesqldb" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/test/utils" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/logutil" @@ -446,7 +445,7 @@ func TestStartFindMysqlPort(t *testing.T) { require.NoError(t, err) assert.Equal(t, int32(0), ti.MysqlPort) - fmd.MysqlPort.Set(3306) + fmd.MysqlPort.Store(3306) for i := 0; i < 10; i++ { ti, err := ts.GetTablet(ctx, tm.tabletAlias) require.NoError(t, err) @@ -647,7 +646,7 @@ func newTestMysqlDaemon(t *testing.T, port int32) *mysqlctl.FakeMysqlDaemon { db.AddQueryPattern("COMMIT", &sqltypes.Result{}) mysqld := mysqlctl.NewFakeMysqlDaemon(db) - mysqld.MysqlPort = sync2.NewAtomicInt32(port) + mysqld.MysqlPort.Store(port) return mysqld } diff --git a/go/vt/vttablet/tabletmanager/vdiff/engine.go b/go/vt/vttablet/tabletmanager/vdiff/engine.go index 27747b8a5cb..c60e585120c 100644 --- a/go/vt/vttablet/tabletmanager/vdiff/engine.go +++ b/go/vt/vttablet/tabletmanager/vdiff/engine.go @@ -31,7 +31,6 @@ import ( "vitess.io/vitess/go/vt/vttablet/tmclient" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" @@ -169,12 +168,12 @@ func (vde *Engine) openLocked(ctx context.Context) error { return nil } -var openRetryInterval = sync2.NewAtomicDuration(1 * time.Second) +var openRetryInterval = 1 * time.Second func (vde *Engine) retry(ctx context.Context, err error) { log.Errorf("Error starting vdiff engine: %v, will keep retrying.", err) for { - timer := time.NewTimer(openRetryInterval.Get()) + timer := time.NewTimer(openRetryInterval) select { case <-ctx.Done(): timer.Stop() diff --git a/go/vt/vttablet/tabletmanager/vreplication/controller.go b/go/vt/vttablet/tabletmanager/vreplication/controller.go index ff3435660cb..ff12b9695e2 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/controller.go +++ b/go/vt/vttablet/tabletmanager/vreplication/controller.go @@ -21,6 +21,7 @@ import ( "fmt" "strconv" "strings" + "sync/atomic" "time" "google.golang.org/protobuf/encoding/prototext" @@ -28,7 +29,6 @@ import ( "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/tb" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/log" @@ -65,7 +65,7 @@ type controller struct { done chan struct{} // The following fields are updated after start. So, they need synchronization. - sourceTablet sync2.AtomicString + sourceTablet atomic.Value lastWorkflowError *vterrors.LastError } @@ -85,6 +85,7 @@ func newController(ctx context.Context, params map[string]string, dbClientFactor done: make(chan struct{}), source: &binlogdatapb.BinlogSource{}, } + ct.sourceTablet.Store("") log.Infof("creating controller with cell: %v, tabletTypes: %v, and params: %v", cell, tabletTypesStr, params) // id @@ -97,7 +98,7 @@ func newController(ctx context.Context, params map[string]string, dbClientFactor ct.lastWorkflowError = vterrors.NewLastError(fmt.Sprintf("VReplication controller %d for workflow %q", ct.id, ct.workflow), maxTimeToRetryError) state := params["state"] - blpStats.State.Set(state) + blpStats.State.Store(state) // Nothing to do if replication is stopped or is known to have an unrecoverable error. if state == binlogplayer.BlpStopped || state == binlogplayer.BlpError { ct.cancel = func() {} @@ -179,7 +180,7 @@ func (ct *controller) run(ctx context.Context) { func (ct *controller) runBlp(ctx context.Context) (err error) { defer func() { - ct.sourceTablet.Set("") + ct.sourceTablet.Store("") if x := recover(); x != nil { log.Errorf("stream %v: caught panic: %v\n%s", ct.id, x, tb.Stack(4)) err = fmt.Errorf("panic: %v", x) @@ -221,7 +222,7 @@ func (ct *controller) runBlp(ctx context.Context) (err error) { } ct.setMessage(dbClient, fmt.Sprintf("Picked source tablet: %s", tablet.Alias.String())) log.Infof("found a tablet eligible for vreplication. stream id: %v tablet: %s", ct.id, tablet.Alias.String()) - ct.sourceTablet.Set(tablet.Alias.String()) + ct.sourceTablet.Store(tablet.Alias.String()) } switch { case len(ct.source.Tables) > 0: diff --git a/go/vt/vttablet/tabletmanager/vreplication/controller_test.go b/go/vt/vttablet/tabletmanager/vreplication/controller_test.go index d2c0f2f04c6..8ced99f07d0 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/controller_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/controller_test.go @@ -27,7 +27,6 @@ import ( querypb "vitess.io/vitess/go/vt/proto/query" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/mysqlctl/tmutils" @@ -89,7 +88,8 @@ func TestControllerKeyRange(t *testing.T) { dbClient.ExpectRequest("commit", nil, nil) dbClientFactory := func() binlogplayer.DBClient { return dbClient } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) ct, err := newController(context.Background(), params, dbClientFactory, mysqld, env.TopoServ, env.Cells[0], "replica", nil, nil) if err != nil { @@ -126,7 +126,6 @@ func TestControllerTables(t *testing.T) { dbClientFactory := func() binlogplayer.DBClient { return dbClient } mysqld := &mysqlctl.FakeMysqlDaemon{ - MysqlPort: sync2.NewAtomicInt32(3306), Schema: &tabletmanagerdatapb.SchemaDefinition{ DatabaseSchema: "", TableDefinitions: []*tabletmanagerdatapb.TableDefinition{ @@ -151,6 +150,7 @@ func TestControllerTables(t *testing.T) { }, }, } + mysqld.MysqlPort.Store(3306) ct, err := newController(context.Background(), params, dbClientFactory, mysqld, env.TopoServ, env.Cells[0], "replica", nil, nil) if err != nil { @@ -218,7 +218,8 @@ func TestControllerOverrides(t *testing.T) { dbClient.ExpectRequest("commit", nil, nil) dbClientFactory := func() binlogplayer.DBClient { return dbClient } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) ct, err := newController(context.Background(), params, dbClientFactory, mysqld, env.TopoServ, env.Cells[0], "rdonly", nil, nil) if err != nil { @@ -286,7 +287,8 @@ func TestControllerRetry(t *testing.T) { dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) dbClient.ExpectRequest("commit", nil, nil) dbClientFactory := func() binlogplayer.DBClient { return dbClient } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) ct, err := newController(context.Background(), params, dbClientFactory, mysqld, env.TopoServ, env.Cells[0], "rdonly", nil, nil) if err != nil { @@ -346,7 +348,8 @@ func TestControllerStopPosition(t *testing.T) { dbClient.ExpectRequest("update _vt.vreplication set state='Stopped', message='Reached stopping position, done playing logs' where id=1", testDMLResponse, nil) dbClientFactory := func() binlogplayer.DBClient { return dbClient } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) ct, err := newController(context.Background(), params, dbClientFactory, mysqld, env.TopoServ, env.Cells[0], "replica", nil, nil) if err != nil { diff --git a/go/vt/vttablet/tabletmanager/vreplication/engine.go b/go/vt/vttablet/tabletmanager/vreplication/engine.go index 5da391bc83c..5d336796b04 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/engine.go +++ b/go/vt/vttablet/tabletmanager/vreplication/engine.go @@ -24,13 +24,13 @@ import ( "sort" "strconv" "sync" + "sync/atomic" "time" "google.golang.org/protobuf/proto" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" @@ -234,12 +234,16 @@ func (vre *Engine) openLocked(ctx context.Context) error { return nil } -var openRetryInterval = sync2.NewAtomicDuration(1 * time.Second) +var openRetryInterval atomic.Int64 + +func init() { + openRetryInterval.Store((1 * time.Second).Nanoseconds()) +} func (vre *Engine) retry(ctx context.Context, err error) { log.Errorf("Error starting vreplication engine: %v, will keep retrying.", err) for { - timer := time.NewTimer(openRetryInterval.Get()) + timer := time.NewTimer(time.Duration(openRetryInterval.Load())) select { case <-ctx.Done(): timer.Stop() diff --git a/go/vt/vttablet/tabletmanager/vreplication/engine_test.go b/go/vt/vttablet/tabletmanager/vreplication/engine_test.go index 21c9e0bd376..d490417784f 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/engine_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/engine_test.go @@ -29,7 +29,6 @@ import ( "github.com/stretchr/testify/require" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/mysqlctl" ) @@ -41,7 +40,8 @@ func TestEngineOpen(t *testing.T) { resetBinlogClient() dbClient := binlogplayer.NewMockDBClient(t) dbClientFactory := func() binlogplayer.DBClient { return dbClient } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil) require.False(t, vre.IsOpen()) @@ -74,14 +74,15 @@ func TestEngineOpen(t *testing.T) { func TestEngineOpenRetry(t *testing.T) { defer func() { globalStats = &vrStats{} }() - defer func(saved time.Duration) { openRetryInterval.Set(saved) }(openRetryInterval.Get()) - openRetryInterval.Set(10 * time.Millisecond) + defer func(saved int64) { openRetryInterval.Store(saved) }(openRetryInterval.Load()) + openRetryInterval.Store((10 * time.Millisecond).Nanoseconds()) defer deleteTablet(addTablet(100)) resetBinlogClient() dbClient := binlogplayer.NewMockDBClient(t) dbClientFactory := func() binlogplayer.DBClient { return dbClient } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil) @@ -132,7 +133,7 @@ func TestEngineOpenRetry(t *testing.T) { // Close should cause the retry to exit. vre.Close() elapsed := time.Since(start) - assert.Greater(t, int64(openRetryInterval.Get()), int64(elapsed)) + assert.Greater(t, openRetryInterval.Load(), elapsed.Nanoseconds()) } func TestEngineExec(t *testing.T) { @@ -142,7 +143,8 @@ func TestEngineExec(t *testing.T) { resetBinlogClient() dbClient := binlogplayer.NewMockDBClient(t) dbClientFactory := func() binlogplayer.DBClient { return dbClient } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) // Test Insert @@ -307,7 +309,8 @@ func TestEngineBadInsert(t *testing.T) { dbClient := binlogplayer.NewMockDBClient(t) dbClientFactory := func() binlogplayer.DBClient { return dbClient } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil) @@ -335,7 +338,8 @@ func TestEngineSelect(t *testing.T) { dbClient := binlogplayer.NewMockDBClient(t) dbClientFactory := func() binlogplayer.DBClient { return dbClient } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil) @@ -368,7 +372,9 @@ func TestWaitForPos(t *testing.T) { waitRetryTime = 10 * time.Millisecond dbClient := binlogplayer.NewMockDBClient(t) - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) + dbClientFactory := func() binlogplayer.DBClient { return dbClient } vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil) @@ -396,7 +402,9 @@ func TestWaitForPos(t *testing.T) { func TestWaitForPosError(t *testing.T) { dbClient := binlogplayer.NewMockDBClient(t) - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) + dbClientFactory := func() binlogplayer.DBClient { return dbClient } vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil) @@ -432,7 +440,9 @@ func TestWaitForPosError(t *testing.T) { func TestWaitForPosCancel(t *testing.T) { dbClient := binlogplayer.NewMockDBClient(t) - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) + dbClientFactory := func() binlogplayer.DBClient { return dbClient } vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil) @@ -475,7 +485,9 @@ func TestGetDBClient(t *testing.T) { dbClientFactoryDba := func() binlogplayer.DBClient { return dbClientDba } dbClientFactoryFiltered := func() binlogplayer.DBClient { return dbClientFiltered } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) + vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactoryFiltered, dbClientFactoryDba, dbClientDba.DBName(), nil) shouldBeDbaClient := vre.getDBClient(true /*runAsAdmin*/) diff --git a/go/vt/vttablet/tabletmanager/vreplication/fuzz.go b/go/vt/vttablet/tabletmanager/vreplication/fuzz.go index 0fcfcce9660..2b9daa0d3cc 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/fuzz.go +++ b/go/vt/vttablet/tabletmanager/vreplication/fuzz.go @@ -23,7 +23,6 @@ import ( "testing" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/mysqlctl" "vitess.io/vitess/go/vt/topo/memorytopo" @@ -94,7 +93,8 @@ func FuzzEngine(data []byte) int { resetBinlogClient() dbClient := binlogplayer.NewMockDBClient(t) dbClientFactory := func() binlogplayer.DBClient { return dbClient } - mysqld := &mysqlctl.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)} + mysqld := &mysqlctl.FakeMysqlDaemon{} + mysqld.MysqlPort.Store(3306) vre := NewTestEngine(topoServer, "cell1", mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil) diff --git a/go/vt/vttablet/tabletmanager/vreplication/stats.go b/go/vt/vttablet/tabletmanager/vreplication/stats.go index 3abfa0573b2..5b3f55a60f5 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/stats.go +++ b/go/vt/vttablet/tabletmanager/vreplication/stats.go @@ -67,7 +67,10 @@ func (st *vrStats) register() { defer st.mu.Unlock() result := make(map[string]string, len(st.controllers)) for _, ct := range st.controllers { - result[ct.workflow+"."+fmt.Sprintf("%v", ct.id)] = ct.blpStats.State.Get() + state := ct.blpStats.State.Load() + if state != nil { + result[ct.workflow+"."+fmt.Sprintf("%v", ct.id)] = state.(string) + } } return result })) @@ -80,7 +83,7 @@ func (st *vrStats) register() { defer st.mu.Unlock() result := make(map[string]int64, len(st.controllers)) for _, ct := range st.controllers { - result[ct.source.Keyspace+"."+ct.source.Shard+"."+ct.workflow+"."+fmt.Sprintf("%v", ct.id)] = ct.blpStats.ReplicationLagSeconds.Get() + result[ct.source.Keyspace+"."+ct.source.Shard+"."+ct.workflow+"."+fmt.Sprintf("%v", ct.id)] = ct.blpStats.ReplicationLagSeconds.Load() } return result }) @@ -93,7 +96,7 @@ func (st *vrStats) register() { defer st.mu.Unlock() result := int64(0) for _, ct := range st.controllers { - result += ct.blpStats.ReplicationLagSeconds.Get() + result += ct.blpStats.ReplicationLagSeconds.Load() } return result }) @@ -142,7 +145,7 @@ func (st *vrStats) register() { defer st.mu.Unlock() result := make(map[string]string, len(st.controllers)) for _, ct := range st.controllers { - result[fmt.Sprintf("%v", ct.id)] = ct.sourceTablet.Get() + result[fmt.Sprintf("%v", ct.id)] = ct.sourceTablet.Load().(string) } return result })) @@ -401,7 +404,7 @@ func (st *vrStats) maxReplicationLagSeconds() int64 { defer st.mu.Unlock() max := int64(0) for _, ct := range st.controllers { - if cur := ct.blpStats.ReplicationLagSeconds.Get(); cur > max { + if cur := ct.blpStats.ReplicationLagSeconds.Load(); cur > max { max = cur } } @@ -424,11 +427,10 @@ func (st *vrStats) status() *EngineStatus { StopPosition: ct.stopPos, LastPosition: ct.blpStats.LastPosition().String(), Heartbeat: ct.blpStats.Heartbeat(), - ReplicationLagSeconds: ct.blpStats.ReplicationLagSeconds.Get(), + ReplicationLagSeconds: ct.blpStats.ReplicationLagSeconds.Load(), Counts: ct.blpStats.Timings.Counts(), Rates: ct.blpStats.Rates.Get(), - State: ct.blpStats.State.Get(), - SourceTablet: ct.sourceTablet.Get(), + SourceTablet: ct.sourceTablet.Load().(string), Messages: ct.blpStats.MessageHistory(), QueryCounts: ct.blpStats.QueryCount.Counts(), PhaseTimings: ct.blpStats.PhaseTimings.Counts(), @@ -437,6 +439,11 @@ func (st *vrStats) status() *EngineStatus { NoopQueryCounts: ct.blpStats.NoopQueryCount.Counts(), TableCopyTimings: ct.blpStats.TableCopyTimings.Counts(), } + state := ct.blpStats.State.Load() + if state != nil { + status.Controllers[i].State = state.(string) + } + i++ } sort.Slice(status.Controllers, func(i, j int) bool { return status.Controllers[i].Index < status.Controllers[j].Index }) diff --git a/go/vt/vttablet/tabletmanager/vreplication/stats_test.go b/go/vt/vttablet/tabletmanager/vreplication/stats_test.go index 80a25b5b638..18ede348166 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/stats_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/stats_test.go @@ -79,7 +79,7 @@ func TestStatusHtml(t *testing.T) { blpStats := binlogplayer.NewStats() blpStats.SetLastPosition(pos) - blpStats.ReplicationLagSeconds.Set(2) + blpStats.ReplicationLagSeconds.Store(2) blpStats.History.Add(&binlogplayer.StatsHistoryRecord{Time: time.Now(), Message: "Test Message1"}) blpStats.History.Add(&binlogplayer.StatsHistoryRecord{Time: time.Now(), Message: "Test Message2"}) @@ -107,8 +107,8 @@ func TestStatusHtml(t *testing.T) { done: make(chan struct{}), }, } - testStats.controllers[1].sourceTablet.Set("src1") - testStats.controllers[2].sourceTablet.Set("src2") + testStats.controllers[1].sourceTablet.Store("src1") + testStats.controllers[2].sourceTablet.Store("src2") close(testStats.controllers[2].done) tpl := template.Must(template.New("test").Parse(vreplicationTemplate)) @@ -135,7 +135,7 @@ func TestVReplicationStats(t *testing.T) { done: make(chan struct{}), }, } - testStats.controllers[1].sourceTablet.Set("src1") + testStats.controllers[1].sourceTablet.Store("src1") sleepTime := 1 * time.Millisecond record := func(phase string) { diff --git a/go/vt/vttablet/tabletmanager/vreplication/vcopier.go b/go/vt/vttablet/tabletmanager/vreplication/vcopier.go index 0692977bd60..90e1495a93d 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vcopier.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vcopier.go @@ -351,7 +351,7 @@ func (vc *vcopier) catchup(ctx context.Context, copyState map[string]*sqltypes.R defer tkr.Stop() seconds := int64(replicaLagTolerance / time.Second) for { - sbm := vc.vr.stats.ReplicationLagSeconds.Get() + sbm := vc.vr.stats.ReplicationLagSeconds.Load() if sbm < seconds { cancel() // Make sure vplayer returns before returning. diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go index 16cbeeecc91..0e33eed5f6a 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go @@ -327,7 +327,7 @@ func (vp *vplayer) applyEvents(ctx context.Context, relay *relayLog) error { // If we're not running, set ReplicationLagSeconds to be very high. // TODO(sougou): if we also stored the time of the last event, we // can estimate this value more accurately. - defer vp.vr.stats.ReplicationLagSeconds.Set(math.MaxInt64) + defer vp.vr.stats.ReplicationLagSeconds.Store(math.MaxInt64) defer vp.vr.stats.VReplicationLags.Add(strconv.Itoa(int(vp.vr.id)), math.MaxInt64) var sbm int64 = -1 for { @@ -348,7 +348,7 @@ func (vp *vplayer) applyEvents(ctx context.Context, relay *relayLog) error { // So, we should assume we're falling behind. if len(items) == 0 { behind := time.Now().UnixNano() - vp.lastTimestampNs - vp.timeOffsetNs - vp.vr.stats.ReplicationLagSeconds.Set(behind / 1e9) + vp.vr.stats.ReplicationLagSeconds.Store(behind / 1e9) vp.vr.stats.VReplicationLags.Add(strconv.Itoa(int(vp.vr.id)), time.Duration(behind/1e9)*time.Second) } // Empty transactions are saved at most once every idleTimeout. @@ -404,7 +404,7 @@ func (vp *vplayer) applyEvents(ctx context.Context, relay *relayLog) error { } if sbm >= 0 { - vp.vr.stats.ReplicationLagSeconds.Set(sbm) + vp.vr.stats.ReplicationLagSeconds.Store(sbm) vp.vr.stats.VReplicationLags.Add(strconv.Itoa(int(vp.vr.id)), time.Duration(sbm)*time.Second) } diff --git a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go index 18d26c015e6..e3f4d8fa5a9 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go @@ -431,7 +431,7 @@ func (vr *vreplicator) setState(state, message string) error { Message: message, }) } - vr.stats.State.Set(state) + vr.stats.State.Store(state) query := fmt.Sprintf("update _vt.vreplication set state='%v', message=%v where id=%v", state, encodeString(binlogplayer.MessageTruncate(message)), vr.id) if _, err := vr.dbClient.ExecuteFetch(query, 1); err != nil { return fmt.Errorf("could not set state: %v: %v", query, err) diff --git a/go/vt/vttablet/tabletserver/connpool/dbconn.go b/go/vt/vttablet/tabletserver/connpool/dbconn.go index c2fdf991056..13d0479fd0c 100644 --- a/go/vt/vttablet/tabletserver/connpool/dbconn.go +++ b/go/vt/vttablet/tabletserver/connpool/dbconn.go @@ -21,6 +21,7 @@ import ( "fmt" "strings" "sync" + "sync/atomic" "time" "vitess.io/vitess/go/pools" @@ -30,7 +31,6 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/trace" "vitess.io/vitess/go/vt/dbconnpool" "vitess.io/vitess/go/vt/log" @@ -52,7 +52,7 @@ type DBConn struct { pool *Pool dbaPool *dbconnpool.ConnectionPool stats *tabletenv.Stats - current sync2.AtomicString + current atomic.Value timeCreated time.Time setting string resetSetting string @@ -73,14 +73,16 @@ func NewDBConn(ctx context.Context, cp *Pool, appParams dbconfigs.Connector) (*D cp.env.CheckMySQL() return nil, err } - return &DBConn{ + db := &DBConn{ conn: c, info: appParams, pool: cp, dbaPool: cp.dbaPool, timeCreated: time.Now(), stats: cp.env.Stats(), - }, nil + } + db.current.Store("") + return db, nil } // NewDBConnNoPool creates a new DBConn without a pool. @@ -97,6 +99,7 @@ func NewDBConnNoPool(ctx context.Context, params dbconfigs.Connector, dbaPool *d timeCreated: time.Now(), stats: tabletenv.NewStats(servenv.NewExporter("Temp", "Tablet")), } + dbconn.current.Store("") if setting == nil { return dbconn, nil } @@ -157,8 +160,8 @@ func (dbc *DBConn) Exec(ctx context.Context, query string, maxrows int, wantfiel } func (dbc *DBConn) execOnce(ctx context.Context, query string, maxrows int, wantfields bool) (*sqltypes.Result, error) { - dbc.current.Set(query) - defer dbc.current.Set("") + dbc.current.Store(query) + defer dbc.current.Store("") // Check if the context is already past its deadline before // trying to execute the query. @@ -262,8 +265,8 @@ func (dbc *DBConn) Stream(ctx context.Context, query string, callback func(*sqlt func (dbc *DBConn) streamOnce(ctx context.Context, query string, callback func(*sqltypes.Result) error, alloc func() *sqltypes.Result, streamBufferSize int) error { defer dbc.stats.MySQLTimings.Record("ExecStream", time.Now()) - dbc.current.Set(query) - defer dbc.current.Set("") + dbc.current.Store(query) + defer dbc.current.Store("") done, wg := dbc.setDeadline(ctx) err := dbc.conn.ExecuteStreamFetch(query, callback, alloc, streamBufferSize) @@ -442,7 +445,7 @@ func (dbc *DBConn) Kill(reason string, elapsed time.Duration) error { // Current returns the currently executing query. func (dbc *DBConn) Current() string { - return dbc.current.Get() + return dbc.current.Load().(string) } // ID returns the connection id. diff --git a/go/vt/vttablet/tabletserver/connpool/pool.go b/go/vt/vttablet/tabletserver/connpool/pool.go index be299367b56..6cb9adf7387 100644 --- a/go/vt/vttablet/tabletserver/connpool/pool.go +++ b/go/vt/vttablet/tabletserver/connpool/pool.go @@ -22,11 +22,11 @@ import ( "net" "strings" "sync" + "sync/atomic" "time" "vitess.io/vitess/go/netutil" "vitess.io/vitess/go/pools" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/trace" "vitess.io/vitess/go/vt/callerid" "vitess.io/vitess/go/vt/dbconfigs" @@ -65,8 +65,8 @@ type Pool struct { idleTimeout time.Duration maxLifetime time.Duration waiterCap int64 - waiterCount sync2.AtomicInt64 - waiterQueueFull sync2.AtomicInt64 + waiterCount atomic.Int64 + waiterQueueFull atomic.Int64 dbaPool *dbconnpool.ConnectionPool appDebugParams dbconfigs.Connector getConnTime *servenv.TimingsWrapper @@ -102,7 +102,7 @@ func NewPool(env tabletenv.Env, name string, cfg tabletenv.ConnPoolConfig) *Pool env.Exporter().NewCounterFunc(name+"IdleClosed", "Tablet server conn pool idle closed", cp.IdleClosed) env.Exporter().NewCounterFunc(name+"MaxLifetimeClosed", "Tablet server conn pool refresh closed", cp.MaxLifetimeClosed) env.Exporter().NewCounterFunc(name+"Exhausted", "Number of times pool had zero available slots", cp.Exhausted) - env.Exporter().NewCounterFunc(name+"WaiterQueueFull", "Number of times the waiter queue was full", cp.waiterQueueFull.Get) + env.Exporter().NewCounterFunc(name+"WaiterQueueFull", "Number of times the waiter queue was full", cp.waiterQueueFull.Load) env.Exporter().NewCounterFunc(name+"Get", "Tablet server conn pool get count", cp.GetCount) env.Exporter().NewCounterFunc(name+"GetSetting", "Tablet server conn pool get with setting count", cp.GetSettingCount) env.Exporter().NewCounterFunc(name+"DiffSetting", "Number of times pool applied different setting", cp.DiffSettingCount) @@ -274,7 +274,7 @@ func (cp *Pool) StatsJSON() string { if closingBraceIndex == -1 { // unexpected... return res } - return fmt.Sprintf(`%s, "WaiterQueueFull": %v}`, res[:closingBraceIndex], cp.waiterQueueFull.Get()) + return fmt.Sprintf(`%s, "WaiterQueueFull": %v}`, res[:closingBraceIndex], cp.waiterQueueFull.Load()) } // Capacity returns the pool capacity. diff --git a/go/vt/vttablet/tabletserver/connpool/pool_test.go b/go/vt/vttablet/tabletserver/connpool/pool_test.go index b07a6ed259a..870af10417a 100644 --- a/go/vt/vttablet/tabletserver/connpool/pool_test.go +++ b/go/vt/vttablet/tabletserver/connpool/pool_test.go @@ -97,7 +97,7 @@ func TestConnPoolMaxWaiters(t *testing.T) { // Wait for the first waiter to increment count. for { runtime.Gosched() - if connPool.waiterCount.Get() == 1 { + if connPool.waiterCount.Load() == 1 { break } } diff --git a/go/vt/vttablet/tabletserver/health_streamer.go b/go/vt/vttablet/tabletserver/health_streamer.go index 436942beaca..ad6119980bf 100644 --- a/go/vt/vttablet/tabletserver/health_streamer.go +++ b/go/vt/vttablet/tabletserver/health_streamer.go @@ -22,6 +22,7 @@ import ( "io" "strings" "sync" + "sync/atomic" "time" "github.com/spf13/pflag" @@ -41,7 +42,6 @@ import ( "google.golang.org/protobuf/proto" "vitess.io/vitess/go/history" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/log" querypb "vitess.io/vitess/go/vt/proto/query" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -74,7 +74,7 @@ func registerHealthStreamerFlags(fs *pflag.FlagSet) { type healthStreamer struct { stats *tabletenv.Stats degradedThreshold time.Duration - unhealthyThreshold sync2.AtomicDuration + unhealthyThreshold atomic.Int64 mu sync.Mutex ctx context.Context @@ -104,11 +104,10 @@ func newHealthStreamer(env tabletenv.Env, alias *topodatapb.TabletAlias) *health IdleTimeoutSeconds: env.Config().OltpReadPool.IdleTimeoutSeconds, }) } - return &healthStreamer{ - stats: env.Stats(), - degradedThreshold: env.Config().Healthcheck.DegradedThresholdSeconds.Get(), - unhealthyThreshold: sync2.NewAtomicDuration(env.Config().Healthcheck.UnhealthyThresholdSeconds.Get()), - clients: make(map[chan *querypb.StreamHealthResponse]struct{}), + hs := &healthStreamer{ + stats: env.Stats(), + degradedThreshold: env.Config().Healthcheck.DegradedThresholdSeconds.Get(), + clients: make(map[chan *querypb.StreamHealthResponse]struct{}), state: &querypb.StreamHealthResponse{ Target: &querypb.Target{}, @@ -124,6 +123,8 @@ func newHealthStreamer(env tabletenv.Env, alias *topodatapb.TabletAlias) *health signalWhenSchemaChange: env.Config().SignalWhenSchemaChange, views: map[string]string{}, } + hs.unhealthyThreshold.Store(env.Config().Healthcheck.UnhealthyThresholdSeconds.Get().Nanoseconds()) + return hs } func (hs *healthStreamer) InitDBConfig(target *querypb.Target, cp dbconfigs.Connector) { @@ -287,7 +288,7 @@ func (hs *healthStreamer) AppendDetails(details []*kv) []*kv { sbm := time.Duration(hs.state.RealtimeStats.ReplicationLagSeconds) * time.Second class := healthyClass switch { - case sbm > hs.unhealthyThreshold.Get(): + case sbm > time.Duration(hs.unhealthyThreshold.Load()): class = unhealthyClass case sbm > hs.degradedThreshold: class = unhappyClass @@ -309,7 +310,7 @@ func (hs *healthStreamer) AppendDetails(details []*kv) []*kv { } func (hs *healthStreamer) SetUnhealthyThreshold(v time.Duration) { - hs.unhealthyThreshold.Set(v) + hs.unhealthyThreshold.Store(v.Nanoseconds()) shr := proto.Clone(hs.state).(*querypb.StreamHealthResponse) for ch := range hs.clients { select { diff --git a/go/vt/vttablet/tabletserver/health_streamer_test.go b/go/vt/vttablet/tabletserver/health_streamer_test.go index c1a36f938e0..c0578eea0ca 100644 --- a/go/vt/vttablet/tabletserver/health_streamer_test.go +++ b/go/vt/vttablet/tabletserver/health_streamer_test.go @@ -21,14 +21,13 @@ import ( "errors" "sort" "sync" + "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/sync2" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/fakesqldb" "vitess.io/vitess/go/sqltypes" @@ -374,14 +373,14 @@ func TestReloadView(t *testing.T) { // setting first test case result. db.AddQuery(mysql.SelectAllViews, tcases[0].res) - var tcCount sync2.AtomicInt32 + var tcCount atomic.Int32 ch := make(chan struct{}) go func() { hs.Stream(ctx, func(response *querypb.StreamHealthResponse) error { if response.RealtimeStats.ViewSchemaChanged != nil { sort.Strings(response.RealtimeStats.ViewSchemaChanged) - assert.Equal(t, tcases[tcCount.Get()].exp, response.RealtimeStats.ViewSchemaChanged) + assert.Equal(t, tcases[tcCount.Load()].exp, response.RealtimeStats.ViewSchemaChanged) tcCount.Add(1) ch <- struct{}{} } @@ -392,10 +391,10 @@ func TestReloadView(t *testing.T) { for { select { case <-ch: - if tcCount.Get() == int32(len(tcases)) { + if tcCount.Load() == int32(len(tcases)) { return } - db.AddQuery(mysql.SelectAllViews, tcases[tcCount.Get()].res) + db.AddQuery(mysql.SelectAllViews, tcases[tcCount.Load()].res) case <-time.After(1000 * time.Second): t.Fatalf("timed out") } diff --git a/go/vt/vttablet/tabletserver/messager/engine.go b/go/vt/vttablet/tabletserver/messager/engine.go index 2fa422c2c7f..2d7fdf2bb82 100644 --- a/go/vt/vttablet/tabletserver/messager/engine.go +++ b/go/vt/vttablet/tabletserver/messager/engine.go @@ -20,8 +20,9 @@ import ( "context" "sync" + "golang.org/x/sync/semaphore" + "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/tabletserver/schema" @@ -56,7 +57,7 @@ type Engine struct { tsv TabletService se *schema.Engine vs VStreamer - postponeSema *sync2.Semaphore + postponeSema *semaphore.Weighted } // NewEngine creates a new Engine. @@ -65,7 +66,7 @@ func NewEngine(tsv TabletService, se *schema.Engine, vs VStreamer) *Engine { tsv: tsv, se: se, vs: vs, - postponeSema: sync2.NewSemaphore(tsv.Config().MessagePostponeParallelism, 0), + postponeSema: semaphore.NewWeighted(int64(tsv.Config().MessagePostponeParallelism)), managers: make(map[string]*messageManager), } } diff --git a/go/vt/vttablet/tabletserver/messager/message_manager.go b/go/vt/vttablet/tabletserver/messager/message_manager.go index e1cb7477c31..39598169baa 100644 --- a/go/vt/vttablet/tabletserver/messager/message_manager.go +++ b/go/vt/vttablet/tabletserver/messager/message_manager.go @@ -25,10 +25,11 @@ import ( "sync" "time" + "golang.org/x/sync/semaphore" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/log" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" @@ -177,7 +178,7 @@ type messageManager struct { batchSize int pollerTicks *timer.Timer purgeTicks *timer.Timer - postponeSema *sync2.Semaphore + postponeSema *semaphore.Weighted mu sync.Mutex isOpen bool @@ -239,7 +240,7 @@ type messageManager struct { // newMessageManager creates a new message manager. // Calls into tsv have to be made asynchronously. Otherwise, // it can lead to deadlocks. -func newMessageManager(tsv TabletService, vs VStreamer, table *schema.Table, postponeSema *sync2.Semaphore) *messageManager { +func newMessageManager(tsv TabletService, vs VStreamer, table *schema.Table, postponeSema *semaphore.Weighted) *messageManager { mm := &messageManager{ tsv: tsv, vs: vs, @@ -573,11 +574,16 @@ func (mm *messageManager) runSend() { // Send the message asynchronously. mm.wg.Add(1) - go mm.send(receiver, &sqltypes.Result{Rows: rows}) // calls the offsetting mm.wg.Done() + go func() { + err := mm.send(context.Background(), receiver, &sqltypes.Result{Rows: rows}) // calls the offsetting mm.wg.Done() + if err != nil { + log.Errorf("messageManager - send failed: %v", err) + } + }() } } -func (mm *messageManager) send(receiver *receiverWithStatus, qr *sqltypes.Result) { +func (mm *messageManager) send(ctx context.Context, receiver *receiverWithStatus, qr *sqltypes.Result) error { defer func() { mm.tsv.LogError() mm.wg.Done() @@ -616,22 +622,23 @@ func (mm *messageManager) send(receiver *receiverWithStatus, qr *sqltypes.Result // big", we'll end up spamming non-stop. log.Errorf("Error sending messages: %v: %v", qr, err) } - mm.postpone(mm.tsv, mm.ackWaitTime, ids) + return mm.postpone(ctx, mm.tsv, mm.ackWaitTime, ids) } -func (mm *messageManager) postpone(tsv TabletService, ackWaitTime time.Duration, ids []string) { +func (mm *messageManager) postpone(ctx context.Context, tsv TabletService, ackWaitTime time.Duration, ids []string) error { // Use the semaphore to limit parallelism. - if !mm.postponeSema.Acquire() { - // Unreachable. - return + if err := mm.postponeSema.Acquire(ctx, 1); err != nil { + // Only happens if context is cancelled. + return err } - defer mm.postponeSema.Release() + defer mm.postponeSema.Release(1) ctx, cancel := context.WithTimeout(tabletenv.LocalContext(), ackWaitTime) defer cancel() if _, err := tsv.PostponeMessages(ctx, nil, mm, ids); err != nil { // This can happen during spikes. Record the incident for monitoring. MessageStats.Add([]string{mm.name.String(), "PostponeFailed"}, 1) } + return nil } func (mm *messageManager) startVStream() { diff --git a/go/vt/vttablet/tabletserver/messager/message_manager_test.go b/go/vt/vttablet/tabletserver/messager/message_manager_test.go index 28ea5b0a38a..d6da59db065 100644 --- a/go/vt/vttablet/tabletserver/messager/message_manager_test.go +++ b/go/vt/vttablet/tabletserver/messager/message_manager_test.go @@ -24,18 +24,17 @@ import ( "reflect" "runtime" "sync" + "sync/atomic" "testing" "time" - "vitess.io/vitess/go/vt/vtgate/evalengine" - - "vitess.io/vitess/go/test/utils" - "github.com/stretchr/testify/assert" + "golang.org/x/sync/semaphore" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" + "vitess.io/vitess/go/test/utils" "vitess.io/vitess/go/vt/sqlparser" + "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/vt/vttablet/tabletserver/schema" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" @@ -108,7 +107,7 @@ func newMMRow(id int64) *querypb.Row { type testReceiver struct { rcv func(*sqltypes.Result) error - count sync2.AtomicInt64 + count atomic.Int64 ch chan *sqltypes.Result } @@ -128,14 +127,14 @@ func (tr *testReceiver) WaitForCount(n int) { for { runtime.Gosched() time.Sleep(10 * time.Millisecond) - if tr.count.Get() == int64(n) { + if tr.count.Load() == int64(n) { return } } } func TestReceiverCancel(t *testing.T) { - mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), newMMTable(), sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), newMMTable(), semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -157,7 +156,7 @@ func TestReceiverCancel(t *testing.T) { } func TestMessageManagerState(t *testing.T) { - mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), newMMTable(), sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), newMMTable(), semaphore.NewWeighted(1)) // Do it twice for i := 0; i < 2; i++ { mm.Open() @@ -175,7 +174,7 @@ func TestMessageManagerState(t *testing.T) { func TestMessageManagerAdd(t *testing.T) { ti := newMMTable() ti.MessageInfo.CacheSize = 1 - mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), ti, sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), ti, semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -206,7 +205,7 @@ func TestMessageManagerAdd(t *testing.T) { func TestMessageManagerSend(t *testing.T) { tsv := newFakeTabletServer() - mm := newMessageManager(tsv, newFakeVStreamer(), newMMTable(), sync2.NewSemaphore(1, 0)) + mm := newMessageManager(tsv, newFakeVStreamer(), newMMTable(), semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -300,7 +299,7 @@ func TestMessageManagerSend(t *testing.T) { func TestMessageManagerPostponeThrottle(t *testing.T) { tsv := newFakeTabletServer() - mm := newMessageManager(tsv, newFakeVStreamer(), newMMTable(), sync2.NewSemaphore(1, 0)) + mm := newMessageManager(tsv, newFakeVStreamer(), newMMTable(), semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -311,7 +310,7 @@ func TestMessageManagerPostponeThrottle(t *testing.T) { // Set the channel to verify call to Postpone. ch := make(chan string) tsv.SetChannel(ch) - tsv.postponeCount.Set(0) + tsv.postponeCount.Store(0) mm.Add(&MessageRow{Row: []sqltypes.Value{sqltypes.NewVarBinary("1"), sqltypes.NULL}}) // Once we receive, mm will obtain the single semaphore and call postpone. @@ -329,7 +328,7 @@ func TestMessageManagerPostponeThrottle(t *testing.T) { time.Sleep(10 * time.Millisecond) } // postponeCount should be 1. Verify for two iterations. - if got, want := tsv.postponeCount.Get(), int64(1); got != want { + if got, want := tsv.postponeCount.Load(), int64(1); got != want { t.Errorf("tsv.postponeCount: %d, want %d", got, want) } @@ -340,7 +339,7 @@ func TestMessageManagerPostponeThrottle(t *testing.T) { runtime.Gosched() time.Sleep(10 * time.Millisecond) } - if got, want := tsv.postponeCount.Get(), int64(1); got != want { + if got, want := tsv.postponeCount.Load(), int64(1); got != want { t.Errorf("tsv.postponeCount: %d, want %d", got, want) } <-ch @@ -348,7 +347,7 @@ func TestMessageManagerPostponeThrottle(t *testing.T) { func TestMessageManagerSendError(t *testing.T) { tsv := newFakeTabletServer() - mm := newMessageManager(tsv, newFakeVStreamer(), newMMTable(), sync2.NewSemaphore(1, 0)) + mm := newMessageManager(tsv, newFakeVStreamer(), newMMTable(), semaphore.NewWeighted(1)) mm.Open() defer mm.Close() ctx := context.Background() @@ -377,7 +376,7 @@ func TestMessageManagerSendError(t *testing.T) { } func TestMessageManagerFieldSendError(t *testing.T) { - mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), newMMTable(), sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), newMMTable(), semaphore.NewWeighted(1)) mm.Open() defer mm.Close() ctx := context.Background() @@ -397,7 +396,7 @@ func TestMessageManagerFieldSendError(t *testing.T) { func TestMessageManagerBatchSend(t *testing.T) { ti := newMMTable() ti.MessageInfo.BatchSize = 2 - mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), ti, sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), ti, semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -467,7 +466,7 @@ func TestMessageManagerStreamerSimple(t *testing.T) { }, { Type: binlogdatapb.VEventType_COMMIT, }}}) - mm := newMessageManager(newFakeTabletServer(), fvs, newMMTable(), sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), fvs, newMMTable(), semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -492,7 +491,7 @@ func TestMessageManagerStreamerAndPoller(t *testing.T) { Fields: testDBFields, Gtid: "MySQL56/33333333-3333-3333-3333-333333333333:1-100", }}) - mm := newMessageManager(newFakeTabletServer(), fvs, newMMTable(), sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), fvs, newMMTable(), semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -589,7 +588,7 @@ func TestMessageManagerPoller(t *testing.T) { newMMRow(3), }, }}) - mm := newMessageManager(newFakeTabletServer(), fvs, ti, sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), fvs, ti, semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -645,7 +644,7 @@ func TestMessagesPending1(t *testing.T) { ti.MessageInfo.CacheSize = 2 ti.MessageInfo.PollInterval = 30 * time.Second fvs := newFakeVStreamer() - mm := newMessageManager(newFakeTabletServer(), fvs, ti, sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), fvs, ti, semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -694,7 +693,7 @@ func TestMessagesPending2(t *testing.T) { }, { Rows: []*querypb.Row{newMMRow(1)}, }}) - mm := newMessageManager(newFakeTabletServer(), fvs, ti, sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), fvs, ti, semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -722,7 +721,7 @@ func TestMessageManagerPurge(t *testing.T) { ti := newMMTable() ti.MessageInfo.PollInterval = 1 * time.Millisecond - mm := newMessageManager(tsv, newFakeVStreamer(), ti, sync2.NewSemaphore(1, 0)) + mm := newMessageManager(tsv, newFakeVStreamer(), ti, semaphore.NewWeighted(1)) mm.Open() defer mm.Close() // Ensure Purge got called. @@ -732,7 +731,7 @@ func TestMessageManagerPurge(t *testing.T) { } func TestMMGenerate(t *testing.T) { - mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), newMMTable(), sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), newMMTable(), semaphore.NewWeighted(1)) mm.Open() defer mm.Close() query, bv := mm.GenerateAckQuery([]string{"1", "2"}) @@ -788,7 +787,7 @@ func TestMMGenerate(t *testing.T) { } func TestMMGenerateWithBackoff(t *testing.T) { - mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), newMMTableWithBackoff(), sync2.NewSemaphore(1, 0)) + mm := newMessageManager(newFakeTabletServer(), newFakeVStreamer(), newMMTableWithBackoff(), semaphore.NewWeighted(1)) mm.Open() defer mm.Close() @@ -824,8 +823,8 @@ func TestMMGenerateWithBackoff(t *testing.T) { type fakeTabletServer struct { tabletenv.Env - postponeCount sync2.AtomicInt64 - purgeCount sync2.AtomicInt64 + postponeCount atomic.Int64 + purgeCount atomic.Int64 mu sync.Mutex ch chan string @@ -869,7 +868,7 @@ func (fts *fakeTabletServer) PurgeMessages(ctx context.Context, target *querypb. } type fakeVStreamer struct { - streamInvocations sync2.AtomicInt64 + streamInvocations atomic.Int64 mu sync.Mutex streamerResponse [][]*binlogdatapb.VEvent pollerResponse []*binlogdatapb.VStreamResultsResponse diff --git a/go/vt/vttablet/tabletserver/query_engine.go b/go/vt/vttablet/tabletserver/query_engine.go index 1a2d62271a6..70335c6353b 100644 --- a/go/vt/vttablet/tabletserver/query_engine.go +++ b/go/vt/vttablet/tabletserver/query_engine.go @@ -155,12 +155,12 @@ type QueryEngine struct { txSerializer *txserializer.TxSerializer // Vars - maxResultSize sync2.AtomicInt64 - warnResultSize sync2.AtomicInt64 - streamBufferSize sync2.AtomicInt64 + maxResultSize atomic.Int64 + warnResultSize atomic.Int64 + streamBufferSize atomic.Int64 // tableaclExemptCount count the number of accesses allowed // based on membership in the superuser ACL - tableaclExemptCount sync2.AtomicInt64 + tableaclExemptCount atomic.Int64 strictTableACL bool enableTableACLDryRun bool // TODO(sougou) There are two acl packages. Need to rename. @@ -168,7 +168,7 @@ type QueryEngine struct { strictTransTables bool - consolidatorMode sync2.AtomicString + consolidatorMode atomic.Value // stats queryCounts, queryTimes, queryErrorCounts, queryRowsAffected, queryRowsReturned *stats.CountersWithMultiLabels @@ -198,7 +198,7 @@ func NewQueryEngine(env tabletenv.Env, se *schema.Engine) *QueryEngine { qe.conns = connpool.NewPool(env, "ConnPool", config.OltpReadPool) qe.streamConns = connpool.NewPool(env, "StreamConnPool", config.OlapReadPool) - qe.consolidatorMode.Set(config.Consolidator) + qe.consolidatorMode.Store(config.Consolidator) qe.consolidator = sync2.NewConsolidator() if config.ConsolidatorStreamTotalSize > 0 && config.ConsolidatorStreamQuerySize > 0 { log.Infof("Stream consolidator is enabled with query size set to %d and total size set to %d.", @@ -227,18 +227,18 @@ func NewQueryEngine(env tabletenv.Env, se *schema.Engine) *QueryEngine { } } - qe.maxResultSize = sync2.NewAtomicInt64(int64(config.Oltp.MaxRows)) - qe.warnResultSize = sync2.NewAtomicInt64(int64(config.Oltp.WarnRows)) - qe.streamBufferSize = sync2.NewAtomicInt64(int64(config.StreamBufferSize)) + qe.maxResultSize.Store(int64(config.Oltp.MaxRows)) + qe.warnResultSize.Store(int64(config.Oltp.WarnRows)) + qe.streamBufferSize.Store(int64(config.StreamBufferSize)) planbuilder.PassthroughDMLs = config.PassthroughDML qe.accessCheckerLogger = logutil.NewThrottledLogger("accessChecker", 1*time.Second) - env.Exporter().NewGaugeFunc("MaxResultSize", "Query engine max result size", qe.maxResultSize.Get) - env.Exporter().NewGaugeFunc("WarnResultSize", "Query engine warn result size", qe.warnResultSize.Get) - env.Exporter().NewGaugeFunc("StreamBufferSize", "Query engine stream buffer size", qe.streamBufferSize.Get) - env.Exporter().NewCounterFunc("TableACLExemptCount", "Query engine table ACL exempt count", qe.tableaclExemptCount.Get) + env.Exporter().NewGaugeFunc("MaxResultSize", "Query engine max result size", qe.maxResultSize.Load) + env.Exporter().NewGaugeFunc("WarnResultSize", "Query engine warn result size", qe.warnResultSize.Load) + env.Exporter().NewGaugeFunc("StreamBufferSize", "Query engine stream buffer size", qe.streamBufferSize.Load) + env.Exporter().NewCounterFunc("TableACLExemptCount", "Query engine table ACL exempt count", qe.tableaclExemptCount.Load) env.Exporter().NewGaugeFunc("QueryCacheLength", "Query engine query cache length", func() int64 { return int64(qe.plans.Len()) diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index b7b198f7f87..61952baa05d 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -108,7 +108,7 @@ func (qre *QueryExecutor) shouldConsolidate() bool { case querypb.ExecuteOptions_CONSOLIDATOR_ENABLED_REPLICAS: return qre.tabletType != topodatapb.TabletType_PRIMARY default: - cm := qre.tsv.qe.consolidatorMode.Get() + cm := qre.tsv.qe.consolidatorMode.Load().(string) return cm == tabletenv.Enable || (cm == tabletenv.NotOnPrimary && qre.tabletType != topodatapb.TabletType_PRIMARY) } } @@ -839,7 +839,7 @@ func (qre *QueryExecutor) execSelect() (*sqltypes.Result, error) { } func (qre *QueryExecutor) execDMLLimit(conn *StatefulConnection) (*sqltypes.Result, error) { - maxrows := qre.tsv.qe.maxResultSize.Get() + maxrows := qre.tsv.qe.maxResultSize.Load() qre.bindVars["#maxLimit"] = sqltypes.Int64BindVariable(maxrows + 1) result, err := qre.txFetch(conn, true) if err != nil { @@ -858,7 +858,7 @@ func (qre *QueryExecutor) verifyRowCount(count, maxrows int64) error { callerID := callerid.ImmediateCallerIDFromContext(qre.ctx) return vterrors.Errorf(vtrpcpb.Code_ABORTED, "caller id: %s: row count exceeded %d", callerID.Username, maxrows) } - warnThreshold := qre.tsv.qe.warnResultSize.Get() + warnThreshold := qre.tsv.qe.warnResultSize.Load() if warnThreshold > 0 && count > warnThreshold { callerID := callerid.ImmediateCallerIDFromContext(qre.ctx) qre.tsv.Stats().Warnings.Add("ResultsExceeded", 1) @@ -1140,7 +1140,7 @@ func (qre *QueryExecutor) execShowThrottlerStatus() (*sqltypes.Result, error) { { sqltypes.NewVarChar(qre.tsv.sm.target.Shard), sqltypes.NewInt32(enabled), - sqltypes.NewFloat64(qre.tsv.lagThrottler.MetricsThreshold.Get()), + sqltypes.NewFloat64(qre.tsv.ThrottleMetricThreshold()), sqltypes.NewVarChar(qre.tsv.lagThrottler.GetMetricsQuery()), }, }, @@ -1161,7 +1161,7 @@ func (qre *QueryExecutor) drainResultSetOnConn(conn *connpool.DBConn) error { } func (qre *QueryExecutor) getSelectLimit() int64 { - return qre.tsv.qe.maxResultSize.Get() + return qre.tsv.qe.maxResultSize.Load() } func (qre *QueryExecutor) execDBConn(conn *connpool.DBConn, sql string, wantfields bool) (*sqltypes.Result, error) { @@ -1174,7 +1174,7 @@ func (qre *QueryExecutor) execDBConn(conn *connpool.DBConn, sql string, wantfiel qre.tsv.statelessql.Add(qd) defer qre.tsv.statelessql.Remove(qd) - return conn.Exec(ctx, sql, int(qre.tsv.qe.maxResultSize.Get()), wantfields) + return conn.Exec(ctx, sql, int(qre.tsv.qe.maxResultSize.Load()), wantfields) } func (qre *QueryExecutor) execStatefulConn(conn *StatefulConnection, sql string, wantfields bool) (*sqltypes.Result, error) { @@ -1187,7 +1187,7 @@ func (qre *QueryExecutor) execStatefulConn(conn *StatefulConnection, sql string, qre.tsv.statefulql.Add(qd) defer qre.tsv.statefulql.Remove(qd) - return conn.Exec(ctx, sql, int(qre.tsv.qe.maxResultSize.Get()), wantfields) + return conn.Exec(ctx, sql, int(qre.tsv.qe.maxResultSize.Load()), wantfields) } func (qre *QueryExecutor) execStreamSQL(conn *connpool.DBConn, isTransaction bool, sql string, callback func(*sqltypes.Result) error) error { @@ -1210,11 +1210,11 @@ func (qre *QueryExecutor) execStreamSQL(conn *connpool.DBConn, isTransaction boo if isTransaction { qre.tsv.statefulql.Add(qd) defer qre.tsv.statefulql.Remove(qd) - return conn.StreamOnce(ctx, sql, callBackClosingSpan, allocStreamResult, int(qre.tsv.qe.streamBufferSize.Get()), sqltypes.IncludeFieldsOrDefault(qre.options)) + return conn.StreamOnce(ctx, sql, callBackClosingSpan, allocStreamResult, int(qre.tsv.qe.streamBufferSize.Load()), sqltypes.IncludeFieldsOrDefault(qre.options)) } qre.tsv.olapql.Add(qd) defer qre.tsv.olapql.Remove(qd) - return conn.Stream(ctx, sql, callBackClosingSpan, allocStreamResult, int(qre.tsv.qe.streamBufferSize.Get()), sqltypes.IncludeFieldsOrDefault(qre.options)) + return conn.Stream(ctx, sql, callBackClosingSpan, allocStreamResult, int(qre.tsv.qe.streamBufferSize.Load()), sqltypes.IncludeFieldsOrDefault(qre.options)) } func (qre *QueryExecutor) recordUserQuery(queryType string, duration int64) { diff --git a/go/vt/vttablet/tabletserver/state_manager.go b/go/vt/vttablet/tabletserver/state_manager.go index 625d2188272..e3a72edeabb 100644 --- a/go/vt/vttablet/tabletserver/state_manager.go +++ b/go/vt/vttablet/tabletserver/state_manager.go @@ -20,18 +20,18 @@ import ( "context" "fmt" "sync" + "sync/atomic" "time" - "vitess.io/vitess/go/vt/servenv" - + "golang.org/x/sync/semaphore" "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/log" querypb "vitess.io/vitess/go/vt/proto/query" topodatapb "vitess.io/vitess/go/vt/proto/topodata" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" ) @@ -76,7 +76,7 @@ type stateManager struct { // If an acquire is successful, we must either Release explicitly // or invoke execTransition, which will release once it's done. // There are no ordering restrictions on using TryAcquire. - transitioning *sync2.Semaphore + transitioning *semaphore.Weighted // mu should be held to access the group of variables under it. // It is required in spite of the transitioning semaphore. @@ -127,11 +127,11 @@ type stateManager struct { // checkMySQLThrottler ensures that CheckMysql // doesn't get spammed. - checkMySQLThrottler *sync2.Semaphore - checkMySQLRunning sync2.AtomicBool + checkMySQLThrottler *semaphore.Weighted + checkMySQLRunning atomic.Bool timebombDuration time.Duration - unhealthyThreshold sync2.AtomicDuration + unhealthyThreshold atomic.Int64 shutdownGracePeriod time.Duration transitionGracePeriod time.Duration } @@ -192,11 +192,11 @@ type ( // Init performs the second phase of initialization. func (sm *stateManager) Init(env tabletenv.Env, target *querypb.Target) { sm.target = proto.Clone(target).(*querypb.Target) - sm.transitioning = sync2.NewSemaphore(1, 0) - sm.checkMySQLThrottler = sync2.NewSemaphore(1, 0) + sm.transitioning = semaphore.NewWeighted(1) + sm.checkMySQLThrottler = semaphore.NewWeighted(1) sm.timebombDuration = env.Config().OltpReadPool.TimeoutSeconds.Get() * 10 sm.hcticks = timer.NewTimer(env.Config().Healthcheck.IntervalSeconds.Get()) - sm.unhealthyThreshold = sync2.NewAtomicDuration(env.Config().Healthcheck.UnhealthyThresholdSeconds.Get()) + sm.unhealthyThreshold.Store(env.Config().Healthcheck.UnhealthyThresholdSeconds.Get().Nanoseconds()) sm.shutdownGracePeriod = env.Config().GracePeriods.ShutdownSeconds.Get() sm.transitionGracePeriod = env.Config().GracePeriods.TransitionSeconds.Get() } @@ -230,7 +230,9 @@ func (sm *stateManager) SetServingType(tabletType topodatapb.TabletType, terTime // already in progress, it waits. If the desired state is already reached, it // returns false without acquiring the semaphore. func (sm *stateManager) mustTransition(tabletType topodatapb.TabletType, terTimestamp time.Time, state servingState, reason string) bool { - sm.transitioning.Acquire() + if sm.transitioning.Acquire(context.Background(), 1) != nil { + return false + } sm.mu.Lock() defer sm.mu.Unlock() @@ -239,14 +241,14 @@ func (sm *stateManager) mustTransition(tabletType topodatapb.TabletType, terTime sm.terTimestamp = terTimestamp sm.reason = reason if sm.target.TabletType == tabletType && sm.state == state { - sm.transitioning.Release() + sm.transitioning.Release(1) return false } return true } func (sm *stateManager) execTransition(tabletType topodatapb.TabletType, state servingState) error { - defer sm.transitioning.Release() + defer sm.transitioning.Release(1) var err error switch state { @@ -301,7 +303,7 @@ func (sm *stateManager) recheckState() bool { sm.retrying = false return true } - if !sm.transitioning.TryAcquire() { + if !sm.transitioning.TryAcquire(1) { return false } go sm.execTransition(sm.wantTabletType, sm.wantState) @@ -312,16 +314,16 @@ func (sm *stateManager) recheckState() bool { // If it fails, then we shutdown the service and initiate // the retry loop. func (sm *stateManager) checkMySQL() { - if !sm.checkMySQLThrottler.TryAcquire() { + if !sm.checkMySQLThrottler.TryAcquire(1) { return } log.Infof("CheckMySQL started") - sm.checkMySQLRunning.Set(true) + sm.checkMySQLRunning.Store(true) go func() { defer func() { time.Sleep(1 * time.Second) - sm.checkMySQLRunning.Set(false) - sm.checkMySQLThrottler.Release() + sm.checkMySQLRunning.Store(false) + sm.checkMySQLThrottler.Release(1) log.Infof("CheckMySQL finished") }() @@ -330,11 +332,11 @@ func (sm *stateManager) checkMySQL() { return } - if !sm.transitioning.TryAcquire() { + if !sm.transitioning.TryAcquire(1) { // If we're already transitioning, don't interfere. return } - defer sm.transitioning.Release() + defer sm.transitioning.Release(1) // This is required to prevent new queries from running in StartRequest // unless they are part of a running transaction. @@ -357,7 +359,7 @@ func (sm *stateManager) setWantState(stateWanted servingState) { // isCheckMySQLRunning returns 1 if CheckMySQL function is in progress func (sm *stateManager) isCheckMySQLRunning() int64 { - if sm.checkMySQLRunning.Get() { + if sm.checkMySQLRunning.Load() { return 1 } return 0 @@ -677,7 +679,7 @@ func (sm *stateManager) refreshReplHealthLocked() (time.Duration, error) { } sm.replHealthy = false } else { - if lag > sm.unhealthyThreshold.Get() { + if lag > time.Duration(sm.unhealthyThreshold.Load()) { if sm.replHealthy { log.Infof("Going unhealthy due to high replication lag: %v", lag) } @@ -806,5 +808,5 @@ func (sm *stateManager) IsServingString() string { } func (sm *stateManager) SetUnhealthyThreshold(v time.Duration) { - sm.unhealthyThreshold.Set(v) + sm.unhealthyThreshold.Store(v.Nanoseconds()) } diff --git a/go/vt/vttablet/tabletserver/state_manager_test.go b/go/vt/vttablet/tabletserver/state_manager_test.go index 5567cc7090a..e06ce4126a1 100644 --- a/go/vt/vttablet/tabletserver/state_manager_test.go +++ b/go/vt/vttablet/tabletserver/state_manager_test.go @@ -20,6 +20,7 @@ import ( "context" "errors" "sync" + "sync/atomic" "testing" "time" @@ -30,7 +31,6 @@ import ( "vitess.io/vitess/go/mysql/fakesqldb" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/log" querypb "vitess.io/vitess/go/vt/proto/query" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -329,9 +329,9 @@ func TestStateManagerTransitionFailRetry(t *testing.T) { // Steal the lock and wait long enough for the retry // to fail, and then release it. The retry will have // to keep retrying. - sm.transitioning.Acquire() + sm.transitioning.Acquire(context.Background(), 1) time.Sleep(30 * time.Millisecond) - sm.transitioning.Release() + sm.transitioning.Release(1) for { sm.mu.Lock() @@ -380,7 +380,7 @@ func (te *delayedTxEngine) Close() { type killableConn struct { id int64 - killed sync2.AtomicBool + killed atomic.Bool } func (k *killableConn) Current() string { @@ -392,7 +392,7 @@ func (k *killableConn) ID() int64 { } func (k *killableConn) Kill(message string, elapsed time.Duration) error { - k.killed.Set(true) + k.killed.Store(true) return nil } @@ -415,15 +415,15 @@ func TestStateManagerShutdownGracePeriod(t *testing.T) { // Transition to replica with no shutdown grace period should kill kconn2 but not kconn1. err := sm.SetServingType(topodatapb.TabletType_PRIMARY, testNow, StateServing, "") require.NoError(t, err) - assert.False(t, kconn1.killed.Get()) - assert.True(t, kconn2.killed.Get()) + assert.False(t, kconn1.killed.Load()) + assert.True(t, kconn2.killed.Load()) // Transition without grace period. No conns should be killed. - kconn2.killed.Set(false) + kconn2.killed.Store(false) err = sm.SetServingType(topodatapb.TabletType_REPLICA, testNow, StateServing, "") require.NoError(t, err) - assert.False(t, kconn1.killed.Get()) - assert.False(t, kconn2.killed.Get()) + assert.False(t, kconn1.killed.Load()) + assert.False(t, kconn2.killed.Load()) // Transition to primary with a short shutdown grace period should kill both conns. err = sm.SetServingType(topodatapb.TabletType_PRIMARY, testNow, StateServing, "") @@ -431,19 +431,19 @@ func TestStateManagerShutdownGracePeriod(t *testing.T) { sm.shutdownGracePeriod = 10 * time.Millisecond err = sm.SetServingType(topodatapb.TabletType_REPLICA, testNow, StateServing, "") require.NoError(t, err) - assert.True(t, kconn1.killed.Get()) - assert.True(t, kconn2.killed.Get()) + assert.True(t, kconn1.killed.Load()) + assert.True(t, kconn2.killed.Load()) // Primary non-serving should also kill the conn. err = sm.SetServingType(topodatapb.TabletType_PRIMARY, testNow, StateServing, "") require.NoError(t, err) sm.shutdownGracePeriod = 10 * time.Millisecond - kconn1.killed.Set(false) - kconn2.killed.Set(false) + kconn1.killed.Store(false) + kconn2.killed.Store(false) err = sm.SetServingType(topodatapb.TabletType_PRIMARY, testNow, StateNotServing, "") require.NoError(t, err) - assert.True(t, kconn1.killed.Get()) - assert.True(t, kconn2.killed.Get()) + assert.True(t, kconn1.killed.Load()) + assert.True(t, kconn2.killed.Load()) } func TestStateManagerCheckMySQL(t *testing.T) { @@ -458,7 +458,7 @@ func TestStateManagerCheckMySQL(t *testing.T) { sm.te = &delayedTxEngine{} sm.qe.(*testQueryEngine).failMySQL = true - order.Set(0) + order.Store(0) sm.checkMySQL() // We know checkMySQL will take atleast 50 milliseconds since txEngine.Close has a sleep in the test code time.Sleep(10 * time.Millisecond) @@ -471,7 +471,7 @@ func TestStateManagerCheckMySQL(t *testing.T) { // Wait for closeAll to get under way. for { - if order.Get() >= 1 { + if order.Load() >= 1 { break } time.Sleep(10 * time.Millisecond) @@ -698,7 +698,7 @@ func verifySubcomponent(t *testing.T, order int64, component any, state testStat } func newTestStateManager(t *testing.T) *stateManager { - order.Set(0) + order.Store(0) config := tabletenv.NewDefaultConfig() env := tabletenv.NewEnv(config, "StateManagerTest") sm := &stateManager{ @@ -726,14 +726,14 @@ func newTestStateManager(t *testing.T) *stateManager { } func (sm *stateManager) isTransitioning() bool { - if sm.transitioning.TryAcquire() { - sm.transitioning.Release() + if sm.transitioning.TryAcquire(1) { + sm.transitioning.Release(1) return false } return true } -var order sync2.AtomicInt64 +var order atomic.Int64 type testState int diff --git a/go/vt/vttablet/tabletserver/stateful_connection_pool.go b/go/vt/vttablet/tabletserver/stateful_connection_pool.go index b1227c82a19..398ad31dfe0 100644 --- a/go/vt/vttablet/tabletserver/stateful_connection_pool.go +++ b/go/vt/vttablet/tabletserver/stateful_connection_pool.go @@ -18,10 +18,10 @@ package tabletserver import ( "context" + "sync/atomic" "time" "vitess.io/vitess/go/pools" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool" @@ -43,7 +43,7 @@ const ( type StatefulConnectionPool struct { env tabletenv.Env - state sync2.AtomicInt64 + state atomic.Int64 // conns is the 'regular' pool. By default, connections // are pulled from here for starting transactions. @@ -55,32 +55,33 @@ type StatefulConnectionPool struct { // connection time. foundRowsPool *connpool.Pool active *pools.Numbered - lastID sync2.AtomicInt64 + lastID atomic.Int64 } // NewStatefulConnPool creates an ActivePool func NewStatefulConnPool(env tabletenv.Env) *StatefulConnectionPool { config := env.Config() - return &StatefulConnectionPool{ + scp := &StatefulConnectionPool{ env: env, conns: connpool.NewPool(env, "TransactionPool", config.TxPool), foundRowsPool: connpool.NewPool(env, "FoundRowsPool", config.TxPool), active: pools.NewNumbered(), - lastID: sync2.NewAtomicInt64(time.Now().UnixNano()), } + scp.lastID.Store(time.Now().UnixNano()) + return scp } // Open makes the TxPool operational. This also starts the transaction killer // that will kill long-running transactions. func (sf *StatefulConnectionPool) Open(appParams, dbaParams, appDebugParams dbconfigs.Connector) { - log.Infof("Starting transaction id: %d", sf.lastID) + log.Infof("Starting transaction id: %d", sf.lastID.Load()) sf.conns.Open(appParams, dbaParams, appDebugParams) foundRowsParam, _ := appParams.MysqlParams() foundRowsParam.EnableClientFoundRows() appParams = dbconfigs.New(foundRowsParam) sf.foundRowsPool.Open(appParams, dbaParams, appDebugParams) - sf.state.Set(scpOpen) + sf.state.Store(scpOpen) } // Close closes the TxPool. A closed pool can be reopened. @@ -98,13 +99,13 @@ func (sf *StatefulConnectionPool) Close() { } sf.conns.Close() sf.foundRowsPool.Close() - sf.state.Set(scpClosed) + sf.state.Store(scpClosed) } // ShutdownNonTx enters the state where all non-transactional connections are killed. // InUse connections will be killed as they are returned. func (sf *StatefulConnectionPool) ShutdownNonTx() { - sf.state.Set(scpKillingNonTx) + sf.state.Store(scpKillingNonTx) conns := mapToTxConn(sf.active.GetByFilter("kill non-tx", func(sc any) bool { return !sc.(*StatefulConnection).IsInTransaction() })) @@ -117,7 +118,7 @@ func (sf *StatefulConnectionPool) ShutdownNonTx() { // It returns all connections that are not in use. They must be rolled back // by the caller (TxPool). InUse connections will be killed as they are returned. func (sf *StatefulConnectionPool) ShutdownAll() []*StatefulConnection { - sf.state.Set(scpKillingAll) + sf.state.Store(scpKillingAll) return mapToTxConn(sf.active.GetByFilter("kill non-tx", func(sc any) bool { return true })) @@ -127,9 +128,9 @@ func (sf *StatefulConnectionPool) ShutdownAll() []*StatefulConnection { // as large as the input value. This will ensure that there are // no dtid collisions with future transactions. func (sf *StatefulConnectionPool) AdjustLastID(id int64) { - if current := sf.lastID.Get(); current < id { + if current := sf.lastID.Load(); current < id { log.Infof("Adjusting transaction id to: %d", id) - sf.lastID.Set(id) + sf.lastID.Store(id) } } @@ -219,7 +220,7 @@ func (sf *StatefulConnectionPool) unregister(id tx.ConnID, reason string) { // markAsNotInUse marks the connection as not in use at the moment func (sf *StatefulConnectionPool) markAsNotInUse(sc *StatefulConnection, updateTime bool) { - switch sf.state.Get() { + switch sf.state.Load() { case scpKillingNonTx: if !sc.IsInTransaction() { sc.Releasef("kill non-tx") diff --git a/go/vt/vttablet/tabletserver/stateful_connection_pool_test.go b/go/vt/vttablet/tabletserver/stateful_connection_pool_test.go index 13b62e9dec4..79e70dc4ffe 100644 --- a/go/vt/vttablet/tabletserver/stateful_connection_pool_test.go +++ b/go/vt/vttablet/tabletserver/stateful_connection_pool_test.go @@ -205,7 +205,7 @@ func TestFailOnConnectionRegistering(t *testing.T) { require.NoError(t, err) defer conn.Close() - pool.lastID.Set(conn.ConnID - 1) + pool.lastID.Store(conn.ConnID - 1) _, err = pool.NewConn(ctx, &querypb.ExecuteOptions{}, nil) require.Error(t, err, "already present") diff --git a/go/vt/vttablet/tabletserver/status.go b/go/vt/vttablet/tabletserver/status.go index 7016f379292..aef46100d62 100644 --- a/go/vt/vttablet/tabletserver/status.go +++ b/go/vt/vttablet/tabletserver/status.go @@ -22,9 +22,9 @@ import ( "fmt" "net/http" "strings" + "sync/atomic" "time" - "vitess.io/vitess/go/sync2" topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) @@ -229,8 +229,8 @@ func (tsv *TabletServer) AddStatusHeader() { // AddStatusPart registers the status part for the status page. func (tsv *TabletServer) AddStatusPart() { // Save the threshold values for reporting. - degradedThreshold.Set(tsv.config.Healthcheck.DegradedThresholdSeconds.Get()) - unhealthyThreshold.Set(tsv.config.Healthcheck.UnhealthyThresholdSeconds.Get()) + degradedThreshold.Store(tsv.config.Healthcheck.DegradedThresholdSeconds.Get().Nanoseconds()) + unhealthyThreshold.Store(tsv.config.Healthcheck.UnhealthyThresholdSeconds.Get().Nanoseconds()) tsv.exporter.AddStatusPart("Health", queryserviceStatusTemplate, func() any { status := queryserviceStatus{ @@ -266,8 +266,8 @@ func (tsv *TabletServer) AddStatusPart() { }) } -var degradedThreshold sync2.AtomicDuration -var unhealthyThreshold sync2.AtomicDuration +var degradedThreshold atomic.Int64 +var unhealthyThreshold atomic.Int64 type historyRecord struct { Time time.Time @@ -279,7 +279,7 @@ type historyRecord struct { func (r *historyRecord) Class() string { if r.serving { - if r.lag > degradedThreshold.Get() { + if r.lag > time.Duration(degradedThreshold.Load()) { return unhappyClass } return healthyClass @@ -289,12 +289,12 @@ func (r *historyRecord) Class() string { func (r *historyRecord) Status() string { if r.serving { - if r.lag > degradedThreshold.Get() { + if r.lag > time.Duration(degradedThreshold.Load()) { return fmt.Sprintf("replication delayed: %v", r.lag) } return "healthy" } - if r.lag > unhealthyThreshold.Get() { + if r.lag > time.Duration(unhealthyThreshold.Load()) { return fmt.Sprintf("not serving: replication delay %v", r.lag) } if r.err != nil { diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index c9c5146783c..c000799c0e4 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -28,6 +28,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "syscall" "time" @@ -38,7 +39,6 @@ import ( "vitess.io/vitess/go/pools" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/tb" "vitess.io/vitess/go/trace" "vitess.io/vitess/go/vt/callerid" @@ -96,7 +96,7 @@ type TabletServer struct { exporter *servenv.Exporter config *tabletenv.TabletConfig stats *tabletenv.Stats - QueryTimeout sync2.AtomicDuration + QueryTimeout atomic.Int64 TerseErrors bool enableHotRowProtection bool topoServer *topo.Server @@ -154,12 +154,12 @@ func NewTabletServer(name string, config *tabletenv.TabletConfig, topoServer *to exporter: exporter, stats: tabletenv.NewStats(exporter), config: config, - QueryTimeout: sync2.NewAtomicDuration(config.Oltp.QueryTimeoutSeconds.Get()), TerseErrors: config.TerseErrors, enableHotRowProtection: config.HotRowProtection.Mode != tabletenv.Disable, topoServer: topoServer, alias: proto.Clone(alias).(*topodatapb.TabletAlias), } + tsv.QueryTimeout.Store(config.Oltp.QueryTimeoutSeconds.Get().Nanoseconds()) tsOnce.Do(func() { srvTopoServer = srvtopo.NewResilientServer(topoServer, "TabletSrvTopo") }) @@ -216,7 +216,7 @@ func NewTabletServer(name string, config *tabletenv.TabletConfig, topoServer *to tsv.exporter.NewGaugesFuncWithMultiLabels("TabletServerState", "Tablet server state labeled by state name", []string{"name"}, func() map[string]int64 { return map[string]int64{tsv.sm.IsServingString(): 1} }) - tsv.exporter.NewGaugeDurationFunc("QueryTimeout", "Tablet server query timeout", tsv.QueryTimeout.Get) + tsv.exporter.NewGaugeDurationFunc("QueryTimeout", "Tablet server query timeout", tsv.loadQueryTimeout) tsv.registerHealthzHealthHandler() tsv.registerDebugHealthHandler() @@ -230,6 +230,10 @@ func NewTabletServer(name string, config *tabletenv.TabletConfig, topoServer *to return tsv } +func (tsv *TabletServer) loadQueryTimeout() time.Duration { + return time.Duration(tsv.QueryTimeout.Load()) +} + // onlineDDLExecutorToggleTableBuffer is called by onlineDDLExecutor as a callback function. onlineDDLExecutor // uses it to start/stop query buffering for a given table. // It is onlineDDLExecutor's responsibility to make sure beffering is stopped after some definite amount of time. @@ -486,7 +490,7 @@ func (tsv *TabletServer) Begin(ctx context.Context, target *querypb.Target, opti func (tsv *TabletServer) begin(ctx context.Context, target *querypb.Target, savepointQueries []string, reservedID int64, settings []string, options *querypb.ExecuteOptions) (state queryservice.TransactionState, err error) { state.TabletAlias = tsv.alias err = tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "Begin", "begin", nil, target, options, false, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -526,7 +530,7 @@ func (tsv *TabletServer) begin(ctx context.Context, target *querypb.Target, save // Commit commits the specified transaction. func (tsv *TabletServer) Commit(ctx context.Context, target *querypb.Target, transactionID int64) (newReservedID int64, err error) { err = tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "Commit", "commit", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -557,7 +561,7 @@ func (tsv *TabletServer) Commit(ctx context.Context, target *querypb.Target, tra // Rollback rollsback the specified transaction. func (tsv *TabletServer) Rollback(ctx context.Context, target *querypb.Target, transactionID int64) (newReservedID int64, err error) { err = tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "Rollback", "rollback", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -577,7 +581,7 @@ func (tsv *TabletServer) Rollback(ctx context.Context, target *querypb.Target, t // Prepare prepares the specified transaction. func (tsv *TabletServer) Prepare(ctx context.Context, target *querypb.Target, transactionID int64, dtid string) (err error) { return tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "Prepare", "prepare", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -594,7 +598,7 @@ func (tsv *TabletServer) Prepare(ctx context.Context, target *querypb.Target, tr // CommitPrepared commits the prepared transaction. func (tsv *TabletServer) CommitPrepared(ctx context.Context, target *querypb.Target, dtid string) (err error) { return tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "CommitPrepared", "commit_prepared", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -611,7 +615,7 @@ func (tsv *TabletServer) CommitPrepared(ctx context.Context, target *querypb.Tar // RollbackPrepared commits the prepared transaction. func (tsv *TabletServer) RollbackPrepared(ctx context.Context, target *querypb.Target, dtid string, originalID int64) (err error) { return tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "RollbackPrepared", "rollback_prepared", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -628,7 +632,7 @@ func (tsv *TabletServer) RollbackPrepared(ctx context.Context, target *querypb.T // CreateTransaction creates the metadata for a 2PC transaction. func (tsv *TabletServer) CreateTransaction(ctx context.Context, target *querypb.Target, dtid string, participants []*querypb.Target) (err error) { return tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "CreateTransaction", "create_transaction", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -646,7 +650,7 @@ func (tsv *TabletServer) CreateTransaction(ctx context.Context, target *querypb. // decision to commit the associated 2pc transaction. func (tsv *TabletServer) StartCommit(ctx context.Context, target *querypb.Target, transactionID int64, dtid string) (err error) { return tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "StartCommit", "start_commit", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -664,7 +668,7 @@ func (tsv *TabletServer) StartCommit(ctx context.Context, target *querypb.Target // If a transaction id is provided, that transaction is also rolled back. func (tsv *TabletServer) SetRollback(ctx context.Context, target *querypb.Target, dtid string, transactionID int64) (err error) { return tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "SetRollback", "set_rollback", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -682,7 +686,7 @@ func (tsv *TabletServer) SetRollback(ctx context.Context, target *querypb.Target // essentially resolving it. func (tsv *TabletServer) ConcludeTransaction(ctx context.Context, target *querypb.Target, dtid string) (err error) { return tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "ConcludeTransaction", "conclude_transaction", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -699,7 +703,7 @@ func (tsv *TabletServer) ConcludeTransaction(ctx context.Context, target *queryp // ReadTransaction returns the metadata for the specified dtid. func (tsv *TabletServer) ReadTransaction(ctx context.Context, target *querypb.Target, dtid string) (metadata *querypb.TransactionMetadata, err error) { err = tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "ReadTransaction", "read_transaction", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -730,7 +734,7 @@ func (tsv *TabletServer) Execute(ctx context.Context, target *querypb.Target, sq func (tsv *TabletServer) execute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, transactionID int64, reservedID int64, settings []string, options *querypb.ExecuteOptions) (result *sqltypes.Result, err error) { allowOnShutdown := false - timeout := tsv.QueryTimeout.Get() + timeout := tsv.loadQueryTimeout() if transactionID != 0 { allowOnShutdown = true // Execute calls happen for OLTP only, so we can directly fetch the @@ -953,7 +957,7 @@ func (tsv *TabletServer) beginWaitForSameRangeTransactions(ctx context.Context, err := tsv.execRequest( // Use (potentially longer) -queryserver-config-query-timeout and not // -queryserver-config-txpool-timeout (defaults to 1s) to limit the waiting. - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "", "waitForSameRangeTransactions", nil, target, options, false, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -1164,7 +1168,7 @@ func (tsv *TabletServer) ReserveBeginExecute(ctx context.Context, target *queryp state.TabletAlias = tsv.alias err = tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "ReserveBegin", "begin", bindVariables, target, options, false, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -1209,7 +1213,7 @@ func (tsv *TabletServer) ReserveBeginStreamExecute( var sessionStateChanges string err = tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "ReserveBegin", "begin", bindVariables, target, options, false, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -1251,7 +1255,7 @@ func (tsv *TabletServer) ReserveExecute(ctx context.Context, target *querypb.Tar state.TabletAlias = tsv.alias allowOnShutdown := false - timeout := tsv.QueryTimeout.Get() + timeout := tsv.loadQueryTimeout() if transactionID != 0 { allowOnShutdown = true // ReserveExecute is for OLTP only, so we can directly fetch the OLTP @@ -1341,7 +1345,7 @@ func (tsv *TabletServer) Release(ctx context.Context, target *querypb.Target, tr return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.NoSuchSession, "connection ID and transaction ID do not exist") } return tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "Release", "", nil, target, nil, true, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -1398,7 +1402,7 @@ func txToReserveState(state queryservice.TransactionState) queryservice.Reserved // GetSchema returns table definitions for the specified tables. func (tsv *TabletServer) GetSchema(ctx context.Context, target *querypb.Target, tableType querypb.SchemaTableType, tableNames []string) (schemaDef map[string]string, err error) { err = tsv.execRequest( - ctx, tsv.QueryTimeout.Get(), + ctx, tsv.loadQueryTimeout(), "GetSchema", "", nil, target, nil, false, /* allowOnShutdown */ func(ctx context.Context, logStats *tabletenv.LogStats) error { @@ -1974,32 +1978,32 @@ func (tsv *TabletServer) QueryPlanCacheWait() { // SetMaxResultSize changes the max result size to the specified value. func (tsv *TabletServer) SetMaxResultSize(val int) { - tsv.qe.maxResultSize.Set(int64(val)) + tsv.qe.maxResultSize.Store(int64(val)) } // MaxResultSize returns the max result size. func (tsv *TabletServer) MaxResultSize() int { - return int(tsv.qe.maxResultSize.Get()) + return int(tsv.qe.maxResultSize.Load()) } // SetWarnResultSize changes the warn result size to the specified value. func (tsv *TabletServer) SetWarnResultSize(val int) { - tsv.qe.warnResultSize.Set(int64(val)) + tsv.qe.warnResultSize.Store(int64(val)) } // WarnResultSize returns the warn result size. func (tsv *TabletServer) WarnResultSize() int { - return int(tsv.qe.warnResultSize.Get()) + return int(tsv.qe.warnResultSize.Load()) } // SetThrottleMetricThreshold changes the throttler metric threshold func (tsv *TabletServer) SetThrottleMetricThreshold(val float64) { - tsv.lagThrottler.MetricsThreshold.Set(val) + tsv.lagThrottler.StoreMetricsThreshold(val) } // ThrottleMetricThreshold returns the throttler metric threshold func (tsv *TabletServer) ThrottleMetricThreshold() float64 { - return tsv.lagThrottler.MetricsThreshold.Get() + return time.Duration(tsv.lagThrottler.MetricsThreshold.Load()).Seconds() } // SetPassthroughDMLs changes the setting to pass through all DMLs @@ -2012,13 +2016,13 @@ func (tsv *TabletServer) SetPassthroughDMLs(val bool) { func (tsv *TabletServer) SetConsolidatorMode(mode string) { switch mode { case tabletenv.NotOnPrimary, tabletenv.Enable, tabletenv.Disable: - tsv.qe.consolidatorMode.Set(mode) + tsv.qe.consolidatorMode.Store(mode) } } // ConsolidatorMode returns the consolidator mode. func (tsv *TabletServer) ConsolidatorMode() string { - return tsv.qe.consolidatorMode.Get() + return tsv.qe.consolidatorMode.Load().(string) } // queryAsString returns a readable normalized version of the query and if sanitize diff --git a/go/vt/vttablet/tabletserver/tabletserver_test.go b/go/vt/vttablet/tabletserver/tabletserver_test.go index ac6b20cab8a..7cb2a3d4ee2 100644 --- a/go/vt/vttablet/tabletserver/tabletserver_test.go +++ b/go/vt/vttablet/tabletserver/tabletserver_test.go @@ -224,7 +224,7 @@ func TestTabletServerRedoLogIsKeptBetweenRestarts(t *testing.T) { turnOffTxEngine() assert.Empty(t, tsv.te.preparedPool.conns, "tsv.te.preparedPool.conns") - tsv.te.txPool.scp.lastID.Set(1) + tsv.te.txPool.scp.lastID.Store(1) // Ensure we continue past errors. db.AddQuery(tpc.readAllRedo, &sqltypes.Result{ Fields: []*querypb.Field{ @@ -260,7 +260,7 @@ func TestTabletServerRedoLogIsKeptBetweenRestarts(t *testing.T) { t.Errorf("Failed dtids: %v, want %v", tsv.te.preparedPool.reserved, wantFailed) } // Verify last id got adjusted. - assert.EqualValues(t, 20, tsv.te.txPool.scp.lastID.Get(), "tsv.te.txPool.lastID.Get()") + assert.EqualValues(t, 20, tsv.te.txPool.scp.lastID.Load(), "tsv.te.txPool.lastID.Get()") turnOffTxEngine() assert.Empty(t, tsv.te.preparedPool.conns, "tsv.te.preparedPool.conns") } @@ -1833,7 +1833,7 @@ func TestConfigChanges(t *testing.T) { if val := tsv.MaxResultSize(); val != newSize { t.Errorf("MaxResultSize: %d, want %d", val, newSize) } - if val := int(tsv.qe.maxResultSize.Get()); val != newSize { + if val := int(tsv.qe.maxResultSize.Load()); val != newSize { t.Errorf("tsv.qe.maxResultSize.Get: %d, want %d", val, newSize) } @@ -1841,7 +1841,7 @@ func TestConfigChanges(t *testing.T) { if val := tsv.WarnResultSize(); val != newSize { t.Errorf("WarnResultSize: %d, want %d", val, newSize) } - if val := int(tsv.qe.warnResultSize.Get()); val != newSize { + if val := int(tsv.qe.warnResultSize.Load()); val != newSize { t.Errorf("tsv.qe.warnResultSize.Get: %d, want %d", val, newSize) } } diff --git a/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go b/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go index 73407fe6f49..8ade7f61c09 100644 --- a/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go +++ b/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go @@ -6,7 +6,9 @@ package config -import "vitess.io/vitess/go/sync2" +import ( + "sync/atomic" +) // // MySQL-specific configuration @@ -15,22 +17,22 @@ import "vitess.io/vitess/go/sync2" // MySQLClusterConfigurationSettings has the settings for a specific MySQL cluster. It derives its information // from MySQLConfigurationSettings type MySQLClusterConfigurationSettings struct { - MetricQuery string // override MySQLConfigurationSettings's, or leave empty to inherit those settings - CacheMillis int // override MySQLConfigurationSettings's, or leave empty to inherit those settings - ThrottleThreshold *sync2.AtomicFloat64 // override MySQLConfigurationSettings's, or leave empty to inherit those settings - Port int // Specify if different than 3306 or if different than specified by MySQLConfigurationSettings - IgnoreHostsCount int // Number of hosts that can be skipped/ignored even on error or on exceeding thresholds - IgnoreHostsThreshold float64 // Threshold beyond which IgnoreHostsCount applies (default: 0) - HTTPCheckPort int // Specify if different than specified by MySQLConfigurationSettings. -1 to disable HTTP check - HTTPCheckPath string // Specify if different than specified by MySQLConfigurationSettings - IgnoreHosts []string // override MySQLConfigurationSettings's, or leave empty to inherit those settings + MetricQuery string // override MySQLConfigurationSettings's, or leave empty to inherit those settings + CacheMillis int // override MySQLConfigurationSettings's, or leave empty to inherit those settings + ThrottleThreshold *atomic.Int64 // override MySQLConfigurationSettings's, or leave empty to inherit those settings + Port int // Specify if different than 3306 or if different than specified by MySQLConfigurationSettings + IgnoreHostsCount int // Number of hosts that can be skipped/ignored even on error or on exceeding thresholds + IgnoreHostsThreshold float64 // Threshold beyond which IgnoreHostsCount applies (default: 0) + HTTPCheckPort int // Specify if different than specified by MySQLConfigurationSettings. -1 to disable HTTP check + HTTPCheckPath string // Specify if different than specified by MySQLConfigurationSettings + IgnoreHosts []string // override MySQLConfigurationSettings's, or leave empty to inherit those settings } // MySQLConfigurationSettings has the general configuration for all MySQL clusters type MySQLConfigurationSettings struct { MetricQuery string CacheMillis int // optional, if defined then probe result will be cached, and future probes may use cached value - ThrottleThreshold *sync2.AtomicFloat64 + ThrottleThreshold *atomic.Int64 Port int // Specify if different than 3306; applies to all clusters IgnoreDialTCPErrors bool // Skip hosts where a metric cannot be retrieved due to TCP dial errors IgnoreHostsCount int // Number of hosts that can be skipped/ignored even on error or on exceeding thresholds diff --git a/go/vt/vttablet/tabletserver/throttle/throttler.go b/go/vt/vttablet/tabletserver/throttle/throttler.go index cbec6893e27..78b425be0ac 100644 --- a/go/vt/vttablet/tabletserver/throttle/throttler.go +++ b/go/vt/vttablet/tabletserver/throttle/throttler.go @@ -24,7 +24,6 @@ import ( "github.com/patrickmn/go-cache" "github.com/spf13/pflag" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/textutil" "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/log" @@ -135,7 +134,7 @@ type Throttler struct { mysqlInventory *mysql.Inventory metricsQuery atomic.Value - MetricsThreshold sync2.AtomicFloat64 + MetricsThreshold atomic.Int64 mysqlClusterThresholds *cache.Cache aggregatedMetrics *cache.Cache @@ -206,9 +205,9 @@ func NewThrottler(env tabletenv.Env, srvTopoServer srvtopo.Server, ts *topo.Serv if throttleMetricQuery != "" { throttler.metricsQuery.Store(throttleMetricQuery) // override } - throttler.MetricsThreshold = sync2.NewAtomicFloat64(throttleThreshold.Seconds()) //default + throttler.MetricsThreshold.Store(throttleThreshold.Nanoseconds()) //default if throttleMetricThreshold != math.MaxFloat64 { - throttler.MetricsThreshold.Set(throttleMetricThreshold) // override + throttler.StoreMetricsThreshold(throttleMetricThreshold) // override } throttler.initConfig() @@ -225,6 +224,10 @@ func (throttler *Throttler) CheckIsReady() error { return ErrThrottlerNotReady } +func (throttler *Throttler) StoreMetricsThreshold(threshold float64) { + throttler.MetricsThreshold.Store(time.Duration(throttleMetricThreshold * float64(time.Second)).Nanoseconds()) +} + // initThrottleTabletTypes reads the user supplied throttle_tablet_types and sets these // for the duration of this tablet's lifetime func (throttler *Throttler) initThrottleTabletTypes() { @@ -338,7 +341,7 @@ func (throttler *Throttler) applyThrottlerConfig(ctx context.Context, throttlerC } else { throttler.metricsQuery.Store(throttlerConfig.CustomQuery) } - throttler.MetricsThreshold.Set(throttlerConfig.Threshold) + throttler.MetricsThreshold.Store(time.Duration(throttlerConfig.Threshold * float64(time.Second)).Nanoseconds()) throttlerCheckAsCheckSelf = throttlerConfig.CheckAsCheckSelf if throttlerConfig.Enabled { go throttler.Enable(ctx) @@ -724,7 +727,7 @@ func (throttler *Throttler) refreshMySQLInventory(ctx context.Context) error { // distribute the query/threshold from the throttler down to the cluster settings and from there to the probes metricsQuery := throttler.GetMetricsQuery() - metricsThreshold := throttler.MetricsThreshold.Get() + metricsThreshold := throttler.MetricsThreshold.Load() addInstanceKey := func(tabletHost string, tabletPort int, key *mysql.InstanceKey, clusterName string, clusterSettings *config.MySQLClusterConfigurationSettings, probes *mysql.Probes) { for _, ignore := range clusterSettings.IgnoreHosts { if strings.Contains(key.StringCode(), ignore) { @@ -751,11 +754,11 @@ func (throttler *Throttler) refreshMySQLInventory(ctx context.Context) error { clusterName := clusterName clusterSettings := clusterSettings clusterSettings.MetricQuery = metricsQuery - clusterSettings.ThrottleThreshold.Set(metricsThreshold) + clusterSettings.ThrottleThreshold.Store(metricsThreshold) // config may dynamically change, but internal structure (config.Settings().Stores.MySQL.Clusters in our case) // is immutable and can only be _replaced_. Hence, it's safe to read in a goroutine: go func() { - throttler.mysqlClusterThresholds.Set(clusterName, clusterSettings.ThrottleThreshold.Get(), cache.DefaultExpiration) + throttler.mysqlClusterThresholds.Set(clusterName, time.Duration(clusterSettings.ThrottleThreshold.Load()).Seconds(), cache.DefaultExpiration) clusterProbes := &mysql.ClusterProbes{ ClusterName: clusterName, IgnoreHostsCount: clusterSettings.IgnoreHostsCount, diff --git a/go/vt/vttablet/tabletserver/tx_engine_test.go b/go/vt/vttablet/tabletserver/tx_engine_test.go index 76eeaee445f..c3d84dd2d5a 100644 --- a/go/vt/vttablet/tabletserver/tx_engine_test.go +++ b/go/vt/vttablet/tabletserver/tx_engine_test.go @@ -207,7 +207,7 @@ func TestTxEngineRenewFails(t *testing.T) { conn2, err := te.txPool.scp.NewConn(ctx, options, nil) require.NoError(t, err) defer conn2.Release(tx.TxCommit) - te.txPool.scp.lastID.Set(conn2.ConnID - 1) + te.txPool.scp.lastID.Store(conn2.ConnID - 1) // commit will do a renew dbConn := conn.dbConn diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go index 7cc98794312..25a41a5f0a9 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go +++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go @@ -32,7 +32,6 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/binlog" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" @@ -55,14 +54,6 @@ const ( // between the two timeouts. var HeartbeatTime = 900 * time.Millisecond -// vschemaUpdateCount is for testing only. -// vstreamer is a mutex free data structure. So, it's not safe to access its members -// from a test. Since VSchema gets updated asynchronously, there's no way for a test -// to wait for it. Instead, the code that updates the vschema increments this atomic -// counter, which will let the tests poll for it to change. -// TODO(sougou): find a better way for this. -var vschemaUpdateCount sync2.AtomicInt64 - // vstreamer is for serving a single vreplication stream on the source side. type vstreamer struct { ctx context.Context @@ -385,8 +376,6 @@ func (vs *vstreamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog if err := vs.rebuildPlans(); err != nil { return err } - // Increment this counter for testing. - vschemaUpdateCount.Add(1) } case err := <-errs: return err diff --git a/go/vt/wrangler/fake_tablet_test.go b/go/vt/wrangler/fake_tablet_test.go index f0ce1d6704c..8ffae2d7328 100644 --- a/go/vt/wrangler/fake_tablet_test.go +++ b/go/vt/wrangler/fake_tablet_test.go @@ -135,7 +135,7 @@ func newFakeTablet(t *testing.T, wr *Wrangler, cell string, uid uint32, tabletTy // create a FakeMysqlDaemon with the right information by default fakeMysqlDaemon := mysqlctl.NewFakeMysqlDaemon(db) - fakeMysqlDaemon.MysqlPort.Set(mysqlPort) + fakeMysqlDaemon.MysqlPort.Store(mysqlPort) return &fakeTablet{ Tablet: tablet, diff --git a/go/vt/wrangler/testlib/external_reparent_test.go b/go/vt/wrangler/testlib/external_reparent_test.go index a0c065261a0..2f17dfa2488 100644 --- a/go/vt/wrangler/testlib/external_reparent_test.go +++ b/go/vt/wrangler/testlib/external_reparent_test.go @@ -244,7 +244,7 @@ func TestTabletExternallyReparentedWithDifferentMysqlPort(t *testing.T) { // On the elected primary, we will respond to // TabletActionReplicaWasPromoted, so we need a MysqlDaemon // that returns no primary, and the new port (as returned by mysql) - newPrimary.FakeMysqlDaemon.MysqlPort.Set(3303) + newPrimary.FakeMysqlDaemon.MysqlPort.Store(3303) newPrimary.StartActionLoop(t, wr) defer newPrimary.StopActionLoop(t) diff --git a/go/vt/wrangler/testlib/fake_tablet.go b/go/vt/wrangler/testlib/fake_tablet.go index ae8f086d78d..0e4d38f59fc 100644 --- a/go/vt/wrangler/testlib/fake_tablet.go +++ b/go/vt/wrangler/testlib/fake_tablet.go @@ -160,7 +160,7 @@ func NewFakeTablet(t *testing.T, wr *wrangler.Wrangler, cell string, uid uint32, // create a FakeMysqlDaemon with the right information by default fakeMysqlDaemon := mysqlctl.NewFakeMysqlDaemon(db) - fakeMysqlDaemon.MysqlPort.Set(mysqlPort) + fakeMysqlDaemon.MysqlPort.Store(mysqlPort) return &FakeTablet{ Tablet: tablet, diff --git a/go/vt/wrangler/traffic_switcher_env_test.go b/go/vt/wrangler/traffic_switcher_env_test.go index dd248f2fe26..713df942cc1 100644 --- a/go/vt/wrangler/traffic_switcher_env_test.go +++ b/go/vt/wrangler/traffic_switcher_env_test.go @@ -17,22 +17,20 @@ limitations under the License. package wrangler import ( + "context" "fmt" "sync" "testing" "time" - "vitess.io/vitess/go/sync2" - "vitess.io/vitess/go/vt/log" - - "vitess.io/vitess/go/mysql/fakesqldb" - - "context" + "golang.org/x/sync/semaphore" "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/fakesqldb" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/key" + "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -108,7 +106,7 @@ func newTestTableMigraterCustom(ctx context.Context, t *testing.T, sourceShards, tme := &testMigraterEnv{} tme.ts = memorytopo.NewServer("cell1", "cell2") tme.wr = New(logutil.NewConsoleLogger(), tme.ts, tmclient.NewTabletManagerClient()) - tme.wr.sem = sync2.NewSemaphore(1, 1) + tme.wr.sem = semaphore.NewWeighted(1) tme.sourceShards = sourceShards tme.targetShards = targetShards tme.tmeDB = fakesqldb.New(t) @@ -271,7 +269,7 @@ func newTestShardMigrater(ctx context.Context, t *testing.T, sourceShards, targe tme.sourceShards = sourceShards tme.targetShards = targetShards tme.tmeDB = fakesqldb.New(t) - tme.wr.sem = sync2.NewSemaphore(1, 0) + tme.wr.sem = semaphore.NewWeighted(1) tabletID := 10 for _, shard := range sourceShards { diff --git a/go/vt/wrangler/workflow.go b/go/vt/wrangler/workflow.go index 0d627c7e954..0cbe1dc2062 100644 --- a/go/vt/wrangler/workflow.go +++ b/go/vt/wrangler/workflow.go @@ -735,7 +735,7 @@ func (wr *Wrangler) deleteWorkflowVDiffData(ctx context.Context, tablet *topodat // the MySQL instance. func (wr *Wrangler) optimizeCopyStateTable(tablet *topodatapb.Tablet) { if wr.sem != nil { - if !wr.sem.TryAcquire() { + if !wr.sem.TryAcquire(1) { log.Warningf("Deferring work to optimize the copy_state table on %q due to hitting the maximum concurrent background job limit.", tablet.Alias.String()) return @@ -744,7 +744,7 @@ func (wr *Wrangler) optimizeCopyStateTable(tablet *topodatapb.Tablet) { go func() { defer func() { if wr.sem != nil { - wr.sem.Release() + wr.sem.Release(1) } }() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) diff --git a/go/vt/wrangler/wrangler.go b/go/vt/wrangler/wrangler.go index 837a1105d8a..dbb046a36b3 100644 --- a/go/vt/wrangler/wrangler.go +++ b/go/vt/wrangler/wrangler.go @@ -21,8 +21,9 @@ package wrangler import ( "context" + "golang.org/x/sync/semaphore" + "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/vtctl/grpcvtctldserver" @@ -55,7 +56,7 @@ type Wrangler struct { // DO NOT USE in production code. VExecFunc func(ctx context.Context, workflow, keyspace, query string, dryRun bool) (map[*topo.TabletInfo]*sqltypes.Result, error) // Limt the number of concurrent background goroutines if needed. - sem *sync2.Semaphore + sem *semaphore.Weighted } // New creates a new Wrangler object. From 180598158ff95fdd6f93012ef751d975242638b5 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Tue, 21 Feb 2023 08:02:55 +0100 Subject: [PATCH 2/4] Don't assume the value is a duration This can be any float, so we need to store the float bits in an atomic uint64 instead (as Go has no atomic floats). Signed-off-by: Dirkjan Bussink --- .../throttle/config/mysql_config.go | 20 +++++++++---------- .../tabletserver/throttle/throttler.go | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go b/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go index 8ade7f61c09..3e3e82adff4 100644 --- a/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go +++ b/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go @@ -17,22 +17,22 @@ import ( // MySQLClusterConfigurationSettings has the settings for a specific MySQL cluster. It derives its information // from MySQLConfigurationSettings type MySQLClusterConfigurationSettings struct { - MetricQuery string // override MySQLConfigurationSettings's, or leave empty to inherit those settings - CacheMillis int // override MySQLConfigurationSettings's, or leave empty to inherit those settings - ThrottleThreshold *atomic.Int64 // override MySQLConfigurationSettings's, or leave empty to inherit those settings - Port int // Specify if different than 3306 or if different than specified by MySQLConfigurationSettings - IgnoreHostsCount int // Number of hosts that can be skipped/ignored even on error or on exceeding thresholds - IgnoreHostsThreshold float64 // Threshold beyond which IgnoreHostsCount applies (default: 0) - HTTPCheckPort int // Specify if different than specified by MySQLConfigurationSettings. -1 to disable HTTP check - HTTPCheckPath string // Specify if different than specified by MySQLConfigurationSettings - IgnoreHosts []string // override MySQLConfigurationSettings's, or leave empty to inherit those settings + MetricQuery string // override MySQLConfigurationSettings's, or leave empty to inherit those settings + CacheMillis int // override MySQLConfigurationSettings's, or leave empty to inherit those settings + ThrottleThreshold *atomic.Uint64 // override MySQLConfigurationSettings's, or leave empty to inherit those settings + Port int // Specify if different than 3306 or if different than specified by MySQLConfigurationSettings + IgnoreHostsCount int // Number of hosts that can be skipped/ignored even on error or on exceeding thresholds + IgnoreHostsThreshold float64 // Threshold beyond which IgnoreHostsCount applies (default: 0) + HTTPCheckPort int // Specify if different than specified by MySQLConfigurationSettings. -1 to disable HTTP check + HTTPCheckPath string // Specify if different than specified by MySQLConfigurationSettings + IgnoreHosts []string // override MySQLConfigurationSettings's, or leave empty to inherit those settings } // MySQLConfigurationSettings has the general configuration for all MySQL clusters type MySQLConfigurationSettings struct { MetricQuery string CacheMillis int // optional, if defined then probe result will be cached, and future probes may use cached value - ThrottleThreshold *atomic.Int64 + ThrottleThreshold *atomic.Uint64 Port int // Specify if different than 3306; applies to all clusters IgnoreDialTCPErrors bool // Skip hosts where a metric cannot be retrieved due to TCP dial errors IgnoreHostsCount int // Number of hosts that can be skipped/ignored even on error or on exceeding thresholds diff --git a/go/vt/vttablet/tabletserver/throttle/throttler.go b/go/vt/vttablet/tabletserver/throttle/throttler.go index 78b425be0ac..bbe276dbfec 100644 --- a/go/vt/vttablet/tabletserver/throttle/throttler.go +++ b/go/vt/vttablet/tabletserver/throttle/throttler.go @@ -134,7 +134,7 @@ type Throttler struct { mysqlInventory *mysql.Inventory metricsQuery atomic.Value - MetricsThreshold atomic.Int64 + MetricsThreshold atomic.Uint64 mysqlClusterThresholds *cache.Cache aggregatedMetrics *cache.Cache @@ -205,7 +205,7 @@ func NewThrottler(env tabletenv.Env, srvTopoServer srvtopo.Server, ts *topo.Serv if throttleMetricQuery != "" { throttler.metricsQuery.Store(throttleMetricQuery) // override } - throttler.MetricsThreshold.Store(throttleThreshold.Nanoseconds()) //default + throttler.StoreMetricsThreshold(throttleThreshold.Seconds()) //default if throttleMetricThreshold != math.MaxFloat64 { throttler.StoreMetricsThreshold(throttleMetricThreshold) // override } @@ -225,7 +225,7 @@ func (throttler *Throttler) CheckIsReady() error { } func (throttler *Throttler) StoreMetricsThreshold(threshold float64) { - throttler.MetricsThreshold.Store(time.Duration(throttleMetricThreshold * float64(time.Second)).Nanoseconds()) + throttler.MetricsThreshold.Store(math.Float64bits(threshold)) } // initThrottleTabletTypes reads the user supplied throttle_tablet_types and sets these @@ -341,7 +341,7 @@ func (throttler *Throttler) applyThrottlerConfig(ctx context.Context, throttlerC } else { throttler.metricsQuery.Store(throttlerConfig.CustomQuery) } - throttler.MetricsThreshold.Store(time.Duration(throttlerConfig.Threshold * float64(time.Second)).Nanoseconds()) + throttler.StoreMetricsThreshold(throttlerConfig.Threshold) throttlerCheckAsCheckSelf = throttlerConfig.CheckAsCheckSelf if throttlerConfig.Enabled { go throttler.Enable(ctx) @@ -758,7 +758,7 @@ func (throttler *Throttler) refreshMySQLInventory(ctx context.Context) error { // config may dynamically change, but internal structure (config.Settings().Stores.MySQL.Clusters in our case) // is immutable and can only be _replaced_. Hence, it's safe to read in a goroutine: go func() { - throttler.mysqlClusterThresholds.Set(clusterName, time.Duration(clusterSettings.ThrottleThreshold.Load()).Seconds(), cache.DefaultExpiration) + throttler.mysqlClusterThresholds.Set(clusterName, math.Float64frombits(clusterSettings.ThrottleThreshold.Load()), cache.DefaultExpiration) clusterProbes := &mysql.ClusterProbes{ ClusterName: clusterName, IgnoreHostsCount: clusterSettings.IgnoreHostsCount, From 5edb96df76c261553665bb6848d6ef4ad35bbf9d Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Tue, 21 Feb 2023 10:51:40 +0100 Subject: [PATCH 3/4] Log actual error if acquiring semaphore fails Signed-off-by: Dirkjan Bussink --- go/vt/vtctl/schematools/reload.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/go/vt/vtctl/schematools/reload.go b/go/vt/vtctl/schematools/reload.go index daa9ae64960..9c9e8ef8c5e 100644 --- a/go/vt/vtctl/schematools/reload.go +++ b/go/vt/vtctl/schematools/reload.go @@ -68,11 +68,11 @@ func ReloadShard(ctx context.Context, ts *topo.Server, tmc tmclient.TabletManage defer wg.Done() if concurrency != nil { - if concurrency.Acquire(ctx, 1) != nil { + if err := concurrency.Acquire(ctx, 1); err != nil { // We timed out waiting for the semaphore. This is best-effort, so just log it and move on. logger.Warningf( - "Failed to reload schema on replica tablet %v in %v/%v (use vtctl ReloadSchema to try again): timed out waiting for concurrency", - topoproto.TabletAliasString(tablet.Alias), keyspace, shard, + "Failed to reload schema on replica tablet %v in %v/%v (use vtctl ReloadSchema to try again): timed out waiting for concurrency: %v", + topoproto.TabletAliasString(tablet.Alias), keyspace, shard, err, ) return } From ab6bda5cad53721f97a22753a084476a71508074 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Tue, 21 Feb 2023 11:27:12 +0100 Subject: [PATCH 4/4] Fix overlooked metrics threshold case Signed-off-by: Dirkjan Bussink --- go/vt/vttablet/tabletserver/tabletserver.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index c000799c0e4..f92bea76ab0 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -21,6 +21,7 @@ import ( "context" "encoding/json" "fmt" + "math" "net/http" "os" "os/signal" @@ -2003,7 +2004,7 @@ func (tsv *TabletServer) SetThrottleMetricThreshold(val float64) { // ThrottleMetricThreshold returns the throttler metric threshold func (tsv *TabletServer) ThrottleMetricThreshold() float64 { - return time.Duration(tsv.lagThrottler.MetricsThreshold.Load()).Seconds() + return math.Float64frombits(tsv.lagThrottler.MetricsThreshold.Load()) } // SetPassthroughDMLs changes the setting to pass through all DMLs