vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/twopcz.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package tabletserver
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"html/template"
    23  	"net/http"
    24  
    25  	"vitess.io/vitess/go/vt/vttablet/tabletserver/tx"
    26  
    27  	"vitess.io/vitess/go/acl"
    28  	"vitess.io/vitess/go/vt/log"
    29  )
    30  
    31  var (
    32  	gridTable = []byte(`<!DOCTYPE html>
    33  	<style type="text/css">
    34  			table.gridtable {
    35  				font-family: verdana,arial,sans-serif;
    36  				font-size: 11px;
    37  				border-width: 1px;
    38  				border-collapse: collapse; table-layout:fixed; overflow: hidden;
    39  			}
    40  			table.gridtable th {
    41  				border-width: 1px;
    42  				padding: 8px;
    43  				border-style: solid;
    44  				background-color: #dedede;
    45  				white-space: nowrap;
    46  			}
    47  			table.gridtable td {
    48  				border-width: 1px;
    49  				padding: 5px;
    50  				border-style: solid;
    51  			}
    52  			table.gridtable th {
    53  				padding-left: 2em;
    54  				padding-right: 2em;
    55  			}
    56  	</style>
    57  	`)
    58  	startTable = []byte(`
    59  	<table class="gridtable">
    60  	`)
    61  	endTable = []byte(`
    62  	</table>
    63  	`)
    64  
    65  	failedzHeader = []byte(`
    66  	<h3>Failed Transactions</h3>
    67  	<thead><tr>
    68  		<th>DTID</th>
    69  		<th>Queries</th>
    70  		<th>Time</th>
    71  		<th>Action</th>
    72  	</tr></thead>
    73  	`)
    74  	failedzRow = template.Must(template.New("failedz").Parse(`
    75  	<tr>
    76  		<td>{{.Dtid}}</td>
    77  		<td>{{range .Queries}}{{.}}<br>{{end}}</td>
    78  		<td>{{.Time}}</td>
    79  		<td><form>
    80  			<input type="hidden" name="dtid" value="{{.Dtid}}"></input>
    81  			<input type="submit" name="Action" value="Discard"></input>
    82  		</form></td>
    83  	</tr>
    84  	`))
    85  
    86  	preparedzHeader = []byte(`
    87  	<h3>Prepared Transactions</h3>
    88  	<thead><tr>
    89  		<th>DTID</th>
    90  		<th>Queries</th>
    91  		<th>Time</th>
    92  		<th>Action</th>
    93  	</tr></thead>
    94  	`)
    95  	preparedzRow = template.Must(template.New("preparedz").Parse(`
    96  	<tr>
    97  		<td>{{.Dtid}}</td>
    98  		<td>{{range .Queries}}{{.}}<br>{{end}}</td>
    99  		<td>{{.Time}}</td>
   100  		<td><form>
   101  			<input type="hidden" name="dtid" value="{{.Dtid}}"></input>
   102  			<input type="submit" name="Action" value="Rollback"></input>
   103  			<input type="submit" name="Action" value="Commit"></input>
   104  		</form></td>
   105  	</tr>
   106  	`))
   107  
   108  	distributedzHeader = []byte(`
   109  	<h3>Distributed Transactions</h3>
   110  	<thead><tr>
   111  		<th>DTID</th>
   112  		<th>State</th>
   113  		<th>Time</th>
   114  		<th>Participants</th>
   115  		<th>Action</th>
   116  	</tr></thead>
   117  	`)
   118  	distributedzRow = template.Must(template.New("distributedz").Parse(`
   119  	<tr>
   120  		<td>{{.Dtid}}</td>
   121  		<td>{{.State}}</td>
   122  		<td>{{.Created}}</td>
   123  		<td>{{range .Participants}}{{.Keyspace}}:{{.Shard}}<br>{{end}}</td>
   124  		<td><form>
   125  			<input type="hidden" name="dtid" value="{{.Dtid}}"></input>
   126  			<input type="submit" name="Action" value="Conclude"></input>
   127  		</form></td>
   128  	</tr>
   129  	`))
   130  )
   131  
   132  func twopczHandler(txe *TxExecutor, w http.ResponseWriter, r *http.Request) {
   133  	if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil {
   134  		acl.SendError(w, err)
   135  		return
   136  	}
   137  	var err error
   138  	dtid := r.FormValue("dtid")
   139  	action := r.FormValue("Action")
   140  	switch action {
   141  	case "Discard", "Rollback":
   142  		err = txe.RollbackPrepared(dtid, 0)
   143  	case "Commit":
   144  		err = txe.CommitPrepared(dtid)
   145  	case "Conclude":
   146  		err = txe.ConcludeTransaction(dtid)
   147  	}
   148  	var msg string
   149  	if action != "" {
   150  		if err != nil {
   151  			msg = fmt.Sprintf("%s(%s): %v", r.FormValue("Action"), dtid, err)
   152  		} else {
   153  			msg = fmt.Sprintf("%s(%s): completed.", r.FormValue("Action"), dtid)
   154  		}
   155  	}
   156  	distributed, prepared, failed, err := txe.ReadTwopcInflight()
   157  	if err != nil {
   158  		http.Error(w, err.Error(), http.StatusInternalServerError)
   159  		return
   160  	}
   161  	format := r.FormValue("format")
   162  	if format == "json" {
   163  		w.Header().Set("Content-Type", "application/json")
   164  		js, err := json.Marshal(struct {
   165  			Distributed      []*tx.DistributedTx
   166  			Prepared, Failed []*tx.PreparedTx
   167  		}{
   168  			Distributed: distributed,
   169  			Prepared:    prepared,
   170  			Failed:      failed,
   171  		})
   172  		if err != nil {
   173  			http.Error(w, err.Error(), http.StatusInternalServerError)
   174  			return
   175  		}
   176  		w.Header().Set("Content-Type", "application/json")
   177  		w.Write(js)
   178  		return
   179  	}
   180  
   181  	w.Write(gridTable)
   182  	w.Write([]byte("<h2>WARNING: Actions on this page can jeopardize data integrity.</h2>\n"))
   183  	if msg != "" {
   184  		fmt.Fprintln(w, msg)
   185  	}
   186  
   187  	w.Write(startTable)
   188  	w.Write(failedzHeader)
   189  	for _, row := range failed {
   190  		if err := failedzRow.Execute(w, row); err != nil {
   191  			log.Errorf("queryz: couldn't execute template: %v", err)
   192  		}
   193  	}
   194  	w.Write(endTable)
   195  
   196  	w.Write(startTable)
   197  	w.Write(preparedzHeader)
   198  	for _, row := range prepared {
   199  		if err := preparedzRow.Execute(w, row); err != nil {
   200  			log.Errorf("queryz: couldn't execute template: %v", err)
   201  		}
   202  	}
   203  	w.Write(endTable)
   204  
   205  	w.Write(startTable)
   206  	w.Write(distributedzHeader)
   207  	for _, row := range distributed {
   208  		if err := distributedzRow.Execute(w, row); err != nil {
   209  			log.Errorf("queryz: couldn't execute template: %v", err)
   210  		}
   211  	}
   212  	w.Write(endTable)
   213  }