Merge branch 'master' into log

This commit is contained in:
Alain Jobart 2015-05-05 07:04:38 -07:00
Родитель 3f52b1b058 2f21ee7a6e
Коммит d6d2619133
20 изменённых файлов: 233 добавлений и 94 удалений

Просмотреть файл

@ -13,6 +13,7 @@ angular.module('app', ['ngRoute'])
.controller('ClassController', ClassController)
.controller('LoadController', LoadController)
.controller('SubmitController', SubmitController)
.controller('SchemaManagerController', SchemaManagerController)
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/editor',{
@ -35,5 +36,9 @@ angular.module('app', ['ngRoute'])
templateUrl: "/content/submit/submit.html",
controller: "SubmitController"
})
.when('/schema-manager',{
templateUrl: "/content/schema_manager/index.html",
controller: "SchemaManagerController"
})
.otherwise({redirectTo: '/'});
}]);
}]);

Просмотреть файл

@ -6,25 +6,27 @@ license that can be found in the LICENSE file.
-->
<html data-ng-app="app">
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<head>
<base href="/" />
<meta charset="US-ASCII">
<title>VTGate schema editor</title>
</head>
<body>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<head>
<base href="/" />
<meta charset="US-ASCII">
<title>Vitess Vtctld</title>
</head>
<body>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/">Vitess</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<div id="navbar" class="navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="/dbtopo">Topology</a></li>
<li><a href="/serving_graph">Serving graph</a></li>
<li><a href="#/editor">Schema editor</a></li>
<li><a href="/vschema">Schema View</a></li>
<li><a href="#/schema-manager">Schema Manager</a></li>
{{with .ToplevelLinks}}
{{range $name, $href := .}}
<li><a href="{{$href}}">{{$name}}</a></li>
@ -34,49 +36,24 @@ license that can be found in the LICENSE file.
</div>
</div>
</nav>
<div data-ng-view></div>
<script src="https://code.jquery.com/jquery-2.1.3.js"
type="text/javascript">
</script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.js"
type="text/javascript">
</script>
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.js"
type="text/javascript">
</script>
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular-route.min.js"
type="text/javascript">
</script>
<script src="content/vindex_info.js" type="text/javascript">
</script>
<script src="content/curschema.js" type="text/javascript">
</script>
<script src="content/editor/sidebar.js" type="text/javascript">
</script>
<script src="content/editor/keyspace.js" type="text/javascript">
</script>
<script src="content/editor/class/class.js" type="text/javascript">
</script>
<script src="content/load/load.js" type="text/javascript">
</script>
<script src="content/submit/submit.js" type="text/javascript">
</script>
<script src="content/app.js" type="text/javascript">
</script>
</body>
<div class="container-fluid">
<div data-ng-view></div>
</div>
<script src="https://code.jquery.com/jquery-2.1.3.js" type="text/javascript"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.js"
type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.js"
type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular-route.min.js"
type="text/javascript"></script>
<script src="content/vindex_info.js" type="text/javascript"></script>
<script src="content/curschema.js" type="text/javascript"></script>
<script src="content/editor/sidebar.js" type="text/javascript"></script>
<script src="content/editor/keyspace.js" type="text/javascript"></script>
<script src="content/editor/class/class.js" type="text/javascript"></script>
<script src="content/load/load.js" type="text/javascript"></script>
<script src="content/submit/submit.js" type="text/javascript"></script>
<script src="content/schema_manager/index.js" type="text/javascript"></script>
<script src="content/app.js" type="text/javascript"></script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,29 @@
<div class="container">
<div class="row-fluid">
<div class="col-xs-2">
<label>Keyspaces</label>
<div class="list-group">
<a href="" class="list-group-item"
ng-class="{active:selected == keyspace}"
ng-click="$parent.selected = keyspace; selectKeyspace(keyspace)"
ng-repeat="keyspace in keyspaces">
{{keyspace}}
</a>
</div>
</div>
<div>
<textarea class="col-xs-8" rows="20" data-ng-model="schemaChanges"></textarea>
</div>
<div class="col-xs-2">
<button type="button" class="btn btn-success" data-ng-click="submitSchema()" >Submit</button>
<div ng-if="shouldShowSchemaChangeStatus">
<label>Schema Change Status</label>
<label>{{schemaStatus}}</label>
<div class="progress">
<div class="progress-bar progress-bar-success progress-bar-striped" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">
</div>
</div>
</div>
</div>
</div>
</div>

