-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add conclude transaction command to vtctld service #16693
Changes from all commits
aaf21e4
3c8dee3
78d55dc
69f2794
dbdb010
89d22e3
5facda3
52e191b
bb38600
3ed6b66
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
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 command | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/spf13/cobra" | ||
|
||
"vitess.io/vitess/go/cmd/vtctldclient/cli" | ||
querypb "vitess.io/vitess/go/vt/proto/query" | ||
vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata" | ||
) | ||
|
||
var ( | ||
DistributedTransaction = &cobra.Command{ | ||
Use: "DistributedTransaction <cmd>", | ||
Short: "Perform commands on distributed transaction", | ||
Args: cobra.MinimumNArgs(2), | ||
|
||
DisableFlagsInUseLine: true, | ||
} | ||
|
||
// GetUnresolvedTransactions makes an GetUnresolvedTransactions gRPC call to a vtctld. | ||
GetUnresolvedTransactions = &cobra.Command{ | ||
Use: "list <keyspace>", | ||
Short: "Retrieves unresolved transactions for the given keyspace.", | ||
Aliases: []string{"List"}, | ||
Args: cobra.ExactArgs(1), | ||
RunE: commandGetUnresolvedTransactions, | ||
|
||
DisableFlagsInUseLine: true, | ||
} | ||
|
||
// ConcludeTransaction makes a ConcludeTransaction gRPC call to a vtctld. | ||
ConcludeTransaction = &cobra.Command{ | ||
Use: "conclude <dtid> [<keyspace/shard> ...]", | ||
Short: "Concludes the unresolved transaction by rolling back the prepared transaction on each participating shard and removing the transaction metadata record.", | ||
Aliases: []string{"Conclude"}, | ||
Args: cobra.MinimumNArgs(1), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From the examples it is not entirely clear to me what the arguments to conclude will look like. But we have found it more useful to specify the parameters as flags rather than depend on For example it could be
You can decide if this works better or not ... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A transaction can span multiple keyspaces so keyspace and shard will go in pair like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not find a good way to record the participants list. |
||
RunE: commandConcludeTransaction, | ||
|
||
DisableFlagsInUseLine: true, | ||
} | ||
) | ||
|
||
type ConcludeTransactionOutput struct { | ||
Dtid string `json:"dtid"` | ||
Message string `json:"message"` | ||
Error string `json:"error,omitempty"` | ||
} | ||
|
||
const ( | ||
concludeSuccess = "Successfully concluded the distributed transaction" | ||
concludeFailure = "Failed to conclude the distributed transaction" | ||
) | ||
|
||
func commandGetUnresolvedTransactions(cmd *cobra.Command, args []string) error { | ||
cli.FinishedParsing(cmd) | ||
|
||
keyspace := cmd.Flags().Arg(0) | ||
resp, err := client.GetUnresolvedTransactions(commandCtx, | ||
&vtctldatapb.GetUnresolvedTransactionsRequest{ | ||
Keyspace: keyspace, | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
data, err := cli.MarshalJSON(resp.Transactions) | ||
if err != nil { | ||
return err | ||
} | ||
fmt.Println(string(data)) | ||
return nil | ||
} | ||
|
||
func commandConcludeTransaction(cmd *cobra.Command, args []string) error { | ||
allArgs := cmd.Flags().Args() | ||
shards, err := cli.ParseKeyspaceShards(allArgs[1:]) | ||
if err != nil { | ||
return err | ||
} | ||
cli.FinishedParsing(cmd) | ||
|
||
dtid := allArgs[0] | ||
var participants []*querypb.Target | ||
for _, shard := range shards { | ||
participants = append(participants, &querypb.Target{ | ||
Keyspace: shard.Keyspace, | ||
Shard: shard.Name, | ||
}) | ||
} | ||
output := ConcludeTransactionOutput{ | ||
Dtid: dtid, | ||
Message: concludeSuccess, | ||
} | ||
|
||
_, err = client.ConcludeTransaction(commandCtx, | ||
&vtctldatapb.ConcludeTransactionRequest{ | ||
Dtid: dtid, | ||
Participants: participants, | ||
}) | ||
if err != nil { | ||
output.Message = concludeFailure | ||
output.Error = err.Error() | ||
} | ||
|
||
data, _ := cli.MarshalJSON(output) | ||
fmt.Println(string(data)) | ||
|
||
return err | ||
} | ||
|
||
func init() { | ||
DistributedTransaction.AddCommand(GetUnresolvedTransactions) | ||
DistributedTransaction.AddCommand(ConcludeTransaction) | ||
|
||
Root.AddCommand(DistributedTransaction) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ Available Commands: | |
DeleteShards Deletes the specified shards from the topology. | ||
DeleteSrvVSchema Deletes the SrvVSchema object in the given cell. | ||
DeleteTablets Deletes tablet(s) from the topology. | ||
DistributedTransaction Perform commands on distributed transaction | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be plural? I see from the discussion below that there is just one dt per shard: is that for all users and connections? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Plural makes more sense to me too, especially for |
||
EmergencyReparentShard Reparents the shard to the new primary. Assumes the old primary is dead and not responding. | ||
ExecuteFetchAsApp Executes the given query as the App user on the remote tablet. | ||
ExecuteFetchAsDBA Executes the given query as the DBA user on the remote tablet. | ||
|
@@ -59,7 +60,6 @@ Available Commands: | |
GetTablets Looks up tablets according to filter criteria. | ||
GetThrottlerStatus Get the throttler status for the given tablet. | ||
GetTopologyPath Gets the value associated with the particular path (key) in the topology server. | ||
GetUnresolvedTransactions Retrieves unresolved transactions for the given keyspace. | ||
GetVSchema Prints a JSON representation of a keyspace's topo record. | ||
GetWorkflows Gets all vreplication workflows (Reshard, MoveTables, etc) in the given keyspace. | ||
LegacyVtctlCommand Invoke a legacy vtctlclient command. Flag parsing is best effort. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we even take in <keyspace/shard> list? Why don't we just conclude the transaction everywhere. Like the user only has one option, which is to conclude the transaction on all the shards, not on some shards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am thinking about it that if the list of keyspace/shard is not provided we will get it and then conclude on all.
This is more from if the user gets the unresolved transactions list then it knows which all shards are involved and can provide the list to conclude.
We can make the flow better. Let's do that in a follow up PR.