diff --git a/changelog/22.0/22.0.0/summary.md b/changelog/22.0/22.0.0/summary.md
index d21acf48a30..ebc0c485fc1 100644
--- a/changelog/22.0/22.0.0/summary.md
+++ b/changelog/22.0/22.0.0/summary.md
@@ -3,9 +3,13 @@
### Table of Contents
- **[Major Changes](#major-changes)**
+ - **[Deprecations and Deletions](#deprecations-and-deletions)**
+ - [Deprecated VTTablet Flags](#vttablet-flags)
- **[RPC Changes](#rpc-changes)**
- **[Prefer not promoting a replica that is currently taking a backup](#reparents-prefer-not-backing-up)**
- **[VTOrc Config File Changes](#vtorc-config-file-changes)**
+- **[Minor Changes](#minor-changes)**
+ - **[VTTablet Flags](#flags-vttablet)**
## Major Changes
@@ -16,6 +20,12 @@ These are the RPC changes made in this release -
1. `GetTransactionInfo` RPC has been added to both `VtctldServer`, and `TabletManagerClient` interface. These RPCs are used to fecilitate the users in reading the state of an unresolved distributed transaction. This can be useful in debugging what went wrong and how to fix the problem.
+### Deprecations and Deletions
+
+#### Deprecated VTTablet Flags
+
+- `twopc_enable` flag is deprecated. Usage of TwoPC commit will be determined by the `transaction_mode` set on VTGate via flag or session variable.
+
### Prefer not promoting a replica that is currently taking a backup
Emergency reparents now prefer not promoting replicas that are currently taking backups with a backup engine other than
@@ -48,3 +58,12 @@ The following fields can be dynamically changed -
13. `change-tablets-with-errant-gtid-to-drained`
To upgrade to the newer version of the configuration file, first switch to using the flags in your current deployment before upgrading. Then you can switch to using the configuration file in the newer release.
+
+
+## Minor Changes
+
+#### VTTablet Flags
+
+- `twopc_abandon_age` flag now supports values in the time.Duration format (e.g., 1s, 2m, 1h).
+While the flag will continue to accept float values (interpreted as seconds) for backward compatibility,
+**float inputs are deprecated** and will be removed in a future release.
diff --git a/go/flags/endtoend/vtcombo.txt b/go/flags/endtoend/vtcombo.txt
index c10d045ecbd..7348fcf1753 100644
--- a/go/flags/endtoend/vtcombo.txt
+++ b/go/flags/endtoend/vtcombo.txt
@@ -395,8 +395,7 @@ Flags:
--transaction_limit_per_user float Maximum number of transactions a single user is allowed to use at any time, represented as fraction of -transaction_cap. (default 0.4)
--transaction_mode string SINGLE: disallow multi-db transactions, MULTI: allow multi-db transactions with best effort commit, TWOPC: allow multi-db transactions with 2pc commit (default "MULTI")
--truncate-error-len int truncate errors sent to client if they are longer than this value (0 means do not truncate)
- --twopc_abandon_age float time in seconds. Any unresolved transaction older than this time will be sent to the coordinator to be resolved.
- --twopc_enable if the flag is on, 2pc is enabled. Other 2pc flags must be supplied.
+ --twopc_abandon_age time.Duration Any unresolved transaction older than this time will be sent to the coordinator to be resolved. NOTE: Providing time as seconds (float64) is deprecated. Use time.Duration format (e.g., '1s', '2m', '1h'). (default 15m0s)
--tx-throttler-config string Synonym to -tx_throttler_config (default "target_replication_lag_sec:2 max_replication_lag_sec:10 initial_rate:100 max_increase:1 emergency_decrease:0.5 min_duration_between_increases_sec:40 max_duration_between_increases_sec:62 min_duration_between_decreases_sec:20 spread_backlog_across_sec:20 age_bad_rate_after_sec:180 bad_rate_increase:0.1 max_rate_approach_threshold:0.9")
--tx-throttler-default-priority int Default priority assigned to queries that lack priority information (default 100)
--tx-throttler-dry-run If present, the transaction throttler only records metrics about requests received and throttled, but does not actually throttle any requests.
diff --git a/go/flags/endtoend/vttablet.txt b/go/flags/endtoend/vttablet.txt
index f79db05f327..e4c6fde66af 100644
--- a/go/flags/endtoend/vttablet.txt
+++ b/go/flags/endtoend/vttablet.txt
@@ -395,8 +395,7 @@ Flags:
--transaction_limit_by_subcomponent Include CallerID.subcomponent when considering who the user is for the purpose of transaction limit.
--transaction_limit_by_username Include VTGateCallerID.username when considering who the user is for the purpose of transaction limit. (default true)
--transaction_limit_per_user float Maximum number of transactions a single user is allowed to use at any time, represented as fraction of -transaction_cap. (default 0.4)
- --twopc_abandon_age float time in seconds. Any unresolved transaction older than this time will be sent to the coordinator to be resolved.
- --twopc_enable if the flag is on, 2pc is enabled. Other 2pc flags must be supplied.
+ --twopc_abandon_age time.Duration Any unresolved transaction older than this time will be sent to the coordinator to be resolved. NOTE: Providing time as seconds (float64) is deprecated. Use time.Duration format (e.g., '1s', '2m', '1h'). (default 15m0s)
--tx-throttler-config string Synonym to -tx_throttler_config (default "target_replication_lag_sec:2 max_replication_lag_sec:10 initial_rate:100 max_increase:1 emergency_decrease:0.5 min_duration_between_increases_sec:40 max_duration_between_increases_sec:62 min_duration_between_decreases_sec:20 spread_backlog_across_sec:20 age_bad_rate_after_sec:180 bad_rate_increase:0.1 max_rate_approach_threshold:0.9")
--tx-throttler-default-priority int Default priority assigned to queries that lack priority information (default 100)
--tx-throttler-dry-run If present, the transaction throttler only records metrics about requests received and throttled, but does not actually throttle any requests.
diff --git a/go/flagutil/float_to_duration.go b/go/flagutil/float_to_duration.go
new file mode 100644
index 00000000000..fe07d42bfaa
--- /dev/null
+++ b/go/flagutil/float_to_duration.go
@@ -0,0 +1,71 @@
+/*
+Copyright 2024 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 flagutil
+
+import (
+ "errors"
+ "strconv"
+ "time"
+
+ "github.com/spf13/pflag"
+)
+
+// FloatOrDuration is a flag that can be set with either a float64 (interpreted as seconds) or a time.Duration
+// The parsed value is stored in the Duration field, and the target pointer is updated with the parsed value
+type FloatOrDuration struct {
+ Target *time.Duration // Pointer to the external duration
+ Duration time.Duration // Stores the current parsed value
+}
+
+// String returns the current value as a string
+func (f *FloatOrDuration) String() string {
+ return f.Duration.String()
+}
+
+// Set parses the input and updates the duration
+func (f *FloatOrDuration) Set(value string) error {
+ // Try to parse as float64 first (interpreted as seconds)
+ if floatVal, err := strconv.ParseFloat(value, 64); err == nil {
+ f.Duration = time.Duration(floatVal * float64(time.Second))
+ *f.Target = f.Duration // Update the target pointer
+ return nil
+ }
+
+ // Try to parse as time.Duration
+ if duration, err := time.ParseDuration(value); err == nil {
+ f.Duration = duration
+ *f.Target = f.Duration // Update the target pointer
+ return nil
+ }
+
+ return errors.New("value must be either a float64 (interpreted as seconds) or a valid time.Duration")
+}
+
+// Type returns the type description
+func (f *FloatOrDuration) Type() string {
+ return "time.Duration"
+}
+
+// FloatDuration defines a flag with the specified name, default value, and usage string and binds it to a time.Duration variable.
+func FloatDuration(fs *pflag.FlagSet, p *time.Duration, name string, defaultValue time.Duration, usage string) {
+ *p = defaultValue
+ fd := FloatOrDuration{
+ Target: p,
+ Duration: defaultValue,
+ }
+ fs.Var(&fd, name, usage)
+}
diff --git a/go/flagutil/float_to_duration_test.go b/go/flagutil/float_to_duration_test.go
new file mode 100644
index 00000000000..50b3a36e94a
--- /dev/null
+++ b/go/flagutil/float_to_duration_test.go
@@ -0,0 +1,104 @@
+/*
+Copyright 2024 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 flagutil
+
+import (
+ "testing"
+ "time"
+
+ "github.com/spf13/pflag"
+ "github.com/stretchr/testify/assert"
+)
+
+// TestFloatOrDuration_ValidFloat64Input verifies that a float64 input
+// (representing seconds) is correctly converted to a time.Duration.
+func TestFloatOrDuration_ValidFloat64Input(t *testing.T) {
+ var duration time.Duration
+ fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
+
+ FloatDuration(fs, &duration, "test_flag", 10*time.Second, "Test flag")
+ err := fs.Parse([]string{"--test_flag=2"})
+ assert.NoError(t, err)
+ assert.Equal(t, 2*time.Second, duration)
+}
+
+// TestFloatOrDuration_ValidDurationInput verifies that a valid time.Duration
+// input (e.g., "1m30s") is parsed and stored correctly.
+func TestFloatOrDuration_ValidDurationInput(t *testing.T) {
+ var duration time.Duration
+ fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
+
+ FloatDuration(fs, &duration, "test_flag", 10*time.Second, "Test flag")
+ err := fs.Parse([]string{"--test_flag=1m30s"})
+ assert.NoError(t, err)
+ assert.Equal(t, 90*time.Second, duration)
+}
+
+// TestFloatOrDuration_DefaultValue ensures that the default value is correctly
+// assigned to the duration when the flag is not provided.
+func TestFloatOrDuration_DefaultValue(t *testing.T) {
+ var duration time.Duration
+ fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
+
+ defaultValue := 15 * time.Second
+ FloatDuration(fs, &duration, "test_flag", defaultValue, "Test flag")
+ err := fs.Parse([]string{})
+ assert.NoError(t, err)
+ assert.Equal(t, defaultValue, duration)
+}
+
+// TestFloatOrDuration_InvalidInput verifies that an invalid input string
+// results in an appropriate error.
+func TestFloatOrDuration_InvalidInput(t *testing.T) {
+ var duration time.Duration
+ fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
+
+ FloatDuration(fs, &duration, "test_flag", 10*time.Second, "Test flag")
+ err := fs.Parse([]string{"--test_flag=invalid"})
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "value must be either a float64 (interpreted as seconds) or a valid time.Duration")
+}
+
+// TestFloatOrDuration_MultipleFlags ensures that multiple FloatDuration flags
+// can coexist and maintain independent values.
+func TestFloatOrDuration_MultipleFlags(t *testing.T) {
+ var duration1, duration2 time.Duration
+ fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
+
+ FloatDuration(fs, &duration1, "flag1", 10*time.Second, "First test flag")
+ FloatDuration(fs, &duration2, "flag2", 20*time.Second, "Second test flag")
+
+ err := fs.Parse([]string{"--flag1=2.5", "--flag2=1m"})
+ assert.NoError(t, err)
+ assert.Equal(t, 2500*time.Millisecond, duration1)
+ assert.Equal(t, 1*time.Minute, duration2)
+}
+
+// TestFloatOrDuration_HelpMessage verifies that the help message includes
+// the correct flag name, description, and default value.
+func TestFloatOrDuration_HelpMessage(t *testing.T) {
+ var duration time.Duration
+ fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
+
+ defaultValue := 10 * time.Second
+ FloatDuration(fs, &duration, "test_flag", defaultValue, "Test flag with default value")
+
+ helpOutput := fs.FlagUsages()
+ assert.Contains(t, helpOutput, "--test_flag time.Duration")
+ assert.Contains(t, helpOutput, "Test flag with default value")
+ assert.Contains(t, helpOutput, "(default 10s)")
+}
diff --git a/go/test/endtoend/tabletmanager/main_test.go b/go/test/endtoend/tabletmanager/main_test.go
index 3c2eb68df5e..019c00d5b84 100644
--- a/go/test/endtoend/tabletmanager/main_test.go
+++ b/go/test/endtoend/tabletmanager/main_test.go
@@ -105,7 +105,6 @@ func TestMain(m *testing.M) {
"--heartbeat_enable",
"--health_check_interval", tabletHealthcheckRefreshInterval.String(),
"--unhealthy_threshold", tabletUnhealthyThreshold.String(),
- "--twopc_enable",
"--twopc_abandon_age", "200",
}
diff --git a/go/test/endtoend/transaction/twopc/fuzz/main_test.go b/go/test/endtoend/transaction/twopc/fuzz/main_test.go
index 15574c8d072..f63dbd1ae87 100644
--- a/go/test/endtoend/transaction/twopc/fuzz/main_test.go
+++ b/go/test/endtoend/transaction/twopc/fuzz/main_test.go
@@ -70,7 +70,6 @@ func TestMain(m *testing.M) {
"--tablet_refresh_interval", "2s",
)
clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs,
- "--twopc_enable",
"--twopc_abandon_age", "1",
"--migration_check_interval", "2s",
)
diff --git a/go/test/endtoend/transaction/twopc/main_test.go b/go/test/endtoend/transaction/twopc/main_test.go
index 631b29647c9..91c8e1ed444 100644
--- a/go/test/endtoend/transaction/twopc/main_test.go
+++ b/go/test/endtoend/transaction/twopc/main_test.go
@@ -82,7 +82,6 @@ func TestMain(m *testing.M) {
"--grpc_use_effective_callerid",
)
clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs,
- "--twopc_enable",
"--twopc_abandon_age", "1",
"--queryserver-config-transaction-cap", "3",
"--queryserver-config-transaction-timeout", "400s",
diff --git a/go/test/endtoend/transaction/twopc/metric/main_test.go b/go/test/endtoend/transaction/twopc/metric/main_test.go
index 73cc380a900..b0a5dc4fb1a 100644
--- a/go/test/endtoend/transaction/twopc/metric/main_test.go
+++ b/go/test/endtoend/transaction/twopc/metric/main_test.go
@@ -69,7 +69,6 @@ func TestMain(m *testing.M) {
"--grpc_use_effective_callerid",
)
clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs,
- "--twopc_enable",
"--twopc_abandon_age", "1",
"--queryserver-config-transaction-cap", "100",
)
diff --git a/go/test/endtoend/transaction/twopc/stress/main_test.go b/go/test/endtoend/transaction/twopc/stress/main_test.go
index 76cd05df50a..ec2392f6043 100644
--- a/go/test/endtoend/transaction/twopc/stress/main_test.go
+++ b/go/test/endtoend/transaction/twopc/stress/main_test.go
@@ -70,7 +70,6 @@ func TestMain(m *testing.M) {
"--tablet_refresh_interval", "2s",
)
clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs,
- "--twopc_enable",
"--twopc_abandon_age", "1",
"--migration_check_interval", "2s",
"--onterm_timeout", "1s",
diff --git a/go/test/endtoend/transaction/tx_test.go b/go/test/endtoend/transaction/tx_test.go
index 753dcfb46bd..0671d0d7136 100644
--- a/go/test/endtoend/transaction/tx_test.go
+++ b/go/test/endtoend/transaction/tx_test.go
@@ -57,7 +57,6 @@ func TestMain(m *testing.M) {
clusterInstance.VtgateGrpcPort = clusterInstance.GetAndReservePort()
// Set extra tablet args for twopc
clusterInstance.VtTabletExtraArgs = []string{
- "--twopc_enable",
"--twopc_abandon_age", "3600",
}
diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go
index 38a3ca7bbb3..65cd1a96181 100644
--- a/go/vt/vtexplain/vtexplain_vttablet.go
+++ b/go/vt/vtexplain/vtexplain_vttablet.go
@@ -22,6 +22,7 @@ import (
"reflect"
"strings"
"sync"
+ "time"
"vitess.io/vitess/go/stats"
"vitess.io/vitess/go/vt/sidecardb"
@@ -113,8 +114,7 @@ func (vte *VTExplain) newTablet(ctx context.Context, env *vtenv.Environment, opt
config := tabletenv.NewCurrentConfig()
config.TrackSchemaVersions = false
if opts.ExecutionMode == ModeTwoPC {
- config.TwoPCAbandonAge = 1.0
- config.TwoPCEnable = true
+ config.TwoPCAbandonAge = 1 * time.Second
}
config.EnableOnlineDDL = false
config.EnableTableGC = false
diff --git a/go/vt/vttablet/endtoend/connecttcp/main_test.go b/go/vt/vttablet/endtoend/connecttcp/main_test.go
index 9d52b1287a1..43be05893cc 100644
--- a/go/vt/vttablet/endtoend/connecttcp/main_test.go
+++ b/go/vt/vttablet/endtoend/connecttcp/main_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"os"
"testing"
+ "time"
"vitess.io/vitess/go/mysql"
vttestpb "vitess.io/vitess/go/vt/proto/vttest"
@@ -86,8 +87,7 @@ func TestMain(m *testing.M) {
defer cancel()
config := tabletenv.NewDefaultConfig()
- config.TwoPCEnable = true
- config.TwoPCAbandonAge = 1
+ config.TwoPCAbandonAge = 1 * time.Second
if err := framework.StartCustomServer(ctx, connParams, connAppDebugParams, cluster.DbName(), config); err != nil {
fmt.Fprintf(os.Stderr, "%v", err)
diff --git a/go/vt/vttablet/endtoend/framework/server.go b/go/vt/vttablet/endtoend/framework/server.go
index 0124bb992ba..3374aadb450 100644
--- a/go/vt/vttablet/endtoend/framework/server.go
+++ b/go/vt/vttablet/endtoend/framework/server.go
@@ -108,8 +108,7 @@ func StartCustomServer(ctx context.Context, connParams, connAppDebugParams mysql
func StartServer(ctx context.Context, connParams, connAppDebugParams mysql.ConnParams, dbName string) error {
config := tabletenv.NewDefaultConfig()
config.StrictTableACL = true
- config.TwoPCEnable = true
- config.TwoPCAbandonAge = 1
+ config.TwoPCAbandonAge = 1 * time.Second
config.HotRowProtection.Mode = tabletenv.Enable
config.TrackSchemaVersions = true
config.GracePeriods.Shutdown = 2 * time.Second
diff --git a/go/vt/vttablet/endtoend/twopc/main_test.go b/go/vt/vttablet/endtoend/twopc/main_test.go
index 090751503d4..3b68ce273e1 100644
--- a/go/vt/vttablet/endtoend/twopc/main_test.go
+++ b/go/vt/vttablet/endtoend/twopc/main_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"os"
"testing"
+ "time"
"vitess.io/vitess/go/mysql"
"vitess.io/vitess/go/vt/vttablet/endtoend/framework"
@@ -83,8 +84,7 @@ func TestMain(m *testing.M) {
defer cancel()
config := tabletenv.NewDefaultConfig()
- config.TwoPCEnable = true
- config.TwoPCAbandonAge = 1
+ config.TwoPCAbandonAge = 1 * time.Second
err := framework.StartCustomServer(ctx, connParams, connAppDebugParams, cluster.DbName(), config)
if err != nil {
fmt.Fprintf(os.Stderr, "%v", err)
diff --git a/go/vt/vttablet/tabletserver/dt_executor_test.go b/go/vt/vttablet/tabletserver/dt_executor_test.go
index d5322f352f9..b21667392d6 100644
--- a/go/vt/vttablet/tabletserver/dt_executor_test.go
+++ b/go/vt/vttablet/tabletserver/dt_executor_test.go
@@ -705,8 +705,10 @@ func TestNoTwopc(t *testing.T) {
want := "2pc is not enabled"
for _, tc := range testcases {
- err := tc.fun()
- require.EqualError(t, err, want)
+ t.Run(tc.desc, func(t *testing.T) {
+ err := tc.fun()
+ require.EqualError(t, err, want)
+ })
}
}
diff --git a/go/vt/vttablet/tabletserver/query_executor_test.go b/go/vt/vttablet/tabletserver/query_executor_test.go
index 78daad2e616..ade79ecaef5 100644
--- a/go/vt/vttablet/tabletserver/query_executor_test.go
+++ b/go/vt/vttablet/tabletserver/query_executor_test.go
@@ -1514,20 +1514,17 @@ func newTestTabletServer(ctx context.Context, flags executorFlags, db *fakesqldb
} else {
cfg.StrictTableACL = false
}
- if flags&noTwopc > 0 {
- cfg.TwoPCEnable = false
- } else {
- cfg.TwoPCEnable = true
- }
if flags&disableOnlineDDL > 0 {
cfg.EnableOnlineDDL = false
} else {
cfg.EnableOnlineDDL = true
}
- if flags&shortTwopcAge > 0 {
- cfg.TwoPCAbandonAge = 0.5
+ if flags&noTwopc > 0 {
+ cfg.TwoPCAbandonAge = 0
+ } else if flags&shortTwopcAge > 0 {
+ cfg.TwoPCAbandonAge = 500 * time.Millisecond
} else {
- cfg.TwoPCAbandonAge = 10
+ cfg.TwoPCAbandonAge = 10 * time.Second
}
if flags&smallResultSize > 0 {
cfg.Oltp.MaxRows = 2
diff --git a/go/vt/vttablet/tabletserver/tabletenv/config.go b/go/vt/vttablet/tabletserver/tabletenv/config.go
index 158f40d5202..994999f2368 100644
--- a/go/vt/vttablet/tabletserver/tabletenv/config.go
+++ b/go/vt/vttablet/tabletserver/tabletenv/config.go
@@ -156,8 +156,12 @@ func registerTabletEnvFlags(fs *pflag.FlagSet) {
fs.BoolVar(¤tConfig.WatchReplication, "watch_replication_stream", false, "When enabled, vttablet will stream the MySQL replication stream from the local server, and use it to update schema when it sees a DDL.")
fs.BoolVar(¤tConfig.TrackSchemaVersions, "track_schema_versions", false, "When enabled, vttablet will store versions of schemas at each position that a DDL is applied and allow retrieval of the schema corresponding to a position")
fs.Int64Var(¤tConfig.SchemaVersionMaxAgeSeconds, "schema-version-max-age-seconds", 0, "max age of schema version records to kept in memory by the vreplication historian")
- fs.BoolVar(¤tConfig.TwoPCEnable, "twopc_enable", defaultConfig.TwoPCEnable, "if the flag is on, 2pc is enabled. Other 2pc flags must be supplied.")
- SecondsVar(fs, ¤tConfig.TwoPCAbandonAge, "twopc_abandon_age", defaultConfig.TwoPCAbandonAge, "time in seconds. Any unresolved transaction older than this time will be sent to the coordinator to be resolved.")
+
+ _ = fs.Bool("twopc_enable", true, "TwoPC is enabled")
+ _ = fs.MarkDeprecated("twopc_enable", "TwoPC is always enabled, the transaction abandon age can be configured")
+ flagutil.FloatDuration(fs, ¤tConfig.TwoPCAbandonAge, "twopc_abandon_age", defaultConfig.TwoPCAbandonAge,
+ "Any unresolved transaction older than this time will be sent to the coordinator to be resolved. NOTE: Providing time as seconds (float64) is deprecated. Use time.Duration format (e.g., '1s', '2m', '1h').")
+
// Tx throttler config
flagutil.DualFormatBoolVar(fs, ¤tConfig.EnableTxThrottler, "enable_tx_throttler", defaultConfig.EnableTxThrottler, "If true replication-lag-based throttling on transactions will be enabled.")
flagutil.DualFormatVar(fs, currentConfig.TxThrottlerConfig, "tx_throttler_config", "The configuration of the transaction throttler as a text-formatted throttlerdata.Configuration protocol buffer message.")
@@ -331,12 +335,11 @@ type TabletConfig struct {
ExternalConnections map[string]*dbconfigs.DBConfigs `json:"externalConnections,omitempty"`
- SanitizeLogMessages bool `json:"-"`
- StrictTableACL bool `json:"-"`
- EnableTableACLDryRun bool `json:"-"`
- TableACLExemptACL string `json:"-"`
- TwoPCEnable bool `json:"-"`
- TwoPCAbandonAge Seconds `json:"-"`
+ SanitizeLogMessages bool `json:"-"`
+ StrictTableACL bool `json:"-"`
+ EnableTableACLDryRun bool `json:"-"`
+ TableACLExemptACL string `json:"-"`
+ TwoPCAbandonAge time.Duration `json:"-"`
EnableTxThrottler bool `json:"-"`
TxThrottlerConfig *TxThrottlerConfigFlag `json:"-"`
@@ -1054,6 +1057,8 @@ var defaultConfig = TabletConfig{
},
EnablePerWorkloadTableMetrics: false,
+
+ TwoPCAbandonAge: 15 * time.Minute,
}
// defaultTxThrottlerConfig returns the default TxThrottlerConfigFlag object based on
diff --git a/go/vt/vttablet/tabletserver/tabletenv/seconds.go b/go/vt/vttablet/tabletserver/tabletenv/seconds.go
deleted file mode 100644
index ae11121f2de..00000000000
--- a/go/vt/vttablet/tabletserver/tabletenv/seconds.go
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-Copyright 2020 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 tabletenv
-
-import (
- "time"
-
- "github.com/spf13/pflag"
-)
-
-// Seconds provides convenience functions for extracting
-// duration from float64 seconds values.
-type Seconds float64
-
-// SecondsVar is like a flag.Float64Var, but it works for Seconds.
-func SecondsVar(fs *pflag.FlagSet, p *Seconds, name string, value Seconds, usage string) {
- fs.Float64Var((*float64)(p), name, float64(value), usage)
-}
-
-// Get converts Seconds to time.Duration
-func (s Seconds) Get() time.Duration {
- return time.Duration(s * Seconds(1*time.Second))
-}
-
-// Set sets the value from time.Duration
-func (s *Seconds) Set(d time.Duration) {
- *s = Seconds(d) / Seconds(1*time.Second)
-}
diff --git a/go/vt/vttablet/tabletserver/tabletenv/seconds_test.go b/go/vt/vttablet/tabletserver/tabletenv/seconds_test.go
deleted file mode 100644
index dc09a3f419f..00000000000
--- a/go/vt/vttablet/tabletserver/tabletenv/seconds_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-Copyright 2020 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 tabletenv
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
- "vitess.io/vitess/go/yaml2"
-)
-
-func TestSecondsYaml(t *testing.T) {
- type testSecond struct {
- Value Seconds `json:"value"`
- }
-
- ts := testSecond{
- Value: 1,
- }
- gotBytes, err := yaml2.Marshal(&ts)
- require.NoError(t, err)
- wantBytes := "value: 1\n"
- assert.Equal(t, wantBytes, string(gotBytes))
-
- var gotts testSecond
- err = yaml2.Unmarshal([]byte(wantBytes), &gotts)
- require.NoError(t, err)
- assert.Equal(t, ts, gotts)
-}
-
-func TestSecondsGetSet(t *testing.T) {
- var val Seconds
- val.Set(2 * time.Second)
- assert.Equal(t, Seconds(2), val)
- assert.Equal(t, 2*time.Second, val.Get())
-}
diff --git a/go/vt/vttablet/tabletserver/tx_engine.go b/go/vt/vttablet/tabletserver/tx_engine.go
index b6e0e69b86d..d0ca4ec498c 100644
--- a/go/vt/vttablet/tabletserver/tx_engine.go
+++ b/go/vt/vttablet/tabletserver/tx_engine.go
@@ -116,20 +116,19 @@ func NewTxEngine(env tabletenv.Env, dxNotifier func()) *TxEngine {
te.txPool = NewTxPool(env, limiter)
// We initially allow twoPC (handles vttablet restarts).
// We will disallow them for a few reasons -
- // 1. when a new tablet is promoted if semi-sync is turned off.
+ // 1. When a new tablet is promoted if semi-sync is turned off.
// 2. TabletControls have been set by a Resharding workflow.
te.twopcAllowed = make([]bool, TwoPCAllowed_Len)
for idx := range te.twopcAllowed {
te.twopcAllowed[idx] = true
}
- te.twopcEnabled = config.TwoPCEnable
- if te.twopcEnabled {
- if config.TwoPCAbandonAge <= 0 {
- log.Error("2PC abandon age not specified: Disabling 2PC")
- te.twopcEnabled = false
- }
+ te.twopcEnabled = true
+ if config.TwoPCAbandonAge <= 0 {
+ log.Error("2PC abandon age not specified: Disabling 2PC")
+ te.twopcEnabled = false
}
- te.abandonAge = config.TwoPCAbandonAge.Get()
+
+ te.abandonAge = config.TwoPCAbandonAge
te.ticks = timer.NewTimer(te.abandonAge / 2)
// Set the prepared pool capacity to something lower than
diff --git a/go/vt/vttablet/tabletserver/tx_engine_test.go b/go/vt/vttablet/tabletserver/tx_engine_test.go
index f4dd0596691..cba7bf86e8f 100644
--- a/go/vt/vttablet/tabletserver/tx_engine_test.go
+++ b/go/vt/vttablet/tabletserver/tx_engine_test.go
@@ -613,8 +613,7 @@ func TestCheckReceivedError(t *testing.T) {
cfg := tabletenv.NewDefaultConfig()
cfg.DB = newDBConfigs(db)
env := tabletenv.NewEnv(vtenv.NewTestEnv(), cfg, "TabletServerTest")
- env.Config().TwoPCEnable = true
- env.Config().TwoPCAbandonAge = 5
+ env.Config().TwoPCAbandonAge = 5 * time.Second
te := NewTxEngine(env, nil)
te.AcceptReadWrite()
@@ -791,8 +790,7 @@ func TestPrepareTx(t *testing.T) {
db.AddRejectedQuery("retryable query", sqlerror.NewSQLError(sqlerror.CRConnectionError, "", "Retryable error"))
cfg := tabletenv.NewDefaultConfig()
cfg.DB = newDBConfigs(db)
- cfg.TwoPCEnable = true
- cfg.TwoPCAbandonAge = 200
+ cfg.TwoPCAbandonAge = 200 * time.Second
te := NewTxEngine(tabletenv.NewEnv(vtenv.NewTestEnv(), cfg, "TabletServerTest"), nil)
te.AcceptReadWrite()
db.ResetQueryLog()