Просмотреть файл

@ -0,0 +1,43 @@
/**
* Copyright 2015, Google Inc. All rights reserved. Use of this source code is
* governed by a BSD-style license that can be found in the LICENSE file.
*/
'use strict';
function SchemaManagerController($scope, $http) {
init();
function init() {
$scope.schemaChanges = "";
$scope.selectedKeyspace = "";
$scope.shouldShowSchemaChangeStatus = false;
$scope.keyspaces = [];
$http.get('/json/Keyspaces').
success(function(data, status, headers, config) {
$scope.keyspaces = data.Keyspaces;
}).
error(function(data, status, headers, config) {
});
}
$scope.selectKeyspace = function(selectedKeyspace) {
$scope.selectedKeyspace = selectedKeyspace;
}
$scope.submitSchema = function() {
$.ajax({
type: 'POST',
url: '/json/schema-manager',
data: {"keyspace": $scope.selectedKeyspace, "data": $scope.schemaChanges},
dataType: 'json'
}).success(function(data) {
$scope.schemaStatus = data.responseText;
$scope.shouldShowSchemaChangeStatus = true;
$scope.$apply();
}).error(function(data) {
$scope.schemaStatus = data.responseText;
$scope.shouldShowSchemaChangeStatus = true;
$scope.$apply();
});
};
}

Просмотреть файл

@ -5,16 +5,21 @@ import (
"fmt"
"net/http"
"strings"
"time"
"golang.org/x/net/context"
log "github.com/golang/glog"
"github.com/youtube/vitess/go/acl"
schmgr "github.com/youtube/vitess/go/vt/schemamanager"
"github.com/youtube/vitess/go/vt/schemamanager/uihandler"
"github.com/youtube/vitess/go/vt/servenv"
"github.com/youtube/vitess/go/vt/tabletmanager/tmclient"
"github.com/youtube/vitess/go/vt/topo"
"github.com/youtube/vitess/go/vt/topotools"
"github.com/youtube/vitess/go/vt/wrangler"
// register gorpc vtgate client
_ "github.com/youtube/vitess/go/vt/vtgate/gorpcvtgateconn"
)
var (
@ -265,12 +270,10 @@ func main() {
templateLoader.ServeTemplate("serving_graph.html", servingGraph, w, r)
})
// vschema editor
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
templateLoader.ServeTemplate("index.html", indexContent, w, r)
})
// vschema editor
http.HandleFunc("/content/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, *templateDir+r.URL.Path[8:])
})
@ -475,6 +478,23 @@ func main() {
}
w.Write(result)
})
http.HandleFunc("/json/schema-manager", func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
httpError(w, "cannot parse form: %s", err)
return
}
sqlStr := r.FormValue("data")
keyspace := r.FormValue("keyspace")
shards, err := ts.GetShardNames(keyspace)
if err != nil {
httpError(w, "error getting shards for keyspace: <"+keyspace+">, error: %v", err)
}
schmgr.Run(
schmgr.NewSimepleDataSourcer(sqlStr),
schmgr.NewVtGateExecutor(
keyspace, nil, 1*time.Second),
uihandler.NewUIEventHandler(w),
shards)
})
servenv.RunDefault()
}

Просмотреть файл

@ -23,7 +23,7 @@ func TestRunSchemaChangesDataSourcerOpenFail(t *testing.T) {
dataSourcer := newFakeDataSourcer([]string{"select * from test_db"}, true, false, false)
handler := newFakeHandler()
fakeConn := newFakeVtGateConn()
exec := newFakeVtGateExecutor("localhost:12345", fakeConn)
exec := newFakeVtGateExecutor(fakeConn)
err := Run(dataSourcer, exec, handler, []string{"0", "1", "2"})
if err != errDataSourcerOpen {
t.Fatalf("data sourcer open fail, shoud get error: %v, but get error: %v",
@ -35,7 +35,7 @@ func TestRunSchemaChangesDataSourcerReadFail(t *testing.T) {
dataSourcer := newFakeDataSourcer([]string{"select * from test_db"}, false, true, false)
handler := newFakeHandler()
fakeConn := newFakeVtGateConn()
exec := newFakeVtGateExecutor("localhost:12345", fakeConn)
exec := newFakeVtGateExecutor(fakeConn)
err := Run(dataSourcer, exec, handler, []string{"0", "1", "2"})
if err != errDataSourcerRead {
t.Fatalf("data sourcer read fail, shoud get error: %v, but get error: %v",
@ -50,7 +50,7 @@ func TestRunSchemaChangesValidationFail(t *testing.T) {
dataSourcer := newFakeDataSourcer([]string{"invalid sql"}, false, false, false)
handler := newFakeHandler()
fakeConn := newFakeVtGateConn()
exec := newFakeVtGateExecutor("localhost:12345", fakeConn)
exec := newFakeVtGateExecutor(fakeConn)
err := Run(dataSourcer, exec, handler, []string{"0", "1", "2"})
if err == nil {
t.Fatalf("run schema change should fail due to executor.Open fail")
@ -61,7 +61,7 @@ func TestRunSchemaChanges(t *testing.T) {
dataSourcer := NewSimepleDataSourcer("select * from test_db;")
handler := newFakeHandler()
fakeConn := newFakeVtGateConn()
exec := newFakeVtGateExecutor("localhost:12345", fakeConn)
exec := newFakeVtGateExecutor(fakeConn)
err := Run(dataSourcer, exec, handler, []string{"0", "1", "2"})
if err != nil {
t.Fatalf("schema change should success but get error: %v", err)
@ -87,10 +87,9 @@ func newFakeVtGateConn() *fakevtgateconn.FakeVTGateConn {
return fakevtgateconn.NewFakeVTGateConn(context.Background(), "", 1*time.Second)
}
func newFakeVtGateExecutor(addr string, conn *fakevtgateconn.FakeVTGateConn) *VtGateExecutor {
func newFakeVtGateExecutor(conn *fakevtgateconn.FakeVTGateConn) *VtGateExecutor {
return NewVtGateExecutor(
"test_keyspace",
addr,
conn,
1*time.Second)
}

Просмотреть файл

@ -0,0 +1,61 @@
// Copyright 2015, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uihandler
import (
"encoding/json"
"fmt"
"net/http"
log "github.com/golang/glog"
"github.com/youtube/vitess/go/vt/schemamanager"
)
// UIEventHandler handles schema events
type UIEventHandler struct {
writer http.ResponseWriter
}
// NewUIEventHandler creates a UIEventHandler instance
func NewUIEventHandler(writer http.ResponseWriter) *UIEventHandler {
return &UIEventHandler{writer: writer}
}
// OnDataSourcerReadSuccess is no-op
func (handler *UIEventHandler) OnDataSourcerReadSuccess(sqls []string) error {
handler.writer.Write([]byte(fmt.Sprintf("OnDataSourcerReadSuccess, sqls: %v\n", sqls)))
return nil
}
// OnDataSourcerReadFail is no-op
func (handler *UIEventHandler) OnDataSourcerReadFail(err error) error {
handler.writer.Write([]byte(fmt.Sprintf("OnDataSourcerReadFail, error: %v\n", err)))
return err
}
// OnValidationSuccess is no-op
func (handler *UIEventHandler) OnValidationSuccess(sqls []string) error {
handler.writer.Write([]byte(fmt.Sprintf("OnValidationSuccess, sqls: %v\n", sqls)))
return nil
}
// OnValidationFail is no-op
func (handler *UIEventHandler) OnValidationFail(err error) error {
handler.writer.Write([]byte(fmt.Sprintf("OnValidationFail, error: %v\n", err)))
return err
}
// OnExecutorComplete is no-op
func (handler *UIEventHandler) OnExecutorComplete(result *schemamanager.ExecuteResult) error {
str, err := json.Marshal(result)
if err != nil {
log.Errorf("Failed to serialize ExecuteResult: %v", err)
return err
}
handler.writer.Write(str)
return nil
}
var _ schemamanager.EventHandler = (*UIEventHandler)(nil)

Просмотреть файл

@ -19,25 +19,22 @@ import (
// VtGateExecutor applies schema changes via VtGate
type VtGateExecutor struct {
keyspace string
conn vtgateconn.VTGateConn
vtGateAddr string
timeout time.Duration
isClosed bool
keyspace string
conn vtgateconn.VTGateConn
timeout time.Duration
isClosed bool
}
// NewVtGateExecutor creates a new VtGateExecutor instance
func NewVtGateExecutor(
keyspace string,
addr string,
conn vtgateconn.VTGateConn,
timeout time.Duration) *VtGateExecutor {
return &VtGateExecutor{
keyspace: keyspace,
vtGateAddr: addr,
conn: conn,
timeout: timeout,
isClosed: true,
keyspace: keyspace,
conn: conn,
timeout: timeout,
isClosed: true,
}
}

Просмотреть файл

@ -14,7 +14,7 @@ import (
func TestOpenVtGateExecutor(t *testing.T) {
fakeConn := newFakeVtGateConn()
exec := newFakeVtGateExecutor("localhost:12345", fakeConn)
exec := newFakeVtGateExecutor(fakeConn)
if err := exec.Open(); err != nil {
t.Fatalf("failed to call executor.Open: %v", err)
}
@ -23,7 +23,7 @@ func TestOpenVtGateExecutor(t *testing.T) {
func TestValidate(t *testing.T) {
fakeConn := newFakeVtGateConn()
exec := newFakeVtGateExecutor("localhost:12345", fakeConn)
exec := newFakeVtGateExecutor(fakeConn)
defer exec.Close()
invalidSelect := []string{"select from test_table"}
@ -56,7 +56,7 @@ func TestExecuteWithoutOpen(t *testing.T) {
shards := []string{"0", "1"}
sqls := []string{"insert into test_table values (1, 2)"}
fakeConn := newFakeVtGateConn()
exec := newFakeVtGateExecutor("localhost:12345", fakeConn)
exec := newFakeVtGateExecutor(fakeConn)
result := exec.Execute(sqls, shards)
if result.ExecutorErr == "" {
t.Fatalf("execute should fail because Execute() is being called before Open()")
@ -86,7 +86,7 @@ func TestExecuteDML(t *testing.T) {
}
}
exec := newFakeVtGateExecutor("localhost:12345", fakeConn)
exec := newFakeVtGateExecutor(fakeConn)
exec.Open()
defer exec.Close()
result := exec.Execute(invalidSqls, shards)
@ -121,7 +121,7 @@ func TestExecuteDDL(t *testing.T) {
&mproto.QueryResult{})
}
}
exec := newFakeVtGateExecutor("localhost:12345", fakeConn)
exec := newFakeVtGateExecutor(fakeConn)
exec.Open()
defer exec.Close()
result := exec.Execute(validSqls, shards)

Просмотреть файл

@ -611,7 +611,7 @@ func (fra *fakeRPCAgent) ExecuteFetch(ctx context.Context, query string, maxrows
func agentRPCTestExecuteFetch(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, ti *topo.TabletInfo) {
testExecuteFetchDbConfigName = dbconfigs.DbaConfigName
qr, err := client.ExecuteFetchAsDba(ctx, ti, testExecuteFetchQuery, testExecuteFetchMaxRows, true, true)
qr, err := client.ExecuteFetchAsDba(ctx, ti, testExecuteFetchQuery, testExecuteFetchMaxRows, true, true, false)
compareError(t, "ExecuteFetch", err, qr, testExecuteFetchResult)
testExecuteFetchDbConfigName = dbconfigs.AppConfigName
qr, err = client.ExecuteFetchAsApp(ctx, ti, testExecuteFetchQuery, testExecuteFetchMaxRows, true)
@ -619,7 +619,7 @@ func agentRPCTestExecuteFetch(ctx context.Context, t *testing.T, client tmclient
}
func agentRPCTestExecuteFetchPanic(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, ti *topo.TabletInfo) {
_, err := client.ExecuteFetchAsDba(ctx, ti, testExecuteFetchQuery, testExecuteFetchMaxRows, true, true)
_, err := client.ExecuteFetchAsDba(ctx, ti, testExecuteFetchQuery, testExecuteFetchMaxRows, true, true, false)
expectRPCWrapPanic(t, err)
_, err = client.ExecuteFetchAsApp(ctx, ti, testExecuteFetchQuery, testExecuteFetchMaxRows, true)

Просмотреть файл

@ -142,7 +142,7 @@ func (client *FakeTabletManagerClient) ApplySchema(ctx context.Context, tablet *
}
// ExecuteFetchAsDba is part of the tmclient.TabletManagerClient interface
func (client *FakeTabletManagerClient) ExecuteFetchAsDba(ctx context.Context, tablet *topo.TabletInfo, query string, maxRows int, wantFields, disableBinlogs bool) (*mproto.QueryResult, error) {
func (client *FakeTabletManagerClient) ExecuteFetchAsDba(ctx context.Context, tablet *topo.TabletInfo, query string, maxRows int, wantFields, disableBinlogs, reloadSchema bool) (*mproto.QueryResult, error) {
var qr mproto.QueryResult
return &qr, nil
}

Просмотреть файл

@ -90,6 +90,7 @@ type ExecuteFetchArgs struct {
MaxRows int
WantFields bool
DisableBinlogs bool
ReloadSchema bool
DBConfigName dbconfigs.DbConfigName
}

Просмотреть файл

@ -223,13 +223,14 @@ func (client *GoRPCTabletManagerClient) ApplySchema(ctx context.Context, tablet
}
// ExecuteFetchAsDba is part of the tmclient.TabletManagerClient interface
func (client *GoRPCTabletManagerClient) ExecuteFetchAsDba(ctx context.Context, tablet *topo.TabletInfo, query string, maxRows int, wantFields, disableBinlogs bool) (*mproto.QueryResult, error) {
func (client *GoRPCTabletManagerClient) ExecuteFetchAsDba(ctx context.Context, tablet *topo.TabletInfo, query string, maxRows int, wantFields, disableBinlogs, reloadSchema bool) (*mproto.QueryResult, error) {
var qr mproto.QueryResult
if err := client.rpcCallTablet(ctx, tablet, actionnode.TabletActionExecuteFetch, &gorpcproto.ExecuteFetchArgs{
Query: query,
MaxRows: maxRows,
WantFields: wantFields,
DisableBinlogs: disableBinlogs,
ReloadSchema: reloadSchema,
DBConfigName: dbconfigs.DbaConfigName,
}, &qr); err != nil {
return nil, err

Просмотреть файл

@ -207,6 +207,9 @@ func (tm *TabletManager) ExecuteFetch(ctx context.Context, args *gorpcproto.Exec
qr, err := tm.agent.ExecuteFetch(ctx, args.Query, args.MaxRows, args.WantFields, args.DisableBinlogs, args.DBConfigName)
if err == nil {
*reply = *qr
if args.ReloadSchema {
tm.agent.ReloadSchema(ctx)
}
}
return err
})

Просмотреть файл

@ -84,7 +84,7 @@ type TabletManagerClient interface {
ApplySchema(ctx context.Context, tablet *topo.TabletInfo, change *myproto.SchemaChange) (*myproto.SchemaChangeResult, error)
// ExecuteFetchAsDba executes a query remotely using the DBA pool
ExecuteFetchAsDba(ctx context.Context, tablet *topo.TabletInfo, query string, maxRows int, wantFields, disableBinlogs bool) (*mproto.QueryResult, error)
ExecuteFetchAsDba(ctx context.Context, tablet *topo.TabletInfo, query string, maxRows int, wantFields, disableBinlogs, reloadSchema bool) (*mproto.QueryResult, error)
// ExecuteFetchAsApp executes a query remotely using the App pool
ExecuteFetchAsApp(ctx context.Context, tablet *topo.TabletInfo, query string, maxRows int, wantFields bool) (*mproto.QueryResult, error)

Просмотреть файл

@ -973,6 +973,8 @@ func commandExecuteFetchAsDba(ctx context.Context, wr *wrangler.Wrangler, subFla
maxRows := subFlags.Int("max_rows", 10000, "maximum number of rows to allow in reset")
wantFields := subFlags.Bool("want_fields", false, "also get the field names")
disableBinlogs := subFlags.Bool("disable_binlogs", false, "disable writing to binlogs during the query")
reloadSchema := subFlags.Bool("reload_schema", false, "if this flag is true, tablet schema will be reloaded after executing given query")
if err := subFlags.Parse(args); err != nil {
return err
}
@ -985,7 +987,7 @@ func commandExecuteFetchAsDba(ctx context.Context, wr *wrangler.Wrangler, subFla
return err
}
query := subFlags.Arg(1)
qr, err := wr.ExecuteFetchAsDba(ctx, alias, query, *maxRows, *wantFields, *disableBinlogs)
qr, err := wr.ExecuteFetchAsDba(ctx, alias, query, *maxRows, *wantFields, *disableBinlogs, *reloadSchema)
if err == nil {
wr.Logger().Printf("%v\n", jscfg.ToJSON(qr))
}

Просмотреть файл

@ -540,8 +540,8 @@ func (wr *Wrangler) CopySchemaShard(ctx context.Context, srcTabletAlias topo.Tab
}
createSql := sd.ToSQLStrings()
for _, sqlLine := range createSql {
err = wr.applySqlShard(ctx, tabletInfo, sqlLine)
for i, sqlLine := range createSql {
err = wr.applySqlShard(ctx, tabletInfo, sqlLine, i == len(createSql)-1)
if err != nil {
return err
}
@ -556,7 +556,7 @@ func (wr *Wrangler) CopySchemaShard(ctx context.Context, srcTabletAlias topo.Tab
// Thus it should be used only for changes that can be applies on a live instance without causing issues;
// it shouldn't be used for anything that will require a pivot.
// The SQL statement string is expected to have {{.DatabaseName}} in place of the actual db name.
func (wr *Wrangler) applySqlShard(ctx context.Context, tabletInfo *topo.TabletInfo, change string) error {
func (wr *Wrangler) applySqlShard(ctx context.Context, tabletInfo *topo.TabletInfo, change string, reloadSchema bool) error {
filledChange, err := fillStringTemplate(change, map[string]string{"DatabaseName": tabletInfo.DbName()})
if err != nil {
return fmt.Errorf("fillStringTemplate failed: %v", err)
@ -564,7 +564,7 @@ func (wr *Wrangler) applySqlShard(ctx context.Context, tabletInfo *topo.TabletIn
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
// Need to make sure that we enable binlog, since we're only applying the statement on masters.
_, err = wr.tmc.ExecuteFetchAsDba(ctx, tabletInfo, filledChange, 0, false, false)
_, err = wr.tmc.ExecuteFetchAsDba(ctx, tabletInfo, filledChange, 0, false, false, reloadSchema)
return err
}

Просмотреть файл

@ -269,10 +269,10 @@ func (wr *Wrangler) DeleteTablet(tabletAlias topo.TabletAlias) error {
}
// ExecuteFetchAsDba executes a query remotely using the DBA pool
func (wr *Wrangler) ExecuteFetchAsDba(ctx context.Context, tabletAlias topo.TabletAlias, query string, maxRows int, wantFields, disableBinlogs bool) (*mproto.QueryResult, error) {
func (wr *Wrangler) ExecuteFetchAsDba(ctx context.Context, tabletAlias topo.TabletAlias, query string, maxRows int, wantFields, disableBinlogs bool, reloadSchema bool) (*mproto.QueryResult, error) {
ti, err := wr.ts.GetTablet(tabletAlias)
if err != nil {
return nil, err
}
return wr.tmc.ExecuteFetchAsDba(ctx, ti, query, maxRows, wantFields, disableBinlogs)
return wr.tmc.ExecuteFetchAsDba(ctx, ti, query, maxRows, wantFields, disableBinlogs, reloadSchema)
}

Просмотреть файл

@ -318,7 +318,7 @@ def get_vars(port):
# wait_for_vars will wait until we can actually get the vars from a process,
# and if var is specified, will wait until that var is in vars
def wait_for_vars(name, port, var=None):
timeout = 5.0
timeout = 10.0
while True:
v = get_vars(port)
if v and (var is None or var in v):

Просмотреть файл

@ -711,7 +711,6 @@ class TestFailures(unittest.TestCase):
def tablet_start(self, tablet, tablet_type, lameduck_period='0.5s'):
return tablet.start_vttablet(lameduck_period=lameduck_period)
# target_tablet_type=tablet_type)
def test_status_with_error(self):
"""Tests that the status page loads correctly after a VTGate error."""
@ -1081,6 +1080,7 @@ class TestFailures(unittest.TestCase):
self.replica_tablet2.wait_for_vttablet_state('SERVING')
self.replica_tablet2.kill_vttablet()
self.replica_tablet.kill_vttablet(wait=False)
time.sleep(0.1)
# send query while vttablet is in lameduck, should fail as no vttablet
try:
vtgate_conn._execute(
@ -1146,6 +1146,7 @@ class TestFailures(unittest.TestCase):
self.assertTrue((t2_query_count_after-t2_query_count_before) == 1)
# kill tablet2 and leave it in lameduck mode
self.replica_tablet2.kill_vttablet(wait=False)
time.sleep(0.1)
# send query while tablet2 is in lameduck, should retry on tablet1
tablet1_vars = utils.get_vars(self.replica_tablet.port)
t1_query_count_before = int(tablet1_vars['Queries']['TotalCount'])